1 //
2 // Copyright 2018 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // vk_helpers:
7 // Helper utility classes that manage Vulkan resources.
8
9 #include "libANGLE/renderer/vulkan/vk_helpers.h"
10
11 #include "common/aligned_memory.h"
12 #include "common/utilities.h"
13 #include "common/vulkan/vk_headers.h"
14 #include "image_util/loadimage.h"
15 #include "libANGLE/Context.h"
16 #include "libANGLE/Display.h"
17 #include "libANGLE/renderer/driver_utils.h"
18 #include "libANGLE/renderer/renderer_utils.h"
19 #include "libANGLE/renderer/vulkan/BufferVk.h"
20 #include "libANGLE/renderer/vulkan/ContextVk.h"
21 #include "libANGLE/renderer/vulkan/DisplayVk.h"
22 #include "libANGLE/renderer/vulkan/FramebufferVk.h"
23 #include "libANGLE/renderer/vulkan/RenderTargetVk.h"
24 #include "libANGLE/renderer/vulkan/android/vk_android_utils.h"
25 #include "libANGLE/renderer/vulkan/vk_ref_counted_event.h"
26 #include "libANGLE/renderer/vulkan/vk_renderer.h"
27 #include "libANGLE/renderer/vulkan/vk_utils.h"
28
29 namespace rx
30 {
31 namespace vk
32 {
33 namespace
34 {
35 // During descriptorSet cache eviction, we keep it in the cache only if it is recently used. If it
36 // has not been used in the past kDescriptorSetCacheRetireAge frames, it will be evicted.
37 constexpr uint32_t kDescriptorSetCacheRetireAge = 10;
38
39 // ANGLE_robust_resource_initialization requires color textures to be initialized to zero.
40 constexpr VkClearColorValue kRobustInitColorValue = {{0, 0, 0, 0}};
41 // When emulating a texture, we want the emulated channels to be 0, with alpha 1.
42 constexpr VkClearColorValue kEmulatedInitColorValue = {{0, 0, 0, 1.0f}};
43 // ANGLE_robust_resource_initialization requires depth to be initialized to 1 and stencil to 0.
44 // We are fine with these values for emulated depth/stencil textures too.
45 constexpr VkClearDepthStencilValue kRobustInitDepthStencilValue = {1.0f, 0};
46
47 constexpr VkImageAspectFlags kDepthStencilAspects =
48 VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_DEPTH_BIT;
49
50 constexpr angle::PackedEnumMap<PipelineStage, VkPipelineStageFlagBits> kPipelineStageFlagBitMap = {
51 {PipelineStage::TopOfPipe, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT},
52 {PipelineStage::DrawIndirect, VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT},
53 {PipelineStage::VertexInput, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT},
54 {PipelineStage::VertexShader, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT},
55 {PipelineStage::TessellationControl, VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT},
56 {PipelineStage::TessellationEvaluation, VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT},
57 {PipelineStage::GeometryShader, VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT},
58 {PipelineStage::TransformFeedback, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT},
59 {PipelineStage::FragmentShadingRate,
60 VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR},
61 {PipelineStage::EarlyFragmentTest, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT},
62 {PipelineStage::FragmentShader, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT},
63 {PipelineStage::LateFragmentTest, VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT},
64 {PipelineStage::ColorAttachmentOutput, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT},
65 {PipelineStage::ComputeShader, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT},
66 {PipelineStage::Transfer, VK_PIPELINE_STAGE_TRANSFER_BIT},
67 {PipelineStage::BottomOfPipe, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT},
68 {PipelineStage::Host, VK_PIPELINE_STAGE_HOST_BIT}};
69
70 constexpr gl::ShaderMap<PipelineStage> kPipelineStageShaderMap = {
71 {gl::ShaderType::Vertex, PipelineStage::VertexShader},
72 {gl::ShaderType::TessControl, PipelineStage::TessellationControl},
73 {gl::ShaderType::TessEvaluation, PipelineStage::TessellationEvaluation},
74 {gl::ShaderType::Geometry, PipelineStage::GeometryShader},
75 {gl::ShaderType::Fragment, PipelineStage::FragmentShader},
76 {gl::ShaderType::Compute, PipelineStage::ComputeShader},
77 };
78
79 // clang-format off
80 constexpr angle::PackedEnumMap<ImageLayout, ImageMemoryBarrierData> kImageMemoryBarrierData = {
81 {
82 ImageLayout::Undefined,
83 ImageMemoryBarrierData{
84 "Undefined",
85 VK_IMAGE_LAYOUT_UNDEFINED,
86 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
87 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
88 // Transition to: we don't expect to transition into Undefined.
89 0,
90 // Transition from: there's no data in the image to care about.
91 0,
92 ResourceAccess::ReadOnly,
93 PipelineStage::InvalidEnum,
94 // We do not directly using this layout in SetEvent. We transit to other layout before using
95 EventStage::InvalidEnum,
96 PipelineStageGroup::Other,
97 },
98 },
99 {
100 ImageLayout::ColorWrite,
101 ImageMemoryBarrierData{
102 "ColorWrite",
103 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
104 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
105 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
106 // Transition to: all reads and writes must happen after barrier.
107 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
108 // Transition from: all writes must finish before barrier.
109 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
110 ResourceAccess::ReadWrite,
111 PipelineStage::ColorAttachmentOutput,
112 EventStage::ColorAttachmentOutput,
113 PipelineStageGroup::FragmentOnly,
114 },
115 },
116 {
117 ImageLayout::ColorWriteAndInput,
118 ImageMemoryBarrierData{
119 "ColorWriteAndInput",
120 VK_IMAGE_LAYOUT_RENDERING_LOCAL_READ_KHR,
121 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
122 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
123 // Transition to: all reads and writes must happen after barrier.
124 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
125 // Transition from: all writes must finish before barrier.
126 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
127 ResourceAccess::ReadWrite,
128 PipelineStage::ColorAttachmentOutput,
129 EventStage::ColorAttachmentOutput,
130 PipelineStageGroup::FragmentOnly,
131 },
132 },
133 {
134 ImageLayout::MSRTTEmulationColorUnresolveAndResolve,
135 ImageMemoryBarrierData{
136 "MSRTTEmulationColorUnresolveAndResolve",
137 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
138 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
139 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
140 // Transition to: all reads and writes must happen after barrier.
141 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT,
142 // Transition from: all writes must finish before barrier.
143 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
144 ResourceAccess::ReadWrite,
145 PipelineStage::FragmentShader,
146 EventStage::ColorAttachmentOutputAndFragmentShader,
147 PipelineStageGroup::FragmentOnly,
148 },
149 },
150 {
151 ImageLayout::DepthWriteStencilWrite,
152 ImageMemoryBarrierData{
153 "DepthWriteStencilWrite",
154 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
155 kAllDepthStencilPipelineStageFlags,
156 kAllDepthStencilPipelineStageFlags,
157 // Transition to: all reads and writes must happen after barrier.
158 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
159 // Transition from: all writes must finish before barrier.
160 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
161 ResourceAccess::ReadWrite,
162 PipelineStage::EarlyFragmentTest,
163 EventStage::AllFragmentTest,
164 PipelineStageGroup::FragmentOnly,
165 },
166 },
167 {
168 ImageLayout::DepthStencilWriteAndInput,
169 ImageMemoryBarrierData{
170 "DepthStencilWriteAndInput",
171 VK_IMAGE_LAYOUT_RENDERING_LOCAL_READ_KHR,
172 kAllDepthStencilPipelineStageFlags,
173 kAllDepthStencilPipelineStageFlags,
174 // Transition to: all reads and writes must happen after barrier.
175 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
176 // Transition from: all writes must finish before barrier.
177 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
178 ResourceAccess::ReadWrite,
179 PipelineStage::EarlyFragmentTest,
180 EventStage::AllFragmentTest,
181 PipelineStageGroup::FragmentOnly,
182 },
183 },
184 {
185 ImageLayout::DepthWriteStencilRead,
186 ImageMemoryBarrierData{
187 "DepthWriteStencilRead",
188 VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL,
189 kAllDepthStencilPipelineStageFlags,
190 kAllDepthStencilPipelineStageFlags,
191 // Transition to: all reads and writes must happen after barrier.
192 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
193 // Transition from: all writes must finish before barrier.
194 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
195 ResourceAccess::ReadWrite,
196 PipelineStage::EarlyFragmentTest,
197 EventStage::AllFragmentTest,
198 PipelineStageGroup::FragmentOnly,
199 },
200 },
201 {
202 ImageLayout::DepthWriteStencilReadFragmentShaderStencilRead,
203 ImageMemoryBarrierData{
204 "DepthWriteStencilReadFragmentShaderStencilRead",
205 VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL,
206 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | kAllDepthStencilPipelineStageFlags,
207 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | kAllDepthStencilPipelineStageFlags,
208 // Transition to: all reads and writes must happen after barrier.
209 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
210 // Transition from: all writes must finish before barrier.
211 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
212 ResourceAccess::ReadWrite,
213 PipelineStage::EarlyFragmentTest,
214 EventStage::AllFragmentTestAndFragmentShader,
215 PipelineStageGroup::FragmentOnly,
216 },
217 },
218 {
219 ImageLayout::DepthWriteStencilReadAllShadersStencilRead,
220 ImageMemoryBarrierData{
221 "DepthWriteStencilReadAllShadersStencilRead",
222 VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL,
223 kAllShadersPipelineStageFlags | kAllDepthStencilPipelineStageFlags,
224 kAllShadersPipelineStageFlags | kAllDepthStencilPipelineStageFlags,
225 // Transition to: all reads and writes must happen after barrier.
226 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
227 // Transition from: all writes must finish before barrier.
228 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
229 ResourceAccess::ReadWrite,
230 PipelineStage::VertexShader,
231 EventStage::AllFragmentTestAndAllShaders,
232 PipelineStageGroup::Other,
233 },
234 },
235 {
236 ImageLayout::DepthReadStencilWrite,
237 ImageMemoryBarrierData{
238 "DepthReadStencilWrite",
239 VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL,
240 kAllDepthStencilPipelineStageFlags,
241 kAllDepthStencilPipelineStageFlags,
242 // Transition to: all reads and writes must happen after barrier.
243 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
244 // Transition from: all writes must finish before barrier.
245 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
246 ResourceAccess::ReadWrite,
247 PipelineStage::EarlyFragmentTest,
248 EventStage::AllFragmentTest,
249 PipelineStageGroup::FragmentOnly,
250 },
251 },
252 {
253 ImageLayout::DepthReadStencilWriteFragmentShaderDepthRead,
254 ImageMemoryBarrierData{
255 "DepthReadStencilWriteFragmentShaderDepthRead",
256 VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL,
257 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | kAllDepthStencilPipelineStageFlags,
258 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | kAllDepthStencilPipelineStageFlags,
259 // Transition to: all reads and writes must happen after barrier.
260 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
261 // Transition from: all writes must finish before barrier.
262 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
263 ResourceAccess::ReadWrite,
264 PipelineStage::EarlyFragmentTest,
265 EventStage::AllFragmentTestAndFragmentShader,
266 PipelineStageGroup::FragmentOnly,
267 },
268 },
269 {
270 ImageLayout::DepthReadStencilWriteAllShadersDepthRead,
271 ImageMemoryBarrierData{
272 "DepthReadStencilWriteAllShadersDepthRead",
273 VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL,
274 kAllShadersPipelineStageFlags | kAllDepthStencilPipelineStageFlags,
275 kAllShadersPipelineStageFlags | kAllDepthStencilPipelineStageFlags,
276 // Transition to: all reads and writes must happen after barrier.
277 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
278 // Transition from: all writes must finish before barrier.
279 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
280 ResourceAccess::ReadWrite,
281 PipelineStage::VertexShader,
282 EventStage::AllFragmentTestAndAllShaders,
283 PipelineStageGroup::Other,
284 },
285 },
286 {
287 ImageLayout::DepthReadStencilRead,
288 ImageMemoryBarrierData{
289 "DepthReadStencilRead",
290 VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
291 kAllDepthStencilPipelineStageFlags,
292 kAllDepthStencilPipelineStageFlags,
293 // Transition to: all reads must happen after barrier.
294 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
295 // Transition from: RAR and WAR don't need memory barrier.
296 0,
297 ResourceAccess::ReadOnly,
298 PipelineStage::EarlyFragmentTest,
299 EventStage::AllFragmentTest,
300 PipelineStageGroup::FragmentOnly,
301 },
302 },
303
304 {
305 ImageLayout::DepthReadStencilReadFragmentShaderRead,
306 ImageMemoryBarrierData{
307 "DepthReadStencilReadFragmentShaderRead",
308 VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
309 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | kAllDepthStencilPipelineStageFlags,
310 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | kAllDepthStencilPipelineStageFlags,
311 // Transition to: all reads must happen after barrier.
312 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
313 // Transition from: RAR and WAR don't need memory barrier.
314 0,
315 ResourceAccess::ReadOnly,
316 PipelineStage::EarlyFragmentTest,
317 EventStage::AllFragmentTestAndFragmentShader,
318 PipelineStageGroup::FragmentOnly,
319 },
320 },
321 {
322 ImageLayout::DepthReadStencilReadAllShadersRead,
323 ImageMemoryBarrierData{
324 "DepthReadStencilReadAllShadersRead",
325 VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
326 kAllShadersPipelineStageFlags | kAllDepthStencilPipelineStageFlags,
327 kAllShadersPipelineStageFlags | kAllDepthStencilPipelineStageFlags,
328 // Transition to: all reads must happen after barrier.
329 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
330 // Transition from: RAR and WAR don't need memory barrier.
331 0,
332 ResourceAccess::ReadOnly,
333 PipelineStage::VertexShader,
334 EventStage::AllFragmentTestAndAllShaders,
335 PipelineStageGroup::Other,
336 },
337 },
338 {
339 ImageLayout::ColorWriteFragmentShaderFeedback,
340 ImageMemoryBarrierData{
341 "ColorWriteFragmentShaderFeedback",
342 VK_IMAGE_LAYOUT_GENERAL,
343 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
344 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
345 // Transition to: all reads and writes must happen after barrier.
346 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT,
347 // Transition from: all writes must finish before barrier.
348 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
349 ResourceAccess::ReadWrite,
350 PipelineStage::FragmentShader,
351 EventStage::ColorAttachmentOutputAndFragmentShader,
352 PipelineStageGroup::FragmentOnly,
353 },
354 },
355 {
356 ImageLayout::ColorWriteAllShadersFeedback,
357 ImageMemoryBarrierData{
358 "ColorWriteAllShadersFeedback",
359 VK_IMAGE_LAYOUT_GENERAL,
360 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | kAllShadersPipelineStageFlags,
361 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | kAllShadersPipelineStageFlags,
362 // Transition to: all reads and writes must happen after barrier.
363 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT,
364 // Transition from: all writes must finish before barrier.
365 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
366 ResourceAccess::ReadWrite,
367 // In case of multiple destination stages, We barrier the earliest stage
368 PipelineStage::VertexShader,
369 EventStage::ColorAttachmentOutputAndAllShaders,
370 PipelineStageGroup::Other,
371 },
372 },
373 {
374 ImageLayout::DepthStencilFragmentShaderFeedback,
375 ImageMemoryBarrierData{
376 "DepthStencilFragmentShaderFeedback",
377 VK_IMAGE_LAYOUT_GENERAL,
378 kAllDepthStencilPipelineStageFlags | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
379 kAllDepthStencilPipelineStageFlags | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
380 // Transition to: all reads and writes must happen after barrier.
381 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT,
382 // Transition from: all writes must finish before barrier.
383 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
384 ResourceAccess::ReadWrite,
385 PipelineStage::FragmentShader,
386 EventStage::AllFragmentTestAndFragmentShader,
387 PipelineStageGroup::FragmentOnly,
388 },
389 },
390 {
391 ImageLayout::DepthStencilAllShadersFeedback,
392 ImageMemoryBarrierData{
393 "DepthStencilAllShadersFeedback",
394 VK_IMAGE_LAYOUT_GENERAL,
395 kAllDepthStencilPipelineStageFlags | kAllShadersPipelineStageFlags,
396 kAllDepthStencilPipelineStageFlags | kAllShadersPipelineStageFlags,
397 // Transition to: all reads and writes must happen after barrier.
398 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT,
399 // Transition from: all writes must finish before barrier.
400 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
401 ResourceAccess::ReadWrite,
402 // In case of multiple destination stages, We barrier the earliest stage
403 PipelineStage::VertexShader,
404 EventStage::AllFragmentTestAndAllShaders,
405 PipelineStageGroup::Other,
406 },
407 },
408 {
409 ImageLayout::DepthStencilResolve,
410 ImageMemoryBarrierData{
411 "DepthStencilResolve",
412 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
413 // Note: depth/stencil resolve uses color output stage and mask!
414 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
415 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
416 // Transition to: all reads and writes must happen after barrier.
417 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
418 // Transition from: all writes must finish before barrier.
419 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
420 ResourceAccess::ReadWrite,
421 PipelineStage::ColorAttachmentOutput,
422 EventStage::ColorAttachmentOutput,
423 PipelineStageGroup::FragmentOnly,
424 },
425 },
426 {
427 ImageLayout::MSRTTEmulationDepthStencilUnresolveAndResolve,
428 ImageMemoryBarrierData{
429 "MSRTTEmulationDepthStencilUnresolveAndResolve",
430 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
431 // Note: depth/stencil resolve uses color output stage and mask!
432 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
433 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
434 // Transition to: all reads and writes must happen after barrier.
435 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT,
436 // Transition from: all writes must finish before barrier.
437 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
438 ResourceAccess::ReadWrite,
439 PipelineStage::FragmentShader,
440 EventStage::ColorAttachmentOutputAndFragmentShader,
441 PipelineStageGroup::FragmentOnly,
442 },
443 },
444 {
445 ImageLayout::Present,
446 ImageMemoryBarrierData{
447 "Present",
448 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
449 // Transition to: do not delay execution of commands in the second synchronization
450 // scope. Allow layout transition to be delayed until present semaphore is signaled.
451 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
452 // Transition from: use same stages as in Acquire Image Semaphore stage mask in order to
453 // build a dependency chain from the Acquire Image Semaphore to the layout transition's
454 // first synchronization scope.
455 kSwapchainAcquireImageWaitStageFlags,
456 // Transition to: vkQueuePresentKHR automatically performs the appropriate memory barriers:
457 //
458 // > Any writes to memory backing the images referenced by the pImageIndices and
459 // > pSwapchains members of pPresentInfo, that are available before vkQueuePresentKHR
460 // > is executed, are automatically made visible to the read access performed by the
461 // > presentation engine.
462 0,
463 // Transition from: RAR and WAR don't need memory barrier.
464 0,
465 ResourceAccess::ReadOnly,
466 PipelineStage::BottomOfPipe,
467 // We do not directly using this layout in SetEvent.
468 EventStage::InvalidEnum,
469 PipelineStageGroup::Other,
470 },
471 },
472 {
473 ImageLayout::SharedPresent,
474 ImageMemoryBarrierData{
475 "SharedPresent",
476 VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR,
477 // All currently possible stages for SharedPresent
478 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
479 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
480 // Transition to: all reads and writes must happen after barrier.
481 VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
482 // Transition from: all writes must finish before barrier.
483 VK_ACCESS_MEMORY_WRITE_BIT,
484 ResourceAccess::ReadWrite,
485 PipelineStage::BottomOfPipe,
486 EventStage::ColorAttachmentOutputAndFragmentShaderAndTransfer,
487 PipelineStageGroup::Other,
488 },
489 },
490 {
491 ImageLayout::ExternalPreInitialized,
492 ImageMemoryBarrierData{
493 "ExternalPreInitialized",
494 // Binding a VkImage with an initial layout of VK_IMAGE_LAYOUT_UNDEFINED to external
495 // memory whose content has already been defined does not make the content undefined
496 // (see 12.8.1. External Resource Sharing).
497 //
498 // Note that for external memory objects, if the content is already defined, the
499 // ownership rules imply that the first operation on the texture must be a call to
500 // glWaitSemaphoreEXT that grants ownership of the image and informs us of the true
501 // layout. If the content is not already defined, the first operation may not be a
502 // glWaitSemaphore, but in this case undefined layout is appropriate.
503 VK_IMAGE_LAYOUT_UNDEFINED,
504 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
505 VK_PIPELINE_STAGE_HOST_BIT | VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
506 // Transition to: we don't expect to transition into PreInitialized.
507 0,
508 // Transition from: all writes must finish before barrier.
509 VK_ACCESS_MEMORY_WRITE_BIT,
510 ResourceAccess::ReadOnly,
511 PipelineStage::InvalidEnum,
512 // We do not directly using this layout in SetEvent. We transit to internal layout before using
513 EventStage::InvalidEnum,
514 PipelineStageGroup::Other,
515 },
516 },
517 {
518 ImageLayout::ExternalShadersReadOnly,
519 ImageMemoryBarrierData{
520 "ExternalShadersReadOnly",
521 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
522 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
523 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
524 // Transition to: all reads must happen after barrier.
525 VK_ACCESS_SHADER_READ_BIT,
526 // Transition from: RAR and WAR don't need memory barrier.
527 0,
528 ResourceAccess::ReadOnly,
529 // In case of multiple destination stages, We barrier the earliest stage
530 PipelineStage::TopOfPipe,
531 // We do not directly using this layout in SetEvent. We transit to internal layout before using
532 EventStage::InvalidEnum,
533 PipelineStageGroup::Other,
534 },
535 },
536 {
537 ImageLayout::ExternalShadersWrite,
538 ImageMemoryBarrierData{
539 "ExternalShadersWrite",
540 VK_IMAGE_LAYOUT_GENERAL,
541 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
542 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
543 // Transition to: all reads and writes must happen after barrier.
544 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
545 // Transition from: all writes must finish before barrier.
546 VK_ACCESS_SHADER_WRITE_BIT,
547 ResourceAccess::ReadWrite,
548 // In case of multiple destination stages, We barrier the earliest stage
549 PipelineStage::TopOfPipe,
550 // We do not directly using this layout in SetEvent. We transit to internal layout before using
551 EventStage::InvalidEnum,
552 PipelineStageGroup::Other,
553 },
554 },
555 {
556 ImageLayout::TransferSrc,
557 ImageMemoryBarrierData{
558 "TransferSrc",
559 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
560 VK_PIPELINE_STAGE_TRANSFER_BIT,
561 VK_PIPELINE_STAGE_TRANSFER_BIT,
562 // Transition to: all reads must happen after barrier.
563 VK_ACCESS_TRANSFER_READ_BIT,
564 // Transition from: RAR and WAR don't need memory barrier.
565 0,
566 ResourceAccess::ReadOnly,
567 PipelineStage::Transfer,
568 EventStage::Transfer,
569 PipelineStageGroup::Other,
570 },
571 },
572 {
573 ImageLayout::TransferDst,
574 ImageMemoryBarrierData{
575 "TransferDst",
576 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
577 VK_PIPELINE_STAGE_TRANSFER_BIT,
578 VK_PIPELINE_STAGE_TRANSFER_BIT,
579 // Transition to: all writes must happen after barrier.
580 VK_ACCESS_TRANSFER_WRITE_BIT,
581 // Transition from: all writes must finish before barrier.
582 VK_ACCESS_TRANSFER_WRITE_BIT,
583 ResourceAccess::ReadWrite,
584 PipelineStage::Transfer,
585 EventStage::Transfer,
586 PipelineStageGroup::Other,
587 },
588 },
589 {
590 ImageLayout::TransferSrcDst,
591 ImageMemoryBarrierData{
592 "TransferSrcDst",
593 VK_IMAGE_LAYOUT_GENERAL,
594 VK_PIPELINE_STAGE_TRANSFER_BIT,
595 VK_PIPELINE_STAGE_TRANSFER_BIT,
596 // Transition to: all reads and writes must happen after barrier.
597 VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
598 // Transition from: all writes must finish before barrier.
599 VK_ACCESS_TRANSFER_WRITE_BIT,
600 ResourceAccess::ReadWrite,
601 PipelineStage::Transfer,
602 EventStage::Transfer,
603 PipelineStageGroup::Other,
604 },
605 },
606 {
607 ImageLayout::HostCopy,
608 ImageMemoryBarrierData{
609 "HostCopy",
610 VK_IMAGE_LAYOUT_GENERAL,
611 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
612 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
613 // Transition to: we don't expect to transition into HostCopy on the GPU.
614 0,
615 // Transition from: the data was initialized in the image by the host. Note that we
616 // only transition to this layout if the image was previously in UNDEFINED, in which
617 // case it didn't contain any data prior to the host copy either.
618 0,
619 ResourceAccess::ReadOnly,
620 PipelineStage::InvalidEnum,
621 // We do not directly using this layout in SetEvent.
622 EventStage::InvalidEnum,
623 PipelineStageGroup::Other,
624 },
625 },
626 {
627 ImageLayout::VertexShaderReadOnly,
628 ImageMemoryBarrierData{
629 "VertexShaderReadOnly",
630 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
631 VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
632 VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
633 // Transition to: all reads must happen after barrier.
634 VK_ACCESS_SHADER_READ_BIT,
635 // Transition from: RAR and WAR don't need memory barrier.
636 0,
637 ResourceAccess::ReadOnly,
638 PipelineStage::VertexShader,
639 EventStage::VertexShader,
640 PipelineStageGroup::PreFragmentOnly,
641 },
642 },
643 {
644 ImageLayout::VertexShaderWrite,
645 ImageMemoryBarrierData{
646 "VertexShaderWrite",
647 VK_IMAGE_LAYOUT_GENERAL,
648 VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
649 VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
650 // Transition to: all reads and writes must happen after barrier.
651 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
652 // Transition from: all writes must finish before barrier.
653 VK_ACCESS_SHADER_WRITE_BIT,
654 ResourceAccess::ReadWrite,
655 PipelineStage::VertexShader,
656 EventStage::VertexShader,
657 PipelineStageGroup::PreFragmentOnly,
658 },
659 },
660 {
661 ImageLayout::PreFragmentShadersReadOnly,
662 ImageMemoryBarrierData{
663 "PreFragmentShadersReadOnly",
664 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
665 kPreFragmentStageFlags,
666 kPreFragmentStageFlags,
667 // Transition to: all reads must happen after barrier.
668 VK_ACCESS_SHADER_READ_BIT,
669 // Transition from: RAR and WAR don't need memory barrier.
670 0,
671 ResourceAccess::ReadOnly,
672 // In case of multiple destination stages, We barrier the earliest stage
673 PipelineStage::VertexShader,
674 EventStage::PreFragmentShaders,
675 PipelineStageGroup::PreFragmentOnly,
676 },
677 },
678 {
679 ImageLayout::PreFragmentShadersWrite,
680 ImageMemoryBarrierData{
681 "PreFragmentShadersWrite",
682 VK_IMAGE_LAYOUT_GENERAL,
683 kPreFragmentStageFlags,
684 kPreFragmentStageFlags,
685 // Transition to: all reads and writes must happen after barrier.
686 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
687 // Transition from: all writes must finish before barrier.
688 VK_ACCESS_SHADER_WRITE_BIT,
689 ResourceAccess::ReadWrite,
690 // In case of multiple destination stages, We barrier the earliest stage
691 PipelineStage::VertexShader,
692 EventStage::PreFragmentShaders,
693 PipelineStageGroup::PreFragmentOnly,
694 },
695 },
696 {
697 ImageLayout::FragmentShadingRateAttachmentReadOnly,
698 ImageMemoryBarrierData{
699 "FragmentShadingRateAttachmentReadOnly",
700 VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR,
701 VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR,
702 VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR,
703 // Transition to: all reads must happen after barrier.
704 VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR,
705 // Transition from: RAR and WAR don't need memory barrier.
706 0,
707 ResourceAccess::ReadOnly,
708 PipelineStage::FragmentShadingRate,
709 EventStage::FragmentShadingRate,
710 PipelineStageGroup::Other,
711 },
712 },
713 {
714 ImageLayout::FragmentShaderReadOnly,
715 ImageMemoryBarrierData{
716 "FragmentShaderReadOnly",
717 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
718 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
719 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
720 // Transition to: all reads must happen after barrier.
721 VK_ACCESS_SHADER_READ_BIT,
722 // Transition from: RAR and WAR don't need memory barrier.
723 0,
724 ResourceAccess::ReadOnly,
725 PipelineStage::FragmentShader,
726 EventStage::FragmentShader,
727 PipelineStageGroup::FragmentOnly,
728 },
729 },
730 {
731 ImageLayout::FragmentShaderWrite,
732 ImageMemoryBarrierData{
733 "FragmentShaderWrite",
734 VK_IMAGE_LAYOUT_GENERAL,
735 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
736 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
737 // Transition to: all reads and writes must happen after barrier.
738 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
739 // Transition from: all writes must finish before barrier.
740 VK_ACCESS_SHADER_WRITE_BIT,
741 ResourceAccess::ReadWrite,
742 PipelineStage::FragmentShader,
743 EventStage::FragmentShader,
744 PipelineStageGroup::FragmentOnly,
745 },
746 },
747 {
748 ImageLayout::ComputeShaderReadOnly,
749 ImageMemoryBarrierData{
750 "ComputeShaderReadOnly",
751 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
752 VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
753 VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
754 // Transition to: all reads must happen after barrier.
755 VK_ACCESS_SHADER_READ_BIT,
756 // Transition from: RAR and WAR don't need memory barrier.
757 0,
758 ResourceAccess::ReadOnly,
759 PipelineStage::ComputeShader,
760 EventStage::ComputeShader,
761 PipelineStageGroup::ComputeOnly,
762 },
763 },
764 {
765 ImageLayout::ComputeShaderWrite,
766 ImageMemoryBarrierData{
767 "ComputeShaderWrite",
768 VK_IMAGE_LAYOUT_GENERAL,
769 VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
770 VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
771 // Transition to: all reads and writes must happen after barrier.
772 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
773 // Transition from: all writes must finish before barrier.
774 VK_ACCESS_SHADER_WRITE_BIT,
775 ResourceAccess::ReadWrite,
776 PipelineStage::ComputeShader,
777 EventStage::ComputeShader,
778 PipelineStageGroup::ComputeOnly,
779 },
780 },
781 {
782 ImageLayout::AllGraphicsShadersReadOnly,
783 ImageMemoryBarrierData{
784 "AllGraphicsShadersReadOnly",
785 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
786 kAllShadersPipelineStageFlags,
787 kAllShadersPipelineStageFlags,
788 // Transition to: all reads must happen after barrier.
789 VK_ACCESS_SHADER_READ_BIT,
790 // Transition from: RAR and WAR don't need memory barrier.
791 0,
792 ResourceAccess::ReadOnly,
793 // In case of multiple destination stages, We barrier the earliest stage
794 PipelineStage::VertexShader,
795 EventStage::AllShaders,
796 PipelineStageGroup::Other,
797 },
798 },
799 {
800 ImageLayout::AllGraphicsShadersWrite,
801 ImageMemoryBarrierData{
802 "AllGraphicsShadersWrite",
803 VK_IMAGE_LAYOUT_GENERAL,
804 kAllShadersPipelineStageFlags,
805 kAllShadersPipelineStageFlags,
806 // Transition to: all reads and writes must happen after barrier.
807 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
808 // Transition from: all writes must finish before barrier.
809 VK_ACCESS_SHADER_WRITE_BIT,
810 ResourceAccess::ReadWrite,
811 // In case of multiple destination stages, We barrier the earliest stage
812 PipelineStage::VertexShader,
813 EventStage::AllShaders,
814 PipelineStageGroup::Other,
815 },
816 },
817 {
818 ImageLayout::TransferDstAndComputeWrite,
819 ImageMemoryBarrierData{
820 "TransferDstAndComputeWrite",
821 VK_IMAGE_LAYOUT_GENERAL,
822 VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT,
823 VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT,
824 // Transition to: all reads and writes must happen after barrier.
825 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT,
826 // Transition from: all writes must finish before barrier.
827 VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
828 ResourceAccess::ReadWrite,
829 // In case of multiple destination stages, We barrier the earliest stage
830 PipelineStage::ComputeShader,
831 EventStage::TransferAndComputeShader,
832 PipelineStageGroup::Other,
833 },
834 },
835 };
836 // clang-format on
837
GetImageLayoutEventStage(ImageLayout layout)838 EventStage GetImageLayoutEventStage(ImageLayout layout)
839 {
840 const ImageMemoryBarrierData &barrierData = kImageMemoryBarrierData[layout];
841 return barrierData.eventStage;
842 }
843
HasBothDepthAndStencilAspects(VkImageAspectFlags aspectFlags)844 bool HasBothDepthAndStencilAspects(VkImageAspectFlags aspectFlags)
845 {
846 return IsMaskFlagSet(aspectFlags, kDepthStencilAspects);
847 }
848
GetContentDefinedLayerRangeBits(uint32_t layerStart,uint32_t layerCount,uint32_t maxLayerCount)849 uint8_t GetContentDefinedLayerRangeBits(uint32_t layerStart,
850 uint32_t layerCount,
851 uint32_t maxLayerCount)
852 {
853 uint8_t layerRangeBits = layerCount >= maxLayerCount ? static_cast<uint8_t>(~0u)
854 : angle::BitMask<uint8_t>(layerCount);
855 layerRangeBits <<= layerStart;
856
857 return layerRangeBits;
858 }
859
GetImageLayerCountForView(const ImageHelper & image)860 uint32_t GetImageLayerCountForView(const ImageHelper &image)
861 {
862 // Depth > 1 means this is a 3D texture and depth is our layer count
863 return image.getExtents().depth > 1 ? image.getExtents().depth : image.getLayerCount();
864 }
865
ReleaseImageViews(ImageViewVector * imageViewVector,GarbageObjects * garbage)866 void ReleaseImageViews(ImageViewVector *imageViewVector, GarbageObjects *garbage)
867 {
868 for (ImageView &imageView : *imageViewVector)
869 {
870 if (imageView.valid())
871 {
872 garbage->emplace_back(GetGarbage(&imageView));
873 }
874 }
875 imageViewVector->clear();
876 }
877
DestroyImageViews(ImageViewVector * imageViewVector,VkDevice device)878 void DestroyImageViews(ImageViewVector *imageViewVector, VkDevice device)
879 {
880 for (ImageView &imageView : *imageViewVector)
881 {
882 imageView.destroy(device);
883 }
884 imageViewVector->clear();
885 }
886
ReleaseLayerLevelImageViews(LayerLevelImageViewVector * imageViewVector,GarbageObjects * garbage)887 void ReleaseLayerLevelImageViews(LayerLevelImageViewVector *imageViewVector,
888 GarbageObjects *garbage)
889 {
890 for (ImageViewVector &layerViews : *imageViewVector)
891 {
892 for (ImageView &imageView : layerViews)
893 {
894 if (imageView.valid())
895 {
896 garbage->emplace_back(GetGarbage(&imageView));
897 }
898 }
899 }
900 imageViewVector->clear();
901 }
902
DestroyLayerLevelImageViews(LayerLevelImageViewVector * imageViewVector,VkDevice device)903 void DestroyLayerLevelImageViews(LayerLevelImageViewVector *imageViewVector, VkDevice device)
904 {
905 for (ImageViewVector &layerViews : *imageViewVector)
906 {
907 for (ImageView &imageView : layerViews)
908 {
909 imageView.destroy(device);
910 }
911 }
912 imageViewVector->clear();
913 }
914
ReleaseSubresourceImageViews(SubresourceImageViewMap * imageViews,GarbageObjects * garbage)915 void ReleaseSubresourceImageViews(SubresourceImageViewMap *imageViews, GarbageObjects *garbage)
916 {
917 for (auto &iter : *imageViews)
918 {
919 std::unique_ptr<ImageView> &imageView = iter.second;
920 if (imageView->valid())
921 {
922 garbage->emplace_back(GetGarbage(imageView.get()));
923 }
924 }
925 imageViews->clear();
926 }
927
DestroySubresourceImageViews(SubresourceImageViewMap * imageViews,VkDevice device)928 void DestroySubresourceImageViews(SubresourceImageViewMap *imageViews, VkDevice device)
929 {
930 for (auto &iter : *imageViews)
931 {
932 std::unique_ptr<ImageView> &imageView = iter.second;
933 imageView->destroy(device);
934 }
935 imageViews->clear();
936 }
937
GetLevelImageView(ImageViewVector * imageViews,LevelIndex levelVk,uint32_t levelCount)938 ImageView *GetLevelImageView(ImageViewVector *imageViews, LevelIndex levelVk, uint32_t levelCount)
939 {
940 // Lazily allocate the storage for image views. We allocate the full level count because we
941 // don't want to trigger any std::vector reallocations. Reallocations could invalidate our
942 // view pointers.
943 if (imageViews->empty())
944 {
945 imageViews->resize(levelCount);
946 }
947 ASSERT(imageViews->size() > levelVk.get());
948
949 return &(*imageViews)[levelVk.get()];
950 }
951
GetLevelLayerImageView(LayerLevelImageViewVector * imageViews,LevelIndex levelVk,uint32_t layer,uint32_t levelCount,uint32_t layerCount)952 ImageView *GetLevelLayerImageView(LayerLevelImageViewVector *imageViews,
953 LevelIndex levelVk,
954 uint32_t layer,
955 uint32_t levelCount,
956 uint32_t layerCount)
957 {
958 // Lazily allocate the storage for image views. We allocate the full layer count because we
959 // don't want to trigger any std::vector reallocations. Reallocations could invalidate our
960 // view pointers.
961 if (imageViews->empty())
962 {
963 imageViews->resize(layerCount);
964 }
965 ASSERT(imageViews->size() > layer);
966
967 return GetLevelImageView(&(*imageViews)[layer], levelVk, levelCount);
968 }
969
970 // Special rules apply to VkBufferImageCopy with depth/stencil. The components are tightly packed
971 // into a depth or stencil section of the destination buffer. See the spec:
972 // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VkBufferImageCopy.html
GetDepthStencilImageToBufferFormat(const angle::Format & imageFormat,VkImageAspectFlagBits copyAspect)973 const angle::Format &GetDepthStencilImageToBufferFormat(const angle::Format &imageFormat,
974 VkImageAspectFlagBits copyAspect)
975 {
976 if (copyAspect == VK_IMAGE_ASPECT_STENCIL_BIT)
977 {
978 ASSERT(imageFormat.id == angle::FormatID::D24_UNORM_S8_UINT ||
979 imageFormat.id == angle::FormatID::D32_FLOAT_S8X24_UINT ||
980 imageFormat.id == angle::FormatID::S8_UINT);
981 return angle::Format::Get(angle::FormatID::S8_UINT);
982 }
983
984 ASSERT(copyAspect == VK_IMAGE_ASPECT_DEPTH_BIT);
985
986 switch (imageFormat.id)
987 {
988 case angle::FormatID::D16_UNORM:
989 return imageFormat;
990 case angle::FormatID::D24_UNORM_X8_UINT:
991 return imageFormat;
992 case angle::FormatID::D24_UNORM_S8_UINT:
993 return angle::Format::Get(angle::FormatID::D24_UNORM_X8_UINT);
994 case angle::FormatID::D32_FLOAT:
995 return imageFormat;
996 case angle::FormatID::D32_FLOAT_S8X24_UINT:
997 return angle::Format::Get(angle::FormatID::D32_FLOAT);
998 default:
999 UNREACHABLE();
1000 return imageFormat;
1001 }
1002 }
1003
GetRobustResourceClearValue(const angle::Format & intendedFormat,const angle::Format & actualFormat)1004 VkClearValue GetRobustResourceClearValue(const angle::Format &intendedFormat,
1005 const angle::Format &actualFormat)
1006 {
1007 VkClearValue clearValue = {};
1008 if (intendedFormat.hasDepthOrStencilBits())
1009 {
1010 clearValue.depthStencil = kRobustInitDepthStencilValue;
1011 }
1012 else
1013 {
1014 clearValue.color = HasEmulatedImageChannels(intendedFormat, actualFormat)
1015 ? kEmulatedInitColorValue
1016 : kRobustInitColorValue;
1017 }
1018 return clearValue;
1019 }
1020
IsShaderReadOnlyLayout(const ImageMemoryBarrierData & imageLayout)1021 bool IsShaderReadOnlyLayout(const ImageMemoryBarrierData &imageLayout)
1022 {
1023 // We also use VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL for texture sample from depth
1024 // texture. See GetImageReadLayout() for detail.
1025 return imageLayout.layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ||
1026 imageLayout.layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
1027 }
1028
IsAnySubresourceContentDefined(const gl::TexLevelArray<angle::BitSet8<8>> & contentDefined)1029 bool IsAnySubresourceContentDefined(const gl::TexLevelArray<angle::BitSet8<8>> &contentDefined)
1030 {
1031 for (const angle::BitSet8<8> &levelContentDefined : contentDefined)
1032 {
1033 if (levelContentDefined.any())
1034 {
1035 return true;
1036 }
1037 }
1038 return false;
1039 }
1040
ExtendRenderPassInvalidateArea(const gl::Rectangle & invalidateArea,gl::Rectangle * out)1041 void ExtendRenderPassInvalidateArea(const gl::Rectangle &invalidateArea, gl::Rectangle *out)
1042 {
1043 if (out->empty())
1044 {
1045 *out = invalidateArea;
1046 }
1047 else
1048 {
1049 gl::ExtendRectangle(*out, invalidateArea, out);
1050 }
1051 }
1052
CanCopyWithTransferForCopyImage(Renderer * renderer,ImageHelper * srcImage,VkImageTiling srcTilingMode,ImageHelper * dstImage,VkImageTiling dstTilingMode)1053 bool CanCopyWithTransferForCopyImage(Renderer *renderer,
1054 ImageHelper *srcImage,
1055 VkImageTiling srcTilingMode,
1056 ImageHelper *dstImage,
1057 VkImageTiling dstTilingMode)
1058 {
1059 // Neither source nor destination formats can be emulated for copy image through transfer,
1060 // unless they are emulated with the same format!
1061 bool isFormatCompatible =
1062 (!srcImage->hasEmulatedImageFormat() && !dstImage->hasEmulatedImageFormat()) ||
1063 srcImage->getActualFormatID() == dstImage->getActualFormatID();
1064
1065 // If neither formats are emulated, GL validation ensures that pixelBytes is the same for both.
1066 ASSERT(!isFormatCompatible ||
1067 srcImage->getActualFormat().pixelBytes == dstImage->getActualFormat().pixelBytes);
1068
1069 return isFormatCompatible &&
1070 CanCopyWithTransfer(renderer, srcImage->getActualFormatID(), srcTilingMode,
1071 dstImage->getActualFormatID(), dstTilingMode);
1072 }
1073
ReleaseBufferListToRenderer(Renderer * renderer,BufferHelperQueue * buffers)1074 void ReleaseBufferListToRenderer(Renderer *renderer, BufferHelperQueue *buffers)
1075 {
1076 for (std::unique_ptr<BufferHelper> &toFree : *buffers)
1077 {
1078 toFree->release(renderer);
1079 }
1080 buffers->clear();
1081 }
1082
DestroyBufferList(Renderer * renderer,BufferHelperQueue * buffers)1083 void DestroyBufferList(Renderer *renderer, BufferHelperQueue *buffers)
1084 {
1085 for (std::unique_ptr<BufferHelper> &toDestroy : *buffers)
1086 {
1087 toDestroy->destroy(renderer);
1088 }
1089 buffers->clear();
1090 }
1091
1092 // Helper functions used below
GetLoadOpShorthand(RenderPassLoadOp loadOp)1093 char GetLoadOpShorthand(RenderPassLoadOp loadOp)
1094 {
1095 switch (loadOp)
1096 {
1097 case RenderPassLoadOp::Clear:
1098 return 'C';
1099 case RenderPassLoadOp::Load:
1100 return 'L';
1101 case RenderPassLoadOp::None:
1102 return 'N';
1103 default:
1104 return 'D';
1105 }
1106 }
1107
GetStoreOpShorthand(RenderPassStoreOp storeOp)1108 char GetStoreOpShorthand(RenderPassStoreOp storeOp)
1109 {
1110 switch (storeOp)
1111 {
1112 case RenderPassStoreOp::Store:
1113 return 'S';
1114 case RenderPassStoreOp::None:
1115 return 'N';
1116 default:
1117 return 'D';
1118 }
1119 }
1120
IsClear(UpdateSource updateSource)1121 bool IsClear(UpdateSource updateSource)
1122 {
1123 return updateSource == UpdateSource::Clear ||
1124 updateSource == UpdateSource::ClearEmulatedChannelsOnly ||
1125 updateSource == UpdateSource::ClearAfterInvalidate;
1126 }
1127
IsClearOfAllChannels(UpdateSource updateSource)1128 bool IsClearOfAllChannels(UpdateSource updateSource)
1129 {
1130 return updateSource == UpdateSource::Clear ||
1131 updateSource == UpdateSource::ClearAfterInvalidate;
1132 }
1133
InitDynamicDescriptorPool(Context * context,const DescriptorSetLayoutDesc & descriptorSetLayoutDesc,const DescriptorSetLayout & descriptorSetLayout,uint32_t descriptorCountMultiplier,DynamicDescriptorPool * poolToInit)1134 angle::Result InitDynamicDescriptorPool(Context *context,
1135 const DescriptorSetLayoutDesc &descriptorSetLayoutDesc,
1136 const DescriptorSetLayout &descriptorSetLayout,
1137 uint32_t descriptorCountMultiplier,
1138 DynamicDescriptorPool *poolToInit)
1139 {
1140 std::vector<VkDescriptorPoolSize> descriptorPoolSizes;
1141 DescriptorSetLayoutBindingVector bindingVector;
1142 descriptorSetLayoutDesc.unpackBindings(&bindingVector);
1143
1144 for (const VkDescriptorSetLayoutBinding &binding : bindingVector)
1145 {
1146 if (binding.descriptorCount > 0)
1147 {
1148 VkDescriptorPoolSize poolSize = {};
1149 poolSize.type = binding.descriptorType;
1150 poolSize.descriptorCount = binding.descriptorCount * descriptorCountMultiplier;
1151 descriptorPoolSizes.emplace_back(poolSize);
1152 }
1153 }
1154
1155 if (!descriptorPoolSizes.empty())
1156 {
1157 ANGLE_TRY(poolToInit->init(context, descriptorPoolSizes.data(), descriptorPoolSizes.size(),
1158 descriptorSetLayout));
1159 }
1160
1161 return angle::Result::Continue;
1162 }
1163
CheckSubpassCommandBufferCount(uint32_t count)1164 bool CheckSubpassCommandBufferCount(uint32_t count)
1165 {
1166 // When using angle::SharedRingBufferAllocator we must ensure that allocator is attached and
1167 // detached from the same priv::SecondaryCommandBuffer instance.
1168 // Custom command buffer (priv::SecondaryCommandBuffer) may contain commands for multiple
1169 // subpasses, therefore we do not need multiple buffers.
1170 return (count == 1 || !RenderPassCommandBuffer::ExecutesInline());
1171 }
1172
IsAnyLayout(VkImageLayout needle,const VkImageLayout * haystack,uint32_t haystackCount)1173 bool IsAnyLayout(VkImageLayout needle, const VkImageLayout *haystack, uint32_t haystackCount)
1174 {
1175 const VkImageLayout *haystackEnd = haystack + haystackCount;
1176 return std::find(haystack, haystackEnd, needle) != haystackEnd;
1177 }
1178
AggregateSkipLevels(const gl::CubeFaceArray<gl::TexLevelMask> & skipLevels)1179 gl::TexLevelMask AggregateSkipLevels(const gl::CubeFaceArray<gl::TexLevelMask> &skipLevels)
1180 {
1181 gl::TexLevelMask skipLevelsAllFaces = skipLevels[0];
1182 for (size_t face = 1; face < gl::kCubeFaceCount; ++face)
1183 {
1184 skipLevelsAllFaces |= skipLevels[face];
1185 }
1186 return skipLevelsAllFaces;
1187 }
1188
1189 // Get layer mask for a particular image level.
GetImageLayerWriteMask(uint32_t layerStart,uint32_t layerCount)1190 ImageLayerWriteMask GetImageLayerWriteMask(uint32_t layerStart, uint32_t layerCount)
1191 {
1192 ImageLayerWriteMask layerMask = angle::BitMask<uint64_t>(layerCount);
1193 uint32_t rotateShift = layerStart % kMaxParallelLayerWrites;
1194 layerMask = (layerMask << rotateShift) | (layerMask >> (kMaxParallelLayerWrites - rotateShift));
1195 return layerMask;
1196 }
1197
MakeImageSubresourceReadRange(gl::LevelIndex level,uint32_t levelCount,uint32_t layer,LayerMode layerMode,ImageViewColorspace readColorspace,ImageViewColorspace writeColorspace)1198 ImageSubresourceRange MakeImageSubresourceReadRange(gl::LevelIndex level,
1199 uint32_t levelCount,
1200 uint32_t layer,
1201 LayerMode layerMode,
1202 ImageViewColorspace readColorspace,
1203 ImageViewColorspace writeColorspace)
1204 {
1205 ImageSubresourceRange range;
1206
1207 SetBitField(range.level, level.get());
1208 SetBitField(range.levelCount, levelCount);
1209 SetBitField(range.layer, layer);
1210 SetBitField(range.layerMode, layerMode);
1211 SetBitField(range.readColorspace, readColorspace == ImageViewColorspace::SRGB ? 1 : 0);
1212 SetBitField(range.writeColorspace, writeColorspace == ImageViewColorspace::SRGB ? 1 : 0);
1213
1214 return range;
1215 }
1216
MakeImageSubresourceDrawRange(gl::LevelIndex level,uint32_t layer,LayerMode layerMode,ImageViewColorspace readColorspace,ImageViewColorspace writeColorspace)1217 ImageSubresourceRange MakeImageSubresourceDrawRange(gl::LevelIndex level,
1218 uint32_t layer,
1219 LayerMode layerMode,
1220 ImageViewColorspace readColorspace,
1221 ImageViewColorspace writeColorspace)
1222 {
1223 ImageSubresourceRange range;
1224
1225 SetBitField(range.level, level.get());
1226 SetBitField(range.levelCount, 1);
1227 SetBitField(range.layer, layer);
1228 SetBitField(range.layerMode, layerMode);
1229 SetBitField(range.readColorspace, readColorspace == ImageViewColorspace::SRGB ? 1 : 0);
1230 SetBitField(range.writeColorspace, writeColorspace == ImageViewColorspace::SRGB ? 1 : 0);
1231
1232 return range;
1233 }
1234
1235 // Obtain VkClearColorValue from input byte data and actual format.
GetVkClearColorValueFromBytes(uint8_t * actualData,const angle::Format & actualFormat,VkClearValue * clearValueOut)1236 void GetVkClearColorValueFromBytes(uint8_t *actualData,
1237 const angle::Format &actualFormat,
1238 VkClearValue *clearValueOut)
1239 {
1240 ASSERT(actualData != nullptr && !actualFormat.hasDepthOrStencilBits());
1241
1242 *clearValueOut = {};
1243 VkClearColorValue colorValue = {{}};
1244 actualFormat.pixelReadFunction(actualData, reinterpret_cast<uint8_t *>(&colorValue));
1245 clearValueOut->color = colorValue;
1246 }
1247
1248 // Obtain VkClearDepthStencilValue from input byte data and intended format.
GetVkClearDepthStencilValueFromBytes(uint8_t * intendedData,const angle::Format & intendedFormat,VkClearValue * clearValueOut)1249 void GetVkClearDepthStencilValueFromBytes(uint8_t *intendedData,
1250 const angle::Format &intendedFormat,
1251 VkClearValue *clearValueOut)
1252 {
1253 ASSERT(intendedData != nullptr && intendedFormat.hasDepthOrStencilBits());
1254
1255 *clearValueOut = {};
1256 uint32_t dsData[4] = {0};
1257 double depthValue = 0;
1258
1259 intendedFormat.pixelReadFunction(intendedData, reinterpret_cast<uint8_t *>(dsData));
1260 memcpy(&depthValue, &dsData[0], sizeof(double));
1261 clearValueOut->depthStencil.depth = static_cast<float>(depthValue);
1262 clearValueOut->depthStencil.stencil = dsData[2];
1263 }
1264 } // anonymous namespace
1265
1266 // This is an arbitrary max. We can change this later if necessary.
1267 uint32_t DynamicDescriptorPool::mMaxSetsPerPool = 16;
1268 uint32_t DynamicDescriptorPool::mMaxSetsPerPoolMultiplier = 2;
1269
GetImageLayoutFromGLImageLayout(Context * context,GLenum layout)1270 ImageLayout GetImageLayoutFromGLImageLayout(Context *context, GLenum layout)
1271 {
1272 const bool supportsMixedReadWriteDepthStencilLayouts =
1273 context->getFeatures().supportsMixedReadWriteDepthStencilLayouts.enabled;
1274 switch (layout)
1275 {
1276 case GL_NONE:
1277 return ImageLayout::Undefined;
1278 case GL_LAYOUT_GENERAL_EXT:
1279 return ImageLayout::ExternalShadersWrite;
1280 case GL_LAYOUT_COLOR_ATTACHMENT_EXT:
1281 return ImageLayout::ColorWrite;
1282 case GL_LAYOUT_DEPTH_STENCIL_ATTACHMENT_EXT:
1283 return ImageLayout::DepthWriteStencilWrite;
1284 case GL_LAYOUT_DEPTH_STENCIL_READ_ONLY_EXT:
1285 return ImageLayout::DepthReadStencilRead;
1286 case GL_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_EXT:
1287 return supportsMixedReadWriteDepthStencilLayouts ? ImageLayout::DepthReadStencilWrite
1288 : ImageLayout::DepthWriteStencilWrite;
1289 case GL_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_EXT:
1290 return supportsMixedReadWriteDepthStencilLayouts ? ImageLayout::DepthWriteStencilRead
1291 : ImageLayout::DepthWriteStencilWrite;
1292 case GL_LAYOUT_SHADER_READ_ONLY_EXT:
1293 return ImageLayout::ExternalShadersReadOnly;
1294 case GL_LAYOUT_TRANSFER_SRC_EXT:
1295 return ImageLayout::TransferSrc;
1296 case GL_LAYOUT_TRANSFER_DST_EXT:
1297 return ImageLayout::TransferDst;
1298 default:
1299 UNREACHABLE();
1300 return vk::ImageLayout::Undefined;
1301 }
1302 }
1303
ConvertImageLayoutToGLImageLayout(ImageLayout layout)1304 GLenum ConvertImageLayoutToGLImageLayout(ImageLayout layout)
1305 {
1306 switch (kImageMemoryBarrierData[layout].layout)
1307 {
1308 case VK_IMAGE_LAYOUT_UNDEFINED:
1309 return GL_NONE;
1310 case VK_IMAGE_LAYOUT_GENERAL:
1311 return GL_LAYOUT_GENERAL_EXT;
1312 case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
1313 return GL_LAYOUT_COLOR_ATTACHMENT_EXT;
1314 case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
1315 return GL_LAYOUT_DEPTH_STENCIL_ATTACHMENT_EXT;
1316 case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
1317 return GL_LAYOUT_DEPTH_STENCIL_READ_ONLY_EXT;
1318 case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
1319 return GL_LAYOUT_SHADER_READ_ONLY_EXT;
1320 case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
1321 return GL_LAYOUT_TRANSFER_SRC_EXT;
1322 case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
1323 return GL_LAYOUT_TRANSFER_DST_EXT;
1324 case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL:
1325 return GL_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_EXT;
1326 case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL:
1327 return GL_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_EXT;
1328 default:
1329 break;
1330 }
1331 UNREACHABLE();
1332 return GL_NONE;
1333 }
1334
ConvertImageLayoutToVkImageLayout(Renderer * renderer,ImageLayout imageLayout)1335 VkImageLayout ConvertImageLayoutToVkImageLayout(Renderer *renderer, ImageLayout imageLayout)
1336 {
1337 const ImageMemoryBarrierData &transition = renderer->getImageMemoryBarrierData(imageLayout);
1338 VkImageLayout layout = transition.layout;
1339
1340 if (ANGLE_LIKELY(renderer->getFeatures().supportsMixedReadWriteDepthStencilLayouts.enabled))
1341 {
1342 return layout;
1343 }
1344
1345 // If the layouts are not supported, substitute them with what's available. This may be
1346 // less optimal and/or introduce synchronization hazards.
1347 if (layout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL ||
1348 layout == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL)
1349 {
1350 layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
1351
1352 // If the replacement layout causes a feedback loop, use the GENERAL layout
1353 if ((transition.dstStageMask &
1354 (VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT)) != 0)
1355 {
1356 layout = VK_IMAGE_LAYOUT_GENERAL;
1357 }
1358 }
1359
1360 return layout;
1361 }
1362
GetPipelineStageGroupFromStageFlags(VkPipelineStageFlags dstStageMask)1363 PipelineStageGroup GetPipelineStageGroupFromStageFlags(VkPipelineStageFlags dstStageMask)
1364 {
1365 if ((dstStageMask & ~kFragmentAndAttachmentPipelineStageFlags) == 0)
1366 {
1367 return PipelineStageGroup::FragmentOnly;
1368 }
1369 else if (dstStageMask == VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT)
1370 {
1371 return PipelineStageGroup::ComputeOnly;
1372 }
1373 else if ((dstStageMask & ~kPreFragmentStageFlags) == 0)
1374 {
1375 return PipelineStageGroup::PreFragmentOnly;
1376 }
1377 return PipelineStageGroup::Other;
1378 }
1379
InitializeImageLayoutAndMemoryBarrierDataMap(angle::PackedEnumMap<ImageLayout,ImageMemoryBarrierData> * map,VkPipelineStageFlags supportedVulkanPipelineStageMask)1380 void InitializeImageLayoutAndMemoryBarrierDataMap(
1381 angle::PackedEnumMap<ImageLayout, ImageMemoryBarrierData> *map,
1382 VkPipelineStageFlags supportedVulkanPipelineStageMask)
1383 {
1384 *map = kImageMemoryBarrierData;
1385 for (ImageMemoryBarrierData &barrierData : *map)
1386 {
1387 barrierData.srcStageMask &= supportedVulkanPipelineStageMask;
1388 barrierData.dstStageMask &= supportedVulkanPipelineStageMask;
1389 ASSERT(barrierData.pipelineStageGroup ==
1390 GetPipelineStageGroupFromStageFlags(barrierData.dstStageMask));
1391 }
1392 }
1393
EventAndPipelineBarrierHaveMatchingStageFlags(const angle::PackedEnumMap<EventStage,VkPipelineStageFlags> & eventStageMap,const angle::PackedEnumMap<ImageLayout,ImageMemoryBarrierData> & barrierDataMap)1394 bool EventAndPipelineBarrierHaveMatchingStageFlags(
1395 const angle::PackedEnumMap<EventStage, VkPipelineStageFlags> &eventStageMap,
1396 const angle::PackedEnumMap<ImageLayout, ImageMemoryBarrierData> &barrierDataMap)
1397 {
1398 // mImageLayoutAndMemoryBarrierData's dstStageMask should match EventStage's
1399 // kEventStageAndPipelineStageFlagsMap
1400 for (const ImageMemoryBarrierData &barrierData : barrierDataMap)
1401 {
1402 if (barrierData.eventStage != EventStage::InvalidEnum &&
1403 eventStageMap[barrierData.eventStage] != barrierData.dstStageMask)
1404 {
1405 return false;
1406 }
1407 }
1408 return true;
1409 }
1410
FormatHasNecessaryFeature(Renderer * renderer,angle::FormatID formatID,VkImageTiling tilingMode,VkFormatFeatureFlags featureBits)1411 bool FormatHasNecessaryFeature(Renderer *renderer,
1412 angle::FormatID formatID,
1413 VkImageTiling tilingMode,
1414 VkFormatFeatureFlags featureBits)
1415 {
1416 return (tilingMode == VK_IMAGE_TILING_OPTIMAL)
1417 ? renderer->hasImageFormatFeatureBits(formatID, featureBits)
1418 : renderer->hasLinearImageFormatFeatureBits(formatID, featureBits);
1419 }
1420
CanCopyWithTransfer(Renderer * renderer,angle::FormatID srcFormatID,VkImageTiling srcTilingMode,angle::FormatID dstFormatID,VkImageTiling dstTilingMode)1421 bool CanCopyWithTransfer(Renderer *renderer,
1422 angle::FormatID srcFormatID,
1423 VkImageTiling srcTilingMode,
1424 angle::FormatID dstFormatID,
1425 VkImageTiling dstTilingMode)
1426 {
1427 // Checks that the formats in the copy transfer have the appropriate tiling and transfer bits
1428 bool isTilingCompatible = srcTilingMode == dstTilingMode;
1429 bool srcFormatHasNecessaryFeature = FormatHasNecessaryFeature(
1430 renderer, srcFormatID, srcTilingMode, VK_FORMAT_FEATURE_TRANSFER_SRC_BIT);
1431 bool dstFormatHasNecessaryFeature = FormatHasNecessaryFeature(
1432 renderer, dstFormatID, dstTilingMode, VK_FORMAT_FEATURE_TRANSFER_DST_BIT);
1433
1434 return isTilingCompatible && srcFormatHasNecessaryFeature && dstFormatHasNecessaryFeature;
1435 }
1436
1437 // PackedClearValuesArray implementation
PackedClearValuesArray()1438 PackedClearValuesArray::PackedClearValuesArray() : mValues{} {}
1439 PackedClearValuesArray::~PackedClearValuesArray() = default;
1440
1441 PackedClearValuesArray::PackedClearValuesArray(const PackedClearValuesArray &other) = default;
1442 PackedClearValuesArray &PackedClearValuesArray::operator=(const PackedClearValuesArray &rhs) =
1443 default;
1444
storeColor(PackedAttachmentIndex index,const VkClearValue & clearValue)1445 void PackedClearValuesArray::storeColor(PackedAttachmentIndex index, const VkClearValue &clearValue)
1446 {
1447 mValues[index.get()] = clearValue;
1448 }
1449
storeDepthStencil(PackedAttachmentIndex index,const VkClearValue & clearValue)1450 void PackedClearValuesArray::storeDepthStencil(PackedAttachmentIndex index,
1451 const VkClearValue &clearValue)
1452 {
1453 mValues[index.get()] = clearValue;
1454 }
1455
1456 // RenderPassAttachment implementation
RenderPassAttachment()1457 RenderPassAttachment::RenderPassAttachment()
1458 {
1459 reset();
1460 }
1461
init(ImageHelper * image,UniqueSerial imageSiblingSerial,gl::LevelIndex levelIndex,uint32_t layerIndex,uint32_t layerCount,VkImageAspectFlagBits aspect)1462 void RenderPassAttachment::init(ImageHelper *image,
1463 UniqueSerial imageSiblingSerial,
1464 gl::LevelIndex levelIndex,
1465 uint32_t layerIndex,
1466 uint32_t layerCount,
1467 VkImageAspectFlagBits aspect)
1468 {
1469 ASSERT(mImage == nullptr);
1470
1471 mImage = image;
1472 mImageSiblingSerial = imageSiblingSerial;
1473 mLevelIndex = levelIndex;
1474 mLayerIndex = layerIndex;
1475 mLayerCount = layerCount;
1476 mAspect = aspect;
1477
1478 mImage->setRenderPassUsageFlag(RenderPassUsage::RenderTargetAttachment);
1479 }
1480
reset()1481 void RenderPassAttachment::reset()
1482 {
1483 mImage = nullptr;
1484
1485 mAccess = ResourceAccess::Unused;
1486
1487 mInvalidatedCmdCount = kInfiniteCmdCount;
1488 mDisabledCmdCount = kInfiniteCmdCount;
1489 mInvalidateArea = gl::Rectangle();
1490 }
1491
onAccess(ResourceAccess access,uint32_t currentCmdCount)1492 void RenderPassAttachment::onAccess(ResourceAccess access, uint32_t currentCmdCount)
1493 {
1494 // Update the access for optimizing this render pass's loadOp
1495 UpdateAccess(&mAccess, access);
1496
1497 // Update the invalidate state for optimizing this render pass's storeOp
1498 if (onAccessImpl(access, currentCmdCount))
1499 {
1500 // The attachment is no longer invalid, so restore its content.
1501 restoreContent();
1502 }
1503 }
1504
invalidate(const gl::Rectangle & invalidateArea,bool isAttachmentEnabled,uint32_t currentCmdCount)1505 void RenderPassAttachment::invalidate(const gl::Rectangle &invalidateArea,
1506 bool isAttachmentEnabled,
1507 uint32_t currentCmdCount)
1508 {
1509 // Keep track of the command count in the render pass at the time of invalidation. If there are
1510 // more commands in the future, invalidate must be undone.
1511 mInvalidatedCmdCount = currentCmdCount;
1512
1513 // Also track the command count if the attachment is currently disabled.
1514 mDisabledCmdCount = isAttachmentEnabled ? kInfiniteCmdCount : currentCmdCount;
1515
1516 // Set/extend the invalidate area.
1517 ExtendRenderPassInvalidateArea(invalidateArea, &mInvalidateArea);
1518 }
1519
onRenderAreaGrowth(ContextVk * contextVk,const gl::Rectangle & newRenderArea)1520 void RenderPassAttachment::onRenderAreaGrowth(ContextVk *contextVk,
1521 const gl::Rectangle &newRenderArea)
1522 {
1523 // Remove invalidate if it's no longer applicable.
1524 if (mInvalidateArea.empty() || mInvalidateArea.encloses(newRenderArea))
1525 {
1526 return;
1527 }
1528
1529 ANGLE_VK_PERF_WARNING(contextVk, GL_DEBUG_SEVERITY_LOW,
1530 "InvalidateSubFramebuffer discarded due to increased scissor region");
1531
1532 mInvalidateArea = gl::Rectangle();
1533 mInvalidatedCmdCount = kInfiniteCmdCount;
1534 }
1535
finalizeLoadStore(Context * context,uint32_t currentCmdCount,bool hasUnresolveAttachment,bool hasResolveAttachment,RenderPassLoadOp * loadOp,RenderPassStoreOp * storeOp,bool * isInvalidatedOut)1536 void RenderPassAttachment::finalizeLoadStore(Context *context,
1537 uint32_t currentCmdCount,
1538 bool hasUnresolveAttachment,
1539 bool hasResolveAttachment,
1540 RenderPassLoadOp *loadOp,
1541 RenderPassStoreOp *storeOp,
1542 bool *isInvalidatedOut)
1543 {
1544 if (mAspect != VK_IMAGE_ASPECT_COLOR_BIT)
1545 {
1546 const RenderPassUsage readOnlyAttachmentUsage =
1547 mAspect == VK_IMAGE_ASPECT_STENCIL_BIT ? RenderPassUsage::StencilReadOnlyAttachment
1548 : RenderPassUsage::DepthReadOnlyAttachment;
1549 // Ensure we don't write to a read-only attachment. (ReadOnly -> !Write)
1550 ASSERT(!mImage->hasRenderPassUsageFlag(readOnlyAttachmentUsage) ||
1551 !HasResourceWriteAccess(mAccess));
1552 }
1553
1554 // If the attachment is invalidated, skip the store op. If we are not loading or clearing the
1555 // attachment and the attachment has not been used, auto-invalidate it.
1556 const bool notLoaded = *loadOp == RenderPassLoadOp::DontCare && !hasUnresolveAttachment;
1557 if (isInvalidated(currentCmdCount) || (notLoaded && !HasResourceWriteAccess(mAccess)))
1558 {
1559 *storeOp = RenderPassStoreOp::DontCare;
1560 *isInvalidatedOut = true;
1561 }
1562 else if (hasWriteAfterInvalidate(currentCmdCount))
1563 {
1564 // The attachment was invalidated, but is now valid. Let the image know the contents are
1565 // now defined so a future render pass would use loadOp=LOAD.
1566 restoreContent();
1567 }
1568
1569 // For read only depth stencil, we can use StoreOpNone if available. DontCare is still
1570 // preferred, so do this after handling DontCare.
1571 const bool supportsLoadStoreOpNone =
1572 context->getFeatures().supportsRenderPassLoadStoreOpNone.enabled;
1573 const bool supportsStoreOpNone =
1574 supportsLoadStoreOpNone || context->getFeatures().supportsRenderPassStoreOpNone.enabled;
1575 if (mAccess == ResourceAccess::ReadOnly && supportsStoreOpNone)
1576 {
1577 if (*storeOp == RenderPassStoreOp::Store && *loadOp != RenderPassLoadOp::Clear)
1578 {
1579 *storeOp = RenderPassStoreOp::None;
1580 }
1581 }
1582
1583 if (mAccess == ResourceAccess::Unused)
1584 {
1585 if (*storeOp != RenderPassStoreOp::DontCare)
1586 {
1587 switch (*loadOp)
1588 {
1589 case RenderPassLoadOp::Clear:
1590 // Cannot optimize away the ops if the attachment is cleared (even if not used
1591 // afterwards)
1592 break;
1593 case RenderPassLoadOp::Load:
1594 // Make sure the attachment is neither loaded nor stored (as it's neither used
1595 // nor invalidated), if possible.
1596 if (supportsLoadStoreOpNone)
1597 {
1598 *loadOp = RenderPassLoadOp::None;
1599 }
1600 if (supportsStoreOpNone)
1601 {
1602 *storeOp = RenderPassStoreOp::None;
1603 }
1604 break;
1605 case RenderPassLoadOp::DontCare:
1606 // loadOp=DontCare should be covered by storeOp=DontCare below.
1607 break;
1608 case RenderPassLoadOp::None:
1609 default:
1610 // loadOp=None is never decided upfront.
1611 UNREACHABLE();
1612 break;
1613 }
1614 }
1615 }
1616
1617 if (mAccess == ResourceAccess::Unused || (mAccess == ResourceAccess::ReadOnly && notLoaded))
1618 {
1619 // If we are loading or clearing the attachment, but the attachment has not been used,
1620 // and the data has also not been stored back into attachment, then just skip the
1621 // load/clear op. If loadOp/storeOp=None is supported, prefer that to reduce the amount
1622 // of synchronization; DontCare is a write operation, while None is not.
1623 //
1624 // Don't optimize away a Load or Clear if there is a resolve attachment. Although the
1625 // storeOp=DontCare the image content needs to be resolved into the resolve attachment.
1626 const bool attachmentNeedsToBeResolved =
1627 hasResolveAttachment &&
1628 (*loadOp == RenderPassLoadOp::Load || *loadOp == RenderPassLoadOp::Clear);
1629 if (*storeOp == RenderPassStoreOp::DontCare && !attachmentNeedsToBeResolved)
1630 {
1631 if (supportsLoadStoreOpNone && !isInvalidated(currentCmdCount))
1632 {
1633 *loadOp = RenderPassLoadOp::None;
1634 *storeOp = RenderPassStoreOp::None;
1635 }
1636 else
1637 {
1638 *loadOp = RenderPassLoadOp::DontCare;
1639 }
1640 }
1641 }
1642 }
1643
restoreContent()1644 void RenderPassAttachment::restoreContent()
1645 {
1646 // Note that the image may have been deleted since the render pass has started.
1647 if (mImage)
1648 {
1649 ASSERT(mImage->valid());
1650 if (mAspect == VK_IMAGE_ASPECT_STENCIL_BIT)
1651 {
1652 mImage->restoreSubresourceStencilContent(mLevelIndex, mLayerIndex, mLayerCount);
1653 }
1654 else
1655 {
1656 mImage->restoreSubresourceContent(mLevelIndex, mLayerIndex, mLayerCount);
1657 }
1658 mInvalidateArea = gl::Rectangle();
1659 }
1660 }
1661
hasWriteAfterInvalidate(uint32_t currentCmdCount) const1662 bool RenderPassAttachment::hasWriteAfterInvalidate(uint32_t currentCmdCount) const
1663 {
1664 return (mInvalidatedCmdCount != kInfiniteCmdCount &&
1665 std::min(mDisabledCmdCount, currentCmdCount) != mInvalidatedCmdCount);
1666 }
1667
isInvalidated(uint32_t currentCmdCount) const1668 bool RenderPassAttachment::isInvalidated(uint32_t currentCmdCount) const
1669 {
1670 return mInvalidatedCmdCount != kInfiniteCmdCount &&
1671 std::min(mDisabledCmdCount, currentCmdCount) == mInvalidatedCmdCount;
1672 }
1673
onAccessImpl(ResourceAccess access,uint32_t currentCmdCount)1674 bool RenderPassAttachment::onAccessImpl(ResourceAccess access, uint32_t currentCmdCount)
1675 {
1676 if (mInvalidatedCmdCount == kInfiniteCmdCount)
1677 {
1678 // If never invalidated or no longer invalidated, return early.
1679 return false;
1680 }
1681 if (HasResourceWriteAccess(access))
1682 {
1683 // Drawing to this attachment is being enabled. Assume that drawing will immediately occur
1684 // after this attachment is enabled, and that means that the attachment will no longer be
1685 // invalidated.
1686 mInvalidatedCmdCount = kInfiniteCmdCount;
1687 mDisabledCmdCount = kInfiniteCmdCount;
1688 // Return true to indicate that the store op should remain STORE and that mContentDefined
1689 // should be set to true;
1690 return true;
1691 }
1692 // Drawing to this attachment is being disabled.
1693 if (hasWriteAfterInvalidate(currentCmdCount))
1694 {
1695 // The attachment was previously drawn while enabled, and so is no longer invalidated.
1696 mInvalidatedCmdCount = kInfiniteCmdCount;
1697 mDisabledCmdCount = kInfiniteCmdCount;
1698 // Return true to indicate that the store op should remain STORE and that mContentDefined
1699 // should be set to true;
1700 return true;
1701 }
1702
1703 // Use the latest CmdCount at the start of being disabled. At the end of the render pass,
1704 // cmdCountDisabled is <= the actual command count, and so it's compared with
1705 // cmdCountInvalidated. If the same, the attachment is still invalidated.
1706 mDisabledCmdCount = currentCmdCount;
1707 return false;
1708 }
1709
1710 // CommandBufferHelperCommon implementation.
CommandBufferHelperCommon()1711 CommandBufferHelperCommon::CommandBufferHelperCommon()
1712 : mCommandPool(nullptr), mHasShaderStorageOutput(false), mHasGLMemoryBarrierIssued(false)
1713 {}
1714
~CommandBufferHelperCommon()1715 CommandBufferHelperCommon::~CommandBufferHelperCommon() {}
1716
initializeImpl()1717 void CommandBufferHelperCommon::initializeImpl()
1718 {
1719 mCommandAllocator.init();
1720 }
1721
resetImpl(Context * context)1722 void CommandBufferHelperCommon::resetImpl(Context *context)
1723 {
1724 ASSERT(!mAcquireNextImageSemaphore.valid());
1725 mCommandAllocator.resetAllocator();
1726 ASSERT(!mIsAnyHostVisibleBufferWritten);
1727
1728 ASSERT(mRefCountedEvents.mask.none());
1729 ASSERT(mRefCountedEventCollector.empty());
1730 }
1731
1732 template <class DerivedT>
attachCommandPoolImpl(Context * context,SecondaryCommandPool * commandPool)1733 angle::Result CommandBufferHelperCommon::attachCommandPoolImpl(Context *context,
1734 SecondaryCommandPool *commandPool)
1735 {
1736 if constexpr (!DerivedT::ExecutesInline())
1737 {
1738 DerivedT *derived = static_cast<DerivedT *>(this);
1739 ASSERT(commandPool != nullptr);
1740 ASSERT(mCommandPool == nullptr);
1741 ASSERT(!derived->getCommandBuffer().valid());
1742
1743 mCommandPool = commandPool;
1744
1745 ANGLE_TRY(derived->initializeCommandBuffer(context));
1746 }
1747 return angle::Result::Continue;
1748 }
1749
1750 template <class DerivedT, bool kIsRenderPassBuffer>
detachCommandPoolImpl(Context * context,SecondaryCommandPool ** commandPoolOut)1751 angle::Result CommandBufferHelperCommon::detachCommandPoolImpl(
1752 Context *context,
1753 SecondaryCommandPool **commandPoolOut)
1754 {
1755 if constexpr (!DerivedT::ExecutesInline())
1756 {
1757 DerivedT *derived = static_cast<DerivedT *>(this);
1758 ASSERT(mCommandPool != nullptr);
1759 ASSERT(derived->getCommandBuffer().valid());
1760
1761 if constexpr (!kIsRenderPassBuffer)
1762 {
1763 ASSERT(!derived->getCommandBuffer().empty());
1764 ANGLE_TRY(derived->endCommandBuffer(context));
1765 }
1766
1767 *commandPoolOut = mCommandPool;
1768 mCommandPool = nullptr;
1769 }
1770 ASSERT(mCommandPool == nullptr);
1771 return angle::Result::Continue;
1772 }
1773
1774 template <class DerivedT>
releaseCommandPoolImpl()1775 void CommandBufferHelperCommon::releaseCommandPoolImpl()
1776 {
1777 if constexpr (!DerivedT::ExecutesInline())
1778 {
1779 DerivedT *derived = static_cast<DerivedT *>(this);
1780 ASSERT(mCommandPool != nullptr);
1781
1782 if (derived->getCommandBuffer().valid())
1783 {
1784 ASSERT(derived->getCommandBuffer().empty());
1785 mCommandPool->collect(&derived->getCommandBuffer());
1786 }
1787
1788 mCommandPool = nullptr;
1789 }
1790 ASSERT(mCommandPool == nullptr);
1791 }
1792
1793 template <class DerivedT>
attachAllocatorImpl(SecondaryCommandMemoryAllocator * allocator)1794 void CommandBufferHelperCommon::attachAllocatorImpl(SecondaryCommandMemoryAllocator *allocator)
1795 {
1796 if constexpr (DerivedT::ExecutesInline())
1797 {
1798 auto &commandBuffer = static_cast<DerivedT *>(this)->getCommandBuffer();
1799 mCommandAllocator.attachAllocator(allocator);
1800 commandBuffer.attachAllocator(mCommandAllocator.getAllocator());
1801 }
1802 }
1803
1804 template <class DerivedT>
detachAllocatorImpl()1805 SecondaryCommandMemoryAllocator *CommandBufferHelperCommon::detachAllocatorImpl()
1806 {
1807 SecondaryCommandMemoryAllocator *result = nullptr;
1808 if constexpr (DerivedT::ExecutesInline())
1809 {
1810 auto &commandBuffer = static_cast<DerivedT *>(this)->getCommandBuffer();
1811 commandBuffer.detachAllocator(mCommandAllocator.getAllocator());
1812 result = mCommandAllocator.detachAllocator(commandBuffer.empty());
1813 }
1814 return result;
1815 }
1816
1817 template <class DerivedT>
assertCanBeRecycledImpl()1818 void CommandBufferHelperCommon::assertCanBeRecycledImpl()
1819 {
1820 DerivedT *derived = static_cast<DerivedT *>(this);
1821 ASSERT(mCommandPool == nullptr);
1822 ASSERT(!mCommandAllocator.hasAllocatorLinks());
1823 // Vulkan secondary command buffers must be invalid (collected).
1824 ASSERT(DerivedT::ExecutesInline() || !derived->getCommandBuffer().valid());
1825 // ANGLEs Custom secondary command buffers must be empty (reset).
1826 ASSERT(!DerivedT::ExecutesInline() || derived->getCommandBuffer().empty());
1827 }
1828
bufferWrite(VkAccessFlags writeAccessType,PipelineStage writeStage,BufferHelper * buffer)1829 void CommandBufferHelperCommon::bufferWrite(VkAccessFlags writeAccessType,
1830 PipelineStage writeStage,
1831 BufferHelper *buffer)
1832 {
1833 buffer->setWriteQueueSerial(mQueueSerial);
1834
1835 VkPipelineStageFlagBits stageBits = kPipelineStageFlagBitMap[writeStage];
1836 buffer->recordWriteBarrier(writeAccessType, stageBits, writeStage, &mPipelineBarriers);
1837
1838 // Make sure host-visible buffer writes result in a barrier inserted at the end of the frame to
1839 // make the results visible to the host. The buffer may be mapped by the application in the
1840 // future.
1841 if (buffer->isHostVisible())
1842 {
1843 mIsAnyHostVisibleBufferWritten = true;
1844 }
1845 }
1846
executeBarriers(Renderer * renderer,CommandsState * commandsState)1847 void CommandBufferHelperCommon::executeBarriers(Renderer *renderer, CommandsState *commandsState)
1848 {
1849 // Add ANI semaphore to the command submission.
1850 if (mAcquireNextImageSemaphore.valid())
1851 {
1852 commandsState->waitSemaphores.emplace_back(mAcquireNextImageSemaphore.release());
1853 commandsState->waitSemaphoreStageMasks.emplace_back(kSwapchainAcquireImageWaitStageFlags);
1854 }
1855
1856 mPipelineBarriers.execute(renderer, &commandsState->primaryCommands);
1857 mEventBarriers.execute(renderer, &commandsState->primaryCommands);
1858 }
1859
bufferReadImpl(VkAccessFlags readAccessType,PipelineStage readStage,BufferHelper * buffer)1860 void CommandBufferHelperCommon::bufferReadImpl(VkAccessFlags readAccessType,
1861 PipelineStage readStage,
1862 BufferHelper *buffer)
1863 {
1864 VkPipelineStageFlagBits stageBits = kPipelineStageFlagBitMap[readStage];
1865 buffer->recordReadBarrier(readAccessType, stageBits, readStage, &mPipelineBarriers);
1866 ASSERT(!usesBufferForWrite(*buffer));
1867 }
1868
imageReadImpl(Context * context,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,BarrierType barrierType,ImageHelper * image)1869 void CommandBufferHelperCommon::imageReadImpl(Context *context,
1870 VkImageAspectFlags aspectFlags,
1871 ImageLayout imageLayout,
1872 BarrierType barrierType,
1873 ImageHelper *image)
1874 {
1875 if (image->isReadBarrierNecessary(context->getRenderer(), imageLayout))
1876 {
1877 updateImageLayoutAndBarrier(context, image, aspectFlags, imageLayout, barrierType);
1878 }
1879 }
1880
imageWriteImpl(Context * context,gl::LevelIndex level,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,BarrierType barrierType,ImageHelper * image)1881 void CommandBufferHelperCommon::imageWriteImpl(Context *context,
1882 gl::LevelIndex level,
1883 uint32_t layerStart,
1884 uint32_t layerCount,
1885 VkImageAspectFlags aspectFlags,
1886 ImageLayout imageLayout,
1887 BarrierType barrierType,
1888 ImageHelper *image)
1889 {
1890 image->onWrite(level, 1, layerStart, layerCount, aspectFlags);
1891 if (image->isWriteBarrierNecessary(imageLayout, level, 1, layerStart, layerCount))
1892 {
1893 updateImageLayoutAndBarrier(context, image, aspectFlags, imageLayout, barrierType);
1894 }
1895 }
1896
updateImageLayoutAndBarrier(Context * context,ImageHelper * image,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,BarrierType barrierType)1897 void CommandBufferHelperCommon::updateImageLayoutAndBarrier(Context *context,
1898 ImageHelper *image,
1899 VkImageAspectFlags aspectFlags,
1900 ImageLayout imageLayout,
1901 BarrierType barrierType)
1902 {
1903 VkSemaphore semaphore = VK_NULL_HANDLE;
1904 image->updateLayoutAndBarrier(context, aspectFlags, imageLayout, barrierType, mQueueSerial,
1905 &mPipelineBarriers, &mEventBarriers, &mRefCountedEventCollector,
1906 &semaphore);
1907 // If image has an ANI semaphore, move it to command buffer so that we can wait for it in
1908 // next submission.
1909 if (semaphore != VK_NULL_HANDLE)
1910 {
1911 ASSERT(!mAcquireNextImageSemaphore.valid());
1912 mAcquireNextImageSemaphore.setHandle(semaphore);
1913 }
1914 }
1915
retainImageWithEvent(Context * context,ImageHelper * image)1916 void CommandBufferHelperCommon::retainImageWithEvent(Context *context, ImageHelper *image)
1917 {
1918 image->setQueueSerial(mQueueSerial);
1919 image->updatePipelineStageAccessHistory();
1920
1921 if (context->getFeatures().useVkEventForImageBarrier.enabled)
1922 {
1923 image->setCurrentRefCountedEvent(context, mRefCountedEvents);
1924 }
1925 }
1926
1927 template <typename CommandBufferT>
flushSetEventsImpl(Context * context,CommandBufferT * commandBuffer)1928 void CommandBufferHelperCommon::flushSetEventsImpl(Context *context, CommandBufferT *commandBuffer)
1929 {
1930 if (mRefCountedEvents.mask.none())
1931 {
1932 return;
1933 }
1934
1935 Renderer *renderer = context->getRenderer();
1936 // Add VkCmdSetEvent here to track the completion of this renderPass.
1937 for (EventStage stage : mRefCountedEvents.mask)
1938 {
1939 RefCountedEvent &refCountedEvent = mRefCountedEvents.map[stage];
1940 ASSERT(refCountedEvent.valid());
1941 VkPipelineStageFlags stageMask = renderer->getPipelineStageMask(stage);
1942 commandBuffer->setEvent(refCountedEvent.getEvent().getHandle(), stageMask);
1943 // We no longer need event, so garbage collect it.
1944 mRefCountedEventCollector.emplace_back(std::move(refCountedEvent));
1945 }
1946 mRefCountedEvents.mask.reset();
1947 }
1948
1949 template void CommandBufferHelperCommon::flushSetEventsImpl<priv::SecondaryCommandBuffer>(
1950 Context *context,
1951 priv::SecondaryCommandBuffer *commandBuffer);
1952 template void CommandBufferHelperCommon::flushSetEventsImpl<VulkanSecondaryCommandBuffer>(
1953 Context *context,
1954 VulkanSecondaryCommandBuffer *commandBuffer);
1955
addCommandDiagnosticsCommon(std::ostringstream * out)1956 void CommandBufferHelperCommon::addCommandDiagnosticsCommon(std::ostringstream *out)
1957 {
1958 mPipelineBarriers.addDiagnosticsString(*out);
1959 mEventBarriers.addDiagnosticsString(*out);
1960 }
1961
setBufferReadQueueSerial(BufferHelper * buffer)1962 void CommandBufferHelperCommon::setBufferReadQueueSerial(BufferHelper *buffer)
1963 {
1964 if (buffer->getResourceUse() >= mQueueSerial)
1965 {
1966 // We should not run into situation that RP is writing to it while we are reading it here
1967 ASSERT(!(buffer->getWriteResourceUse() >= mQueueSerial));
1968 // A buffer could have read accessed by both renderPassCommands and
1969 // outsideRenderPassCommands and there is no need to endRP or flush. In this case, the
1970 // renderPassCommands' read will override the outsideRenderPassCommands' read, since its
1971 // queueSerial must be greater than outsideRP.
1972 }
1973 else
1974 {
1975 buffer->setQueueSerial(mQueueSerial);
1976 }
1977 }
1978
1979 // OutsideRenderPassCommandBufferHelper implementation.
OutsideRenderPassCommandBufferHelper()1980 OutsideRenderPassCommandBufferHelper::OutsideRenderPassCommandBufferHelper() {}
1981
~OutsideRenderPassCommandBufferHelper()1982 OutsideRenderPassCommandBufferHelper::~OutsideRenderPassCommandBufferHelper() {}
1983
initialize(Context * context)1984 angle::Result OutsideRenderPassCommandBufferHelper::initialize(Context *context)
1985 {
1986 initializeImpl();
1987 return initializeCommandBuffer(context);
1988 }
initializeCommandBuffer(Context * context)1989 angle::Result OutsideRenderPassCommandBufferHelper::initializeCommandBuffer(Context *context)
1990 {
1991 // Skip initialization in the Pool-detached state.
1992 if (!ExecutesInline() && mCommandPool == nullptr)
1993 {
1994 return angle::Result::Continue;
1995 }
1996 return mCommandBuffer.initialize(context, mCommandPool, false,
1997 mCommandAllocator.getAllocator());
1998 }
1999
reset(Context * context,SecondaryCommandBufferCollector * commandBufferCollector)2000 angle::Result OutsideRenderPassCommandBufferHelper::reset(
2001 Context *context,
2002 SecondaryCommandBufferCollector *commandBufferCollector)
2003 {
2004 resetImpl(context);
2005
2006 // Collect/Reset the command buffer
2007 commandBufferCollector->collectCommandBuffer(std::move(mCommandBuffer));
2008 mIsCommandBufferEnded = false;
2009
2010 // Invalidate the queue serial here. We will get a new queue serial after commands flush.
2011 mQueueSerial = QueueSerial();
2012
2013 return initializeCommandBuffer(context);
2014 }
2015
imageRead(Context * context,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,ImageHelper * image)2016 void OutsideRenderPassCommandBufferHelper::imageRead(Context *context,
2017 VkImageAspectFlags aspectFlags,
2018 ImageLayout imageLayout,
2019 ImageHelper *image)
2020 {
2021 if (image->getResourceUse() >= mQueueSerial)
2022 {
2023 // If image is already used by renderPass, it may already set the event to renderPass's
2024 // event. In this case we already lost the previous event to wait for, thus use pipeline
2025 // barrier instead of event
2026 imageReadImpl(context, aspectFlags, imageLayout, BarrierType::Pipeline, image);
2027 }
2028 else
2029 {
2030 imageReadImpl(context, aspectFlags, imageLayout, BarrierType::Event, image);
2031 // Usually an image can only used by a RenderPassCommands or OutsideRenderPassCommands
2032 // because the layout will be different, except with image sampled from compute shader. In
2033 // this case, the renderPassCommands' read will override the outsideRenderPassCommands'
2034 retainImageWithEvent(context, image);
2035 }
2036 }
2037
imageWrite(Context * context,gl::LevelIndex level,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,ImageHelper * image)2038 void OutsideRenderPassCommandBufferHelper::imageWrite(Context *context,
2039 gl::LevelIndex level,
2040 uint32_t layerStart,
2041 uint32_t layerCount,
2042 VkImageAspectFlags aspectFlags,
2043 ImageLayout imageLayout,
2044 ImageHelper *image)
2045 {
2046 imageWriteImpl(context, level, layerStart, layerCount, aspectFlags, imageLayout,
2047 BarrierType::Event, image);
2048 retainImageWithEvent(context, image);
2049 }
2050
retainImage(ImageHelper * image)2051 void OutsideRenderPassCommandBufferHelper::retainImage(ImageHelper *image)
2052 {
2053 // We want explicit control on when VkEvent is used for outsideRPCommands to minimize the
2054 // overhead, so do not setEvent here.
2055 image->setQueueSerial(mQueueSerial);
2056 image->updatePipelineStageAccessHistory();
2057 }
2058
trackImageWithEvent(Context * context,ImageHelper * image)2059 void OutsideRenderPassCommandBufferHelper::trackImageWithEvent(Context *context, ImageHelper *image)
2060 {
2061 image->setCurrentRefCountedEvent(context, mRefCountedEvents);
2062 flushSetEventsImpl(context, &mCommandBuffer);
2063 }
2064
collectRefCountedEventsGarbage(RefCountedEventsGarbageRecycler * garbageRecycler)2065 void OutsideRenderPassCommandBufferHelper::collectRefCountedEventsGarbage(
2066 RefCountedEventsGarbageRecycler *garbageRecycler)
2067 {
2068 ASSERT(garbageRecycler != nullptr);
2069 if (!mRefCountedEventCollector.empty())
2070 {
2071 garbageRecycler->collectGarbage(mQueueSerial, std::move(mRefCountedEventCollector));
2072 }
2073 }
2074
flushToPrimary(Context * context,CommandsState * commandsState)2075 angle::Result OutsideRenderPassCommandBufferHelper::flushToPrimary(Context *context,
2076 CommandsState *commandsState)
2077 {
2078 ANGLE_TRACE_EVENT0("gpu.angle", "OutsideRenderPassCommandBufferHelper::flushToPrimary");
2079 ASSERT(!empty());
2080
2081 Renderer *renderer = context->getRenderer();
2082
2083 // Commands that are added to primary before beginRenderPass command
2084 executeBarriers(renderer, commandsState);
2085
2086 // When using Vulkan secondary command buffers and "asyncCommandQueue" is enabled, command
2087 // buffer MUST be already ended in the detachCommandPool() (called in the CommandProcessor).
2088 // After the detach, nothing is written to the buffer (the barriers above are written directly
2089 // to the primary buffer).
2090 // Note: RenderPass Command Buffers are explicitly ended in the endRenderPass().
2091 if (ExecutesInline() || !renderer->isAsyncCommandQueueEnabled())
2092 {
2093 ANGLE_TRY(endCommandBuffer(context));
2094 }
2095 ASSERT(mIsCommandBufferEnded);
2096 mCommandBuffer.executeCommands(&commandsState->primaryCommands);
2097
2098 // Call VkCmdSetEvent to track the completion of this renderPass.
2099 flushSetEventsImpl(context, &commandsState->primaryCommands);
2100
2101 // Proactively reset all released events before ending command buffer.
2102 context->getRenderer()->getRefCountedEventRecycler()->resetEvents(
2103 context, mQueueSerial, &commandsState->primaryCommands);
2104
2105 // Restart the command buffer.
2106 return reset(context, &commandsState->secondaryCommands);
2107 }
2108
endCommandBuffer(Context * context)2109 angle::Result OutsideRenderPassCommandBufferHelper::endCommandBuffer(Context *context)
2110 {
2111 ASSERT(ExecutesInline() || mCommandPool != nullptr);
2112 ASSERT(mCommandBuffer.valid());
2113 ASSERT(!mIsCommandBufferEnded);
2114
2115 ANGLE_TRY(mCommandBuffer.end(context));
2116 mIsCommandBufferEnded = true;
2117
2118 return angle::Result::Continue;
2119 }
2120
attachCommandPool(Context * context,SecondaryCommandPool * commandPool)2121 angle::Result OutsideRenderPassCommandBufferHelper::attachCommandPool(
2122 Context *context,
2123 SecondaryCommandPool *commandPool)
2124 {
2125 return attachCommandPoolImpl<OutsideRenderPassCommandBufferHelper>(context, commandPool);
2126 }
2127
detachCommandPool(Context * context,SecondaryCommandPool ** commandPoolOut)2128 angle::Result OutsideRenderPassCommandBufferHelper::detachCommandPool(
2129 Context *context,
2130 SecondaryCommandPool **commandPoolOut)
2131 {
2132 return detachCommandPoolImpl<OutsideRenderPassCommandBufferHelper, false>(context,
2133 commandPoolOut);
2134 }
2135
releaseCommandPool()2136 void OutsideRenderPassCommandBufferHelper::releaseCommandPool()
2137 {
2138 releaseCommandPoolImpl<OutsideRenderPassCommandBufferHelper>();
2139 }
2140
attachAllocator(SecondaryCommandMemoryAllocator * allocator)2141 void OutsideRenderPassCommandBufferHelper::attachAllocator(
2142 SecondaryCommandMemoryAllocator *allocator)
2143 {
2144 attachAllocatorImpl<OutsideRenderPassCommandBufferHelper>(allocator);
2145 }
2146
detachAllocator()2147 SecondaryCommandMemoryAllocator *OutsideRenderPassCommandBufferHelper::detachAllocator()
2148 {
2149 return detachAllocatorImpl<OutsideRenderPassCommandBufferHelper>();
2150 }
2151
assertCanBeRecycled()2152 void OutsideRenderPassCommandBufferHelper::assertCanBeRecycled()
2153 {
2154 assertCanBeRecycledImpl<OutsideRenderPassCommandBufferHelper>();
2155 }
2156
getCommandDiagnostics()2157 std::string OutsideRenderPassCommandBufferHelper::getCommandDiagnostics()
2158 {
2159 std::ostringstream out;
2160 addCommandDiagnosticsCommon(&out);
2161
2162 out << mCommandBuffer.dumpCommands("\\l");
2163
2164 return out.str();
2165 }
2166
2167 // RenderPassFramebuffer implementation.
reset()2168 void RenderPassFramebuffer::reset()
2169 {
2170 mInitialFramebuffer.release();
2171 mImageViews.clear();
2172 mIsImageless = false;
2173 mIsDefault = false;
2174 }
2175
addResolveAttachment(size_t viewIndex,VkImageView view)2176 void RenderPassFramebuffer::addResolveAttachment(size_t viewIndex, VkImageView view)
2177 {
2178 // The initial framebuffer is no longer usable.
2179 mInitialFramebuffer.release();
2180
2181 if (viewIndex >= mImageViews.size())
2182 {
2183 mImageViews.resize(viewIndex + 1, VK_NULL_HANDLE);
2184 }
2185
2186 ASSERT(mImageViews[viewIndex] == VK_NULL_HANDLE);
2187 mImageViews[viewIndex] = view;
2188 }
2189
packResolveViewsAndCreateFramebuffer(Context * context,const RenderPass & renderPass,Framebuffer * framebufferOut)2190 angle::Result RenderPassFramebuffer::packResolveViewsAndCreateFramebuffer(
2191 Context *context,
2192 const RenderPass &renderPass,
2193 Framebuffer *framebufferOut)
2194 {
2195 // This is only called if the initial framebuffer was not usable. Since this is called when
2196 // the render pass is finalized, the render pass that is passed in is the final one (not a
2197 // compatible one) and the framebuffer that is created is not imageless.
2198 ASSERT(!mInitialFramebuffer.valid());
2199
2200 PackViews(&mImageViews);
2201 mIsImageless = false;
2202
2203 VkFramebufferCreateInfo framebufferInfo = {};
2204 framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
2205 framebufferInfo.flags = 0;
2206 framebufferInfo.renderPass = renderPass.getHandle();
2207 framebufferInfo.attachmentCount = static_cast<uint32_t>(mImageViews.size());
2208 framebufferInfo.pAttachments = mImageViews.data();
2209 framebufferInfo.width = mWidth;
2210 framebufferInfo.height = mHeight;
2211 framebufferInfo.layers = mLayers;
2212
2213 ANGLE_VK_TRY(context, framebufferOut->init(context->getDevice(), framebufferInfo));
2214 return angle::Result::Continue;
2215 }
2216
packResolveViewsForRenderPassBegin(VkRenderPassAttachmentBeginInfo * beginInfoOut)2217 void RenderPassFramebuffer::packResolveViewsForRenderPassBegin(
2218 VkRenderPassAttachmentBeginInfo *beginInfoOut)
2219 {
2220 // Called when using the initial framebuffer which is imageless
2221 ASSERT(mInitialFramebuffer.valid());
2222 ASSERT(mIsImageless);
2223
2224 PackViews(&mImageViews);
2225
2226 *beginInfoOut = {};
2227 beginInfoOut->sType = VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO_KHR;
2228 beginInfoOut->attachmentCount = static_cast<uint32_t>(mImageViews.size());
2229 beginInfoOut->pAttachments = mImageViews.data();
2230 }
2231
2232 // static
PackViews(FramebufferAttachmentsVector<VkImageView> * views)2233 void RenderPassFramebuffer::PackViews(FramebufferAttachmentsVector<VkImageView> *views)
2234 {
2235 PackedAttachmentIndex packIndex = kAttachmentIndexZero;
2236 for (size_t viewIndex = 0; viewIndex < views->size(); ++viewIndex)
2237 {
2238 if ((*views)[viewIndex] != VK_NULL_HANDLE)
2239 {
2240 (*views)[packIndex.get()] = (*views)[viewIndex];
2241 ++packIndex;
2242 }
2243 }
2244
2245 views->resize(packIndex.get());
2246 }
2247
2248 // RenderPassCommandBufferHelper implementation.
RenderPassCommandBufferHelper()2249 RenderPassCommandBufferHelper::RenderPassCommandBufferHelper()
2250 : mCurrentSubpassCommandBufferIndex(0),
2251 mCounter(0),
2252 mClearValues{},
2253 mRenderPassStarted(false),
2254 mTransformFeedbackCounterBuffers{},
2255 mTransformFeedbackCounterBufferOffsets{},
2256 mValidTransformFeedbackBufferCount(0),
2257 mRebindTransformFeedbackBuffers(false),
2258 mIsTransformFeedbackActiveUnpaused(false),
2259 mPreviousSubpassesCmdCount(0),
2260 mDepthStencilAttachmentIndex(kAttachmentIndexInvalid),
2261 mColorAttachmentsCount(0),
2262 mImageOptimizeForPresent(nullptr),
2263 mImageOptimizeForPresentOriginalLayout(ImageLayout::Undefined)
2264 {}
2265
~RenderPassCommandBufferHelper()2266 RenderPassCommandBufferHelper::~RenderPassCommandBufferHelper() {}
2267
initialize(Context * context)2268 angle::Result RenderPassCommandBufferHelper::initialize(Context *context)
2269 {
2270 initializeImpl();
2271 return initializeCommandBuffer(context);
2272 }
initializeCommandBuffer(Context * context)2273 angle::Result RenderPassCommandBufferHelper::initializeCommandBuffer(Context *context)
2274 {
2275 // Skip initialization in the Pool-detached state.
2276 if (!ExecutesInline() && mCommandPool == nullptr)
2277 {
2278 return angle::Result::Continue;
2279 }
2280 return getCommandBuffer().initialize(context, mCommandPool, true,
2281 mCommandAllocator.getAllocator());
2282 }
2283
reset(Context * context,SecondaryCommandBufferCollector * commandBufferCollector)2284 angle::Result RenderPassCommandBufferHelper::reset(
2285 Context *context,
2286 SecondaryCommandBufferCollector *commandBufferCollector)
2287 {
2288 resetImpl(context);
2289
2290 for (PackedAttachmentIndex index = kAttachmentIndexZero; index < mColorAttachmentsCount;
2291 ++index)
2292 {
2293 mColorAttachments[index].reset();
2294 mColorResolveAttachments[index].reset();
2295 }
2296
2297 mDepthAttachment.reset();
2298 mDepthResolveAttachment.reset();
2299 mStencilAttachment.reset();
2300 mStencilResolveAttachment.reset();
2301
2302 mFragmentShadingRateAtachment.reset();
2303
2304 mRenderPassStarted = false;
2305 mValidTransformFeedbackBufferCount = 0;
2306 mRebindTransformFeedbackBuffers = false;
2307 mHasShaderStorageOutput = false;
2308 mHasGLMemoryBarrierIssued = false;
2309 mPreviousSubpassesCmdCount = 0;
2310 mColorAttachmentsCount = PackedAttachmentCount(0);
2311 mDepthStencilAttachmentIndex = kAttachmentIndexInvalid;
2312 mImageOptimizeForPresent = nullptr;
2313 mImageOptimizeForPresentOriginalLayout = ImageLayout::Undefined;
2314
2315 ASSERT(CheckSubpassCommandBufferCount(getSubpassCommandBufferCount()));
2316
2317 // Collect/Reset the command buffers
2318 for (uint32_t subpass = 0; subpass < getSubpassCommandBufferCount(); ++subpass)
2319 {
2320 commandBufferCollector->collectCommandBuffer(std::move(mCommandBuffers[subpass]));
2321 }
2322
2323 mCurrentSubpassCommandBufferIndex = 0;
2324
2325 // Reset the image views used for imageless framebuffer (if any)
2326 mFramebuffer.reset();
2327
2328 // Invalidate the queue serial here. We will get a new queue serial when we begin renderpass.
2329 mQueueSerial = QueueSerial();
2330
2331 return initializeCommandBuffer(context);
2332 }
2333
imageRead(ContextVk * contextVk,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,ImageHelper * image)2334 void RenderPassCommandBufferHelper::imageRead(ContextVk *contextVk,
2335 VkImageAspectFlags aspectFlags,
2336 ImageLayout imageLayout,
2337 ImageHelper *image)
2338 {
2339 imageReadImpl(contextVk, aspectFlags, imageLayout, BarrierType::Event, image);
2340 // As noted in the header we don't support multiple read layouts for Images.
2341 // We allow duplicate uses in the RP to accommodate for normal GL sampler usage.
2342 retainImageWithEvent(contextVk, image);
2343 }
2344
imageWrite(ContextVk * contextVk,gl::LevelIndex level,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,ImageHelper * image)2345 void RenderPassCommandBufferHelper::imageWrite(ContextVk *contextVk,
2346 gl::LevelIndex level,
2347 uint32_t layerStart,
2348 uint32_t layerCount,
2349 VkImageAspectFlags aspectFlags,
2350 ImageLayout imageLayout,
2351 ImageHelper *image)
2352 {
2353 imageWriteImpl(contextVk, level, layerStart, layerCount, aspectFlags, imageLayout,
2354 BarrierType::Event, image);
2355 retainImageWithEvent(contextVk, image);
2356 }
2357
colorImagesDraw(gl::LevelIndex level,uint32_t layerStart,uint32_t layerCount,ImageHelper * image,ImageHelper * resolveImage,UniqueSerial imageSiblingSerial,PackedAttachmentIndex packedAttachmentIndex)2358 void RenderPassCommandBufferHelper::colorImagesDraw(gl::LevelIndex level,
2359 uint32_t layerStart,
2360 uint32_t layerCount,
2361 ImageHelper *image,
2362 ImageHelper *resolveImage,
2363 UniqueSerial imageSiblingSerial,
2364 PackedAttachmentIndex packedAttachmentIndex)
2365 {
2366 ASSERT(packedAttachmentIndex < mColorAttachmentsCount);
2367
2368 image->onRenderPassAttach(mQueueSerial);
2369
2370 mColorAttachments[packedAttachmentIndex].init(image, imageSiblingSerial, level, layerStart,
2371 layerCount, VK_IMAGE_ASPECT_COLOR_BIT);
2372
2373 if (resolveImage)
2374 {
2375 resolveImage->onRenderPassAttach(mQueueSerial);
2376 mColorResolveAttachments[packedAttachmentIndex].init(resolveImage, imageSiblingSerial,
2377 level, layerStart, layerCount,
2378 VK_IMAGE_ASPECT_COLOR_BIT);
2379 }
2380 }
2381
depthStencilImagesDraw(gl::LevelIndex level,uint32_t layerStart,uint32_t layerCount,ImageHelper * image,ImageHelper * resolveImage,UniqueSerial imageSiblingSerial)2382 void RenderPassCommandBufferHelper::depthStencilImagesDraw(gl::LevelIndex level,
2383 uint32_t layerStart,
2384 uint32_t layerCount,
2385 ImageHelper *image,
2386 ImageHelper *resolveImage,
2387 UniqueSerial imageSiblingSerial)
2388 {
2389 ASSERT(!usesImage(*image));
2390 ASSERT(!resolveImage || !usesImage(*resolveImage));
2391
2392 // Because depthStencil buffer's read/write property can change while we build renderpass, we
2393 // defer the image layout changes until endRenderPass time or when images going away so that we
2394 // only insert layout change barrier once.
2395 image->onRenderPassAttach(mQueueSerial);
2396
2397 mDepthAttachment.init(image, imageSiblingSerial, level, layerStart, layerCount,
2398 VK_IMAGE_ASPECT_DEPTH_BIT);
2399 mStencilAttachment.init(image, imageSiblingSerial, level, layerStart, layerCount,
2400 VK_IMAGE_ASPECT_STENCIL_BIT);
2401
2402 if (resolveImage)
2403 {
2404 // Note that the resolve depth/stencil image has the same level/layer index as the
2405 // depth/stencil image as currently it can only ever come from
2406 // multisampled-render-to-texture renderbuffers.
2407 resolveImage->onRenderPassAttach(mQueueSerial);
2408
2409 mDepthResolveAttachment.init(resolveImage, imageSiblingSerial, level, layerStart,
2410 layerCount, VK_IMAGE_ASPECT_DEPTH_BIT);
2411 mStencilResolveAttachment.init(resolveImage, imageSiblingSerial, level, layerStart,
2412 layerCount, VK_IMAGE_ASPECT_STENCIL_BIT);
2413 }
2414 }
2415
fragmentShadingRateImageRead(ImageHelper * image)2416 void RenderPassCommandBufferHelper::fragmentShadingRateImageRead(ImageHelper *image)
2417 {
2418 ASSERT(image && image->valid());
2419 ASSERT(!usesImage(*image));
2420
2421 image->onRenderPassAttach(mQueueSerial);
2422
2423 // Initialize RenderPassAttachment for fragment shading rate attachment.
2424 mFragmentShadingRateAtachment.init(image, {}, gl::LevelIndex(0), 0, 1,
2425 VK_IMAGE_ASPECT_COLOR_BIT);
2426
2427 image->resetRenderPassUsageFlags();
2428 image->setRenderPassUsageFlag(RenderPassUsage::FragmentShadingRateReadOnlyAttachment);
2429 }
2430
onColorAccess(PackedAttachmentIndex packedAttachmentIndex,ResourceAccess access)2431 void RenderPassCommandBufferHelper::onColorAccess(PackedAttachmentIndex packedAttachmentIndex,
2432 ResourceAccess access)
2433 {
2434 ASSERT(packedAttachmentIndex < mColorAttachmentsCount);
2435 mColorAttachments[packedAttachmentIndex].onAccess(access, getRenderPassWriteCommandCount());
2436 }
2437
onDepthAccess(ResourceAccess access)2438 void RenderPassCommandBufferHelper::onDepthAccess(ResourceAccess access)
2439 {
2440 mDepthAttachment.onAccess(access, getRenderPassWriteCommandCount());
2441 }
2442
onStencilAccess(ResourceAccess access)2443 void RenderPassCommandBufferHelper::onStencilAccess(ResourceAccess access)
2444 {
2445 mStencilAttachment.onAccess(access, getRenderPassWriteCommandCount());
2446 }
2447
updateDepthReadOnlyMode(RenderPassUsageFlags dsUsageFlags)2448 void RenderPassCommandBufferHelper::updateDepthReadOnlyMode(RenderPassUsageFlags dsUsageFlags)
2449 {
2450 ASSERT(mRenderPassStarted);
2451 updateStartedRenderPassWithDepthStencilMode(&mDepthResolveAttachment, hasDepthWriteOrClear(),
2452 dsUsageFlags,
2453 RenderPassUsage::DepthReadOnlyAttachment);
2454 }
2455
updateStencilReadOnlyMode(RenderPassUsageFlags dsUsageFlags)2456 void RenderPassCommandBufferHelper::updateStencilReadOnlyMode(RenderPassUsageFlags dsUsageFlags)
2457 {
2458 ASSERT(mRenderPassStarted);
2459 updateStartedRenderPassWithDepthStencilMode(&mStencilResolveAttachment,
2460 hasStencilWriteOrClear(), dsUsageFlags,
2461 RenderPassUsage::StencilReadOnlyAttachment);
2462 }
2463
updateDepthStencilReadOnlyMode(RenderPassUsageFlags dsUsageFlags,VkImageAspectFlags dsAspectFlags)2464 void RenderPassCommandBufferHelper::updateDepthStencilReadOnlyMode(
2465 RenderPassUsageFlags dsUsageFlags,
2466 VkImageAspectFlags dsAspectFlags)
2467 {
2468 ASSERT(mRenderPassStarted);
2469 if ((dsAspectFlags & VK_IMAGE_ASPECT_DEPTH_BIT) != 0)
2470 {
2471 updateDepthReadOnlyMode(dsUsageFlags);
2472 }
2473 if ((dsAspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) != 0)
2474 {
2475 updateStencilReadOnlyMode(dsUsageFlags);
2476 }
2477 }
2478
updateStartedRenderPassWithDepthStencilMode(RenderPassAttachment * resolveAttachment,bool renderPassHasWriteOrClear,RenderPassUsageFlags dsUsageFlags,RenderPassUsage readOnlyAttachmentUsage)2479 void RenderPassCommandBufferHelper::updateStartedRenderPassWithDepthStencilMode(
2480 RenderPassAttachment *resolveAttachment,
2481 bool renderPassHasWriteOrClear,
2482 RenderPassUsageFlags dsUsageFlags,
2483 RenderPassUsage readOnlyAttachmentUsage)
2484 {
2485 ASSERT(mRenderPassStarted);
2486 ASSERT(mDepthAttachment.getImage() == mStencilAttachment.getImage());
2487 ASSERT(mDepthResolveAttachment.getImage() == mStencilResolveAttachment.getImage());
2488
2489 // Determine read-only mode for depth or stencil
2490 const bool readOnlyMode =
2491 mDepthStencilAttachmentIndex != kAttachmentIndexInvalid &&
2492 resolveAttachment->getImage() == nullptr &&
2493 (dsUsageFlags.test(readOnlyAttachmentUsage) || !renderPassHasWriteOrClear);
2494
2495 // If readOnlyMode is false, we are switching out of read only mode due to depth/stencil write.
2496 // We must not be in the read only feedback loop mode because the logic in
2497 // DIRTY_BIT_READ_ONLY_DEPTH_FEEDBACK_LOOP_MODE should ensure we end the previous renderpass and
2498 // a new renderpass will start with feedback loop disabled.
2499 ASSERT(readOnlyMode || !dsUsageFlags.test(readOnlyAttachmentUsage));
2500
2501 ImageHelper *depthStencilImage = mDepthAttachment.getImage();
2502 if (depthStencilImage)
2503 {
2504 if (readOnlyMode)
2505 {
2506 depthStencilImage->setRenderPassUsageFlag(readOnlyAttachmentUsage);
2507 }
2508 else
2509 {
2510 depthStencilImage->clearRenderPassUsageFlag(readOnlyAttachmentUsage);
2511 }
2512 }
2513 // The depth/stencil resolve image is never in read-only mode
2514 }
2515
finalizeColorImageLayout(Context * context,ImageHelper * image,PackedAttachmentIndex packedAttachmentIndex,bool isResolveImage)2516 void RenderPassCommandBufferHelper::finalizeColorImageLayout(
2517 Context *context,
2518 ImageHelper *image,
2519 PackedAttachmentIndex packedAttachmentIndex,
2520 bool isResolveImage)
2521 {
2522 ASSERT(packedAttachmentIndex < mColorAttachmentsCount);
2523 ASSERT(image != nullptr);
2524
2525 // Do layout change.
2526 ImageLayout imageLayout;
2527 if (image->usedByCurrentRenderPassAsAttachmentAndSampler(RenderPassUsage::ColorTextureSampler))
2528 {
2529 // texture code already picked layout and inserted barrier
2530 imageLayout = image->getCurrentImageLayout();
2531 ASSERT(imageLayout == ImageLayout::ColorWriteFragmentShaderFeedback ||
2532 imageLayout == ImageLayout::ColorWriteAllShadersFeedback);
2533 }
2534 else
2535 {
2536 // When color is unresolved, use a layout that includes fragment shader reads. This is done
2537 // for all color resolve attachments even if they are not all unresolved for simplicity. In
2538 // particular, the GL color index is not available (only the packed index) at this point,
2539 // but that is needed to query whether the attachment is unresolved or not.
2540 const bool hasUnresolve =
2541 isResolveImage && mRenderPassDesc.getColorUnresolveAttachmentMask().any();
2542 imageLayout = hasUnresolve ? ImageLayout::MSRTTEmulationColorUnresolveAndResolve
2543 : ImageLayout::ColorWrite;
2544 if (context->getFeatures().preferDynamicRendering.enabled &&
2545 mRenderPassDesc.hasColorFramebufferFetch())
2546 {
2547 // Note MSRTT emulation is not implemented with dynamic rendering.
2548 ASSERT(imageLayout == ImageLayout::ColorWrite);
2549 imageLayout = ImageLayout::ColorWriteAndInput;
2550 }
2551
2552 updateImageLayoutAndBarrier(context, image, VK_IMAGE_ASPECT_COLOR_BIT, imageLayout,
2553 BarrierType::Event);
2554 }
2555
2556 if (!isResolveImage)
2557 {
2558 mAttachmentOps.setLayouts(packedAttachmentIndex, imageLayout, imageLayout);
2559 }
2560
2561 // Dynamic rendering does not have implicit layout transitions at render pass boundaries. This
2562 // optimization is instead done by recording the necessary transition after the render pass
2563 // directly on the primary command buffer.
2564 if (mImageOptimizeForPresent == image)
2565 {
2566 ASSERT(isDefault());
2567 ASSERT(context->getFeatures().supportsPresentation.enabled);
2568 ASSERT(packedAttachmentIndex == kAttachmentIndexZero);
2569
2570 // Use finalLayout instead of extra barrier for layout change to present. For dynamic
2571 // rendering, this is not possible and is done when the render pass is flushed. However,
2572 // because this function is expected to finalize the image layout, we still have to pretend
2573 // the image is in the present layout already.
2574 mImageOptimizeForPresentOriginalLayout = mImageOptimizeForPresent->getCurrentImageLayout();
2575 mImageOptimizeForPresent->setCurrentImageLayout(context->getRenderer(),
2576 ImageLayout::Present);
2577
2578 if (!context->getFeatures().preferDynamicRendering.enabled)
2579 {
2580 if (isResolveImage)
2581 {
2582 SetBitField(mAttachmentOps[packedAttachmentIndex].finalResolveLayout,
2583 mImageOptimizeForPresent->getCurrentImageLayout());
2584 }
2585 else
2586 {
2587 SetBitField(mAttachmentOps[packedAttachmentIndex].finalLayout,
2588 mImageOptimizeForPresent->getCurrentImageLayout());
2589 }
2590 mImageOptimizeForPresent = nullptr;
2591 mImageOptimizeForPresentOriginalLayout = ImageLayout::Undefined;
2592 }
2593 }
2594
2595 if (isResolveImage)
2596 {
2597 // Note: the color image will have its flags reset after load/store ops are determined.
2598 image->resetRenderPassUsageFlags();
2599 }
2600 }
2601
finalizeColorImageLoadStore(Context * context,PackedAttachmentIndex packedAttachmentIndex)2602 void RenderPassCommandBufferHelper::finalizeColorImageLoadStore(
2603 Context *context,
2604 PackedAttachmentIndex packedAttachmentIndex)
2605 {
2606 PackedAttachmentOpsDesc &ops = mAttachmentOps[packedAttachmentIndex];
2607 RenderPassLoadOp loadOp = static_cast<RenderPassLoadOp>(ops.loadOp);
2608 RenderPassStoreOp storeOp = static_cast<RenderPassStoreOp>(ops.storeOp);
2609
2610 // This has to be called after layout been finalized
2611 ASSERT(ops.initialLayout != static_cast<uint16_t>(ImageLayout::Undefined));
2612
2613 uint32_t currentCmdCount = getRenderPassWriteCommandCount();
2614 bool isInvalidated = false;
2615
2616 RenderPassAttachment &colorAttachment = mColorAttachments[packedAttachmentIndex];
2617 colorAttachment.finalizeLoadStore(
2618 context, currentCmdCount, mRenderPassDesc.getColorUnresolveAttachmentMask().any(),
2619 mRenderPassDesc.getColorResolveAttachmentMask().any(), &loadOp, &storeOp, &isInvalidated);
2620
2621 if (isInvalidated)
2622 {
2623 ops.isInvalidated = true;
2624 }
2625
2626 if (!ops.isInvalidated)
2627 {
2628 mColorResolveAttachments[packedAttachmentIndex].restoreContent();
2629 }
2630
2631 // If the image is being written to, mark its contents defined.
2632 // This has to be done after storeOp has been finalized.
2633 if (storeOp == RenderPassStoreOp::Store)
2634 {
2635 colorAttachment.restoreContent();
2636 }
2637
2638 SetBitField(ops.loadOp, loadOp);
2639 SetBitField(ops.storeOp, storeOp);
2640 }
2641
finalizeDepthStencilImageLayout(Context * context)2642 void RenderPassCommandBufferHelper::finalizeDepthStencilImageLayout(Context *context)
2643 {
2644 ASSERT(mDepthAttachment.getImage() != nullptr);
2645 ASSERT(mDepthAttachment.getImage() == mStencilAttachment.getImage());
2646
2647 ImageHelper *depthStencilImage = mDepthAttachment.getImage();
2648
2649 // Do depth stencil layout change.
2650 ImageLayout imageLayout;
2651 bool barrierRequired;
2652
2653 const bool isDepthAttachmentAndSampler =
2654 depthStencilImage->usedByCurrentRenderPassAsAttachmentAndSampler(
2655 RenderPassUsage::DepthTextureSampler);
2656 const bool isStencilAttachmentAndSampler =
2657 depthStencilImage->usedByCurrentRenderPassAsAttachmentAndSampler(
2658 RenderPassUsage::StencilTextureSampler);
2659 const bool isReadOnlyDepth =
2660 depthStencilImage->hasRenderPassUsageFlag(RenderPassUsage::DepthReadOnlyAttachment);
2661 const bool isReadOnlyStencil =
2662 depthStencilImage->hasRenderPassUsageFlag(RenderPassUsage::StencilReadOnlyAttachment);
2663 BarrierType barrierType = BarrierType::Event;
2664
2665 if (isDepthAttachmentAndSampler || isStencilAttachmentAndSampler)
2666 {
2667 // texture code already picked layout and inserted barrier
2668 imageLayout = depthStencilImage->getCurrentImageLayout();
2669
2670 if ((isDepthAttachmentAndSampler && !isReadOnlyDepth) ||
2671 (isStencilAttachmentAndSampler && !isReadOnlyStencil))
2672 {
2673 ASSERT(imageLayout == ImageLayout::DepthStencilFragmentShaderFeedback ||
2674 imageLayout == ImageLayout::DepthStencilAllShadersFeedback);
2675 barrierRequired = true;
2676 }
2677 else
2678 {
2679 ASSERT(imageLayout == ImageLayout::DepthWriteStencilReadFragmentShaderStencilRead ||
2680 imageLayout == ImageLayout::DepthWriteStencilReadAllShadersStencilRead ||
2681 imageLayout == ImageLayout::DepthReadStencilWriteFragmentShaderDepthRead ||
2682 imageLayout == ImageLayout::DepthReadStencilWriteAllShadersDepthRead ||
2683 imageLayout == ImageLayout::DepthReadStencilReadFragmentShaderRead ||
2684 imageLayout == ImageLayout::DepthReadStencilReadAllShadersRead);
2685 barrierRequired =
2686 depthStencilImage->isReadBarrierNecessary(context->getRenderer(), imageLayout);
2687 }
2688 }
2689 else
2690 {
2691 if (mRenderPassDesc.hasDepthStencilFramebufferFetch())
2692 {
2693 imageLayout = ImageLayout::DepthStencilWriteAndInput;
2694 }
2695 else if (isReadOnlyDepth)
2696 {
2697 imageLayout = isReadOnlyStencil ? ImageLayout::DepthReadStencilRead
2698 : ImageLayout::DepthReadStencilWrite;
2699 }
2700 else
2701 {
2702 imageLayout = isReadOnlyStencil ? ImageLayout::DepthWriteStencilRead
2703 : ImageLayout::DepthWriteStencilWrite;
2704 }
2705
2706 barrierRequired =
2707 !isReadOnlyDepth || !isReadOnlyStencil ||
2708 depthStencilImage->isReadBarrierNecessary(context->getRenderer(), imageLayout);
2709 }
2710
2711 mAttachmentOps.setLayouts(mDepthStencilAttachmentIndex, imageLayout, imageLayout);
2712
2713 if (barrierRequired)
2714 {
2715 const angle::Format &format = depthStencilImage->getActualFormat();
2716 ASSERT(format.hasDepthOrStencilBits());
2717 VkImageAspectFlags aspectFlags = GetDepthStencilAspectFlags(format);
2718 updateImageLayoutAndBarrier(context, depthStencilImage, aspectFlags, imageLayout,
2719 barrierType);
2720 }
2721 }
2722
finalizeDepthStencilResolveImageLayout(Context * context)2723 void RenderPassCommandBufferHelper::finalizeDepthStencilResolveImageLayout(Context *context)
2724 {
2725 ASSERT(mDepthResolveAttachment.getImage() != nullptr);
2726 ASSERT(mDepthResolveAttachment.getImage() == mStencilResolveAttachment.getImage());
2727
2728 ImageHelper *depthStencilResolveImage = mDepthResolveAttachment.getImage();
2729
2730 // When depth/stencil is unresolved, use a layout that includes fragment shader reads.
2731 ImageLayout imageLayout = mRenderPassDesc.hasDepthStencilUnresolveAttachment()
2732 ? ImageLayout::MSRTTEmulationDepthStencilUnresolveAndResolve
2733 : ImageLayout::DepthStencilResolve;
2734 const angle::Format &format = depthStencilResolveImage->getActualFormat();
2735 ASSERT(format.hasDepthOrStencilBits());
2736 VkImageAspectFlags aspectFlags = GetDepthStencilAspectFlags(format);
2737
2738 updateImageLayoutAndBarrier(context, depthStencilResolveImage, aspectFlags, imageLayout,
2739 BarrierType::Event);
2740
2741 // The resolve image can never be read-only.
2742 ASSERT(!depthStencilResolveImage->hasRenderPassUsageFlag(
2743 RenderPassUsage::DepthReadOnlyAttachment));
2744 ASSERT(!depthStencilResolveImage->hasRenderPassUsageFlag(
2745 RenderPassUsage::StencilReadOnlyAttachment));
2746 ASSERT(mDepthStencilAttachmentIndex != kAttachmentIndexInvalid);
2747 const PackedAttachmentOpsDesc &dsOps = mAttachmentOps[mDepthStencilAttachmentIndex];
2748
2749 // If the image is being written to, mark its contents defined.
2750 if (!dsOps.isInvalidated && mRenderPassDesc.hasDepthResolveAttachment())
2751 {
2752 mDepthResolveAttachment.restoreContent();
2753 }
2754 if (!dsOps.isStencilInvalidated && mRenderPassDesc.hasStencilResolveAttachment())
2755 {
2756 mStencilResolveAttachment.restoreContent();
2757 }
2758
2759 depthStencilResolveImage->resetRenderPassUsageFlags();
2760 }
2761
finalizeFragmentShadingRateImageLayout(Context * context)2762 void RenderPassCommandBufferHelper::finalizeFragmentShadingRateImageLayout(Context *context)
2763 {
2764 ImageHelper *image = mFragmentShadingRateAtachment.getImage();
2765 ImageLayout imageLayout = ImageLayout::FragmentShadingRateAttachmentReadOnly;
2766 ASSERT(image && image->valid());
2767 if (image->isReadBarrierNecessary(context->getRenderer(), imageLayout))
2768 {
2769 updateImageLayoutAndBarrier(context, image, VK_IMAGE_ASPECT_COLOR_BIT, imageLayout,
2770 BarrierType::Event);
2771 }
2772 image->resetRenderPassUsageFlags();
2773 }
2774
finalizeImageLayout(Context * context,const ImageHelper * image,UniqueSerial imageSiblingSerial)2775 void RenderPassCommandBufferHelper::finalizeImageLayout(Context *context,
2776 const ImageHelper *image,
2777 UniqueSerial imageSiblingSerial)
2778 {
2779 if (image->hasRenderPassUsageFlag(RenderPassUsage::RenderTargetAttachment))
2780 {
2781 for (PackedAttachmentIndex index = kAttachmentIndexZero; index < mColorAttachmentsCount;
2782 ++index)
2783 {
2784 if (mColorAttachments[index].hasImage(image, imageSiblingSerial))
2785 {
2786 finalizeColorImageLayoutAndLoadStore(context, index);
2787 mColorAttachments[index].reset();
2788 }
2789 else if (mColorResolveAttachments[index].hasImage(image, imageSiblingSerial))
2790 {
2791 finalizeColorImageLayout(context, mColorResolveAttachments[index].getImage(), index,
2792 true);
2793 mColorResolveAttachments[index].reset();
2794 }
2795 }
2796 }
2797
2798 if (mDepthAttachment.hasImage(image, imageSiblingSerial))
2799 {
2800 finalizeDepthStencilImageLayoutAndLoadStore(context);
2801 mDepthAttachment.reset();
2802 mStencilAttachment.reset();
2803 }
2804
2805 if (mDepthResolveAttachment.hasImage(image, imageSiblingSerial))
2806 {
2807 finalizeDepthStencilResolveImageLayout(context);
2808 mDepthResolveAttachment.reset();
2809 mStencilResolveAttachment.reset();
2810 }
2811
2812 if (mFragmentShadingRateAtachment.hasImage(image, imageSiblingSerial))
2813 {
2814 finalizeFragmentShadingRateImageLayout(context);
2815 mFragmentShadingRateAtachment.reset();
2816 }
2817 }
2818
finalizeDepthStencilLoadStore(Context * context)2819 void RenderPassCommandBufferHelper::finalizeDepthStencilLoadStore(Context *context)
2820 {
2821 ASSERT(mDepthStencilAttachmentIndex != kAttachmentIndexInvalid);
2822
2823 PackedAttachmentOpsDesc &dsOps = mAttachmentOps[mDepthStencilAttachmentIndex];
2824 RenderPassLoadOp depthLoadOp = static_cast<RenderPassLoadOp>(dsOps.loadOp);
2825 RenderPassStoreOp depthStoreOp = static_cast<RenderPassStoreOp>(dsOps.storeOp);
2826 RenderPassLoadOp stencilLoadOp = static_cast<RenderPassLoadOp>(dsOps.stencilLoadOp);
2827 RenderPassStoreOp stencilStoreOp = static_cast<RenderPassStoreOp>(dsOps.stencilStoreOp);
2828
2829 // This has to be called after layout been finalized
2830 ASSERT(dsOps.initialLayout != static_cast<uint16_t>(ImageLayout::Undefined));
2831
2832 uint32_t currentCmdCount = getRenderPassWriteCommandCount();
2833 bool isDepthInvalidated = false;
2834 bool isStencilInvalidated = false;
2835 bool hasDepthResolveAttachment = mRenderPassDesc.hasDepthResolveAttachment();
2836 bool hasStencilResolveAttachment = mRenderPassDesc.hasStencilResolveAttachment();
2837
2838 mDepthAttachment.finalizeLoadStore(
2839 context, currentCmdCount, mRenderPassDesc.hasDepthUnresolveAttachment(),
2840 hasDepthResolveAttachment, &depthLoadOp, &depthStoreOp, &isDepthInvalidated);
2841 mStencilAttachment.finalizeLoadStore(
2842 context, currentCmdCount, mRenderPassDesc.hasStencilUnresolveAttachment(),
2843 hasStencilResolveAttachment, &stencilLoadOp, &stencilStoreOp, &isStencilInvalidated);
2844
2845 const bool disableMixedDepthStencilLoadOpNoneAndLoad =
2846 context->getFeatures().disallowMixedDepthStencilLoadOpNoneAndLoad.enabled;
2847
2848 if (disableMixedDepthStencilLoadOpNoneAndLoad)
2849 {
2850 if (depthLoadOp == RenderPassLoadOp::None && stencilLoadOp != RenderPassLoadOp::None)
2851 {
2852 depthLoadOp = RenderPassLoadOp::Load;
2853 }
2854 if (depthLoadOp != RenderPassLoadOp::None && stencilLoadOp == RenderPassLoadOp::None)
2855 {
2856 stencilLoadOp = RenderPassLoadOp::Load;
2857 }
2858 }
2859
2860 if (isDepthInvalidated)
2861 {
2862 dsOps.isInvalidated = true;
2863 }
2864 if (isStencilInvalidated)
2865 {
2866 dsOps.isStencilInvalidated = true;
2867 }
2868
2869 // If any aspect is missing, set the corresponding ops to don't care.
2870 const uint32_t depthStencilIndexGL =
2871 static_cast<uint32_t>(mRenderPassDesc.depthStencilAttachmentIndex());
2872 const angle::FormatID attachmentFormatID = mRenderPassDesc[depthStencilIndexGL];
2873 ASSERT(attachmentFormatID != angle::FormatID::NONE);
2874 const angle::Format &angleFormat = angle::Format::Get(attachmentFormatID);
2875
2876 if (angleFormat.depthBits == 0)
2877 {
2878 depthLoadOp = RenderPassLoadOp::DontCare;
2879 depthStoreOp = RenderPassStoreOp::DontCare;
2880 }
2881 if (angleFormat.stencilBits == 0)
2882 {
2883 stencilLoadOp = RenderPassLoadOp::DontCare;
2884 stencilStoreOp = RenderPassStoreOp::DontCare;
2885 }
2886
2887 // If the image is being written to, mark its contents defined.
2888 // This has to be done after storeOp has been finalized.
2889 ASSERT(mDepthAttachment.getImage() == mStencilAttachment.getImage());
2890 if (!mDepthAttachment.getImage()->hasRenderPassUsageFlag(
2891 RenderPassUsage::DepthReadOnlyAttachment))
2892 {
2893 if (depthStoreOp == RenderPassStoreOp::Store)
2894 {
2895 mDepthAttachment.restoreContent();
2896 }
2897 }
2898 if (!mStencilAttachment.getImage()->hasRenderPassUsageFlag(
2899 RenderPassUsage::StencilReadOnlyAttachment))
2900 {
2901 if (stencilStoreOp == RenderPassStoreOp::Store)
2902 {
2903 mStencilAttachment.restoreContent();
2904 }
2905 }
2906
2907 SetBitField(dsOps.loadOp, depthLoadOp);
2908 SetBitField(dsOps.storeOp, depthStoreOp);
2909 SetBitField(dsOps.stencilLoadOp, stencilLoadOp);
2910 SetBitField(dsOps.stencilStoreOp, stencilStoreOp);
2911 }
2912
finalizeColorImageLayoutAndLoadStore(Context * context,PackedAttachmentIndex packedAttachmentIndex)2913 void RenderPassCommandBufferHelper::finalizeColorImageLayoutAndLoadStore(
2914 Context *context,
2915 PackedAttachmentIndex packedAttachmentIndex)
2916 {
2917 finalizeColorImageLayout(context, mColorAttachments[packedAttachmentIndex].getImage(),
2918 packedAttachmentIndex, false);
2919 finalizeColorImageLoadStore(context, packedAttachmentIndex);
2920
2921 mColorAttachments[packedAttachmentIndex].getImage()->resetRenderPassUsageFlags();
2922 }
2923
finalizeDepthStencilImageLayoutAndLoadStore(Context * context)2924 void RenderPassCommandBufferHelper::finalizeDepthStencilImageLayoutAndLoadStore(Context *context)
2925 {
2926 finalizeDepthStencilImageLayout(context);
2927 finalizeDepthStencilLoadStore(context);
2928
2929 ASSERT(mDepthAttachment.getImage() == mStencilAttachment.getImage());
2930 mDepthAttachment.getImage()->resetRenderPassUsageFlags();
2931 }
2932
executeSetEvents(Context * context,PrimaryCommandBuffer * primary)2933 void RenderPassCommandBufferHelper::executeSetEvents(Context *context,
2934 PrimaryCommandBuffer *primary)
2935 {
2936 Renderer *renderer = context->getRenderer();
2937 // Add VkCmdSetEvent here to track the completion of this renderPass.
2938 for (EventStage stage : mRefCountedEvents.mask)
2939 {
2940 // This must have been garbage collected. The VkEvent handle should have been copied to
2941 // VkEvents.
2942 ASSERT(!mRefCountedEvents.map[stage].valid());
2943 ASSERT(mRefCountedEvents.vkEvents[stage] != VK_NULL_HANDLE);
2944 primary->setEvent(mRefCountedEvents.vkEvents[stage], renderer->getPipelineStageMask(stage));
2945 mRefCountedEvents.vkEvents[stage] = VK_NULL_HANDLE;
2946 }
2947 mRefCountedEvents.mask.reset();
2948 }
2949
collectRefCountedEventsGarbage(RefCountedEventsGarbageRecycler * garbageRecycler)2950 void RenderPassCommandBufferHelper::collectRefCountedEventsGarbage(
2951 RefCountedEventsGarbageRecycler *garbageRecycler)
2952 {
2953 // For render pass the VkCmdSetEvent works differently from OutsideRenderPassCommands.
2954 // VkCmdEndRenderPass are called in the primary command buffer, and VkCmdSetEvents has to be
2955 // issued after VkCmdEndRenderPass. This means VkCmdSetEvent has to be delayed. Because of this,
2956 // here we simply make a local copy of the VkEvent and then add the RefCountedEvent to the
2957 // garbage collector. No VkCmdSetEvent call is issued here (they will be issued at
2958 // flushToPrimary time).
2959 for (EventStage stage : mRefCountedEvents.mask)
2960 {
2961 ASSERT(mRefCountedEvents.map[stage].valid());
2962 mRefCountedEvents.vkEvents[stage] = mRefCountedEvents.map[stage].getEvent().getHandle();
2963 mRefCountedEventCollector.emplace_back(std::move(mRefCountedEvents.map[stage]));
2964 }
2965
2966 if (!mRefCountedEventCollector.empty())
2967 {
2968 garbageRecycler->collectGarbage(mQueueSerial, std::move(mRefCountedEventCollector));
2969 }
2970 }
2971
updatePerfCountersForDynamicRenderingInstance(Context * context,angle::VulkanPerfCounters * countersOut)2972 void RenderPassCommandBufferHelper::updatePerfCountersForDynamicRenderingInstance(
2973 Context *context,
2974 angle::VulkanPerfCounters *countersOut)
2975 {
2976 mRenderPassDesc.updatePerfCounters(context, mFramebuffer.getUnpackedImageViews(),
2977 mAttachmentOps, countersOut);
2978 }
2979
beginRenderPass(ContextVk * contextVk,RenderPassFramebuffer && framebuffer,const gl::Rectangle & renderArea,const RenderPassDesc & renderPassDesc,const AttachmentOpsArray & renderPassAttachmentOps,const PackedAttachmentCount colorAttachmentCount,const PackedAttachmentIndex depthStencilAttachmentIndex,const PackedClearValuesArray & clearValues,const QueueSerial & queueSerial,RenderPassCommandBuffer ** commandBufferOut)2980 angle::Result RenderPassCommandBufferHelper::beginRenderPass(
2981 ContextVk *contextVk,
2982 RenderPassFramebuffer &&framebuffer,
2983 const gl::Rectangle &renderArea,
2984 const RenderPassDesc &renderPassDesc,
2985 const AttachmentOpsArray &renderPassAttachmentOps,
2986 const PackedAttachmentCount colorAttachmentCount,
2987 const PackedAttachmentIndex depthStencilAttachmentIndex,
2988 const PackedClearValuesArray &clearValues,
2989 const QueueSerial &queueSerial,
2990 RenderPassCommandBuffer **commandBufferOut)
2991 {
2992 ASSERT(!mRenderPassStarted);
2993
2994 mRenderPassDesc = renderPassDesc;
2995 mAttachmentOps = renderPassAttachmentOps;
2996 mDepthStencilAttachmentIndex = depthStencilAttachmentIndex;
2997 mColorAttachmentsCount = colorAttachmentCount;
2998 mFramebuffer = std::move(framebuffer);
2999 mRenderArea = renderArea;
3000 mClearValues = clearValues;
3001 mQueueSerial = queueSerial;
3002 *commandBufferOut = &getCommandBuffer();
3003
3004 mRenderPassStarted = true;
3005 mCounter++;
3006
3007 return beginRenderPassCommandBuffer(contextVk);
3008 }
3009
beginRenderPassCommandBuffer(ContextVk * contextVk)3010 angle::Result RenderPassCommandBufferHelper::beginRenderPassCommandBuffer(ContextVk *contextVk)
3011 {
3012 VkCommandBufferInheritanceInfo inheritanceInfo;
3013 VkCommandBufferInheritanceRenderingInfo renderingInfo;
3014 gl::DrawBuffersArray<VkFormat> colorFormatStorage;
3015
3016 ANGLE_TRY(RenderPassCommandBuffer::InitializeRenderPassInheritanceInfo(
3017 contextVk, mFramebuffer.getFramebuffer(), mRenderPassDesc, &inheritanceInfo, &renderingInfo,
3018 &colorFormatStorage));
3019 inheritanceInfo.subpass = mCurrentSubpassCommandBufferIndex;
3020
3021 return getCommandBuffer().begin(contextVk, inheritanceInfo);
3022 }
3023
endRenderPass(ContextVk * contextVk)3024 angle::Result RenderPassCommandBufferHelper::endRenderPass(ContextVk *contextVk)
3025 {
3026 ANGLE_TRY(endRenderPassCommandBuffer(contextVk));
3027
3028 for (PackedAttachmentIndex index = kAttachmentIndexZero; index < mColorAttachmentsCount;
3029 ++index)
3030 {
3031 if (mColorAttachments[index].getImage() != nullptr)
3032 {
3033 finalizeColorImageLayoutAndLoadStore(contextVk, index);
3034 }
3035 if (mColorResolveAttachments[index].getImage() != nullptr)
3036 {
3037 finalizeColorImageLayout(contextVk, mColorResolveAttachments[index].getImage(), index,
3038 true);
3039 }
3040 }
3041
3042 if (mFragmentShadingRateAtachment.getImage() != nullptr)
3043 {
3044 finalizeFragmentShadingRateImageLayout(contextVk);
3045 }
3046
3047 if (mDepthStencilAttachmentIndex != kAttachmentIndexInvalid)
3048 {
3049 // Do depth stencil layout change and load store optimization.
3050 ASSERT(mDepthAttachment.getImage() == mStencilAttachment.getImage());
3051 ASSERT(mDepthResolveAttachment.getImage() == mStencilResolveAttachment.getImage());
3052 if (mDepthAttachment.getImage() != nullptr)
3053 {
3054 finalizeDepthStencilImageLayoutAndLoadStore(contextVk);
3055 }
3056 if (mDepthResolveAttachment.getImage() != nullptr)
3057 {
3058 finalizeDepthStencilResolveImageLayout(contextVk);
3059 }
3060 }
3061
3062 return angle::Result::Continue;
3063 }
3064
endRenderPassCommandBuffer(ContextVk * contextVk)3065 angle::Result RenderPassCommandBufferHelper::endRenderPassCommandBuffer(ContextVk *contextVk)
3066 {
3067 return getCommandBuffer().end(contextVk);
3068 }
3069
nextSubpass(ContextVk * contextVk,RenderPassCommandBuffer ** commandBufferOut)3070 angle::Result RenderPassCommandBufferHelper::nextSubpass(ContextVk *contextVk,
3071 RenderPassCommandBuffer **commandBufferOut)
3072 {
3073 ASSERT(!contextVk->getFeatures().preferDynamicRendering.enabled);
3074
3075 if (ExecutesInline())
3076 {
3077 // When using ANGLE secondary command buffers, the commands are inline and are executed on
3078 // the primary command buffer. This means that vkCmdNextSubpass can be intermixed with the
3079 // rest of the commands, and there is no need to split command buffers.
3080 //
3081 // Note also that the command buffer handle doesn't change in this case.
3082 getCommandBuffer().nextSubpass(VK_SUBPASS_CONTENTS_INLINE);
3083 return angle::Result::Continue;
3084 }
3085
3086 // When using Vulkan secondary command buffers, each subpass's contents must be recorded in a
3087 // separate command buffer that is vkCmdExecuteCommands'ed in the primary command buffer.
3088 // vkCmdNextSubpass calls must also be issued in the primary command buffer.
3089 //
3090 // To support this, a list of command buffers are kept, one for each subpass. When moving to
3091 // the next subpass, the previous command buffer is ended and a new one is initialized and
3092 // begun.
3093
3094 // Accumulate command count for tracking purposes.
3095 mPreviousSubpassesCmdCount = getRenderPassWriteCommandCount();
3096
3097 ANGLE_TRY(endRenderPassCommandBuffer(contextVk));
3098 markClosed();
3099
3100 ++mCurrentSubpassCommandBufferIndex;
3101 ASSERT(getSubpassCommandBufferCount() <= kMaxSubpassCount);
3102
3103 ANGLE_TRY(initializeCommandBuffer(contextVk));
3104 ANGLE_TRY(beginRenderPassCommandBuffer(contextVk));
3105 markOpen();
3106
3107 // Return the new command buffer handle
3108 *commandBufferOut = &getCommandBuffer();
3109 return angle::Result::Continue;
3110 }
3111
beginTransformFeedback(size_t validBufferCount,const VkBuffer * counterBuffers,const VkDeviceSize * counterBufferOffsets,bool rebindBuffers)3112 void RenderPassCommandBufferHelper::beginTransformFeedback(size_t validBufferCount,
3113 const VkBuffer *counterBuffers,
3114 const VkDeviceSize *counterBufferOffsets,
3115 bool rebindBuffers)
3116 {
3117 mValidTransformFeedbackBufferCount = static_cast<uint32_t>(validBufferCount);
3118 mRebindTransformFeedbackBuffers = rebindBuffers;
3119
3120 for (size_t index = 0; index < validBufferCount; index++)
3121 {
3122 mTransformFeedbackCounterBuffers[index] = counterBuffers[index];
3123 mTransformFeedbackCounterBufferOffsets[index] = counterBufferOffsets[index];
3124 }
3125 }
3126
endTransformFeedback()3127 void RenderPassCommandBufferHelper::endTransformFeedback()
3128 {
3129 pauseTransformFeedback();
3130 mValidTransformFeedbackBufferCount = 0;
3131 }
3132
invalidateRenderPassColorAttachment(const gl::State & state,size_t colorIndexGL,PackedAttachmentIndex attachmentIndex,const gl::Rectangle & invalidateArea)3133 void RenderPassCommandBufferHelper::invalidateRenderPassColorAttachment(
3134 const gl::State &state,
3135 size_t colorIndexGL,
3136 PackedAttachmentIndex attachmentIndex,
3137 const gl::Rectangle &invalidateArea)
3138 {
3139 // Color write is enabled if:
3140 //
3141 // - Draw buffer is enabled (this is implicit, as invalidate only affects enabled draw buffers)
3142 // - Color output is not entirely masked
3143 // - Rasterizer-discard is not enabled
3144 const gl::BlendStateExt &blendStateExt = state.getBlendStateExt();
3145 const bool isColorWriteEnabled =
3146 blendStateExt.getColorMaskIndexed(colorIndexGL) != 0 && !state.isRasterizerDiscardEnabled();
3147 mColorAttachments[attachmentIndex].invalidate(invalidateArea, isColorWriteEnabled,
3148 getRenderPassWriteCommandCount());
3149 }
3150
invalidateRenderPassDepthAttachment(const gl::DepthStencilState & dsState,const gl::Rectangle & invalidateArea)3151 void RenderPassCommandBufferHelper::invalidateRenderPassDepthAttachment(
3152 const gl::DepthStencilState &dsState,
3153 const gl::Rectangle &invalidateArea)
3154 {
3155 const bool isDepthWriteEnabled = dsState.depthTest && dsState.depthMask;
3156 mDepthAttachment.invalidate(invalidateArea, isDepthWriteEnabled,
3157 getRenderPassWriteCommandCount());
3158 }
3159
invalidateRenderPassStencilAttachment(const gl::DepthStencilState & dsState,GLuint framebufferStencilSize,const gl::Rectangle & invalidateArea)3160 void RenderPassCommandBufferHelper::invalidateRenderPassStencilAttachment(
3161 const gl::DepthStencilState &dsState,
3162 GLuint framebufferStencilSize,
3163 const gl::Rectangle &invalidateArea)
3164 {
3165 const bool isStencilWriteEnabled =
3166 dsState.stencilTest && (!dsState.isStencilNoOp(framebufferStencilSize) ||
3167 !dsState.isStencilBackNoOp(framebufferStencilSize));
3168 mStencilAttachment.invalidate(invalidateArea, isStencilWriteEnabled,
3169 getRenderPassWriteCommandCount());
3170 }
3171
flushToPrimary(Context * context,CommandsState * commandsState,const RenderPass & renderPass,VkFramebuffer framebufferOverride)3172 angle::Result RenderPassCommandBufferHelper::flushToPrimary(Context *context,
3173 CommandsState *commandsState,
3174 const RenderPass &renderPass,
3175 VkFramebuffer framebufferOverride)
3176 {
3177 // |framebufferOverride| must only be provided if the initial framebuffer the render pass was
3178 // started with is not usable (due to the addition of resolve attachments after the fact).
3179 ASSERT(framebufferOverride == VK_NULL_HANDLE ||
3180 mFramebuffer.needsNewFramebufferWithResolveAttachments());
3181 // When a new framebuffer had to be created because of addition of resolve attachments, it's
3182 // never imageless.
3183 ASSERT(!(framebufferOverride != VK_NULL_HANDLE && mFramebuffer.isImageless()));
3184
3185 ANGLE_TRACE_EVENT0("gpu.angle", "RenderPassCommandBufferHelper::flushToPrimary");
3186 ASSERT(mRenderPassStarted);
3187 PrimaryCommandBuffer &primary = commandsState->primaryCommands;
3188
3189 // Commands that are added to primary before beginRenderPass command
3190 executeBarriers(context->getRenderer(), commandsState);
3191
3192 constexpr VkSubpassContents kSubpassContents =
3193 ExecutesInline() ? VK_SUBPASS_CONTENTS_INLINE
3194 : VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS;
3195
3196 if (!renderPass.valid())
3197 {
3198 mRenderPassDesc.beginRendering(context, &primary, mRenderArea, kSubpassContents,
3199 mFramebuffer.getUnpackedImageViews(), mAttachmentOps,
3200 mClearValues, mFramebuffer.getLayers());
3201 }
3202 else
3203 {
3204 // With imageless framebuffers, the attachments should be also added to beginInfo.
3205 VkRenderPassAttachmentBeginInfo attachmentBeginInfo = {};
3206 if (mFramebuffer.isImageless())
3207 {
3208 mFramebuffer.packResolveViewsForRenderPassBegin(&attachmentBeginInfo);
3209
3210 // If nullColorAttachmentWithExternalFormatResolve is true, there will be no color
3211 // attachment even though mRenderPassDesc indicates so.
3212 ASSERT((mRenderPassDesc.hasYUVResolveAttachment() &&
3213 context->getRenderer()->nullColorAttachmentWithExternalFormatResolve()) ||
3214 attachmentBeginInfo.attachmentCount == mRenderPassDesc.attachmentCount());
3215 }
3216
3217 mRenderPassDesc.beginRenderPass(
3218 context, &primary, renderPass,
3219 framebufferOverride ? framebufferOverride : mFramebuffer.getFramebuffer().getHandle(),
3220 mRenderArea, kSubpassContents, mClearValues,
3221 mFramebuffer.isImageless() ? &attachmentBeginInfo : nullptr);
3222 }
3223
3224 // Run commands inside the RenderPass.
3225 for (uint32_t subpass = 0; subpass < getSubpassCommandBufferCount(); ++subpass)
3226 {
3227 if (subpass > 0)
3228 {
3229 ASSERT(!context->getFeatures().preferDynamicRendering.enabled);
3230 primary.nextSubpass(kSubpassContents);
3231 }
3232 mCommandBuffers[subpass].executeCommands(&primary);
3233 }
3234
3235 if (!renderPass.valid())
3236 {
3237 primary.endRendering();
3238
3239 if (mImageOptimizeForPresent != nullptr)
3240 {
3241 // finalizeColorImageLayout forces layout to Present. If this is not the case, that
3242 // code was not run (so mImageOptimizeForPresentOriginalLayout is invalid).
3243 ASSERT(mImageOptimizeForPresent->getCurrentImageLayout() == ImageLayout::Present);
3244
3245 // Restore the original layout of the image and do the real transition after the render
3246 // pass ends.
3247 mImageOptimizeForPresent->setCurrentImageLayout(context->getRenderer(),
3248 mImageOptimizeForPresentOriginalLayout);
3249 mImageOptimizeForPresent->recordWriteBarrierOneOff(context, ImageLayout::Present,
3250 &primary, nullptr);
3251 mImageOptimizeForPresent = nullptr;
3252 mImageOptimizeForPresentOriginalLayout = ImageLayout::Undefined;
3253 }
3254 }
3255 else
3256 {
3257 primary.endRenderPass();
3258 }
3259
3260 // Now issue VkCmdSetEvents to primary command buffer
3261 executeSetEvents(context, &primary);
3262
3263 // Restart the command buffer.
3264 return reset(context, &commandsState->secondaryCommands);
3265 }
3266
addColorResolveAttachment(size_t colorIndexGL,ImageHelper * image,VkImageView view,gl::LevelIndex level,uint32_t layerStart,uint32_t layerCount,UniqueSerial imageSiblingSerial)3267 void RenderPassCommandBufferHelper::addColorResolveAttachment(size_t colorIndexGL,
3268 ImageHelper *image,
3269 VkImageView view,
3270 gl::LevelIndex level,
3271 uint32_t layerStart,
3272 uint32_t layerCount,
3273 UniqueSerial imageSiblingSerial)
3274 {
3275 mFramebuffer.addColorResolveAttachment(colorIndexGL, view);
3276 mRenderPassDesc.packColorResolveAttachment(colorIndexGL);
3277
3278 PackedAttachmentIndex packedAttachmentIndex =
3279 mRenderPassDesc.getPackedColorAttachmentIndex(colorIndexGL);
3280 ASSERT(mColorResolveAttachments[packedAttachmentIndex].getImage() == nullptr);
3281
3282 image->onRenderPassAttach(mQueueSerial);
3283 mColorResolveAttachments[packedAttachmentIndex].init(
3284 image, imageSiblingSerial, level, layerStart, layerCount, VK_IMAGE_ASPECT_COLOR_BIT);
3285 }
3286
addDepthStencilResolveAttachment(ImageHelper * image,VkImageView view,VkImageAspectFlags aspects,gl::LevelIndex level,uint32_t layerStart,uint32_t layerCount,UniqueSerial imageSiblingSerial)3287 void RenderPassCommandBufferHelper::addDepthStencilResolveAttachment(
3288 ImageHelper *image,
3289 VkImageView view,
3290 VkImageAspectFlags aspects,
3291 gl::LevelIndex level,
3292 uint32_t layerStart,
3293 uint32_t layerCount,
3294 UniqueSerial imageSiblingSerial)
3295 {
3296 mFramebuffer.addDepthStencilResolveAttachment(view);
3297 if ((aspects & VK_IMAGE_ASPECT_DEPTH_BIT) != 0)
3298 {
3299 mRenderPassDesc.packDepthResolveAttachment();
3300 }
3301 if ((aspects & VK_IMAGE_ASPECT_STENCIL_BIT) != 0)
3302 {
3303 mRenderPassDesc.packStencilResolveAttachment();
3304 }
3305
3306 image->onRenderPassAttach(mQueueSerial);
3307 mDepthResolveAttachment.init(image, imageSiblingSerial, level, layerStart, layerCount,
3308 VK_IMAGE_ASPECT_DEPTH_BIT);
3309 mStencilResolveAttachment.init(image, imageSiblingSerial, level, layerStart, layerCount,
3310 VK_IMAGE_ASPECT_STENCIL_BIT);
3311 }
3312
resumeTransformFeedback()3313 void RenderPassCommandBufferHelper::resumeTransformFeedback()
3314 {
3315 ASSERT(isTransformFeedbackStarted());
3316
3317 uint32_t numCounterBuffers =
3318 mRebindTransformFeedbackBuffers ? 0 : mValidTransformFeedbackBufferCount;
3319
3320 mRebindTransformFeedbackBuffers = false;
3321 mIsTransformFeedbackActiveUnpaused = true;
3322
3323 getCommandBuffer().beginTransformFeedback(0, numCounterBuffers,
3324 mTransformFeedbackCounterBuffers.data(),
3325 mTransformFeedbackCounterBufferOffsets.data());
3326 }
3327
pauseTransformFeedback()3328 void RenderPassCommandBufferHelper::pauseTransformFeedback()
3329 {
3330 ASSERT(isTransformFeedbackStarted() && isTransformFeedbackActiveUnpaused());
3331 mIsTransformFeedbackActiveUnpaused = false;
3332 getCommandBuffer().endTransformFeedback(0, mValidTransformFeedbackBufferCount,
3333 mTransformFeedbackCounterBuffers.data(),
3334 mTransformFeedbackCounterBufferOffsets.data());
3335 }
3336
updateRenderPassColorClear(PackedAttachmentIndex colorIndexVk,const VkClearValue & clearValue)3337 void RenderPassCommandBufferHelper::updateRenderPassColorClear(PackedAttachmentIndex colorIndexVk,
3338 const VkClearValue &clearValue)
3339 {
3340 mAttachmentOps.setClearOp(colorIndexVk);
3341 mClearValues.storeColor(colorIndexVk, clearValue);
3342 }
3343
updateRenderPassDepthStencilClear(VkImageAspectFlags aspectFlags,const VkClearValue & clearValue)3344 void RenderPassCommandBufferHelper::updateRenderPassDepthStencilClear(
3345 VkImageAspectFlags aspectFlags,
3346 const VkClearValue &clearValue)
3347 {
3348 // Don't overwrite prior clear values for individual aspects.
3349 VkClearValue combinedClearValue = mClearValues[mDepthStencilAttachmentIndex];
3350
3351 if ((aspectFlags & VK_IMAGE_ASPECT_DEPTH_BIT) != 0)
3352 {
3353 mAttachmentOps.setClearOp(mDepthStencilAttachmentIndex);
3354 combinedClearValue.depthStencil.depth = clearValue.depthStencil.depth;
3355 }
3356
3357 if ((aspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) != 0)
3358 {
3359 mAttachmentOps.setClearStencilOp(mDepthStencilAttachmentIndex);
3360 combinedClearValue.depthStencil.stencil = clearValue.depthStencil.stencil;
3361 }
3362
3363 // Bypass special D/S handling. This clear values array stores values packed.
3364 mClearValues.storeDepthStencil(mDepthStencilAttachmentIndex, combinedClearValue);
3365 }
3366
growRenderArea(ContextVk * contextVk,const gl::Rectangle & newRenderArea)3367 void RenderPassCommandBufferHelper::growRenderArea(ContextVk *contextVk,
3368 const gl::Rectangle &newRenderArea)
3369 {
3370 // The render area is grown such that it covers both the previous and the new render areas.
3371 gl::GetEnclosingRectangle(mRenderArea, newRenderArea, &mRenderArea);
3372
3373 // Remove invalidates that are no longer applicable.
3374 mDepthAttachment.onRenderAreaGrowth(contextVk, mRenderArea);
3375 mStencilAttachment.onRenderAreaGrowth(contextVk, mRenderArea);
3376 }
3377
attachCommandPool(Context * context,SecondaryCommandPool * commandPool)3378 angle::Result RenderPassCommandBufferHelper::attachCommandPool(Context *context,
3379 SecondaryCommandPool *commandPool)
3380 {
3381 ASSERT(!mRenderPassStarted);
3382 ASSERT(getSubpassCommandBufferCount() == 1);
3383 return attachCommandPoolImpl<RenderPassCommandBufferHelper>(context, commandPool);
3384 }
3385
detachCommandPool(SecondaryCommandPool ** commandPoolOut)3386 void RenderPassCommandBufferHelper::detachCommandPool(SecondaryCommandPool **commandPoolOut)
3387 {
3388 ASSERT(mRenderPassStarted);
3389 angle::Result result =
3390 detachCommandPoolImpl<RenderPassCommandBufferHelper, true>(nullptr, commandPoolOut);
3391 ASSERT(result == angle::Result::Continue);
3392 }
3393
releaseCommandPool()3394 void RenderPassCommandBufferHelper::releaseCommandPool()
3395 {
3396 ASSERT(!mRenderPassStarted);
3397 ASSERT(getSubpassCommandBufferCount() == 1);
3398 releaseCommandPoolImpl<RenderPassCommandBufferHelper>();
3399 }
3400
attachAllocator(SecondaryCommandMemoryAllocator * allocator)3401 void RenderPassCommandBufferHelper::attachAllocator(SecondaryCommandMemoryAllocator *allocator)
3402 {
3403 ASSERT(CheckSubpassCommandBufferCount(getSubpassCommandBufferCount()));
3404 attachAllocatorImpl<RenderPassCommandBufferHelper>(allocator);
3405 }
3406
detachAllocator()3407 SecondaryCommandMemoryAllocator *RenderPassCommandBufferHelper::detachAllocator()
3408 {
3409 ASSERT(CheckSubpassCommandBufferCount(getSubpassCommandBufferCount()));
3410 return detachAllocatorImpl<RenderPassCommandBufferHelper>();
3411 }
3412
assertCanBeRecycled()3413 void RenderPassCommandBufferHelper::assertCanBeRecycled()
3414 {
3415 ASSERT(!mRenderPassStarted);
3416 ASSERT(getSubpassCommandBufferCount() == 1);
3417 assertCanBeRecycledImpl<RenderPassCommandBufferHelper>();
3418 }
3419
getCommandDiagnostics()3420 std::string RenderPassCommandBufferHelper::getCommandDiagnostics()
3421 {
3422 std::ostringstream out;
3423 addCommandDiagnosticsCommon(&out);
3424
3425 size_t attachmentCount = mRenderPassDesc.clearableAttachmentCount();
3426 size_t depthStencilAttachmentCount = mRenderPassDesc.hasDepthStencilAttachment() ? 1 : 0;
3427 size_t colorAttachmentCount = attachmentCount - depthStencilAttachmentCount;
3428
3429 PackedAttachmentIndex attachmentIndexVk(0);
3430 std::string loadOps, storeOps;
3431
3432 if (colorAttachmentCount > 0)
3433 {
3434 loadOps += " Color: ";
3435 storeOps += " Color: ";
3436
3437 for (size_t i = 0; i < colorAttachmentCount; ++i)
3438 {
3439 loadOps += GetLoadOpShorthand(
3440 static_cast<RenderPassLoadOp>(mAttachmentOps[attachmentIndexVk].loadOp));
3441 storeOps += GetStoreOpShorthand(
3442 static_cast<RenderPassStoreOp>(mAttachmentOps[attachmentIndexVk].storeOp));
3443 ++attachmentIndexVk;
3444 }
3445 }
3446
3447 if (depthStencilAttachmentCount > 0)
3448 {
3449 ASSERT(depthStencilAttachmentCount == 1);
3450
3451 loadOps += " Depth/Stencil: ";
3452 storeOps += " Depth/Stencil: ";
3453
3454 loadOps += GetLoadOpShorthand(
3455 static_cast<RenderPassLoadOp>(mAttachmentOps[attachmentIndexVk].loadOp));
3456 loadOps += GetLoadOpShorthand(
3457 static_cast<RenderPassLoadOp>(mAttachmentOps[attachmentIndexVk].stencilLoadOp));
3458
3459 storeOps += GetStoreOpShorthand(
3460 static_cast<RenderPassStoreOp>(mAttachmentOps[attachmentIndexVk].storeOp));
3461 storeOps += GetStoreOpShorthand(
3462 static_cast<RenderPassStoreOp>(mAttachmentOps[attachmentIndexVk].stencilStoreOp));
3463 }
3464
3465 if (attachmentCount > 0)
3466 {
3467 out << "LoadOp: " << loadOps << "\\l";
3468 out << "StoreOp: " << storeOps << "\\l";
3469 }
3470
3471 for (uint32_t subpass = 0; subpass < getSubpassCommandBufferCount(); ++subpass)
3472 {
3473 if (subpass > 0)
3474 {
3475 out << "Next Subpass" << "\\l";
3476 }
3477 out << mCommandBuffers[subpass].dumpCommands("\\l");
3478 }
3479
3480 return out.str();
3481 }
3482
3483 // CommandBufferRecycler implementation.
3484 template <typename CommandBufferHelperT>
onDestroy()3485 void CommandBufferRecycler<CommandBufferHelperT>::onDestroy()
3486 {
3487 std::unique_lock<angle::SimpleMutex> lock(mMutex);
3488 for (CommandBufferHelperT *commandBufferHelper : mCommandBufferHelperFreeList)
3489 {
3490 SafeDelete(commandBufferHelper);
3491 }
3492 mCommandBufferHelperFreeList.clear();
3493 }
3494
3495 template void CommandBufferRecycler<OutsideRenderPassCommandBufferHelper>::onDestroy();
3496 template void CommandBufferRecycler<RenderPassCommandBufferHelper>::onDestroy();
3497
3498 template <typename CommandBufferHelperT>
getCommandBufferHelper(Context * context,SecondaryCommandPool * commandPool,SecondaryCommandMemoryAllocator * commandsAllocator,CommandBufferHelperT ** commandBufferHelperOut)3499 angle::Result CommandBufferRecycler<CommandBufferHelperT>::getCommandBufferHelper(
3500 Context *context,
3501 SecondaryCommandPool *commandPool,
3502 SecondaryCommandMemoryAllocator *commandsAllocator,
3503 CommandBufferHelperT **commandBufferHelperOut)
3504 {
3505 std::unique_lock<angle::SimpleMutex> lock(mMutex);
3506 if (mCommandBufferHelperFreeList.empty())
3507 {
3508 CommandBufferHelperT *commandBuffer = new CommandBufferHelperT();
3509 *commandBufferHelperOut = commandBuffer;
3510 ANGLE_TRY(commandBuffer->initialize(context));
3511 }
3512 else
3513 {
3514 CommandBufferHelperT *commandBuffer = mCommandBufferHelperFreeList.back();
3515 mCommandBufferHelperFreeList.pop_back();
3516 *commandBufferHelperOut = commandBuffer;
3517 }
3518
3519 ANGLE_TRY((*commandBufferHelperOut)->attachCommandPool(context, commandPool));
3520
3521 // Attach functions are only used for ring buffer allocators.
3522 (*commandBufferHelperOut)->attachAllocator(commandsAllocator);
3523
3524 return angle::Result::Continue;
3525 }
3526
3527 template angle::Result
3528 CommandBufferRecycler<OutsideRenderPassCommandBufferHelper>::getCommandBufferHelper(
3529 Context *,
3530 SecondaryCommandPool *,
3531 SecondaryCommandMemoryAllocator *,
3532 OutsideRenderPassCommandBufferHelper **);
3533 template angle::Result CommandBufferRecycler<RenderPassCommandBufferHelper>::getCommandBufferHelper(
3534 Context *,
3535 SecondaryCommandPool *,
3536 SecondaryCommandMemoryAllocator *,
3537 RenderPassCommandBufferHelper **);
3538
3539 template <typename CommandBufferHelperT>
recycleCommandBufferHelper(CommandBufferHelperT ** commandBuffer)3540 void CommandBufferRecycler<CommandBufferHelperT>::recycleCommandBufferHelper(
3541 CommandBufferHelperT **commandBuffer)
3542 {
3543 (*commandBuffer)->assertCanBeRecycled();
3544 (*commandBuffer)->markOpen();
3545
3546 {
3547 std::unique_lock<angle::SimpleMutex> lock(mMutex);
3548 mCommandBufferHelperFreeList.push_back(*commandBuffer);
3549 }
3550
3551 *commandBuffer = nullptr;
3552 }
3553
3554 template void
3555 CommandBufferRecycler<OutsideRenderPassCommandBufferHelper>::recycleCommandBufferHelper(
3556 OutsideRenderPassCommandBufferHelper **);
3557 template void CommandBufferRecycler<RenderPassCommandBufferHelper>::recycleCommandBufferHelper(
3558 RenderPassCommandBufferHelper **);
3559
3560 // SecondaryCommandBufferCollector implementation.
collectCommandBuffer(priv::SecondaryCommandBuffer && commandBuffer)3561 void SecondaryCommandBufferCollector::collectCommandBuffer(
3562 priv::SecondaryCommandBuffer &&commandBuffer)
3563 {
3564 commandBuffer.reset();
3565 }
3566
collectCommandBuffer(VulkanSecondaryCommandBuffer && commandBuffer)3567 void SecondaryCommandBufferCollector::collectCommandBuffer(
3568 VulkanSecondaryCommandBuffer &&commandBuffer)
3569 {
3570 ASSERT(commandBuffer.valid());
3571 mCollectedCommandBuffers.emplace_back(std::move(commandBuffer));
3572 }
3573
releaseCommandBuffers()3574 void SecondaryCommandBufferCollector::releaseCommandBuffers()
3575 {
3576 // Note: we currently free the command buffers individually, but we could potentially reset the
3577 // entire command pool. https://issuetracker.google.com/issues/166793850
3578 for (VulkanSecondaryCommandBuffer &commandBuffer : mCollectedCommandBuffers)
3579 {
3580 commandBuffer.destroy();
3581 }
3582 mCollectedCommandBuffers.clear();
3583 }
3584
3585 // DynamicBuffer implementation.
DynamicBuffer()3586 DynamicBuffer::DynamicBuffer()
3587 : mUsage(0),
3588 mHostVisible(false),
3589 mInitialSize(0),
3590 mNextAllocationOffset(0),
3591 mSize(0),
3592 mSizeInRecentHistory(0),
3593 mAlignment(0),
3594 mMemoryPropertyFlags(0)
3595 {}
3596
DynamicBuffer(DynamicBuffer && other)3597 DynamicBuffer::DynamicBuffer(DynamicBuffer &&other)
3598 : mUsage(other.mUsage),
3599 mHostVisible(other.mHostVisible),
3600 mInitialSize(other.mInitialSize),
3601 mBuffer(std::move(other.mBuffer)),
3602 mNextAllocationOffset(other.mNextAllocationOffset),
3603 mSize(other.mSize),
3604 mSizeInRecentHistory(other.mSizeInRecentHistory),
3605 mAlignment(other.mAlignment),
3606 mMemoryPropertyFlags(other.mMemoryPropertyFlags),
3607 mInFlightBuffers(std::move(other.mInFlightBuffers)),
3608 mBufferFreeList(std::move(other.mBufferFreeList))
3609 {}
3610
init(Renderer * renderer,VkBufferUsageFlags usage,size_t alignment,size_t initialSize,bool hostVisible)3611 void DynamicBuffer::init(Renderer *renderer,
3612 VkBufferUsageFlags usage,
3613 size_t alignment,
3614 size_t initialSize,
3615 bool hostVisible)
3616 {
3617 mUsage = usage;
3618 mHostVisible = hostVisible;
3619 mMemoryPropertyFlags =
3620 (hostVisible) ? VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT : VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
3621
3622 if (hostVisible && renderer->getFeatures().preferHostCachedForNonStaticBufferUsage.enabled)
3623 {
3624 mMemoryPropertyFlags |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
3625 }
3626
3627 // Check that we haven't overridden the initial size of the buffer in setMinimumSizeForTesting.
3628 if (mInitialSize == 0)
3629 {
3630 mInitialSize = initialSize;
3631 mSize = 0;
3632 mSizeInRecentHistory = initialSize;
3633 }
3634
3635 // Workaround for the mock ICD not supporting allocations greater than 0x1000.
3636 // Could be removed if https://github.com/KhronosGroup/Vulkan-Tools/issues/84 is fixed.
3637 if (renderer->isMockICDEnabled())
3638 {
3639 mSize = std::min<size_t>(mSize, 0x1000);
3640 }
3641
3642 requireAlignment(renderer, alignment);
3643 }
3644
~DynamicBuffer()3645 DynamicBuffer::~DynamicBuffer()
3646 {
3647 ASSERT(mBuffer == nullptr);
3648 ASSERT(mInFlightBuffers.empty());
3649 ASSERT(mBufferFreeList.empty());
3650 }
3651
allocateNewBuffer(Context * context)3652 angle::Result DynamicBuffer::allocateNewBuffer(Context *context)
3653 {
3654 context->getPerfCounters().dynamicBufferAllocations++;
3655
3656 // Allocate the buffer
3657 ASSERT(!mBuffer);
3658 mBuffer = std::make_unique<BufferHelper>();
3659
3660 VkBufferCreateInfo createInfo = {};
3661 createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
3662 createInfo.flags = 0;
3663 createInfo.size = mSize;
3664 createInfo.usage = mUsage;
3665 createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
3666 createInfo.queueFamilyIndexCount = 0;
3667 createInfo.pQueueFamilyIndices = nullptr;
3668
3669 return mBuffer->init(context, createInfo, mMemoryPropertyFlags);
3670 }
3671
allocateFromCurrentBuffer(size_t sizeInBytes,BufferHelper ** bufferHelperOut)3672 bool DynamicBuffer::allocateFromCurrentBuffer(size_t sizeInBytes, BufferHelper **bufferHelperOut)
3673 {
3674 mNextAllocationOffset =
3675 roundUp<uint32_t>(mNextAllocationOffset, static_cast<uint32_t>(mAlignment));
3676
3677 ASSERT(bufferHelperOut);
3678 size_t sizeToAllocate = roundUp(sizeInBytes, mAlignment);
3679 angle::base::CheckedNumeric<size_t> checkedNextWriteOffset = mNextAllocationOffset;
3680 checkedNextWriteOffset += sizeToAllocate;
3681
3682 if (!checkedNextWriteOffset.IsValid() || checkedNextWriteOffset.ValueOrDie() > mSize)
3683 {
3684 return false;
3685 }
3686
3687 ASSERT(mBuffer != nullptr);
3688 ASSERT(mHostVisible);
3689 ASSERT(mBuffer->getMappedMemory());
3690 mBuffer->setSuballocationOffsetAndSize(mNextAllocationOffset, sizeToAllocate);
3691 *bufferHelperOut = mBuffer.get();
3692
3693 mNextAllocationOffset += static_cast<uint32_t>(sizeToAllocate);
3694 return true;
3695 }
3696
allocate(Context * context,size_t sizeInBytes,BufferHelper ** bufferHelperOut,bool * newBufferAllocatedOut)3697 angle::Result DynamicBuffer::allocate(Context *context,
3698 size_t sizeInBytes,
3699 BufferHelper **bufferHelperOut,
3700 bool *newBufferAllocatedOut)
3701 {
3702 bool newBuffer = !allocateFromCurrentBuffer(sizeInBytes, bufferHelperOut);
3703 if (newBufferAllocatedOut)
3704 {
3705 *newBufferAllocatedOut = newBuffer;
3706 }
3707
3708 if (!newBuffer)
3709 {
3710 return angle::Result::Continue;
3711 }
3712
3713 size_t sizeToAllocate = roundUp(sizeInBytes, mAlignment);
3714
3715 if (mBuffer)
3716 {
3717 // Make sure the buffer is not released externally.
3718 ASSERT(mBuffer->valid());
3719 mInFlightBuffers.push_back(std::move(mBuffer));
3720 ASSERT(!mBuffer);
3721 }
3722
3723 Renderer *renderer = context->getRenderer();
3724
3725 const size_t minRequiredBlockSize = std::max(mInitialSize, sizeToAllocate);
3726
3727 // The average required buffer size in recent history is used to determine whether the currently
3728 // used buffer size needs to be reduced (when it goes below 1/8 of the current buffer size).
3729 constexpr uint32_t kDecayCoeffPercent = 20;
3730 static_assert(kDecayCoeffPercent >= 0 && kDecayCoeffPercent <= 100);
3731 mSizeInRecentHistory = (mSizeInRecentHistory * kDecayCoeffPercent +
3732 minRequiredBlockSize * (100 - kDecayCoeffPercent) + 50) /
3733 100;
3734
3735 if (sizeToAllocate > mSize || mSizeInRecentHistory < mSize / 8)
3736 {
3737 mSize = minRequiredBlockSize;
3738 // Clear the free list since the free buffers are now either too small or too big.
3739 ReleaseBufferListToRenderer(renderer, &mBufferFreeList);
3740 }
3741
3742 // The front of the free list should be the oldest. Thus if it is in use the rest of the
3743 // free list should be in use as well.
3744 if (mBufferFreeList.empty() ||
3745 !renderer->hasResourceUseFinished(mBufferFreeList.front()->getResourceUse()))
3746 {
3747 ANGLE_TRY(allocateNewBuffer(context));
3748 }
3749 else
3750 {
3751 mBuffer = std::move(mBufferFreeList.front());
3752 mBufferFreeList.pop_front();
3753 }
3754
3755 ASSERT(mBuffer->getBlockMemorySize() == mSize);
3756
3757 mNextAllocationOffset = 0;
3758
3759 ASSERT(mBuffer != nullptr);
3760 mBuffer->setSuballocationOffsetAndSize(mNextAllocationOffset, sizeToAllocate);
3761 *bufferHelperOut = mBuffer.get();
3762
3763 mNextAllocationOffset += static_cast<uint32_t>(sizeToAllocate);
3764 return angle::Result::Continue;
3765 }
3766
release(Renderer * renderer)3767 void DynamicBuffer::release(Renderer *renderer)
3768 {
3769 reset();
3770
3771 ReleaseBufferListToRenderer(renderer, &mInFlightBuffers);
3772 ReleaseBufferListToRenderer(renderer, &mBufferFreeList);
3773
3774 if (mBuffer)
3775 {
3776 mBuffer->release(renderer);
3777 mBuffer.reset(nullptr);
3778 }
3779 }
3780
updateQueueSerialAndReleaseInFlightBuffers(ContextVk * contextVk,const QueueSerial & queueSerial)3781 void DynamicBuffer::updateQueueSerialAndReleaseInFlightBuffers(ContextVk *contextVk,
3782 const QueueSerial &queueSerial)
3783 {
3784 for (std::unique_ptr<BufferHelper> &bufferHelper : mInFlightBuffers)
3785 {
3786 // This function is used only for internal buffers, and they are all read-only.
3787 // It's possible this may change in the future, but there isn't a good way to detect that,
3788 // unfortunately.
3789 bufferHelper->setQueueSerial(queueSerial);
3790
3791 // We only keep free buffers that have the same size. Note that bufferHelper's size is
3792 // suballocation's size. We need to use the whole block memory size here.
3793 if (bufferHelper->getBlockMemorySize() != mSize)
3794 {
3795 bufferHelper->release(contextVk->getRenderer());
3796 }
3797 else
3798 {
3799 mBufferFreeList.push_back(std::move(bufferHelper));
3800 }
3801 }
3802 mInFlightBuffers.clear();
3803 }
3804
destroy(Renderer * renderer)3805 void DynamicBuffer::destroy(Renderer *renderer)
3806 {
3807 reset();
3808
3809 DestroyBufferList(renderer, &mInFlightBuffers);
3810 DestroyBufferList(renderer, &mBufferFreeList);
3811
3812 if (mBuffer)
3813 {
3814 mBuffer->unmap(renderer);
3815 mBuffer->destroy(renderer);
3816 mBuffer.reset(nullptr);
3817 }
3818 }
3819
requireAlignment(Renderer * renderer,size_t alignment)3820 void DynamicBuffer::requireAlignment(Renderer *renderer, size_t alignment)
3821 {
3822 ASSERT(alignment > 0);
3823
3824 size_t prevAlignment = mAlignment;
3825
3826 // If alignment was never set, initialize it with the atom size limit.
3827 if (prevAlignment == 0)
3828 {
3829 prevAlignment =
3830 static_cast<size_t>(renderer->getPhysicalDeviceProperties().limits.nonCoherentAtomSize);
3831 ASSERT(gl::isPow2(prevAlignment));
3832 }
3833
3834 // We need lcm(prevAlignment, alignment). Usually, one divides the other so std::max() could be
3835 // used instead. Only known case where this assumption breaks is for 3-component types with
3836 // 16- or 32-bit channels, so that's special-cased to avoid a full-fledged lcm implementation.
3837
3838 if (gl::isPow2(prevAlignment * alignment))
3839 {
3840 ASSERT(alignment % prevAlignment == 0 || prevAlignment % alignment == 0);
3841
3842 alignment = std::max(prevAlignment, alignment);
3843 }
3844 else
3845 {
3846 ASSERT(prevAlignment % 3 != 0 || gl::isPow2(prevAlignment / 3));
3847 ASSERT(alignment % 3 != 0 || gl::isPow2(alignment / 3));
3848
3849 prevAlignment = prevAlignment % 3 == 0 ? prevAlignment / 3 : prevAlignment;
3850 alignment = alignment % 3 == 0 ? alignment / 3 : alignment;
3851
3852 alignment = std::max(prevAlignment, alignment) * 3;
3853 }
3854
3855 // If alignment has changed, make sure the next allocation is done at an aligned offset.
3856 if (alignment != mAlignment)
3857 {
3858 mNextAllocationOffset = roundUp(mNextAllocationOffset, static_cast<uint32_t>(alignment));
3859 }
3860
3861 mAlignment = alignment;
3862 }
3863
setMinimumSizeForTesting(size_t minSize)3864 void DynamicBuffer::setMinimumSizeForTesting(size_t minSize)
3865 {
3866 // This will really only have an effect next time we call allocate.
3867 mInitialSize = minSize;
3868
3869 // Forces a new allocation on the next allocate.
3870 mSize = 0;
3871 mSizeInRecentHistory = 0;
3872 }
3873
reset()3874 void DynamicBuffer::reset()
3875 {
3876 mSize = 0;
3877 mSizeInRecentHistory = 0;
3878 mNextAllocationOffset = 0;
3879 }
3880
3881 // BufferPool implementation.
BufferPool()3882 BufferPool::BufferPool()
3883 : mVirtualBlockCreateFlags(vma::VirtualBlockCreateFlagBits::GENERAL),
3884 mUsage(0),
3885 mHostVisible(false),
3886 mSize(0),
3887 mMemoryTypeIndex(0),
3888 mTotalMemorySize(0),
3889 mNumberOfNewBuffersNeededSinceLastPrune(0)
3890 {}
3891
BufferPool(BufferPool && other)3892 BufferPool::BufferPool(BufferPool &&other)
3893 : mVirtualBlockCreateFlags(other.mVirtualBlockCreateFlags),
3894 mUsage(other.mUsage),
3895 mHostVisible(other.mHostVisible),
3896 mSize(other.mSize),
3897 mMemoryTypeIndex(other.mMemoryTypeIndex)
3898 {}
3899
initWithFlags(Renderer * renderer,vma::VirtualBlockCreateFlags flags,VkBufferUsageFlags usage,VkDeviceSize initialSize,uint32_t memoryTypeIndex,VkMemoryPropertyFlags memoryPropertyFlags)3900 void BufferPool::initWithFlags(Renderer *renderer,
3901 vma::VirtualBlockCreateFlags flags,
3902 VkBufferUsageFlags usage,
3903 VkDeviceSize initialSize,
3904 uint32_t memoryTypeIndex,
3905 VkMemoryPropertyFlags memoryPropertyFlags)
3906 {
3907 mVirtualBlockCreateFlags = flags;
3908 mUsage = usage;
3909 mMemoryTypeIndex = memoryTypeIndex;
3910 if (initialSize)
3911 {
3912 // Should be power of two
3913 ASSERT(gl::isPow2(initialSize));
3914 mSize = initialSize;
3915 }
3916 else
3917 {
3918 mSize = renderer->getPreferedBufferBlockSize(memoryTypeIndex);
3919 }
3920 mHostVisible = ((memoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0);
3921 }
3922
~BufferPool()3923 BufferPool::~BufferPool()
3924 {
3925 ASSERT(mBufferBlocks.empty());
3926 ASSERT(mEmptyBufferBlocks.empty());
3927 }
3928
pruneEmptyBuffers(Renderer * renderer)3929 void BufferPool::pruneEmptyBuffers(Renderer *renderer)
3930 {
3931 // First try to walk through mBuffers and move empty buffers to mEmptyBuffer and remove null
3932 // pointers for allocation performance.
3933 // The expectation is that we will find none needs to be compacted in most calls.
3934 bool needsCompact = false;
3935 for (std::unique_ptr<BufferBlock> &block : mBufferBlocks)
3936 {
3937 if (block->isEmpty())
3938 {
3939 // We will always free empty buffers that has smaller size. Or if the empty buffer has
3940 // been found empty for long enough time, or we accumulated too many empty buffers, we
3941 // also free it.
3942 if (block->getMemorySize() < mSize)
3943 {
3944 mTotalMemorySize -= block->getMemorySize();
3945 block->destroy(renderer);
3946 block.reset();
3947 }
3948 else
3949 {
3950 mEmptyBufferBlocks.push_back(std::move(block));
3951 }
3952 needsCompact = true;
3953 }
3954 }
3955
3956 // Now remove the null pointers that left by empty buffers all at once, if any.
3957 if (needsCompact)
3958 {
3959 BufferBlockPointerVector compactedBlocks;
3960 for (std::unique_ptr<BufferBlock> &block : mBufferBlocks)
3961 {
3962 if (block)
3963 {
3964 compactedBlocks.push_back(std::move(block));
3965 }
3966 }
3967 mBufferBlocks = std::move(compactedBlocks);
3968 }
3969
3970 // Decide how many empty buffers to keep around and trim down the excessive empty buffers. We
3971 // keep track of how many buffers are needed since last prune. Assume we are in stable state,
3972 // which means we may still need that many empty buffers in next prune cycle. To reduce chance
3973 // to call into vulkan driver to allocate new buffers, we try to keep that many empty buffers
3974 // around, subject to the maximum cap. If we overestimate, next cycle they used fewer buffers,
3975 // we will trim excessive empty buffers at next prune call. Or if we underestimate, we will end
3976 // up have to call into vulkan driver allocate new buffers, but next cycle we should correct
3977 // ourselves to keep enough number of empty buffers around.
3978 size_t buffersToKeep = std::min(mNumberOfNewBuffersNeededSinceLastPrune,
3979 static_cast<size_t>(kMaxTotalEmptyBufferBytes / mSize));
3980 while (mEmptyBufferBlocks.size() > buffersToKeep)
3981 {
3982 std::unique_ptr<BufferBlock> &block = mEmptyBufferBlocks.back();
3983 mTotalMemorySize -= block->getMemorySize();
3984 block->destroy(renderer);
3985 mEmptyBufferBlocks.pop_back();
3986 }
3987 mNumberOfNewBuffersNeededSinceLastPrune = 0;
3988 }
3989
allocateNewBuffer(Context * context,VkDeviceSize sizeInBytes)3990 VkResult BufferPool::allocateNewBuffer(Context *context, VkDeviceSize sizeInBytes)
3991 {
3992 Renderer *renderer = context->getRenderer();
3993 const Allocator &allocator = renderer->getAllocator();
3994
3995 VkDeviceSize heapSize =
3996 renderer->getMemoryProperties().getHeapSizeForMemoryType(mMemoryTypeIndex);
3997
3998 // First ensure we are not exceeding the heapSize to avoid the validation error.
3999 VK_RESULT_CHECK(sizeInBytes <= heapSize, VK_ERROR_OUT_OF_DEVICE_MEMORY);
4000
4001 // Double the size until meet the requirement. This also helps reducing the fragmentation. Since
4002 // this is global pool, we have less worry about memory waste.
4003 VkDeviceSize newSize = mSize;
4004 while (newSize < sizeInBytes)
4005 {
4006 newSize <<= 1;
4007 }
4008 mSize = std::min(newSize, heapSize);
4009
4010 // Allocate buffer
4011 VkBufferCreateInfo createInfo = {};
4012 createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4013 createInfo.flags = 0;
4014 createInfo.size = mSize;
4015 createInfo.usage = mUsage;
4016 createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
4017 createInfo.queueFamilyIndexCount = 0;
4018 createInfo.pQueueFamilyIndices = nullptr;
4019
4020 VkMemoryPropertyFlags memoryPropertyFlags;
4021 allocator.getMemoryTypeProperties(mMemoryTypeIndex, &memoryPropertyFlags);
4022
4023 DeviceScoped<Buffer> buffer(renderer->getDevice());
4024 VK_RESULT_TRY(buffer.get().init(context->getDevice(), createInfo));
4025
4026 DeviceScoped<DeviceMemory> deviceMemory(renderer->getDevice());
4027 VkMemoryPropertyFlags memoryPropertyFlagsOut;
4028 VkDeviceSize sizeOut;
4029 uint32_t memoryTypeIndex;
4030 VK_RESULT_TRY(AllocateBufferMemory(context, MemoryAllocationType::Buffer, memoryPropertyFlags,
4031 &memoryPropertyFlagsOut, nullptr, &buffer.get(),
4032 &memoryTypeIndex, &deviceMemory.get(), &sizeOut));
4033 ASSERT(sizeOut >= mSize);
4034
4035 // Allocate bufferBlock
4036 std::unique_ptr<BufferBlock> block = std::make_unique<BufferBlock>();
4037 VK_RESULT_TRY(block->init(context, buffer.get(), memoryTypeIndex, mVirtualBlockCreateFlags,
4038 deviceMemory.get(), memoryPropertyFlagsOut, mSize));
4039
4040 if (mHostVisible)
4041 {
4042 VK_RESULT_TRY(block->map(context->getDevice()));
4043 }
4044
4045 mTotalMemorySize += block->getMemorySize();
4046 // Append the bufferBlock into the pool
4047 mBufferBlocks.push_back(std::move(block));
4048 context->getPerfCounters().allocateNewBufferBlockCalls++;
4049
4050 return VK_SUCCESS;
4051 }
4052
allocateBuffer(Context * context,VkDeviceSize sizeInBytes,VkDeviceSize alignment,BufferSuballocation * suballocation)4053 VkResult BufferPool::allocateBuffer(Context *context,
4054 VkDeviceSize sizeInBytes,
4055 VkDeviceSize alignment,
4056 BufferSuballocation *suballocation)
4057 {
4058 ASSERT(alignment);
4059 VmaVirtualAllocation allocation;
4060 VkDeviceSize offset;
4061 VkDeviceSize alignedSize = roundUp(sizeInBytes, alignment);
4062
4063 if (alignedSize >= kMaxBufferSizeForSuballocation)
4064 {
4065 VkDeviceSize heapSize =
4066 context->getRenderer()->getMemoryProperties().getHeapSizeForMemoryType(
4067 mMemoryTypeIndex);
4068 // First ensure we are not exceeding the heapSize to avoid the validation error.
4069 VK_RESULT_CHECK(sizeInBytes <= heapSize, VK_ERROR_OUT_OF_DEVICE_MEMORY);
4070
4071 // Allocate buffer
4072 VkBufferCreateInfo createInfo = {};
4073 createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4074 createInfo.flags = 0;
4075 createInfo.size = alignedSize;
4076 createInfo.usage = mUsage;
4077 createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
4078 createInfo.queueFamilyIndexCount = 0;
4079 createInfo.pQueueFamilyIndices = nullptr;
4080
4081 VkMemoryPropertyFlags memoryPropertyFlags;
4082 const Allocator &allocator = context->getRenderer()->getAllocator();
4083 allocator.getMemoryTypeProperties(mMemoryTypeIndex, &memoryPropertyFlags);
4084
4085 DeviceScoped<Buffer> buffer(context->getDevice());
4086 VK_RESULT_TRY(buffer.get().init(context->getDevice(), createInfo));
4087
4088 DeviceScoped<DeviceMemory> deviceMemory(context->getDevice());
4089 VkMemoryPropertyFlags memoryPropertyFlagsOut;
4090 VkDeviceSize sizeOut;
4091 uint32_t memoryTypeIndex;
4092 VK_RESULT_TRY(AllocateBufferMemory(
4093 context, MemoryAllocationType::Buffer, memoryPropertyFlags, &memoryPropertyFlagsOut,
4094 nullptr, &buffer.get(), &memoryTypeIndex, &deviceMemory.get(), &sizeOut));
4095 ASSERT(sizeOut >= alignedSize);
4096
4097 suballocation->initWithEntireBuffer(context, buffer.get(), MemoryAllocationType::Buffer,
4098 memoryTypeIndex, deviceMemory.get(),
4099 memoryPropertyFlagsOut, alignedSize, sizeOut);
4100 if (mHostVisible)
4101 {
4102 VK_RESULT_TRY(suballocation->map(context));
4103 }
4104 return VK_SUCCESS;
4105 }
4106
4107 // We always allocate from reverse order so that older buffers have a chance to be empty. The
4108 // assumption is that to allocate from new buffers first may have a better chance to leave the
4109 // older buffers completely empty and we may able to free it.
4110 for (auto iter = mBufferBlocks.rbegin(); iter != mBufferBlocks.rend();)
4111 {
4112 std::unique_ptr<BufferBlock> &block = *iter;
4113 if (block->isEmpty() && block->getMemorySize() < mSize)
4114 {
4115 // Don't try to allocate from an empty buffer that has smaller size. It will get
4116 // released when pruneEmptyBuffers get called later on.
4117 ++iter;
4118 continue;
4119 }
4120
4121 if (block->allocate(alignedSize, alignment, &allocation, &offset) == VK_SUCCESS)
4122 {
4123 suballocation->init(block.get(), allocation, offset, alignedSize);
4124 return VK_SUCCESS;
4125 }
4126 ++iter;
4127 }
4128
4129 // Try to allocate from empty buffers
4130 while (!mEmptyBufferBlocks.empty())
4131 {
4132 std::unique_ptr<BufferBlock> &block = mEmptyBufferBlocks.back();
4133 if (block->getMemorySize() < mSize)
4134 {
4135 mTotalMemorySize -= block->getMemorySize();
4136 block->destroy(context->getRenderer());
4137 mEmptyBufferBlocks.pop_back();
4138 }
4139 else
4140 {
4141 VK_RESULT_TRY(block->allocate(alignedSize, alignment, &allocation, &offset));
4142 suballocation->init(block.get(), allocation, offset, alignedSize);
4143 mBufferBlocks.push_back(std::move(block));
4144 mEmptyBufferBlocks.pop_back();
4145 mNumberOfNewBuffersNeededSinceLastPrune++;
4146 return VK_SUCCESS;
4147 }
4148 }
4149
4150 // Failed to allocate from empty buffer. Now try to allocate a new buffer.
4151 VK_RESULT_TRY(allocateNewBuffer(context, alignedSize));
4152
4153 // Sub-allocate from the bufferBlock.
4154 std::unique_ptr<BufferBlock> &block = mBufferBlocks.back();
4155 VK_RESULT_CHECK(block->allocate(alignedSize, alignment, &allocation, &offset) == VK_SUCCESS,
4156 VK_ERROR_OUT_OF_DEVICE_MEMORY);
4157 suballocation->init(block.get(), allocation, offset, alignedSize);
4158 mNumberOfNewBuffersNeededSinceLastPrune++;
4159
4160 return VK_SUCCESS;
4161 }
4162
destroy(Renderer * renderer,bool orphanNonEmptyBufferBlock)4163 void BufferPool::destroy(Renderer *renderer, bool orphanNonEmptyBufferBlock)
4164 {
4165 for (std::unique_ptr<BufferBlock> &block : mBufferBlocks)
4166 {
4167 if (block->isEmpty())
4168 {
4169 block->destroy(renderer);
4170 }
4171 else
4172 {
4173 // When orphan is not allowed, all BufferBlocks must be empty.
4174 ASSERT(orphanNonEmptyBufferBlock);
4175 renderer->addBufferBlockToOrphanList(block.release());
4176 }
4177 }
4178 mBufferBlocks.clear();
4179
4180 for (std::unique_ptr<BufferBlock> &block : mEmptyBufferBlocks)
4181 {
4182 block->destroy(renderer);
4183 }
4184 mEmptyBufferBlocks.clear();
4185 }
4186
getTotalEmptyMemorySize() const4187 VkDeviceSize BufferPool::getTotalEmptyMemorySize() const
4188 {
4189 VkDeviceSize totalMemorySize = 0;
4190 for (const std::unique_ptr<BufferBlock> &block : mEmptyBufferBlocks)
4191 {
4192 totalMemorySize += block->getMemorySize();
4193 }
4194 return totalMemorySize;
4195 }
4196
addStats(std::ostringstream * out) const4197 void BufferPool::addStats(std::ostringstream *out) const
4198 {
4199 VkDeviceSize totalUnusedBytes = 0;
4200 VkDeviceSize totalMemorySize = 0;
4201 for (size_t i = 0; i < mBufferBlocks.size(); i++)
4202 {
4203 const std::unique_ptr<BufferBlock> &block = mBufferBlocks[i];
4204 vma::StatInfo statInfo;
4205 block->calculateStats(&statInfo);
4206 ASSERT(statInfo.basicInfo.blockCount == 1);
4207 INFO() << "[" << i << "]={" << " allocationCount:" << statInfo.basicInfo.allocationCount
4208 << " blockBytes:" << statInfo.basicInfo.blockBytes
4209 << " allocationBytes:" << statInfo.basicInfo.allocationBytes
4210 << " unusedRangeCount:" << statInfo.unusedRangeCount
4211 << " allocationSizeMin:" << statInfo.allocationSizeMin
4212 << " allocationSizeMax:" << statInfo.allocationSizeMax
4213 << " unusedRangeSizeMin:" << statInfo.unusedRangeSizeMin
4214 << " unusedRangeSizeMax:" << statInfo.unusedRangeSizeMax << " }";
4215 VkDeviceSize unusedBytes =
4216 statInfo.basicInfo.blockBytes - statInfo.basicInfo.allocationBytes;
4217 totalUnusedBytes += unusedBytes;
4218 totalMemorySize += block->getMemorySize();
4219 }
4220 *out << "mBufferBlocks.size():" << mBufferBlocks.size()
4221 << " totalUnusedBytes:" << totalUnusedBytes / 1024
4222 << "KB / totalMemorySize:" << totalMemorySize / 1024 << "KB";
4223 *out << " emptyBuffers [memorySize:" << getTotalEmptyMemorySize() / 1024 << "KB "
4224 << " count:" << mEmptyBufferBlocks.size()
4225 << " needed: " << mNumberOfNewBuffersNeededSinceLastPrune << "]";
4226 }
4227
4228 // DescriptorSetHelper implementation.
destroy(VkDevice device)4229 void DescriptorSetHelper::destroy(VkDevice device)
4230 {
4231 if (valid())
4232 {
4233 // Since the pool is created without VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, we
4234 // don't call vkFreeDescriptorSets. We always add to garbage list so that it can be
4235 // recycled. Since we dont actually know if it is GPU completed, we always just add to the
4236 // pending garbage list assuming the worst case.
4237 DescriptorPoolPointer pool(device, mPool);
4238 DescriptorSetPointer garbage(device, std::move(*this));
4239 pool->addPendingGarbage(std::move(garbage));
4240 ASSERT(!valid());
4241 }
4242 }
4243
4244 // DescriptorPoolHelper implementation.
DescriptorPoolHelper()4245 DescriptorPoolHelper::DescriptorPoolHelper()
4246 : mMaxDescriptorSets(0), mValidDescriptorSets(0), mFreeDescriptorSets(0)
4247 {}
4248
~DescriptorPoolHelper()4249 DescriptorPoolHelper::~DescriptorPoolHelper()
4250 {
4251 ASSERT(mPendingGarbageList.empty());
4252 ASSERT(mFinishedGarbageList.empty());
4253 }
4254
init(Context * context,const std::vector<VkDescriptorPoolSize> & poolSizesIn,uint32_t maxSets)4255 angle::Result DescriptorPoolHelper::init(Context *context,
4256 const std::vector<VkDescriptorPoolSize> &poolSizesIn,
4257 uint32_t maxSets)
4258 {
4259 Renderer *renderer = context->getRenderer();
4260
4261 ASSERT(mPendingGarbageList.empty());
4262 ASSERT(mFinishedGarbageList.empty());
4263
4264 if (mDescriptorPool.valid())
4265 {
4266 mDescriptorPool.destroy(renderer->getDevice());
4267 }
4268
4269 // Make a copy of the pool sizes, so we can grow them to satisfy the specified maxSets.
4270 std::vector<VkDescriptorPoolSize> poolSizes = poolSizesIn;
4271
4272 for (VkDescriptorPoolSize &poolSize : poolSizes)
4273 {
4274 poolSize.descriptorCount *= maxSets;
4275 }
4276
4277 VkDescriptorPoolCreateInfo descriptorPoolInfo = {};
4278 descriptorPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
4279 descriptorPoolInfo.flags = 0;
4280 descriptorPoolInfo.maxSets = maxSets;
4281 descriptorPoolInfo.poolSizeCount = static_cast<uint32_t>(poolSizes.size());
4282 descriptorPoolInfo.pPoolSizes = poolSizes.data();
4283
4284 mMaxDescriptorSets = maxSets;
4285 mFreeDescriptorSets = maxSets;
4286 mValidDescriptorSets = 0;
4287
4288 ANGLE_VK_TRY(context, mDescriptorPool.init(renderer->getDevice(), descriptorPoolInfo));
4289
4290 mRenderer = renderer;
4291
4292 return angle::Result::Continue;
4293 }
4294
destroy(VkDevice device)4295 void DescriptorPoolHelper::destroy(VkDevice device)
4296 {
4297 ASSERT(mValidDescriptorSets == 0);
4298 ASSERT(mPendingGarbageList.empty());
4299 ASSERT(mFinishedGarbageList.empty());
4300 mDescriptorPool.destroy(device);
4301 }
4302
allocateVkDescriptorSet(Context * context,const DescriptorSetLayout & descriptorSetLayout,VkDescriptorSet * descriptorSetOut)4303 bool DescriptorPoolHelper::allocateVkDescriptorSet(Context *context,
4304 const DescriptorSetLayout &descriptorSetLayout,
4305 VkDescriptorSet *descriptorSetOut)
4306 {
4307 if (mFreeDescriptorSets > 0)
4308 {
4309 VkDescriptorSetAllocateInfo allocInfo = {};
4310 allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
4311 allocInfo.descriptorPool = mDescriptorPool.getHandle();
4312 allocInfo.descriptorSetCount = 1;
4313 allocInfo.pSetLayouts = descriptorSetLayout.ptr();
4314
4315 VkResult result = mDescriptorPool.allocateDescriptorSets(context->getDevice(), allocInfo,
4316 descriptorSetOut);
4317 ++context->getPerfCounters().descriptorSetAllocations;
4318 // If fail, it means our own accounting has a bug.
4319 ASSERT(result == VK_SUCCESS);
4320 mFreeDescriptorSets--;
4321 mValidDescriptorSets++;
4322 return true;
4323 }
4324
4325 return false;
4326 }
4327
cleanupPendingGarbage()4328 void DescriptorPoolHelper::cleanupPendingGarbage()
4329 {
4330 while (!mPendingGarbageList.empty())
4331 {
4332 DescriptorSetPointer &garbage = mPendingGarbageList.front();
4333 if (!mRenderer->hasResourceUseFinished(garbage->getResourceUse()))
4334 {
4335 break;
4336 }
4337 mFinishedGarbageList.push_back(std::move(garbage));
4338 mPendingGarbageList.pop_front();
4339 }
4340 }
4341
recycleFromGarbage(Renderer * renderer,DescriptorSetPointer * descriptorSetOut)4342 bool DescriptorPoolHelper::recycleFromGarbage(Renderer *renderer,
4343 DescriptorSetPointer *descriptorSetOut)
4344 {
4345 if (mFinishedGarbageList.empty())
4346 {
4347 cleanupPendingGarbage();
4348 }
4349
4350 if (!mFinishedGarbageList.empty())
4351 {
4352 DescriptorSetPointer &garbage = mFinishedGarbageList.front();
4353 *descriptorSetOut = std::move(garbage);
4354 mFinishedGarbageList.pop_front();
4355 mValidDescriptorSets++;
4356 return true;
4357 }
4358
4359 return false;
4360 }
4361
allocateDescriptorSet(Context * context,const DescriptorSetLayout & descriptorSetLayout,const DescriptorPoolPointer & pool,DescriptorSetPointer * descriptorSetOut)4362 bool DescriptorPoolHelper::allocateDescriptorSet(Context *context,
4363 const DescriptorSetLayout &descriptorSetLayout,
4364 const DescriptorPoolPointer &pool,
4365 DescriptorSetPointer *descriptorSetOut)
4366 {
4367 ASSERT(pool.get() == this);
4368 VkDescriptorSet descriptorSet;
4369 if (allocateVkDescriptorSet(context, descriptorSetLayout, &descriptorSet))
4370 {
4371 DescriptorSetHelper helper = DescriptorSetHelper(descriptorSet, pool);
4372 *descriptorSetOut = DescriptorSetPointer(context->getDevice(), std::move(helper));
4373 return true;
4374 }
4375 return false;
4376 }
4377
destroyGarbage()4378 void DescriptorPoolHelper::destroyGarbage()
4379 {
4380 ASSERT(mPendingGarbageList.empty());
4381
4382 while (!mFinishedGarbageList.empty())
4383 {
4384 DescriptorSetPointer &garbage = mFinishedGarbageList.front();
4385 ASSERT(garbage.unique());
4386 ASSERT(garbage->valid());
4387 // Because we do not use VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT when pool is
4388 // created, We can't free each individual descriptor set before destroying the pool, we
4389 // simply clear the descriptorSet and the mPool weak pointer so that
4390 // DescriptorSetHelper::destroy will not find it the garbage being valid and try to add to
4391 // garbage list again.
4392 garbage->mDescriptorSet = VK_NULL_HANDLE;
4393 garbage->mPool.reset();
4394 ASSERT(!garbage->valid());
4395 mFinishedGarbageList.pop_front();
4396 }
4397 }
4398
4399 // DynamicDescriptorPool implementation.
DynamicDescriptorPool()4400 DynamicDescriptorPool::DynamicDescriptorPool() : mCachedDescriptorSetLayout(VK_NULL_HANDLE) {}
4401
~DynamicDescriptorPool()4402 DynamicDescriptorPool::~DynamicDescriptorPool()
4403 {
4404 ASSERT(mLRUList.empty());
4405 ASSERT(mDescriptorSetCache.empty());
4406 ASSERT(mDescriptorPools.empty());
4407 }
4408
DynamicDescriptorPool(DynamicDescriptorPool && other)4409 DynamicDescriptorPool::DynamicDescriptorPool(DynamicDescriptorPool &&other)
4410 : DynamicDescriptorPool()
4411 {
4412 *this = std::move(other);
4413 }
4414
operator =(DynamicDescriptorPool && other)4415 DynamicDescriptorPool &DynamicDescriptorPool::operator=(DynamicDescriptorPool &&other)
4416 {
4417 std::swap(mDescriptorPools, other.mDescriptorPools);
4418 std::swap(mPoolSizes, other.mPoolSizes);
4419 std::swap(mCachedDescriptorSetLayout, other.mCachedDescriptorSetLayout);
4420 std::swap(mLRUList, other.mLRUList);
4421 std::swap(mDescriptorSetCache, other.mDescriptorSetCache);
4422 return *this;
4423 }
4424
init(Context * context,const VkDescriptorPoolSize * setSizes,size_t setSizeCount,const DescriptorSetLayout & descriptorSetLayout)4425 angle::Result DynamicDescriptorPool::init(Context *context,
4426 const VkDescriptorPoolSize *setSizes,
4427 size_t setSizeCount,
4428 const DescriptorSetLayout &descriptorSetLayout)
4429 {
4430 ASSERT(setSizes);
4431 ASSERT(setSizeCount);
4432 ASSERT(mDescriptorPools.empty());
4433 ASSERT(mCachedDescriptorSetLayout == VK_NULL_HANDLE);
4434
4435 mPoolSizes.assign(setSizes, setSizes + setSizeCount);
4436 mCachedDescriptorSetLayout = descriptorSetLayout.getHandle();
4437
4438 DescriptorPoolPointer newPool = DescriptorPoolPointer::MakeShared(context->getDevice());
4439 ANGLE_TRY(newPool->init(context, mPoolSizes, mMaxSetsPerPool));
4440
4441 mDescriptorPools.emplace_back(std::move(newPool));
4442
4443 return angle::Result::Continue;
4444 }
4445
destroy(VkDevice device)4446 void DynamicDescriptorPool::destroy(VkDevice device)
4447 {
4448 // Destroy cache
4449 mDescriptorSetCache.clear();
4450
4451 // Destroy LRU list and SharedDescriptorSetCacheKey.
4452 for (auto it = mLRUList.begin(); it != mLRUList.end();)
4453 {
4454 (it->sharedCacheKey)->destroy(device);
4455 it = mLRUList.erase(it);
4456 }
4457 ASSERT(mLRUList.empty());
4458
4459 for (DescriptorPoolPointer &pool : mDescriptorPools)
4460 {
4461 pool->cleanupPendingGarbage();
4462 pool->destroyGarbage();
4463 ASSERT(pool.unique());
4464 }
4465 mDescriptorPools.clear();
4466
4467 mCachedDescriptorSetLayout = VK_NULL_HANDLE;
4468 }
4469
allocateFromExistingPool(Context * context,const DescriptorSetLayout & descriptorSetLayout,DescriptorSetPointer * descriptorSetOut)4470 bool DynamicDescriptorPool::allocateFromExistingPool(Context *context,
4471 const DescriptorSetLayout &descriptorSetLayout,
4472 DescriptorSetPointer *descriptorSetOut)
4473 {
4474 for (size_t poolIndex = 0; poolIndex < mDescriptorPools.size(); ++poolIndex)
4475 {
4476 DescriptorPoolPointer &pool = mDescriptorPools[poolIndex];
4477 if (!pool || !pool->valid())
4478 {
4479 continue;
4480 }
4481 if (pool->allocateDescriptorSet(context, descriptorSetLayout, pool, descriptorSetOut))
4482 {
4483 return true;
4484 }
4485 }
4486 return false;
4487 }
4488
recycleFromGarbage(Renderer * renderer,DescriptorSetPointer * descriptorSetOut)4489 bool DynamicDescriptorPool::recycleFromGarbage(Renderer *renderer,
4490 DescriptorSetPointer *descriptorSetOut)
4491 {
4492 for (DescriptorPoolPointer &pool : mDescriptorPools)
4493 {
4494 if (pool->recycleFromGarbage(renderer, descriptorSetOut))
4495 {
4496 return true;
4497 }
4498 }
4499 return false;
4500 }
4501
evictStaleDescriptorSets(Renderer * renderer,uint32_t oldestFrameToKeep,uint32_t currentFrame)4502 bool DynamicDescriptorPool::evictStaleDescriptorSets(Renderer *renderer,
4503 uint32_t oldestFrameToKeep,
4504 uint32_t currentFrame)
4505 {
4506 ASSERT(oldestFrameToKeep < currentFrame);
4507 size_t descriptorSetEvicted = 0;
4508 // Walk LRU list backwards from oldest to most recent, evict anything that earlier than
4509 // oldestFrameIDToKeep.
4510 auto it = mLRUList.rbegin();
4511 while (it != mLRUList.rend())
4512 {
4513 DescriptorSetPointer &descriptorSet = it->descriptorSet;
4514 if (descriptorSet.unique())
4515 {
4516 // Stop if it is recently being used.
4517 if (descriptorSet->getLastUsedFrame() > oldestFrameToKeep)
4518 {
4519 break;
4520 }
4521 // Stop if GPU is still busy
4522 if (!renderer->hasResourceUseFinished(descriptorSet->getResourceUse()))
4523 {
4524 break;
4525 }
4526 // Evict it from the cache and remove it from LRU list.
4527 bool removed = mDescriptorSetCache.eraseDescriptorSet(it->sharedCacheKey->getDesc());
4528 ASSERT(removed);
4529
4530 // Note that erase it from LRU list will "destroy" descriptorSet. Since we
4531 // never actually destroy descriptorSet, it will just add to the garbage list. Here we
4532 // want more explicit control to add it to the front of list (because we know it is
4533 // already GPU completed) instead to the end of the list, so we do it explicitly.
4534 DescriptorPoolWeakPointer pool = descriptorSet->getPool();
4535 pool->addFinishedGarbage(std::move(descriptorSet));
4536 descriptorSetEvicted++;
4537
4538 // This should destroy descriptorSet, which is already invalid;
4539 it = decltype(it)(mLRUList.erase(std::next(it).base()));
4540 mCacheStats.decrementSize();
4541 }
4542 else
4543 {
4544 // It means it is still bound to one of the programs. Move it to the front of the LRU
4545 // list to avoid repeatedly hitting it for every eviction.
4546 mLRUList.splice(mLRUList.begin(), mLRUList, std::next(it).base());
4547 ++it;
4548 // Update to currentFrame to maintain LRU order
4549 descriptorSet->updateLastUsedFrame(currentFrame);
4550 }
4551 }
4552
4553 if (descriptorSetEvicted > 0)
4554 {
4555 // If there is any pool that is completely empty, destroy it first so that we can allocate
4556 // from partial pool.
4557 checkAndDestroyUnusedPool(renderer);
4558 return true;
4559 }
4560
4561 return false;
4562 }
4563
allocateDescriptorSet(Context * context,const DescriptorSetLayout & descriptorSetLayout,DescriptorSetPointer * descriptorSetOut)4564 angle::Result DynamicDescriptorPool::allocateDescriptorSet(
4565 Context *context,
4566 const DescriptorSetLayout &descriptorSetLayout,
4567 DescriptorSetPointer *descriptorSetOut)
4568 {
4569 ASSERT(!mDescriptorPools.empty());
4570 ASSERT(descriptorSetLayout.getHandle() == mCachedDescriptorSetLayout);
4571
4572 if (allocateFromExistingPool(context, descriptorSetLayout, descriptorSetOut))
4573 {
4574 return angle::Result::Continue;
4575 }
4576
4577 if (recycleFromGarbage(context->getRenderer(), descriptorSetOut))
4578 {
4579 return angle::Result::Continue;
4580 }
4581
4582 // Last, try to allocate a new pool (and/or evict an existing pool)
4583 ANGLE_TRY(allocateNewPool(context));
4584 bool success = allocateFromExistingPool(context, descriptorSetLayout, descriptorSetOut);
4585 // Allocate from a new pool must succeed.
4586 ASSERT(success);
4587
4588 return angle::Result::Continue;
4589 }
4590
getOrAllocateDescriptorSet(Context * context,uint32_t currentFrame,const DescriptorSetDesc & desc,const DescriptorSetLayout & descriptorSetLayout,DescriptorSetPointer * descriptorSetOut,SharedDescriptorSetCacheKey * newSharedCacheKeyOut)4591 angle::Result DynamicDescriptorPool::getOrAllocateDescriptorSet(
4592 Context *context,
4593 uint32_t currentFrame,
4594 const DescriptorSetDesc &desc,
4595 const DescriptorSetLayout &descriptorSetLayout,
4596 DescriptorSetPointer *descriptorSetOut,
4597 SharedDescriptorSetCacheKey *newSharedCacheKeyOut)
4598 {
4599 Renderer *renderer = context->getRenderer();
4600 ASSERT(context->getFeatures().descriptorSetCache.enabled);
4601 bool success;
4602
4603 // First scan the descriptorSet cache.
4604 DescriptorSetLRUListIterator listIterator;
4605 if (mDescriptorSetCache.getDescriptorSet(desc, &listIterator))
4606 {
4607 *descriptorSetOut = listIterator->descriptorSet;
4608 (*newSharedCacheKeyOut).reset();
4609 // Move it to the front of the LRU list.
4610 mLRUList.splice(mLRUList.begin(), mLRUList, listIterator);
4611 mCacheStats.hit();
4612 return angle::Result::Continue;
4613 }
4614
4615 // Try to allocate from the existing pool (or recycle from grabage list)
4616 success = allocateFromExistingPool(context, descriptorSetLayout, descriptorSetOut);
4617
4618 // Try to recycle from the garbage list.
4619 if (!success)
4620 {
4621 success = recycleFromGarbage(context->getRenderer(), descriptorSetOut);
4622 }
4623
4624 // Try to evict oldest descriptorSets that has not being used in last
4625 // kDescriptorSetCacheRetireAge.
4626 if (!success && currentFrame > kDescriptorSetCacheRetireAge)
4627 {
4628 uint32_t oldestFrameToKeep = currentFrame - kDescriptorSetCacheRetireAge;
4629 if (evictStaleDescriptorSets(renderer, oldestFrameToKeep, currentFrame))
4630 {
4631 success = recycleFromGarbage(renderer, descriptorSetOut);
4632 }
4633 }
4634
4635 // Last, try to allocate a new pool
4636 if (!success)
4637 {
4638 ANGLE_TRY(allocateNewPool(context));
4639 success = allocateFromExistingPool(context, descriptorSetLayout, descriptorSetOut);
4640 // Allocate from a new pool must succeed.
4641 ASSERT(success);
4642 }
4643
4644 ASSERT(descriptorSetOut->unique());
4645 ASSERT((*descriptorSetOut)->valid());
4646
4647 // Let pool know there is a shared cache key created and destroys the shared cache key
4648 // when it destroys the pool.
4649 SharedDescriptorSetCacheKey sharedCacheKey = CreateSharedDescriptorSetCacheKey(desc, this);
4650
4651 // Add to the front of the LRU list and add list iterator to the cache
4652 mLRUList.push_front({sharedCacheKey, *descriptorSetOut});
4653 mDescriptorSetCache.insertDescriptorSet(desc, mLRUList.begin());
4654 mCacheStats.missAndIncrementSize();
4655
4656 *newSharedCacheKeyOut = sharedCacheKey;
4657 return angle::Result::Continue;
4658 }
4659
allocateNewPool(Context * context)4660 angle::Result DynamicDescriptorPool::allocateNewPool(Context *context)
4661 {
4662 static constexpr size_t kMaxPools = 99999;
4663 ANGLE_VK_CHECK(context, mDescriptorPools.size() < kMaxPools, VK_ERROR_TOO_MANY_OBJECTS);
4664 // This pool is getting hot, so grow its max size to try and prevent allocating another pool in
4665 // the future.
4666 if (mMaxSetsPerPool < kMaxSetsPerPoolMax)
4667 {
4668 mMaxSetsPerPool *= mMaxSetsPerPoolMultiplier;
4669 }
4670 DescriptorPoolPointer newPool = DescriptorPoolPointer::MakeShared(context->getDevice());
4671 ANGLE_TRY(newPool->init(context, mPoolSizes, mMaxSetsPerPool));
4672 mDescriptorPools.emplace_back(std::move(newPool));
4673
4674 return angle::Result::Continue;
4675 }
4676
releaseCachedDescriptorSet(Renderer * renderer,const DescriptorSetDesc & desc)4677 void DynamicDescriptorPool::releaseCachedDescriptorSet(Renderer *renderer,
4678 const DescriptorSetDesc &desc)
4679 {
4680 ASSERT(renderer->getFeatures().descriptorSetCache.enabled);
4681 DescriptorSetLRUListIterator listIter;
4682 // Remove from the cache hash map. Note that we can't delete it until refcount goes to 0
4683 if (mDescriptorSetCache.eraseDescriptorSet(desc, &listIter))
4684 {
4685 DescriptorSetPointer descriptorSet = std::move(listIter->descriptorSet);
4686 mCacheStats.decrementSize();
4687 mLRUList.erase(listIter);
4688
4689 if (descriptorSet.unique())
4690 {
4691 DescriptorPoolWeakPointer pool = descriptorSet->getPool();
4692 pool->addPendingGarbage(std::move(descriptorSet));
4693 }
4694 }
4695 }
4696
destroyCachedDescriptorSet(Renderer * renderer,const DescriptorSetDesc & desc)4697 void DynamicDescriptorPool::destroyCachedDescriptorSet(Renderer *renderer,
4698 const DescriptorSetDesc &desc)
4699 {
4700 ASSERT(renderer->getFeatures().descriptorSetCache.enabled);
4701 DescriptorSetLRUListIterator listIter;
4702 // Remove from the cache hash map. Note that we can't delete it until refcount goes to 0
4703 if (mDescriptorSetCache.eraseDescriptorSet(desc, &listIter))
4704 {
4705 DescriptorSetPointer descriptorSet = std::move(listIter->descriptorSet);
4706 mCacheStats.decrementSize();
4707 mLRUList.erase(listIter);
4708
4709 if (descriptorSet.unique())
4710 {
4711 DescriptorPoolWeakPointer pool = descriptorSet->getPool();
4712 pool->addFinishedGarbage(std::move(descriptorSet));
4713 if (pool->canDestroy())
4714 {
4715 destroyUnusedPool(renderer, pool);
4716 }
4717 }
4718 }
4719 }
4720
destroyUnusedPool(Renderer * renderer,const DescriptorPoolWeakPointer & pool)4721 void DynamicDescriptorPool::destroyUnusedPool(Renderer *renderer,
4722 const DescriptorPoolWeakPointer &pool)
4723 {
4724 ASSERT(renderer->getFeatures().descriptorSetCache.enabled);
4725 ASSERT(pool->canDestroy());
4726
4727 // We always keep at least one pool around.
4728 if (mDescriptorPools.size() < 2)
4729 {
4730 return;
4731 }
4732
4733 // Erase it from the array
4734 for (auto it = mDescriptorPools.begin(); it != mDescriptorPools.end(); ++it)
4735 {
4736 if (pool.owner_equal(*it))
4737 {
4738 ASSERT(pool->valid());
4739 pool->destroyGarbage();
4740 ASSERT((*it).unique());
4741 it = mDescriptorPools.erase(it);
4742 return;
4743 }
4744 }
4745 }
4746
checkAndDestroyUnusedPool(Renderer * renderer)4747 void DynamicDescriptorPool::checkAndDestroyUnusedPool(Renderer *renderer)
4748 {
4749 ASSERT(renderer->getFeatures().descriptorSetCache.enabled);
4750 for (auto pool : mDescriptorPools)
4751 {
4752 pool->cleanupPendingGarbage();
4753 }
4754
4755 // We always keep at least one pool around.
4756 if (mDescriptorPools.size() < 2)
4757 {
4758 return;
4759 }
4760
4761 // Erase it from the array
4762 for (auto it = mDescriptorPools.begin(); it != mDescriptorPools.end();)
4763 {
4764 if ((*it)->canDestroy())
4765 {
4766 (*it)->destroyGarbage();
4767 ASSERT((*it).unique());
4768 it = mDescriptorPools.erase(it);
4769 }
4770 else
4771 {
4772 ++it;
4773 }
4774 }
4775 }
4776
4777 // For testing only!
GetMaxSetsPerPoolForTesting()4778 uint32_t DynamicDescriptorPool::GetMaxSetsPerPoolForTesting()
4779 {
4780 return mMaxSetsPerPool;
4781 }
4782
4783 // For testing only!
SetMaxSetsPerPoolForTesting(uint32_t maxSetsPerPool)4784 void DynamicDescriptorPool::SetMaxSetsPerPoolForTesting(uint32_t maxSetsPerPool)
4785 {
4786 mMaxSetsPerPool = maxSetsPerPool;
4787 }
4788
4789 // For testing only!
GetMaxSetsPerPoolMultiplierForTesting()4790 uint32_t DynamicDescriptorPool::GetMaxSetsPerPoolMultiplierForTesting()
4791 {
4792 return mMaxSetsPerPoolMultiplier;
4793 }
4794
4795 // For testing only!
SetMaxSetsPerPoolMultiplierForTesting(uint32_t maxSetsPerPoolMultiplier)4796 void DynamicDescriptorPool::SetMaxSetsPerPoolMultiplierForTesting(uint32_t maxSetsPerPoolMultiplier)
4797 {
4798 mMaxSetsPerPoolMultiplier = maxSetsPerPoolMultiplier;
4799 }
4800
4801 // DynamicallyGrowingPool implementation
4802 template <typename Pool>
DynamicallyGrowingPool()4803 DynamicallyGrowingPool<Pool>::DynamicallyGrowingPool()
4804 : mPoolSize(0), mCurrentPool(0), mCurrentFreeEntry(0)
4805 {}
4806
4807 template <typename Pool>
4808 DynamicallyGrowingPool<Pool>::~DynamicallyGrowingPool() = default;
4809
4810 template <typename Pool>
initEntryPool(Context * contextVk,uint32_t poolSize)4811 angle::Result DynamicallyGrowingPool<Pool>::initEntryPool(Context *contextVk, uint32_t poolSize)
4812 {
4813 ASSERT(mPools.empty());
4814 mPoolSize = poolSize;
4815 mCurrentFreeEntry = poolSize;
4816 return angle::Result::Continue;
4817 }
4818
4819 template <typename Pool>
destroyEntryPool(VkDevice device)4820 void DynamicallyGrowingPool<Pool>::destroyEntryPool(VkDevice device)
4821 {
4822 for (PoolResource &resource : mPools)
4823 {
4824 destroyPoolImpl(device, resource.pool);
4825 }
4826 mPools.clear();
4827 }
4828
4829 template <typename Pool>
findFreeEntryPool(ContextVk * contextVk)4830 bool DynamicallyGrowingPool<Pool>::findFreeEntryPool(ContextVk *contextVk)
4831 {
4832 Renderer *renderer = contextVk->getRenderer();
4833 for (size_t poolIndex = 0; poolIndex < mPools.size(); ++poolIndex)
4834 {
4835 PoolResource &pool = mPools[poolIndex];
4836 if (pool.freedCount == mPoolSize && renderer->hasResourceUseFinished(pool.getResourceUse()))
4837 {
4838 mCurrentPool = poolIndex;
4839 mCurrentFreeEntry = 0;
4840
4841 pool.freedCount = 0;
4842
4843 return true;
4844 }
4845 }
4846
4847 return false;
4848 }
4849
4850 template <typename Pool>
allocateNewEntryPool(ContextVk * contextVk,Pool && pool)4851 angle::Result DynamicallyGrowingPool<Pool>::allocateNewEntryPool(ContextVk *contextVk, Pool &&pool)
4852 {
4853 mPools.emplace_back(std::move(pool), 0);
4854
4855 mCurrentPool = mPools.size() - 1;
4856 mCurrentFreeEntry = 0;
4857
4858 return angle::Result::Continue;
4859 }
4860
4861 template <typename Pool>
onEntryFreed(ContextVk * contextVk,size_t poolIndex,const ResourceUse & use)4862 void DynamicallyGrowingPool<Pool>::onEntryFreed(ContextVk *contextVk,
4863 size_t poolIndex,
4864 const ResourceUse &use)
4865 {
4866 ASSERT(poolIndex < mPools.size() && mPools[poolIndex].freedCount < mPoolSize);
4867 if (!contextVk->getRenderer()->hasResourceUseFinished(use))
4868 {
4869 mPools[poolIndex].mergeResourceUse(use);
4870 }
4871 ++mPools[poolIndex].freedCount;
4872 }
4873
4874 template <typename Pool>
allocatePoolEntries(ContextVk * contextVk,uint32_t entryCount,uint32_t * poolIndex,uint32_t * currentEntryOut)4875 angle::Result DynamicallyGrowingPool<Pool>::allocatePoolEntries(ContextVk *contextVk,
4876 uint32_t entryCount,
4877 uint32_t *poolIndex,
4878 uint32_t *currentEntryOut)
4879 {
4880 if (mCurrentFreeEntry + entryCount > mPoolSize)
4881 {
4882 if (!findFreeEntryPool(contextVk))
4883 {
4884 Pool newPool;
4885 ANGLE_TRY(allocatePoolImpl(contextVk, newPool, mPoolSize));
4886 ANGLE_TRY(allocateNewEntryPool(contextVk, std::move(newPool)));
4887 }
4888 }
4889
4890 *poolIndex = static_cast<uint32_t>(mCurrentPool);
4891 *currentEntryOut = mCurrentFreeEntry;
4892
4893 mCurrentFreeEntry += entryCount;
4894
4895 return angle::Result::Continue;
4896 }
4897
4898 template <typename Pool>
PoolResource(Pool && poolIn,uint32_t freedCountIn)4899 DynamicallyGrowingPool<Pool>::PoolResource::PoolResource(Pool &&poolIn, uint32_t freedCountIn)
4900 : pool(std::move(poolIn)), freedCount(freedCountIn)
4901 {}
4902
4903 template <typename Pool>
PoolResource(PoolResource && other)4904 DynamicallyGrowingPool<Pool>::PoolResource::PoolResource(PoolResource &&other)
4905 : Resource(std::move(other)), pool(std::move(other.pool)), freedCount(other.freedCount)
4906 {}
4907
4908 // DynamicQueryPool implementation
4909 DynamicQueryPool::DynamicQueryPool() = default;
4910
4911 DynamicQueryPool::~DynamicQueryPool() = default;
4912
init(ContextVk * contextVk,VkQueryType type,uint32_t poolSize)4913 angle::Result DynamicQueryPool::init(ContextVk *contextVk, VkQueryType type, uint32_t poolSize)
4914 {
4915 // SecondaryCommandBuffer's ResetQueryPoolParams would like the query index to fit in 24 bits.
4916 ASSERT(poolSize < (1 << 24));
4917
4918 ANGLE_TRY(initEntryPool(contextVk, poolSize));
4919 mQueryType = type;
4920 return angle::Result::Continue;
4921 }
4922
destroy(VkDevice device)4923 void DynamicQueryPool::destroy(VkDevice device)
4924 {
4925 destroyEntryPool(device);
4926 }
4927
destroyPoolImpl(VkDevice device,QueryPool & poolToDestroy)4928 void DynamicQueryPool::destroyPoolImpl(VkDevice device, QueryPool &poolToDestroy)
4929 {
4930 poolToDestroy.destroy(device);
4931 }
4932
allocateQuery(ContextVk * contextVk,QueryHelper * queryOut,uint32_t queryCount)4933 angle::Result DynamicQueryPool::allocateQuery(ContextVk *contextVk,
4934 QueryHelper *queryOut,
4935 uint32_t queryCount)
4936 {
4937 ASSERT(!queryOut->valid());
4938
4939 uint32_t currentPool = 0;
4940 uint32_t queryIndex = 0;
4941 ANGLE_TRY(allocatePoolEntries(contextVk, queryCount, ¤tPool, &queryIndex));
4942
4943 queryOut->init(this, currentPool, queryIndex, queryCount);
4944
4945 return angle::Result::Continue;
4946 }
4947
allocatePoolImpl(ContextVk * contextVk,QueryPool & poolToAllocate,uint32_t entriesToAllocate)4948 angle::Result DynamicQueryPool::allocatePoolImpl(ContextVk *contextVk,
4949 QueryPool &poolToAllocate,
4950 uint32_t entriesToAllocate)
4951 {
4952 VkQueryPoolCreateInfo queryPoolInfo = {};
4953 queryPoolInfo.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
4954 queryPoolInfo.flags = 0;
4955 queryPoolInfo.queryType = this->mQueryType;
4956 queryPoolInfo.queryCount = entriesToAllocate;
4957 queryPoolInfo.pipelineStatistics = 0;
4958
4959 if (this->mQueryType == VK_QUERY_TYPE_PIPELINE_STATISTICS)
4960 {
4961 queryPoolInfo.pipelineStatistics = VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT;
4962 }
4963
4964 ANGLE_VK_TRY(contextVk, poolToAllocate.init(contextVk->getDevice(), queryPoolInfo));
4965 return angle::Result::Continue;
4966 }
4967
freeQuery(ContextVk * contextVk,QueryHelper * query)4968 void DynamicQueryPool::freeQuery(ContextVk *contextVk, QueryHelper *query)
4969 {
4970 if (query->valid())
4971 {
4972 size_t poolIndex = query->mQueryPoolIndex;
4973 ASSERT(getQueryPool(poolIndex).valid());
4974
4975 onEntryFreed(contextVk, poolIndex, query->getResourceUse());
4976
4977 query->deinit();
4978 }
4979 }
4980
4981 // QueryResult implementation
setResults(uint64_t * results,uint32_t queryCount)4982 void QueryResult::setResults(uint64_t *results, uint32_t queryCount)
4983 {
4984 ASSERT(mResults[0] == 0 && mResults[1] == 0);
4985
4986 // Accumulate the query results. For multiview, where multiple query indices are used to return
4987 // the results, it's undefined how the results are distributed between indices, but the sum is
4988 // guaranteed to be the desired result.
4989 for (uint32_t query = 0; query < queryCount; ++query)
4990 {
4991 for (uint32_t perQueryIndex = 0; perQueryIndex < mIntsPerResult; ++perQueryIndex)
4992 {
4993 mResults[perQueryIndex] += results[query * mIntsPerResult + perQueryIndex];
4994 }
4995 }
4996 }
4997
4998 // QueryHelper implementation
QueryHelper()4999 QueryHelper::QueryHelper()
5000 : mDynamicQueryPool(nullptr),
5001 mQueryPoolIndex(0),
5002 mQuery(0),
5003 mQueryCount(0),
5004 mStatus(QueryStatus::Inactive)
5005 {}
5006
~QueryHelper()5007 QueryHelper::~QueryHelper() {}
5008
5009 // Move constructor
QueryHelper(QueryHelper && rhs)5010 QueryHelper::QueryHelper(QueryHelper &&rhs)
5011 : Resource(std::move(rhs)),
5012 mDynamicQueryPool(rhs.mDynamicQueryPool),
5013 mQueryPoolIndex(rhs.mQueryPoolIndex),
5014 mQuery(rhs.mQuery),
5015 mQueryCount(rhs.mQueryCount),
5016 mStatus(rhs.mStatus)
5017 {
5018 rhs.mDynamicQueryPool = nullptr;
5019 rhs.mQueryPoolIndex = 0;
5020 rhs.mQuery = 0;
5021 rhs.mQueryCount = 0;
5022 rhs.mStatus = QueryStatus::Inactive;
5023 }
5024
operator =(QueryHelper && rhs)5025 QueryHelper &QueryHelper::operator=(QueryHelper &&rhs)
5026 {
5027 Resource::operator=(std::move(rhs));
5028 std::swap(mDynamicQueryPool, rhs.mDynamicQueryPool);
5029 std::swap(mQueryPoolIndex, rhs.mQueryPoolIndex);
5030 std::swap(mQuery, rhs.mQuery);
5031 std::swap(mQueryCount, rhs.mQueryCount);
5032 std::swap(mStatus, rhs.mStatus);
5033 return *this;
5034 }
5035
init(const DynamicQueryPool * dynamicQueryPool,const size_t queryPoolIndex,uint32_t query,uint32_t queryCount)5036 void QueryHelper::init(const DynamicQueryPool *dynamicQueryPool,
5037 const size_t queryPoolIndex,
5038 uint32_t query,
5039 uint32_t queryCount)
5040 {
5041 mDynamicQueryPool = dynamicQueryPool;
5042 mQueryPoolIndex = queryPoolIndex;
5043 mQuery = query;
5044 mQueryCount = queryCount;
5045
5046 ASSERT(mQueryCount <= gl::IMPLEMENTATION_ANGLE_MULTIVIEW_MAX_VIEWS);
5047 }
5048
deinit()5049 void QueryHelper::deinit()
5050 {
5051 mDynamicQueryPool = nullptr;
5052 mQueryPoolIndex = 0;
5053 mQuery = 0;
5054 mQueryCount = 0;
5055 mUse.reset();
5056 mStatus = QueryStatus::Inactive;
5057 }
5058
5059 template <typename CommandBufferT>
beginQueryImpl(ContextVk * contextVk,OutsideRenderPassCommandBuffer * resetCommandBuffer,CommandBufferT * commandBuffer)5060 void QueryHelper::beginQueryImpl(ContextVk *contextVk,
5061 OutsideRenderPassCommandBuffer *resetCommandBuffer,
5062 CommandBufferT *commandBuffer)
5063 {
5064 ASSERT(mStatus != QueryStatus::Active);
5065 const QueryPool &queryPool = getQueryPool();
5066 resetQueryPoolImpl(contextVk, queryPool, resetCommandBuffer);
5067 commandBuffer->beginQuery(queryPool, mQuery, 0);
5068 mStatus = QueryStatus::Active;
5069 }
5070
5071 template <typename CommandBufferT>
endQueryImpl(ContextVk * contextVk,CommandBufferT * commandBuffer)5072 void QueryHelper::endQueryImpl(ContextVk *contextVk, CommandBufferT *commandBuffer)
5073 {
5074 ASSERT(mStatus != QueryStatus::Ended);
5075 commandBuffer->endQuery(getQueryPool(), mQuery);
5076 mStatus = QueryStatus::Ended;
5077 }
5078
beginQuery(ContextVk * contextVk)5079 angle::Result QueryHelper::beginQuery(ContextVk *contextVk)
5080 {
5081 if (contextVk->hasActiveRenderPass())
5082 {
5083 ANGLE_TRY(contextVk->flushCommandsAndEndRenderPass(
5084 RenderPassClosureReason::BeginNonRenderPassQuery));
5085 }
5086
5087 OutsideRenderPassCommandBuffer *commandBuffer;
5088 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer({}, &commandBuffer));
5089
5090 ANGLE_TRY(contextVk->handleGraphicsEventLog(rx::GraphicsEventCmdBuf::InOutsideCmdBufQueryCmd));
5091
5092 beginQueryImpl(contextVk, commandBuffer, commandBuffer);
5093
5094 return angle::Result::Continue;
5095 }
5096
endQuery(ContextVk * contextVk)5097 angle::Result QueryHelper::endQuery(ContextVk *contextVk)
5098 {
5099 if (contextVk->hasActiveRenderPass())
5100 {
5101 ANGLE_TRY(contextVk->flushCommandsAndEndRenderPass(
5102 RenderPassClosureReason::EndNonRenderPassQuery));
5103 }
5104
5105 CommandBufferAccess access;
5106 OutsideRenderPassCommandBuffer *commandBuffer;
5107 access.onQueryAccess(this);
5108 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
5109
5110 ANGLE_TRY(contextVk->handleGraphicsEventLog(rx::GraphicsEventCmdBuf::InOutsideCmdBufQueryCmd));
5111
5112 endQueryImpl(contextVk, commandBuffer);
5113
5114 return angle::Result::Continue;
5115 }
5116
5117 template <typename CommandBufferT>
resetQueryPoolImpl(ContextVk * contextVk,const QueryPool & queryPool,CommandBufferT * commandBuffer)5118 void QueryHelper::resetQueryPoolImpl(ContextVk *contextVk,
5119 const QueryPool &queryPool,
5120 CommandBufferT *commandBuffer)
5121 {
5122 Renderer *renderer = contextVk->getRenderer();
5123 if (renderer->getFeatures().supportsHostQueryReset.enabled)
5124 {
5125 vkResetQueryPoolEXT(contextVk->getDevice(), queryPool.getHandle(), mQuery, mQueryCount);
5126 }
5127 else
5128 {
5129 commandBuffer->resetQueryPool(queryPool, mQuery, mQueryCount);
5130 }
5131 }
5132
beginRenderPassQuery(ContextVk * contextVk)5133 angle::Result QueryHelper::beginRenderPassQuery(ContextVk *contextVk)
5134 {
5135 OutsideRenderPassCommandBuffer *outsideRenderPassCommandBuffer;
5136 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer({}, &outsideRenderPassCommandBuffer));
5137
5138 RenderPassCommandBuffer *renderPassCommandBuffer =
5139 &contextVk->getStartedRenderPassCommands().getCommandBuffer();
5140
5141 beginQueryImpl(contextVk, outsideRenderPassCommandBuffer, renderPassCommandBuffer);
5142
5143 return angle::Result::Continue;
5144 }
5145
endRenderPassQuery(ContextVk * contextVk)5146 void QueryHelper::endRenderPassQuery(ContextVk *contextVk)
5147 {
5148 if (mStatus == QueryStatus::Active)
5149 {
5150 endQueryImpl(contextVk, &contextVk->getStartedRenderPassCommands().getCommandBuffer());
5151 contextVk->getStartedRenderPassCommands().retainResource(this);
5152 }
5153 }
5154
flushAndWriteTimestamp(ContextVk * contextVk)5155 angle::Result QueryHelper::flushAndWriteTimestamp(ContextVk *contextVk)
5156 {
5157 if (contextVk->hasActiveRenderPass())
5158 {
5159 ANGLE_TRY(
5160 contextVk->flushCommandsAndEndRenderPass(RenderPassClosureReason::TimestampQuery));
5161 }
5162
5163 CommandBufferAccess access;
5164 OutsideRenderPassCommandBuffer *commandBuffer;
5165 access.onQueryAccess(this);
5166 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
5167 writeTimestamp(contextVk, commandBuffer);
5168 return angle::Result::Continue;
5169 }
5170
writeTimestampToPrimary(ContextVk * contextVk,PrimaryCommandBuffer * primary)5171 void QueryHelper::writeTimestampToPrimary(ContextVk *contextVk, PrimaryCommandBuffer *primary)
5172 {
5173 // Note that commands may not be flushed at this point.
5174
5175 const QueryPool &queryPool = getQueryPool();
5176 resetQueryPoolImpl(contextVk, queryPool, primary);
5177 primary->writeTimestamp(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, queryPool, mQuery);
5178 }
5179
writeTimestamp(ContextVk * contextVk,OutsideRenderPassCommandBuffer * commandBuffer)5180 void QueryHelper::writeTimestamp(ContextVk *contextVk,
5181 OutsideRenderPassCommandBuffer *commandBuffer)
5182 {
5183 const QueryPool &queryPool = getQueryPool();
5184 resetQueryPoolImpl(contextVk, queryPool, commandBuffer);
5185 commandBuffer->writeTimestamp(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, queryPool, mQuery);
5186 }
5187
hasSubmittedCommands() const5188 bool QueryHelper::hasSubmittedCommands() const
5189 {
5190 return mUse.valid();
5191 }
5192
getUint64ResultNonBlocking(ContextVk * contextVk,QueryResult * resultOut,bool * availableOut)5193 angle::Result QueryHelper::getUint64ResultNonBlocking(ContextVk *contextVk,
5194 QueryResult *resultOut,
5195 bool *availableOut)
5196 {
5197 ASSERT(valid());
5198 VkResult result;
5199
5200 // Ensure that we only wait if we have inserted a query in command buffer. Otherwise you will
5201 // wait forever and trigger GPU timeout.
5202 if (hasSubmittedCommands())
5203 {
5204 constexpr VkQueryResultFlags kFlags = VK_QUERY_RESULT_64_BIT;
5205 result = getResultImpl(contextVk, kFlags, resultOut);
5206 }
5207 else
5208 {
5209 result = VK_SUCCESS;
5210 *resultOut = 0;
5211 }
5212
5213 if (result == VK_NOT_READY)
5214 {
5215 *availableOut = false;
5216 return angle::Result::Continue;
5217 }
5218 else
5219 {
5220 ANGLE_VK_TRY(contextVk, result);
5221 *availableOut = true;
5222 }
5223 return angle::Result::Continue;
5224 }
5225
getUint64Result(ContextVk * contextVk,QueryResult * resultOut)5226 angle::Result QueryHelper::getUint64Result(ContextVk *contextVk, QueryResult *resultOut)
5227 {
5228 ASSERT(valid());
5229 if (hasSubmittedCommands())
5230 {
5231 constexpr VkQueryResultFlags kFlags = VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT;
5232 ANGLE_VK_TRY(contextVk, getResultImpl(contextVk, kFlags, resultOut));
5233 }
5234 else
5235 {
5236 *resultOut = 0;
5237 }
5238 return angle::Result::Continue;
5239 }
5240
getResultImpl(ContextVk * contextVk,const VkQueryResultFlags flags,QueryResult * resultOut)5241 VkResult QueryHelper::getResultImpl(ContextVk *contextVk,
5242 const VkQueryResultFlags flags,
5243 QueryResult *resultOut)
5244 {
5245 std::array<uint64_t, 2 * gl::IMPLEMENTATION_ANGLE_MULTIVIEW_MAX_VIEWS> results;
5246
5247 VkDevice device = contextVk->getDevice();
5248 VkResult result = getQueryPool().getResults(device, mQuery, mQueryCount, sizeof(results),
5249 results.data(), sizeof(uint64_t), flags);
5250
5251 if (result == VK_SUCCESS)
5252 {
5253 resultOut->setResults(results.data(), mQueryCount);
5254 }
5255
5256 return result;
5257 }
5258
5259 // SemaphoreHelper implementation
SemaphoreHelper()5260 SemaphoreHelper::SemaphoreHelper() : mSemaphorePoolIndex(0), mSemaphore(0) {}
5261
~SemaphoreHelper()5262 SemaphoreHelper::~SemaphoreHelper() {}
5263
SemaphoreHelper(SemaphoreHelper && other)5264 SemaphoreHelper::SemaphoreHelper(SemaphoreHelper &&other)
5265 : mSemaphorePoolIndex(other.mSemaphorePoolIndex), mSemaphore(other.mSemaphore)
5266 {
5267 other.mSemaphore = nullptr;
5268 }
5269
operator =(SemaphoreHelper && other)5270 SemaphoreHelper &SemaphoreHelper::operator=(SemaphoreHelper &&other)
5271 {
5272 std::swap(mSemaphorePoolIndex, other.mSemaphorePoolIndex);
5273 std::swap(mSemaphore, other.mSemaphore);
5274 return *this;
5275 }
5276
init(const size_t semaphorePoolIndex,const Semaphore * semaphore)5277 void SemaphoreHelper::init(const size_t semaphorePoolIndex, const Semaphore *semaphore)
5278 {
5279 mSemaphorePoolIndex = semaphorePoolIndex;
5280 mSemaphore = semaphore;
5281 }
5282
deinit()5283 void SemaphoreHelper::deinit()
5284 {
5285 mSemaphorePoolIndex = 0;
5286 mSemaphore = nullptr;
5287 }
5288
GetPipelineStage(gl::ShaderType stage)5289 PipelineStage GetPipelineStage(gl::ShaderType stage)
5290 {
5291 const PipelineStage pipelineStage = kPipelineStageShaderMap[stage];
5292 ASSERT(pipelineStage == PipelineStage::VertexShader ||
5293 pipelineStage == PipelineStage::TessellationControl ||
5294 pipelineStage == PipelineStage::TessellationEvaluation ||
5295 pipelineStage == PipelineStage::GeometryShader ||
5296 pipelineStage == PipelineStage::FragmentShader ||
5297 pipelineStage == PipelineStage::ComputeShader);
5298 return pipelineStage;
5299 }
5300
5301 // PipelineBarrier implementation.
addDiagnosticsString(std::ostringstream & out) const5302 void PipelineBarrier::addDiagnosticsString(std::ostringstream &out) const
5303 {
5304 if (mMemoryBarrierSrcAccess != 0 || mMemoryBarrierDstAccess != 0)
5305 {
5306 out << "Src: 0x" << std::hex << mMemoryBarrierSrcAccess << " → Dst: 0x" << std::hex
5307 << mMemoryBarrierDstAccess << std::endl;
5308 }
5309 }
5310
5311 // PipelineBarrierArray implementation.
execute(Renderer * renderer,PrimaryCommandBuffer * primary)5312 void PipelineBarrierArray::execute(Renderer *renderer, PrimaryCommandBuffer *primary)
5313 {
5314 // make a local copy for faster access
5315 PipelineStagesMask mask = mBarrierMask;
5316 if (mask.none())
5317 {
5318 return;
5319 }
5320
5321 if (renderer->getFeatures().preferAggregateBarrierCalls.enabled)
5322 {
5323 PipelineStagesMask::Iterator iter = mask.begin();
5324 PipelineBarrier &barrier = mBarriers[*iter];
5325 for (++iter; iter != mask.end(); ++iter)
5326 {
5327 barrier.merge(&mBarriers[*iter]);
5328 }
5329 barrier.execute(primary);
5330 }
5331 else
5332 {
5333 for (PipelineStage pipelineStage : mask)
5334 {
5335 PipelineBarrier &barrier = mBarriers[pipelineStage];
5336 barrier.execute(primary);
5337 }
5338 }
5339 mBarrierMask.reset();
5340 }
5341
addDiagnosticsString(std::ostringstream & out) const5342 void PipelineBarrierArray::addDiagnosticsString(std::ostringstream &out) const
5343 {
5344 out << "Memory Barrier: ";
5345 for (PipelineStage pipelineStage : mBarrierMask)
5346 {
5347 const PipelineBarrier &barrier = mBarriers[pipelineStage];
5348 if (!barrier.isEmpty())
5349 {
5350 barrier.addDiagnosticsString(out);
5351 }
5352 }
5353 out << "\\l";
5354 }
5355
5356 // BufferHelper implementation.
BufferHelper()5357 BufferHelper::BufferHelper()
5358 : mCurrentWriteAccess(0),
5359 mCurrentReadAccess(0),
5360 mCurrentWriteStages(0),
5361 mCurrentReadStages(0),
5362 mSerial(),
5363 mClientBuffer(nullptr),
5364 mIsReleasedToExternal(false)
5365 {}
5366
~BufferHelper()5367 BufferHelper::~BufferHelper()
5368 {
5369 // We must have released external buffer properly
5370 ASSERT(mClientBuffer == nullptr);
5371 }
5372
BufferHelper(BufferHelper && other)5373 BufferHelper::BufferHelper(BufferHelper &&other)
5374 {
5375 *this = std::move(other);
5376 }
5377
operator =(BufferHelper && other)5378 BufferHelper &BufferHelper::operator=(BufferHelper &&other)
5379 {
5380 ReadWriteResource::operator=(std::move(other));
5381
5382 mSuballocation = std::move(other.mSuballocation);
5383 mBufferWithUserSize = std::move(other.mBufferWithUserSize);
5384
5385 mCurrentDeviceQueueIndex = other.mCurrentDeviceQueueIndex;
5386 mIsReleasedToExternal = other.mIsReleasedToExternal;
5387 mCurrentWriteAccess = other.mCurrentWriteAccess;
5388 mCurrentReadAccess = other.mCurrentReadAccess;
5389 mCurrentWriteStages = other.mCurrentWriteStages;
5390 mCurrentReadStages = other.mCurrentReadStages;
5391 mSerial = other.mSerial;
5392 mClientBuffer = std::move(other.mClientBuffer);
5393
5394 return *this;
5395 }
5396
init(Context * context,const VkBufferCreateInfo & requestedCreateInfo,VkMemoryPropertyFlags memoryPropertyFlags)5397 angle::Result BufferHelper::init(Context *context,
5398 const VkBufferCreateInfo &requestedCreateInfo,
5399 VkMemoryPropertyFlags memoryPropertyFlags)
5400 {
5401 Renderer *renderer = context->getRenderer();
5402 const Allocator &allocator = renderer->getAllocator();
5403
5404 initializeBarrierTracker(context);
5405
5406 VkBufferCreateInfo modifiedCreateInfo;
5407 const VkBufferCreateInfo *createInfo = &requestedCreateInfo;
5408
5409 if (renderer->getFeatures().padBuffersToMaxVertexAttribStride.enabled)
5410 {
5411 const VkDeviceSize maxVertexAttribStride = renderer->getMaxVertexAttribStride();
5412 ASSERT(maxVertexAttribStride);
5413 modifiedCreateInfo = requestedCreateInfo;
5414 modifiedCreateInfo.size += maxVertexAttribStride;
5415 createInfo = &modifiedCreateInfo;
5416 }
5417
5418 VkMemoryPropertyFlags requiredFlags =
5419 (memoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
5420 VkMemoryPropertyFlags preferredFlags =
5421 (memoryPropertyFlags & (~VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT));
5422
5423 bool persistentlyMapped = renderer->getFeatures().persistentlyMappedBuffers.enabled;
5424
5425 // Check that the allocation is not too large.
5426 uint32_t memoryTypeIndex = kInvalidMemoryTypeIndex;
5427 ANGLE_VK_TRY(context, allocator.findMemoryTypeIndexForBufferInfo(
5428 *createInfo, requiredFlags, preferredFlags, persistentlyMapped,
5429 &memoryTypeIndex));
5430
5431 VkDeviceSize heapSize =
5432 renderer->getMemoryProperties().getHeapSizeForMemoryType(memoryTypeIndex);
5433
5434 ANGLE_VK_CHECK(context, createInfo->size <= heapSize, VK_ERROR_OUT_OF_DEVICE_MEMORY);
5435
5436 VkMemoryPropertyFlags memoryPropertyFlagsOut;
5437 allocator.getMemoryTypeProperties(memoryTypeIndex, &memoryPropertyFlagsOut);
5438 // Allocate buffer object
5439 DeviceScoped<Buffer> buffer(renderer->getDevice());
5440 ANGLE_VK_TRY(context, buffer.get().init(context->getDevice(), *createInfo));
5441
5442 DeviceScoped<DeviceMemory> deviceMemory(renderer->getDevice());
5443 VkDeviceSize sizeOut;
5444 uint32_t bufferMemoryTypeIndex;
5445 ANGLE_VK_TRY(context,
5446 AllocateBufferMemory(context, MemoryAllocationType::Buffer, memoryPropertyFlagsOut,
5447 &memoryPropertyFlagsOut, nullptr, &buffer.get(),
5448 &bufferMemoryTypeIndex, &deviceMemory.get(), &sizeOut));
5449 ASSERT(sizeOut >= createInfo->size);
5450
5451 mSuballocation.initWithEntireBuffer(context, buffer.get(), MemoryAllocationType::Buffer,
5452 bufferMemoryTypeIndex, deviceMemory.get(),
5453 memoryPropertyFlagsOut, requestedCreateInfo.size, sizeOut);
5454 if (isHostVisible())
5455 {
5456 uint8_t *ptrOut;
5457 ANGLE_TRY(map(context, &ptrOut));
5458 }
5459
5460 if (renderer->getFeatures().allocateNonZeroMemory.enabled)
5461 {
5462 ANGLE_TRY(initializeNonZeroMemory(context, createInfo->usage, createInfo->size));
5463 }
5464
5465 return angle::Result::Continue;
5466 }
5467
initExternal(Context * context,VkMemoryPropertyFlags memoryProperties,const VkBufferCreateInfo & requestedCreateInfo,GLeglClientBufferEXT clientBuffer)5468 angle::Result BufferHelper::initExternal(Context *context,
5469 VkMemoryPropertyFlags memoryProperties,
5470 const VkBufferCreateInfo &requestedCreateInfo,
5471 GLeglClientBufferEXT clientBuffer)
5472 {
5473 ASSERT(IsAndroid());
5474
5475 Renderer *renderer = context->getRenderer();
5476
5477 initializeBarrierTracker(context);
5478
5479 VkBufferCreateInfo modifiedCreateInfo = requestedCreateInfo;
5480 VkExternalMemoryBufferCreateInfo externCreateInfo = {};
5481 externCreateInfo.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO;
5482 externCreateInfo.handleTypes =
5483 VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
5484 externCreateInfo.pNext = nullptr;
5485 modifiedCreateInfo.pNext = &externCreateInfo;
5486
5487 DeviceScoped<Buffer> buffer(renderer->getDevice());
5488 ANGLE_VK_TRY(context, buffer.get().init(renderer->getDevice(), modifiedCreateInfo));
5489
5490 DeviceScoped<DeviceMemory> deviceMemory(renderer->getDevice());
5491 VkMemoryPropertyFlags memoryPropertyFlagsOut;
5492 VkDeviceSize allocatedSize = 0;
5493 uint32_t memoryTypeIndex;
5494 ANGLE_TRY(InitAndroidExternalMemory(context, clientBuffer, memoryProperties, &buffer.get(),
5495 &memoryPropertyFlagsOut, &memoryTypeIndex,
5496 &deviceMemory.get(), &allocatedSize));
5497 mClientBuffer = clientBuffer;
5498
5499 mSuballocation.initWithEntireBuffer(context, buffer.get(), MemoryAllocationType::BufferExternal,
5500 memoryTypeIndex, deviceMemory.get(), memoryPropertyFlagsOut,
5501 requestedCreateInfo.size, allocatedSize);
5502 if (isHostVisible())
5503 {
5504 uint8_t *ptrOut;
5505 ANGLE_TRY(map(context, &ptrOut));
5506 }
5507 return angle::Result::Continue;
5508 }
5509
initSuballocation(Context * context,uint32_t memoryTypeIndex,size_t size,size_t alignment,BufferUsageType usageType,BufferPool * pool)5510 VkResult BufferHelper::initSuballocation(Context *context,
5511 uint32_t memoryTypeIndex,
5512 size_t size,
5513 size_t alignment,
5514 BufferUsageType usageType,
5515 BufferPool *pool)
5516 {
5517 ASSERT(pool != nullptr);
5518 Renderer *renderer = context->getRenderer();
5519
5520 // We should reset these in case the BufferHelper object has been released and called
5521 // initSuballocation again.
5522 initializeBarrierTracker(context);
5523
5524 if (renderer->getFeatures().padBuffersToMaxVertexAttribStride.enabled)
5525 {
5526 const VkDeviceSize maxVertexAttribStride = renderer->getMaxVertexAttribStride();
5527 ASSERT(maxVertexAttribStride);
5528 size += maxVertexAttribStride;
5529 }
5530
5531 VK_RESULT_TRY(pool->allocateBuffer(context, size, alignment, &mSuballocation));
5532
5533 context->getPerfCounters().bufferSuballocationCalls++;
5534
5535 return VK_SUCCESS;
5536 }
5537
initializeBarrierTracker(Context * context)5538 void BufferHelper::initializeBarrierTracker(Context *context)
5539 {
5540 Renderer *renderer = context->getRenderer();
5541 mCurrentDeviceQueueIndex = context->getDeviceQueueIndex();
5542 mIsReleasedToExternal = false;
5543 mSerial = renderer->getResourceSerialFactory().generateBufferSerial();
5544 mCurrentWriteAccess = 0;
5545 mCurrentReadAccess = 0;
5546 mCurrentWriteStages = 0;
5547 mCurrentReadStages = 0;
5548 }
5549
initializeNonZeroMemory(Context * context,VkBufferUsageFlags usage,VkDeviceSize size)5550 angle::Result BufferHelper::initializeNonZeroMemory(Context *context,
5551 VkBufferUsageFlags usage,
5552 VkDeviceSize size)
5553 {
5554 Renderer *renderer = context->getRenderer();
5555
5556 // This memory can't be mapped, so the buffer must be marked as a transfer destination so we
5557 // can use a staging resource to initialize it to a non-zero value. If the memory is
5558 // mappable we do the initialization in AllocateBufferMemory.
5559 if (!isHostVisible() && (usage & VK_BUFFER_USAGE_TRANSFER_DST_BIT) != 0)
5560 {
5561 ASSERT((usage & VK_BUFFER_USAGE_TRANSFER_DST_BIT) != 0);
5562 // Staging buffer memory is non-zero-initialized in 'init'.
5563 StagingBuffer stagingBuffer;
5564 ANGLE_TRY(stagingBuffer.init(context, size, StagingUsage::Both));
5565
5566 PrimaryCommandBuffer commandBuffer;
5567 ANGLE_TRY(
5568 renderer->getCommandBufferOneOff(context, ProtectionType::Unprotected, &commandBuffer));
5569
5570 // Queue a DMA copy.
5571 VkBufferCopy copyRegion = {};
5572 copyRegion.srcOffset = 0;
5573 copyRegion.dstOffset = getOffset();
5574 copyRegion.size = size;
5575
5576 commandBuffer.copyBuffer(stagingBuffer.getBuffer(), getBuffer(), 1, ©Region);
5577
5578 ANGLE_VK_TRY(context, commandBuffer.end());
5579
5580 QueueSerial queueSerial;
5581 ANGLE_TRY(renderer->queueSubmitOneOff(context, std::move(commandBuffer),
5582 ProtectionType::Unprotected,
5583 egl::ContextPriority::Medium, VK_NULL_HANDLE, 0,
5584 vk::SubmitPolicy::AllowDeferred, &queueSerial));
5585
5586 stagingBuffer.collectGarbage(renderer, queueSerial);
5587 // Update both ResourceUse objects, since mReadOnlyUse tracks when the buffer can be
5588 // destroyed, and mReadWriteUse tracks when the write has completed.
5589 setWriteQueueSerial(queueSerial);
5590 }
5591 else if (isHostVisible())
5592 {
5593 // Can map the memory.
5594 // Pick an arbitrary value to initialize non-zero memory for sanitization.
5595 constexpr int kNonZeroInitValue = 55;
5596 uint8_t *mapPointer = mSuballocation.getMappedMemory();
5597 memset(mapPointer, kNonZeroInitValue, static_cast<size_t>(getSize()));
5598 if (!isCoherent())
5599 {
5600 mSuballocation.flush(renderer->getDevice());
5601 }
5602 }
5603
5604 return angle::Result::Continue;
5605 }
5606
getBufferForVertexArray(ContextVk * contextVk,VkDeviceSize actualDataSize,VkDeviceSize * offsetOut)5607 const Buffer &BufferHelper::getBufferForVertexArray(ContextVk *contextVk,
5608 VkDeviceSize actualDataSize,
5609 VkDeviceSize *offsetOut)
5610 {
5611 ASSERT(mSuballocation.valid());
5612 ASSERT(actualDataSize <= mSuballocation.getSize());
5613
5614 if (!contextVk->hasRobustAccess() || !mSuballocation.isSuballocated() ||
5615 actualDataSize == mSuballocation.getSize())
5616 {
5617 *offsetOut = mSuballocation.getOffset();
5618 return mSuballocation.getBuffer();
5619 }
5620
5621 if (!mBufferWithUserSize.valid())
5622 {
5623 // Allocate buffer that is backed by sub-range of the memory for vertex array usage. This is
5624 // only needed when robust resource init is enabled so that vulkan driver will know the
5625 // exact size of the vertex buffer it is supposedly to use and prevent out of bound access.
5626 VkBufferCreateInfo createInfo = {};
5627 createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
5628 createInfo.flags = 0;
5629 createInfo.size = actualDataSize;
5630 createInfo.usage = kVertexBufferUsageFlags | kIndexBufferUsageFlags;
5631 createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
5632 createInfo.queueFamilyIndexCount = 0;
5633 createInfo.pQueueFamilyIndices = nullptr;
5634 mBufferWithUserSize.init(contextVk->getDevice(), createInfo);
5635
5636 VkMemoryRequirements memoryRequirements;
5637 mBufferWithUserSize.getMemoryRequirements(contextVk->getDevice(), &memoryRequirements);
5638 ASSERT(contextVk->getRenderer()->isMockICDEnabled() ||
5639 mSuballocation.getSize() >= memoryRequirements.size);
5640 ASSERT(!contextVk->getRenderer()->isMockICDEnabled() ||
5641 mSuballocation.getOffset() % memoryRequirements.alignment == 0);
5642
5643 mBufferWithUserSize.bindMemory(contextVk->getDevice(), mSuballocation.getDeviceMemory(),
5644 mSuballocation.getOffset());
5645 }
5646 *offsetOut = 0;
5647 return mBufferWithUserSize;
5648 }
5649
onBufferUserSizeChange(Renderer * renderer)5650 bool BufferHelper::onBufferUserSizeChange(Renderer *renderer)
5651 {
5652 // Buffer's user size and allocation size may be different due to alignment requirement. In
5653 // normal usage we just use the actual allocation size and it is good enough. But when
5654 // robustResourceInit is enabled, mBufferWithUserSize is created to mjatch the exact user
5655 // size. Thus when user size changes, we must clear and recreate this mBufferWithUserSize.
5656 if (mBufferWithUserSize.valid())
5657 {
5658 BufferSuballocation unusedSuballocation;
5659 renderer->collectSuballocationGarbage(mUse, std::move(unusedSuballocation),
5660 std::move(mBufferWithUserSize));
5661 mSerial = renderer->getResourceSerialFactory().generateBufferSerial();
5662 return true;
5663 }
5664 return false;
5665 }
5666
destroy(Renderer * renderer)5667 void BufferHelper::destroy(Renderer *renderer)
5668 {
5669 mDescriptorSetCacheManager.destroyKeys(renderer);
5670 unmap(renderer);
5671 mBufferWithUserSize.destroy(renderer->getDevice());
5672 mSuballocation.destroy(renderer);
5673 if (mClientBuffer != nullptr)
5674 {
5675 ReleaseAndroidExternalMemory(renderer, mClientBuffer);
5676 mClientBuffer = nullptr;
5677 }
5678 }
5679
release(Renderer * renderer)5680 void BufferHelper::release(Renderer *renderer)
5681 {
5682 ASSERT(mDescriptorSetCacheManager.empty());
5683 unmap(renderer);
5684
5685 if (mSuballocation.valid())
5686 {
5687 if (!mSuballocation.isSuballocated())
5688 {
5689 // Destroy cacheKeys now to avoid getting into situation that having to destroy
5690 // descriptorSet from garbage collection thread.
5691 mSuballocation.getBufferBlock()->releaseAllCachedDescriptorSetCacheKeys(renderer);
5692 }
5693 renderer->collectSuballocationGarbage(mUse, std::move(mSuballocation),
5694 std::move(mBufferWithUserSize));
5695 }
5696 mUse.reset();
5697 mWriteUse.reset();
5698 ASSERT(!mBufferWithUserSize.valid());
5699
5700 if (mClientBuffer != nullptr)
5701 {
5702 ReleaseAndroidExternalMemory(renderer, mClientBuffer);
5703 mClientBuffer = nullptr;
5704 }
5705 }
5706
releaseBufferAndDescriptorSetCache(Renderer * renderer)5707 void BufferHelper::releaseBufferAndDescriptorSetCache(Renderer *renderer)
5708 {
5709 if (renderer->hasResourceUseFinished(getResourceUse()))
5710 {
5711 mDescriptorSetCacheManager.destroyKeys(renderer);
5712 }
5713 else
5714 {
5715 mDescriptorSetCacheManager.releaseKeys(renderer);
5716 }
5717
5718 release(renderer);
5719 }
5720
map(Context * context,uint8_t ** ptrOut)5721 angle::Result BufferHelper::map(Context *context, uint8_t **ptrOut)
5722 {
5723 if (!mSuballocation.isMapped())
5724 {
5725 ANGLE_VK_TRY(context, mSuballocation.map(context));
5726 }
5727 *ptrOut = mSuballocation.getMappedMemory();
5728 return angle::Result::Continue;
5729 }
5730
mapWithOffset(Context * context,uint8_t ** ptrOut,size_t offset)5731 angle::Result BufferHelper::mapWithOffset(Context *context, uint8_t **ptrOut, size_t offset)
5732 {
5733 uint8_t *mapBufPointer;
5734 ANGLE_TRY(map(context, &mapBufPointer));
5735 *ptrOut = mapBufPointer + offset;
5736 return angle::Result::Continue;
5737 }
5738
flush(Renderer * renderer,VkDeviceSize offset,VkDeviceSize size)5739 angle::Result BufferHelper::flush(Renderer *renderer, VkDeviceSize offset, VkDeviceSize size)
5740 {
5741 mSuballocation.flush(renderer->getDevice());
5742 return angle::Result::Continue;
5743 }
flush(Renderer * renderer)5744 angle::Result BufferHelper::flush(Renderer *renderer)
5745 {
5746 return flush(renderer, 0, getSize());
5747 }
5748
invalidate(Renderer * renderer,VkDeviceSize offset,VkDeviceSize size)5749 angle::Result BufferHelper::invalidate(Renderer *renderer, VkDeviceSize offset, VkDeviceSize size)
5750 {
5751 mSuballocation.invalidate(renderer->getDevice());
5752 return angle::Result::Continue;
5753 }
invalidate(Renderer * renderer)5754 angle::Result BufferHelper::invalidate(Renderer *renderer)
5755 {
5756 return invalidate(renderer, 0, getSize());
5757 }
5758
changeQueueFamily(uint32_t srcQueueFamilyIndex,uint32_t dstQueueFamilyIndex,OutsideRenderPassCommandBuffer * commandBuffer)5759 void BufferHelper::changeQueueFamily(uint32_t srcQueueFamilyIndex,
5760 uint32_t dstQueueFamilyIndex,
5761 OutsideRenderPassCommandBuffer *commandBuffer)
5762 {
5763 VkBufferMemoryBarrier bufferMemoryBarrier = {};
5764 bufferMemoryBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
5765 bufferMemoryBarrier.srcAccessMask = 0;
5766 bufferMemoryBarrier.dstAccessMask = 0;
5767 bufferMemoryBarrier.srcQueueFamilyIndex = srcQueueFamilyIndex;
5768 bufferMemoryBarrier.dstQueueFamilyIndex = dstQueueFamilyIndex;
5769 bufferMemoryBarrier.buffer = getBuffer().getHandle();
5770 bufferMemoryBarrier.offset = getOffset();
5771 bufferMemoryBarrier.size = getSize();
5772
5773 commandBuffer->bufferBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
5774 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, &bufferMemoryBarrier);
5775 }
5776
acquireFromExternal(DeviceQueueIndex externalQueueFamilyIndex,DeviceQueueIndex newDeviceQueueIndex,OutsideRenderPassCommandBuffer * commandBuffer)5777 void BufferHelper::acquireFromExternal(DeviceQueueIndex externalQueueFamilyIndex,
5778 DeviceQueueIndex newDeviceQueueIndex,
5779 OutsideRenderPassCommandBuffer *commandBuffer)
5780 {
5781 changeQueueFamily(externalQueueFamilyIndex.familyIndex(), newDeviceQueueIndex.familyIndex(),
5782 commandBuffer);
5783 mCurrentDeviceQueueIndex = newDeviceQueueIndex;
5784 mIsReleasedToExternal = false;
5785 }
5786
releaseToExternal(DeviceQueueIndex externalQueueIndex,OutsideRenderPassCommandBuffer * commandBuffer)5787 void BufferHelper::releaseToExternal(DeviceQueueIndex externalQueueIndex,
5788 OutsideRenderPassCommandBuffer *commandBuffer)
5789 {
5790 if (mCurrentDeviceQueueIndex.familyIndex() != externalQueueIndex.familyIndex())
5791 {
5792 changeQueueFamily(mCurrentDeviceQueueIndex.familyIndex(), externalQueueIndex.familyIndex(),
5793 commandBuffer);
5794 mCurrentDeviceQueueIndex = kInvalidDeviceQueueIndex;
5795 }
5796 mIsReleasedToExternal = true;
5797 }
5798
isReleasedToExternal() const5799 bool BufferHelper::isReleasedToExternal() const
5800 {
5801 return mIsReleasedToExternal;
5802 }
5803
recordReadBarrier(VkAccessFlags readAccessType,VkPipelineStageFlags readStage,PipelineStage stageIndex,PipelineBarrierArray * barriers)5804 void BufferHelper::recordReadBarrier(VkAccessFlags readAccessType,
5805 VkPipelineStageFlags readStage,
5806 PipelineStage stageIndex,
5807 PipelineBarrierArray *barriers)
5808 {
5809 // If there was a prior write and we are making a read that is either a new access type or from
5810 // a new stage, we need a barrier
5811 if (mCurrentWriteAccess != 0 && (((mCurrentReadAccess & readAccessType) != readAccessType) ||
5812 ((mCurrentReadStages & readStage) != readStage)))
5813 {
5814 barriers->mergeMemoryBarrier(stageIndex, mCurrentWriteStages, readStage,
5815 mCurrentWriteAccess, readAccessType);
5816 }
5817
5818 // Accumulate new read usage.
5819 mCurrentReadAccess |= readAccessType;
5820 mCurrentReadStages |= readStage;
5821 }
5822
recordWriteBarrier(VkAccessFlags writeAccessType,VkPipelineStageFlags writeStage,PipelineStage stageIndex,PipelineBarrierArray * barriers)5823 void BufferHelper::recordWriteBarrier(VkAccessFlags writeAccessType,
5824 VkPipelineStageFlags writeStage,
5825 PipelineStage stageIndex,
5826 PipelineBarrierArray *barriers)
5827 {
5828 // We don't need to check mCurrentReadStages here since if it is not zero, mCurrentReadAccess
5829 // must not be zero as well. stage is finer grain than accessType.
5830 ASSERT((!mCurrentReadStages && !mCurrentReadAccess) ||
5831 (mCurrentReadStages && mCurrentReadAccess));
5832 if (mCurrentReadAccess != 0 || mCurrentWriteAccess != 0)
5833 {
5834 VkPipelineStageFlags srcStageMask = mCurrentWriteStages | mCurrentReadStages;
5835 barriers->mergeMemoryBarrier(stageIndex, srcStageMask, writeStage, mCurrentWriteAccess,
5836 writeAccessType);
5837 }
5838
5839 // Reset usages on the new write.
5840 mCurrentWriteAccess = writeAccessType;
5841 mCurrentReadAccess = 0;
5842 mCurrentWriteStages = writeStage;
5843 mCurrentReadStages = 0;
5844 }
5845
fillWithColor(const angle::Color<uint8_t> & color,const gl::InternalFormat & internalFormat)5846 void BufferHelper::fillWithColor(const angle::Color<uint8_t> &color,
5847 const gl::InternalFormat &internalFormat)
5848 {
5849 uint32_t count =
5850 static_cast<uint32_t>(getSize()) / static_cast<uint32_t>(internalFormat.pixelBytes);
5851 void *buffer = static_cast<void *>(getMappedMemory());
5852
5853 switch (internalFormat.internalFormat)
5854 {
5855 case GL_RGB565:
5856 {
5857 uint16_t pixelColor =
5858 ((color.blue & 0xF8) << 11) | ((color.green & 0xFC) << 5) | (color.red & 0xF8);
5859 uint16_t *pixelPtr = static_cast<uint16_t *>(buffer);
5860 std::fill_n<uint16_t *, uint32_t, uint16_t>(pixelPtr, count, pixelColor);
5861 }
5862 break;
5863 case GL_RGBA8:
5864 {
5865 uint32_t pixelColor =
5866 (color.alpha << 24) | (color.blue << 16) | (color.green << 8) | (color.red);
5867 uint32_t *pixelPtr = static_cast<uint32_t *>(buffer);
5868 std::fill_n<uint32_t *, uint32_t, uint32_t>(pixelPtr, count, pixelColor);
5869 }
5870 break;
5871 case GL_BGR565_ANGLEX:
5872 {
5873 uint16_t pixelColor =
5874 ((color.red & 0xF8) << 11) | ((color.green & 0xFC) << 5) | (color.blue & 0xF8);
5875 uint16_t *pixelPtr = static_cast<uint16_t *>(buffer);
5876 std::fill_n<uint16_t *, uint32_t, uint16_t>(pixelPtr, count, pixelColor);
5877 }
5878 break;
5879 case GL_BGRA8_EXT:
5880 {
5881 uint32_t pixelColor =
5882 (color.alpha << 24) | (color.red << 16) | (color.green << 8) | (color.blue);
5883 uint32_t *pixelPtr = static_cast<uint32_t *>(buffer);
5884 std::fill_n<uint32_t *, uint32_t, uint32_t>(pixelPtr, count, pixelColor);
5885 }
5886 break;
5887 default:
5888 UNREACHABLE(); // Unsupported format
5889 }
5890 }
5891
fillWithPattern(const void * pattern,size_t patternSize,size_t offset,size_t size)5892 void BufferHelper::fillWithPattern(const void *pattern,
5893 size_t patternSize,
5894 size_t offset,
5895 size_t size)
5896 {
5897 ASSERT(offset + size <= getSize());
5898 ASSERT((size % patternSize) == 0);
5899 ASSERT((offset % patternSize) == 0);
5900
5901 uint8_t *buffer = getMappedMemory() + offset;
5902 std::memcpy(buffer, pattern, patternSize);
5903 size_t remaining = size - patternSize;
5904 while (remaining > patternSize)
5905 {
5906 std::memcpy(buffer + patternSize, buffer, patternSize);
5907 remaining -= patternSize;
5908 patternSize *= 2;
5909 }
5910 std::memcpy(buffer + patternSize, buffer, remaining);
5911 return;
5912 }
5913
5914 // Used for ImageHelper non-zero memory allocation when useVmaForImageSuballocation is disabled.
InitMappableDeviceMemory(Context * context,DeviceMemory * deviceMemory,VkDeviceSize size,int value,VkMemoryPropertyFlags memoryPropertyFlags)5915 angle::Result InitMappableDeviceMemory(Context *context,
5916 DeviceMemory *deviceMemory,
5917 VkDeviceSize size,
5918 int value,
5919 VkMemoryPropertyFlags memoryPropertyFlags)
5920 {
5921 ASSERT(!context->getFeatures().useVmaForImageSuballocation.enabled);
5922 VkDevice device = context->getDevice();
5923
5924 uint8_t *mapPointer;
5925 ANGLE_VK_TRY(context, deviceMemory->map(device, 0, VK_WHOLE_SIZE, 0, &mapPointer));
5926 memset(mapPointer, value, static_cast<size_t>(size));
5927
5928 // if the memory type is not host coherent, we perform an explicit flush.
5929 if ((memoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) == 0)
5930 {
5931 VkMappedMemoryRange mappedRange = {};
5932 mappedRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
5933 mappedRange.memory = deviceMemory->getHandle();
5934 mappedRange.size = VK_WHOLE_SIZE;
5935 ANGLE_VK_TRY(context, vkFlushMappedMemoryRanges(device, 1, &mappedRange));
5936 }
5937
5938 deviceMemory->unmap(device);
5939
5940 return angle::Result::Continue;
5941 }
5942
5943 // ImageHelper implementation.
ImageHelper()5944 ImageHelper::ImageHelper()
5945 {
5946 resetCachedProperties();
5947 }
5948
~ImageHelper()5949 ImageHelper::~ImageHelper()
5950 {
5951 ASSERT(!valid());
5952 ASSERT(!mAcquireNextImageSemaphore.valid());
5953 }
5954
resetCachedProperties()5955 void ImageHelper::resetCachedProperties()
5956 {
5957 mImageType = VK_IMAGE_TYPE_2D;
5958 mTilingMode = VK_IMAGE_TILING_OPTIMAL;
5959 mCreateFlags = kVkImageCreateFlagsNone;
5960 mUsage = 0;
5961 mExtents = {};
5962 mRotatedAspectRatio = false;
5963 mIntendedFormatID = angle::FormatID::NONE;
5964 mActualFormatID = angle::FormatID::NONE;
5965 mSamples = 1;
5966 mImageSerial = kInvalidImageSerial;
5967 mCurrentLayout = ImageLayout::Undefined;
5968 mCurrentDeviceQueueIndex = kInvalidDeviceQueueIndex;
5969 mIsReleasedToExternal = false;
5970 mLastNonShaderReadOnlyLayout = ImageLayout::Undefined;
5971 mCurrentShaderReadStageMask = 0;
5972 mFirstAllocatedLevel = gl::LevelIndex(0);
5973 mLayerCount = 0;
5974 mLevelCount = 0;
5975 mTotalStagedBufferUpdateSize = 0;
5976 mAllocationSize = 0;
5977 mMemoryAllocationType = MemoryAllocationType::InvalidEnum;
5978 mMemoryTypeIndex = kInvalidMemoryTypeIndex;
5979 std::fill(mViewFormats.begin(), mViewFormats.begin() + mViewFormats.max_size(),
5980 VK_FORMAT_UNDEFINED);
5981 mYcbcrConversionDesc.reset();
5982 mCurrentSingleClearValue.reset();
5983 mRenderPassUsageFlags.reset();
5984
5985 setEntireContentUndefined();
5986 }
5987
setEntireContentDefined()5988 void ImageHelper::setEntireContentDefined()
5989 {
5990 for (LevelContentDefinedMask &levelContentDefined : mContentDefined)
5991 {
5992 levelContentDefined.set();
5993 }
5994 for (LevelContentDefinedMask &levelContentDefined : mStencilContentDefined)
5995 {
5996 levelContentDefined.set();
5997 }
5998 }
5999
setEntireContentUndefined()6000 void ImageHelper::setEntireContentUndefined()
6001 {
6002 for (LevelContentDefinedMask &levelContentDefined : mContentDefined)
6003 {
6004 levelContentDefined.reset();
6005 }
6006 for (LevelContentDefinedMask &levelContentDefined : mStencilContentDefined)
6007 {
6008 levelContentDefined.reset();
6009 }
6010
6011 // Note: this function is typically called during init/release, but also when importing an image
6012 // from Vulkan, so unlike invalidateSubresourceContentImpl, it doesn't attempt to make sure
6013 // emulated formats have a clear staged.
6014 }
6015
setContentDefined(LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags)6016 void ImageHelper::setContentDefined(LevelIndex levelStart,
6017 uint32_t levelCount,
6018 uint32_t layerStart,
6019 uint32_t layerCount,
6020 VkImageAspectFlags aspectFlags)
6021 {
6022 // Mark the range as defined. Layers above 8 are discarded, and are always assumed to have
6023 // defined contents.
6024 if (layerStart >= kMaxContentDefinedLayerCount)
6025 {
6026 return;
6027 }
6028
6029 uint8_t layerRangeBits =
6030 GetContentDefinedLayerRangeBits(layerStart, layerCount, kMaxContentDefinedLayerCount);
6031
6032 for (uint32_t levelOffset = 0; levelOffset < levelCount; ++levelOffset)
6033 {
6034 LevelIndex level = levelStart + levelOffset;
6035
6036 if ((aspectFlags & ~VK_IMAGE_ASPECT_STENCIL_BIT) != 0)
6037 {
6038 getLevelContentDefined(level) |= layerRangeBits;
6039 }
6040 if ((aspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) != 0)
6041 {
6042 getLevelStencilContentDefined(level) |= layerRangeBits;
6043 }
6044 }
6045 }
6046
getLevelContentDefined(LevelIndex level)6047 ImageHelper::LevelContentDefinedMask &ImageHelper::getLevelContentDefined(LevelIndex level)
6048 {
6049 return mContentDefined[level.get()];
6050 }
6051
getLevelStencilContentDefined(LevelIndex level)6052 ImageHelper::LevelContentDefinedMask &ImageHelper::getLevelStencilContentDefined(LevelIndex level)
6053 {
6054 return mStencilContentDefined[level.get()];
6055 }
6056
getLevelContentDefined(LevelIndex level) const6057 const ImageHelper::LevelContentDefinedMask &ImageHelper::getLevelContentDefined(
6058 LevelIndex level) const
6059 {
6060 return mContentDefined[level.get()];
6061 }
6062
getLevelStencilContentDefined(LevelIndex level) const6063 const ImageHelper::LevelContentDefinedMask &ImageHelper::getLevelStencilContentDefined(
6064 LevelIndex level) const
6065 {
6066 return mStencilContentDefined[level.get()];
6067 }
6068
deriveConversionDesc(Context * context,angle::FormatID actualFormatID,angle::FormatID intendedFormatID)6069 YcbcrConversionDesc ImageHelper::deriveConversionDesc(Context *context,
6070 angle::FormatID actualFormatID,
6071 angle::FormatID intendedFormatID)
6072 {
6073 YcbcrConversionDesc conversionDesc{};
6074 const angle::Format &actualFormat = angle::Format::Get(actualFormatID);
6075
6076 if (actualFormat.isYUV)
6077 {
6078 // Build a suitable conversionDesc; the image is not external but may be YUV
6079 // if app is using ANGLE's YUV internalformat extensions.
6080 Renderer *renderer = context->getRenderer();
6081
6082 // The Vulkan spec states: The potential format features of the sampler YCBCR conversion
6083 // must support VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT or
6084 // VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT
6085 constexpr VkFormatFeatureFlags kChromaSubSampleFeatureBits =
6086 VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT |
6087 VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT |
6088 VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT;
6089
6090 VkFormatFeatureFlags supportedFeatureBits =
6091 renderer->getImageFormatFeatureBits(actualFormatID, kChromaSubSampleFeatureBits);
6092
6093 VkChromaLocation supportedLocation =
6094 (supportedFeatureBits & VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT) != 0
6095 ? VK_CHROMA_LOCATION_COSITED_EVEN
6096 : VK_CHROMA_LOCATION_MIDPOINT;
6097 vk::YcbcrLinearFilterSupport linearFilterSupported =
6098 (supportedFeatureBits &
6099 VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT) != 0
6100 ? vk::YcbcrLinearFilterSupport::Supported
6101 : vk::YcbcrLinearFilterSupport::Unsupported;
6102
6103 VkSamplerYcbcrModelConversion conversionModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601;
6104 VkSamplerYcbcrRange colorRange = VK_SAMPLER_YCBCR_RANGE_ITU_NARROW;
6105 VkFilter chromaFilter = kDefaultYCbCrChromaFilter;
6106 VkComponentMapping components = {
6107 VK_COMPONENT_SWIZZLE_IDENTITY,
6108 VK_COMPONENT_SWIZZLE_IDENTITY,
6109 VK_COMPONENT_SWIZZLE_IDENTITY,
6110 VK_COMPONENT_SWIZZLE_IDENTITY,
6111 };
6112
6113 conversionDesc.update(renderer, 0, conversionModel, colorRange, supportedLocation,
6114 supportedLocation, chromaFilter, components, intendedFormatID,
6115 linearFilterSupported);
6116 }
6117
6118 return conversionDesc;
6119 }
6120
init(Context * context,gl::TextureType textureType,const VkExtent3D & extents,const Format & format,GLint samples,VkImageUsageFlags usage,gl::LevelIndex firstLevel,uint32_t mipLevels,uint32_t layerCount,bool isRobustResourceInitEnabled,bool hasProtectedContent)6121 angle::Result ImageHelper::init(Context *context,
6122 gl::TextureType textureType,
6123 const VkExtent3D &extents,
6124 const Format &format,
6125 GLint samples,
6126 VkImageUsageFlags usage,
6127 gl::LevelIndex firstLevel,
6128 uint32_t mipLevels,
6129 uint32_t layerCount,
6130 bool isRobustResourceInitEnabled,
6131 bool hasProtectedContent)
6132 {
6133 return initExternal(context, textureType, extents, format.getIntendedFormatID(),
6134 format.getActualRenderableImageFormatID(), samples, usage,
6135 kVkImageCreateFlagsNone, ImageLayout::Undefined, nullptr, firstLevel,
6136 mipLevels, layerCount, isRobustResourceInitEnabled, hasProtectedContent,
6137 deriveConversionDesc(context, format.getActualRenderableImageFormatID(),
6138 format.getIntendedFormatID()),
6139 nullptr);
6140 }
6141
initFromCreateInfo(Context * context,const VkImageCreateInfo & requestedCreateInfo,VkMemoryPropertyFlags memoryPropertyFlags)6142 angle::Result ImageHelper::initFromCreateInfo(Context *context,
6143 const VkImageCreateInfo &requestedCreateInfo,
6144 VkMemoryPropertyFlags memoryPropertyFlags)
6145 {
6146 ASSERT(!valid());
6147 ASSERT(!IsAnySubresourceContentDefined(mContentDefined));
6148 ASSERT(!IsAnySubresourceContentDefined(mStencilContentDefined));
6149
6150 mImageType = requestedCreateInfo.imageType;
6151 mExtents = requestedCreateInfo.extent;
6152 mRotatedAspectRatio = false;
6153 mSamples = std::max((int)requestedCreateInfo.samples, 1);
6154 mImageSerial = context->getRenderer()->getResourceSerialFactory().generateImageSerial();
6155 mLayerCount = requestedCreateInfo.arrayLayers;
6156 mLevelCount = requestedCreateInfo.mipLevels;
6157 mUsage = requestedCreateInfo.usage;
6158
6159 // Validate that mLayerCount is compatible with the image type
6160 ASSERT(requestedCreateInfo.imageType != VK_IMAGE_TYPE_3D || mLayerCount == 1);
6161 ASSERT(requestedCreateInfo.imageType != VK_IMAGE_TYPE_2D || mExtents.depth == 1);
6162
6163 mCurrentLayout = ImageLayout::Undefined;
6164
6165 ANGLE_VK_TRY(context, mImage.init(context->getDevice(), requestedCreateInfo));
6166
6167 mVkImageCreateInfo = requestedCreateInfo;
6168 mVkImageCreateInfo.pNext = nullptr;
6169 mVkImageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
6170
6171 MemoryProperties memoryProperties = {};
6172
6173 ANGLE_TRY(initMemoryAndNonZeroFillIfNeeded(context, false, memoryProperties,
6174 memoryPropertyFlags,
6175 vk::MemoryAllocationType::StagingImage));
6176 return angle::Result::Continue;
6177 }
6178
copyToBufferOneOff(Context * context,BufferHelper * stagingBuffer,VkBufferImageCopy copyRegion)6179 angle::Result ImageHelper::copyToBufferOneOff(Context *context,
6180 BufferHelper *stagingBuffer,
6181 VkBufferImageCopy copyRegion)
6182 {
6183 Renderer *renderer = context->getRenderer();
6184 PrimaryCommandBuffer commandBuffer;
6185 ANGLE_TRY(
6186 renderer->getCommandBufferOneOff(context, ProtectionType::Unprotected, &commandBuffer));
6187
6188 VkSemaphore acquireNextImageSemaphore;
6189 barrierImpl(context, getAspectFlags(), ImageLayout::TransferDst,
6190 renderer->getQueueFamilyIndex(), nullptr, &commandBuffer,
6191 &acquireNextImageSemaphore);
6192 commandBuffer.copyBufferToImage(stagingBuffer->getBuffer().getHandle(), getImage(),
6193 getCurrentLayout(renderer), 1, ©Region);
6194 ANGLE_VK_TRY(context, commandBuffer.end());
6195
6196 QueueSerial submitQueueSerial;
6197 ANGLE_TRY(renderer->queueSubmitOneOff(
6198 context, std::move(commandBuffer), ProtectionType::Unprotected,
6199 egl::ContextPriority::Medium, acquireNextImageSemaphore,
6200 kSwapchainAcquireImageWaitStageFlags, SubmitPolicy::AllowDeferred, &submitQueueSerial));
6201
6202 return renderer->finishQueueSerial(context, submitQueueSerial);
6203 }
6204
initMSAASwapchain(Context * context,gl::TextureType textureType,const VkExtent3D & extents,bool rotatedAspectRatio,const Format & format,GLint samples,VkImageUsageFlags usage,gl::LevelIndex firstLevel,uint32_t mipLevels,uint32_t layerCount,bool isRobustResourceInitEnabled,bool hasProtectedContent)6205 angle::Result ImageHelper::initMSAASwapchain(Context *context,
6206 gl::TextureType textureType,
6207 const VkExtent3D &extents,
6208 bool rotatedAspectRatio,
6209 const Format &format,
6210 GLint samples,
6211 VkImageUsageFlags usage,
6212 gl::LevelIndex firstLevel,
6213 uint32_t mipLevels,
6214 uint32_t layerCount,
6215 bool isRobustResourceInitEnabled,
6216 bool hasProtectedContent)
6217 {
6218 ANGLE_TRY(initExternal(context, textureType, extents, format.getIntendedFormatID(),
6219 format.getActualRenderableImageFormatID(), samples, usage,
6220 kVkImageCreateFlagsNone, ImageLayout::Undefined, nullptr, firstLevel,
6221 mipLevels, layerCount, isRobustResourceInitEnabled, hasProtectedContent,
6222 YcbcrConversionDesc{}, nullptr));
6223 if (rotatedAspectRatio)
6224 {
6225 std::swap(mExtents.width, mExtents.height);
6226 }
6227 mRotatedAspectRatio = rotatedAspectRatio;
6228 return angle::Result::Continue;
6229 }
6230
initExternal(Context * context,gl::TextureType textureType,const VkExtent3D & extents,angle::FormatID intendedFormatID,angle::FormatID actualFormatID,GLint samples,VkImageUsageFlags usage,VkImageCreateFlags additionalCreateFlags,ImageLayout initialLayout,const void * externalImageCreateInfo,gl::LevelIndex firstLevel,uint32_t mipLevels,uint32_t layerCount,bool isRobustResourceInitEnabled,bool hasProtectedContent,YcbcrConversionDesc conversionDesc,const void * compressionControl)6231 angle::Result ImageHelper::initExternal(Context *context,
6232 gl::TextureType textureType,
6233 const VkExtent3D &extents,
6234 angle::FormatID intendedFormatID,
6235 angle::FormatID actualFormatID,
6236 GLint samples,
6237 VkImageUsageFlags usage,
6238 VkImageCreateFlags additionalCreateFlags,
6239 ImageLayout initialLayout,
6240 const void *externalImageCreateInfo,
6241 gl::LevelIndex firstLevel,
6242 uint32_t mipLevels,
6243 uint32_t layerCount,
6244 bool isRobustResourceInitEnabled,
6245 bool hasProtectedContent,
6246 YcbcrConversionDesc conversionDesc,
6247 const void *compressionControl)
6248 {
6249 ASSERT(!valid());
6250 ASSERT(!IsAnySubresourceContentDefined(mContentDefined));
6251 ASSERT(!IsAnySubresourceContentDefined(mStencilContentDefined));
6252
6253 Renderer *renderer = context->getRenderer();
6254
6255 mImageType = gl_vk::GetImageType(textureType);
6256 mExtents = extents;
6257 mRotatedAspectRatio = false;
6258 mIntendedFormatID = intendedFormatID;
6259 mActualFormatID = actualFormatID;
6260 mSamples = std::max(samples, 1);
6261 mImageSerial = renderer->getResourceSerialFactory().generateImageSerial();
6262 mFirstAllocatedLevel = firstLevel;
6263 mLevelCount = mipLevels;
6264 mLayerCount = layerCount;
6265 mCreateFlags =
6266 vk::GetMinimalImageCreateFlags(renderer, textureType, usage) | additionalCreateFlags;
6267 mUsage = usage;
6268
6269 // Validate that mLayerCount is compatible with the texture type
6270 ASSERT(textureType != gl::TextureType::_3D || mLayerCount == 1);
6271 ASSERT(textureType != gl::TextureType::_2DArray || mExtents.depth == 1);
6272 ASSERT(textureType != gl::TextureType::External || mLayerCount == 1);
6273 ASSERT(textureType != gl::TextureType::Rectangle || mLayerCount == 1);
6274 ASSERT(textureType != gl::TextureType::CubeMap || mLayerCount == gl::kCubeFaceCount);
6275 ASSERT(textureType != gl::TextureType::CubeMapArray || mLayerCount % gl::kCubeFaceCount == 0);
6276
6277 // If externalImageCreateInfo is provided, use that directly. Otherwise derive the necessary
6278 // pNext chain.
6279 const void *imageCreateInfoPNext = externalImageCreateInfo;
6280 VkImageFormatListCreateInfoKHR imageFormatListInfoStorage;
6281 ImageListFormats imageListFormatsStorage;
6282
6283 if (externalImageCreateInfo == nullptr)
6284 {
6285 imageCreateInfoPNext = DeriveCreateInfoPNext(context, actualFormatID, compressionControl,
6286 &imageFormatListInfoStorage,
6287 &imageListFormatsStorage, &mCreateFlags);
6288 }
6289 else
6290 {
6291 // Derive the tiling for external images.
6292 deriveExternalImageTiling(externalImageCreateInfo);
6293 }
6294
6295 mYcbcrConversionDesc = conversionDesc;
6296
6297 const angle::Format &actualFormat = angle::Format::Get(actualFormatID);
6298 const angle::Format &intendedFormat = angle::Format::Get(intendedFormatID);
6299 VkFormat actualVkFormat = GetVkFormatFromFormatID(renderer, actualFormatID);
6300
6301 ANGLE_TRACE_EVENT_INSTANT("gpu.angle.texture_metrics", "ImageHelper::initExternal",
6302 "intended_format", intendedFormat.glInternalFormat, "actual_format",
6303 actualFormat.glInternalFormat, "width", extents.width, "height",
6304 extents.height);
6305
6306 if (actualFormat.isYUV)
6307 {
6308 ASSERT(mYcbcrConversionDesc.valid());
6309
6310 // The Vulkan spec states: If the pNext chain includes a VkExternalFormatANDROID structure
6311 // whose externalFormat member is not 0, flags must not include
6312 // VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT
6313 if (!IsYUVExternalFormat(actualFormatID))
6314 {
6315 // The Vulkan spec states: If sampler is used and the VkFormat of the image is a
6316 // multi-planar format, the image must have been created with
6317 // VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT
6318 mCreateFlags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
6319 }
6320 }
6321
6322 if (hasProtectedContent)
6323 {
6324 mCreateFlags |= VK_IMAGE_CREATE_PROTECTED_BIT;
6325 }
6326
6327 VkImageCreateInfo imageInfo = {};
6328 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
6329 imageInfo.pNext = imageCreateInfoPNext;
6330 imageInfo.flags = mCreateFlags;
6331 imageInfo.imageType = mImageType;
6332 imageInfo.format = actualVkFormat;
6333 imageInfo.extent = mExtents;
6334 imageInfo.mipLevels = mLevelCount;
6335 imageInfo.arrayLayers = mLayerCount;
6336 imageInfo.samples =
6337 gl_vk::GetSamples(mSamples, context->getFeatures().limitSampleCountTo2.enabled);
6338 imageInfo.tiling = mTilingMode;
6339 imageInfo.usage = mUsage;
6340 imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
6341 imageInfo.queueFamilyIndexCount = 0;
6342 imageInfo.pQueueFamilyIndices = nullptr;
6343 imageInfo.initialLayout = ConvertImageLayoutToVkImageLayout(renderer, initialLayout);
6344
6345 mCurrentLayout = initialLayout;
6346 mCurrentDeviceQueueIndex = kInvalidDeviceQueueIndex;
6347 mIsReleasedToExternal = false;
6348 mLastNonShaderReadOnlyLayout = ImageLayout::Undefined;
6349 mCurrentShaderReadStageMask = 0;
6350
6351 ANGLE_VK_TRY(context, mImage.init(context->getDevice(), imageInfo));
6352
6353 // Find the image formats in pNext chain in imageInfo.
6354 deriveImageViewFormatFromCreateInfoPNext(imageInfo, mViewFormats);
6355
6356 mVkImageCreateInfo = imageInfo;
6357 mVkImageCreateInfo.pNext = nullptr;
6358 mVkImageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
6359
6360 stageClearIfEmulatedFormat(isRobustResourceInitEnabled, externalImageCreateInfo != nullptr);
6361
6362 // Consider the contents defined for any image that has the PREINITIALIZED layout, or is
6363 // imported from external.
6364 if (initialLayout != ImageLayout::Undefined || externalImageCreateInfo != nullptr)
6365 {
6366 setEntireContentDefined();
6367 }
6368
6369 return angle::Result::Continue;
6370 }
6371
6372 // static
DeriveCreateInfoPNext(Context * context,angle::FormatID actualFormatID,const void * pNext,VkImageFormatListCreateInfoKHR * imageFormatListInfoStorage,std::array<VkFormat,kImageListFormatCount> * imageListFormatsStorage,VkImageCreateFlags * createFlagsOut)6373 const void *ImageHelper::DeriveCreateInfoPNext(
6374 Context *context,
6375 angle::FormatID actualFormatID,
6376 const void *pNext,
6377 VkImageFormatListCreateInfoKHR *imageFormatListInfoStorage,
6378 std::array<VkFormat, kImageListFormatCount> *imageListFormatsStorage,
6379 VkImageCreateFlags *createFlagsOut)
6380 {
6381 // With the introduction of sRGB related GLES extensions any sample/render target could be
6382 // respecified causing it to be interpreted in a different colorspace. Create the VkImage
6383 // accordingly.
6384 Renderer *renderer = context->getRenderer();
6385 const angle::Format &actualFormat = angle::Format::Get(actualFormatID);
6386 angle::FormatID additionalFormat =
6387 actualFormat.isSRGB ? ConvertToLinear(actualFormatID) : ConvertToSRGB(actualFormatID);
6388 (*imageListFormatsStorage)[0] = vk::GetVkFormatFromFormatID(renderer, actualFormatID);
6389 (*imageListFormatsStorage)[1] = vk::GetVkFormatFromFormatID(renderer, additionalFormat);
6390
6391 if (renderer->getFeatures().supportsImageFormatList.enabled &&
6392 renderer->haveSameFormatFeatureBits(actualFormatID, additionalFormat))
6393 {
6394 // Add VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT to VkImage create flag
6395 *createFlagsOut |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
6396
6397 // There is just 1 additional format we might use to create a VkImageView for this
6398 // VkImage
6399 imageFormatListInfoStorage->sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR;
6400 imageFormatListInfoStorage->pNext = pNext;
6401 imageFormatListInfoStorage->viewFormatCount = kImageListFormatCount;
6402 imageFormatListInfoStorage->pViewFormats = imageListFormatsStorage->data();
6403
6404 pNext = imageFormatListInfoStorage;
6405 }
6406
6407 return pNext;
6408 }
6409
6410 // static
FormatSupportsUsage(Renderer * renderer,VkFormat format,VkImageType imageType,VkImageTiling tilingMode,VkImageUsageFlags usageFlags,VkImageCreateFlags createFlags,void * formatInfoPNext,void * propertiesPNext,const FormatSupportCheck formatSupportCheck)6411 bool ImageHelper::FormatSupportsUsage(Renderer *renderer,
6412 VkFormat format,
6413 VkImageType imageType,
6414 VkImageTiling tilingMode,
6415 VkImageUsageFlags usageFlags,
6416 VkImageCreateFlags createFlags,
6417 void *formatInfoPNext,
6418 void *propertiesPNext,
6419 const FormatSupportCheck formatSupportCheck)
6420 {
6421 VkPhysicalDeviceImageFormatInfo2 imageFormatInfo = {};
6422 imageFormatInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
6423 imageFormatInfo.pNext = formatInfoPNext;
6424 imageFormatInfo.format = format;
6425 imageFormatInfo.type = imageType;
6426 imageFormatInfo.tiling = tilingMode;
6427 imageFormatInfo.usage = usageFlags;
6428 imageFormatInfo.flags = createFlags;
6429
6430 VkImageFormatProperties2 imageFormatProperties2 = {};
6431 imageFormatProperties2.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
6432 imageFormatProperties2.pNext = propertiesPNext;
6433
6434 VkResult result = vkGetPhysicalDeviceImageFormatProperties2(
6435 renderer->getPhysicalDevice(), &imageFormatInfo, &imageFormatProperties2);
6436
6437 if (formatSupportCheck == FormatSupportCheck::RequireMultisampling)
6438 {
6439 // Some drivers return success but sampleCounts == 1 which means no MSRTT
6440 return result == VK_SUCCESS &&
6441 imageFormatProperties2.imageFormatProperties.sampleCounts > 1;
6442 }
6443 return result == VK_SUCCESS;
6444 }
6445
setImageFormatsFromActualFormat(VkFormat actualFormat,ImageFormats & imageFormatsOut)6446 void ImageHelper::setImageFormatsFromActualFormat(VkFormat actualFormat,
6447 ImageFormats &imageFormatsOut)
6448 {
6449 imageFormatsOut.push_back(actualFormat);
6450 }
6451
deriveImageViewFormatFromCreateInfoPNext(VkImageCreateInfo & imageInfo,ImageFormats & formatOut)6452 void ImageHelper::deriveImageViewFormatFromCreateInfoPNext(VkImageCreateInfo &imageInfo,
6453 ImageFormats &formatOut)
6454 {
6455 const VkBaseInStructure *pNextChain =
6456 reinterpret_cast<const VkBaseInStructure *>(imageInfo.pNext);
6457 while (pNextChain != nullptr &&
6458 pNextChain->sType != VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR)
6459 {
6460 pNextChain = pNextChain->pNext;
6461 }
6462
6463 // Clear formatOut in case it has leftovers from previous VkImage in the case of releaseImage
6464 // followed by initExternal.
6465 std::fill(formatOut.begin(), formatOut.begin() + formatOut.max_size(), VK_FORMAT_UNDEFINED);
6466 if (pNextChain != nullptr)
6467 {
6468 const VkImageFormatListCreateInfoKHR *imageFormatCreateInfo =
6469 reinterpret_cast<const VkImageFormatListCreateInfoKHR *>(pNextChain);
6470
6471 for (uint32_t i = 0; i < imageFormatCreateInfo->viewFormatCount; i++)
6472 {
6473 formatOut.push_back(*(imageFormatCreateInfo->pViewFormats + i));
6474 }
6475 }
6476 else
6477 {
6478 setImageFormatsFromActualFormat(imageInfo.format, formatOut);
6479 }
6480 }
6481
deriveExternalImageTiling(const void * createInfoChain)6482 void ImageHelper::deriveExternalImageTiling(const void *createInfoChain)
6483 {
6484 const VkBaseInStructure *chain = reinterpret_cast<const VkBaseInStructure *>(createInfoChain);
6485 while (chain != nullptr)
6486 {
6487 if (chain->sType == VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT ||
6488 chain->sType == VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT)
6489 {
6490 mTilingMode = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
6491 return;
6492 }
6493
6494 chain = reinterpret_cast<const VkBaseInStructure *>(chain->pNext);
6495 }
6496 }
6497
releaseImage(Renderer * renderer)6498 void ImageHelper::releaseImage(Renderer *renderer)
6499 {
6500 // mDeviceMemory and mVmaAllocation should not be valid at the same time.
6501 ASSERT(!mDeviceMemory.valid() || !mVmaAllocation.valid());
6502 if (mDeviceMemory.valid())
6503 {
6504 renderer->onMemoryDealloc(mMemoryAllocationType, mAllocationSize, mMemoryTypeIndex,
6505 mDeviceMemory.getHandle());
6506 }
6507 if (mVmaAllocation.valid())
6508 {
6509 renderer->onMemoryDealloc(mMemoryAllocationType, mAllocationSize, mMemoryTypeIndex,
6510 mVmaAllocation.getHandle());
6511 }
6512 mCurrentEvent.release(renderer);
6513 mLastNonShaderReadOnlyEvent.release(renderer);
6514 renderer->collectGarbage(mUse, &mImage, &mDeviceMemory, &mVmaAllocation);
6515 mViewFormats.clear();
6516 mUse.reset();
6517 mImageSerial = kInvalidImageSerial;
6518 mMemoryAllocationType = MemoryAllocationType::InvalidEnum;
6519 setEntireContentUndefined();
6520 }
6521
releaseImageFromShareContexts(Renderer * renderer,ContextVk * contextVk,UniqueSerial imageSiblingSerial)6522 void ImageHelper::releaseImageFromShareContexts(Renderer *renderer,
6523 ContextVk *contextVk,
6524 UniqueSerial imageSiblingSerial)
6525 {
6526 finalizeImageLayoutInShareContexts(renderer, contextVk, imageSiblingSerial);
6527 contextVk->addToPendingImageGarbage(mUse, mAllocationSize);
6528 releaseImage(renderer);
6529 }
6530
finalizeImageLayoutInShareContexts(Renderer * renderer,ContextVk * contextVk,UniqueSerial imageSiblingSerial)6531 void ImageHelper::finalizeImageLayoutInShareContexts(Renderer *renderer,
6532 ContextVk *contextVk,
6533 UniqueSerial imageSiblingSerial)
6534 {
6535 if (contextVk && mImageSerial.valid())
6536 {
6537 for (auto context : contextVk->getShareGroup()->getContexts())
6538 {
6539 vk::GetImpl(context.second)->finalizeImageLayout(this, imageSiblingSerial);
6540 }
6541 }
6542 }
6543
releaseStagedUpdates(Renderer * renderer)6544 void ImageHelper::releaseStagedUpdates(Renderer *renderer)
6545 {
6546 ASSERT(validateSubresourceUpdateRefCountsConsistent());
6547
6548 // Remove updates that never made it to the texture.
6549 for (std::vector<SubresourceUpdate> &levelUpdates : mSubresourceUpdates)
6550 {
6551 for (SubresourceUpdate &update : levelUpdates)
6552 {
6553 update.release(renderer);
6554 }
6555 }
6556
6557 ASSERT(validateSubresourceUpdateRefCountsConsistent());
6558
6559 mSubresourceUpdates.clear();
6560 mTotalStagedBufferUpdateSize = 0;
6561 mCurrentSingleClearValue.reset();
6562 }
6563
resetImageWeakReference()6564 void ImageHelper::resetImageWeakReference()
6565 {
6566 mImage.reset();
6567 mImageSerial = kInvalidImageSerial;
6568 mRotatedAspectRatio = false;
6569 // Caller must ensure ANI semaphores are properly waited or released.
6570 ASSERT(!mAcquireNextImageSemaphore.valid());
6571 }
6572
initializeNonZeroMemory(Context * context,bool hasProtectedContent,VkMemoryPropertyFlags flags,VkDeviceSize size)6573 angle::Result ImageHelper::initializeNonZeroMemory(Context *context,
6574 bool hasProtectedContent,
6575 VkMemoryPropertyFlags flags,
6576 VkDeviceSize size)
6577 {
6578 // If available, memory mapping should be used.
6579 Renderer *renderer = context->getRenderer();
6580
6581 if ((flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0)
6582 {
6583 // Wipe memory to an invalid value when the 'allocateNonZeroMemory' feature is enabled. The
6584 // invalid values ensures our testing doesn't assume zero-initialized memory.
6585 constexpr int kNonZeroInitValue = 0x3F;
6586 if (renderer->getFeatures().useVmaForImageSuballocation.enabled)
6587 {
6588 ANGLE_VK_TRY(context,
6589 renderer->getImageMemorySuballocator().mapMemoryAndInitWithNonZeroValue(
6590 renderer, &mVmaAllocation, size, kNonZeroInitValue, flags));
6591 }
6592 else
6593 {
6594 ANGLE_TRY(vk::InitMappableDeviceMemory(context, &mDeviceMemory, size, kNonZeroInitValue,
6595 flags));
6596 }
6597
6598 return angle::Result::Continue;
6599 }
6600
6601 // If mapping the memory is unavailable, a staging resource is used.
6602 const angle::Format &angleFormat = getActualFormat();
6603 bool isCompressedFormat = angleFormat.isBlock;
6604
6605 if (angleFormat.isYUV)
6606 {
6607 // VUID-vkCmdClearColorImage-image-01545
6608 // vkCmdClearColorImage(): format must not be one of the formats requiring sampler YCBCR
6609 // conversion for VK_IMAGE_ASPECT_COLOR_BIT image views
6610 return angle::Result::Continue;
6611 }
6612
6613 // Since we are going to do a one off out of order submission, there shouldn't any pending
6614 // setEvent.
6615 ASSERT(!mCurrentEvent.valid());
6616
6617 PrimaryCommandBuffer commandBuffer;
6618 auto protectionType = ConvertProtectionBoolToType(hasProtectedContent);
6619 ANGLE_TRY(renderer->getCommandBufferOneOff(context, protectionType, &commandBuffer));
6620
6621 // Queue a DMA copy.
6622 VkSemaphore acquireNextImageSemaphore;
6623 barrierImpl(context, getAspectFlags(), ImageLayout::TransferDst, context->getDeviceQueueIndex(),
6624 nullptr, &commandBuffer, &acquireNextImageSemaphore);
6625 // SwapChain image should not come here
6626 ASSERT(acquireNextImageSemaphore == VK_NULL_HANDLE);
6627
6628 StagingBuffer stagingBuffer;
6629
6630 if (isCompressedFormat)
6631 {
6632 // If format is compressed, set its contents through buffer copies.
6633
6634 // The staging buffer memory is non-zero-initialized in 'init'.
6635 ANGLE_TRY(stagingBuffer.init(context, size, StagingUsage::Write));
6636
6637 for (LevelIndex level(0); level < LevelIndex(mLevelCount); ++level)
6638 {
6639 VkBufferImageCopy copyRegion = {};
6640
6641 gl_vk::GetExtent(getLevelExtents(level), ©Region.imageExtent);
6642 copyRegion.imageSubresource.aspectMask = getAspectFlags();
6643 copyRegion.imageSubresource.layerCount = mLayerCount;
6644
6645 // If image has depth and stencil, copy to each individually per Vulkan spec.
6646 bool hasBothDepthAndStencil = isCombinedDepthStencilFormat();
6647 if (hasBothDepthAndStencil)
6648 {
6649 copyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
6650 }
6651
6652 commandBuffer.copyBufferToImage(stagingBuffer.getBuffer().getHandle(), mImage,
6653 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Region);
6654
6655 if (hasBothDepthAndStencil)
6656 {
6657 copyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
6658
6659 commandBuffer.copyBufferToImage(stagingBuffer.getBuffer().getHandle(), mImage,
6660 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1,
6661 ©Region);
6662 }
6663 }
6664 }
6665 else
6666 {
6667 // Otherwise issue clear commands.
6668 VkImageSubresourceRange subresource = {};
6669 subresource.aspectMask = getAspectFlags();
6670 subresource.baseMipLevel = 0;
6671 subresource.levelCount = mLevelCount;
6672 subresource.baseArrayLayer = 0;
6673 subresource.layerCount = mLayerCount;
6674
6675 // Arbitrary value to initialize the memory with. Note: the given uint value, reinterpreted
6676 // as float is about 0.7.
6677 constexpr uint32_t kInitValue = 0x3F345678;
6678 constexpr float kInitValueFloat = 0.12345f;
6679
6680 if ((subresource.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) != 0)
6681 {
6682 VkClearColorValue clearValue;
6683 clearValue.uint32[0] = kInitValue;
6684 clearValue.uint32[1] = kInitValue;
6685 clearValue.uint32[2] = kInitValue;
6686 clearValue.uint32[3] = kInitValue;
6687
6688 commandBuffer.clearColorImage(mImage, getCurrentLayout(renderer), clearValue, 1,
6689 &subresource);
6690 }
6691 else
6692 {
6693 VkClearDepthStencilValue clearValue;
6694 clearValue.depth = kInitValueFloat;
6695 clearValue.stencil = kInitValue;
6696
6697 commandBuffer.clearDepthStencilImage(mImage, getCurrentLayout(renderer), clearValue, 1,
6698 &subresource);
6699 }
6700 }
6701
6702 ANGLE_VK_TRY(context, commandBuffer.end());
6703
6704 QueueSerial queueSerial;
6705 ANGLE_TRY(renderer->queueSubmitOneOff(context, std::move(commandBuffer), protectionType,
6706 egl::ContextPriority::Medium, VK_NULL_HANDLE, 0,
6707 vk::SubmitPolicy::AllowDeferred, &queueSerial));
6708
6709 if (isCompressedFormat)
6710 {
6711 stagingBuffer.collectGarbage(renderer, queueSerial);
6712 }
6713 mUse.setQueueSerial(queueSerial);
6714
6715 return angle::Result::Continue;
6716 }
6717
initMemory(Context * context,const MemoryProperties & memoryProperties,VkMemoryPropertyFlags flags,VkMemoryPropertyFlags excludedFlags,const VkMemoryRequirements * memoryRequirements,const bool allocateDedicatedMemory,MemoryAllocationType allocationType,VkMemoryPropertyFlags * flagsOut,VkDeviceSize * sizeOut)6718 VkResult ImageHelper::initMemory(Context *context,
6719 const MemoryProperties &memoryProperties,
6720 VkMemoryPropertyFlags flags,
6721 VkMemoryPropertyFlags excludedFlags,
6722 const VkMemoryRequirements *memoryRequirements,
6723 const bool allocateDedicatedMemory,
6724 MemoryAllocationType allocationType,
6725 VkMemoryPropertyFlags *flagsOut,
6726 VkDeviceSize *sizeOut)
6727 {
6728 mMemoryAllocationType = allocationType;
6729
6730 // To allocate memory here, if possible, we use the image memory suballocator which uses VMA.
6731 ASSERT(excludedFlags < VK_MEMORY_PROPERTY_FLAG_BITS_MAX_ENUM);
6732 Renderer *renderer = context->getRenderer();
6733 if (renderer->getFeatures().useVmaForImageSuballocation.enabled)
6734 {
6735 // While it may be preferable to allocate the image on the device, it should also be
6736 // possible to allocate on other memory types if the device is out of memory.
6737 VkMemoryPropertyFlags requiredFlags = flags & (~excludedFlags);
6738 VkMemoryPropertyFlags preferredFlags = flags;
6739 VK_RESULT_TRY(renderer->getImageMemorySuballocator().allocateAndBindMemory(
6740 context, &mImage, &mVkImageCreateInfo, requiredFlags, preferredFlags,
6741 memoryRequirements, allocateDedicatedMemory, mMemoryAllocationType, &mVmaAllocation,
6742 flagsOut, &mMemoryTypeIndex, &mAllocationSize));
6743 }
6744 else
6745 {
6746 VK_RESULT_TRY(AllocateImageMemory(context, mMemoryAllocationType, flags, flagsOut, nullptr,
6747 &mImage, &mMemoryTypeIndex, &mDeviceMemory,
6748 &mAllocationSize));
6749 }
6750
6751 mCurrentDeviceQueueIndex = context->getDeviceQueueIndex();
6752 mIsReleasedToExternal = false;
6753 *sizeOut = mAllocationSize;
6754
6755 return VK_SUCCESS;
6756 }
6757
initMemoryAndNonZeroFillIfNeeded(Context * context,bool hasProtectedContent,const MemoryProperties & memoryProperties,VkMemoryPropertyFlags flags,MemoryAllocationType allocationType)6758 angle::Result ImageHelper::initMemoryAndNonZeroFillIfNeeded(
6759 Context *context,
6760 bool hasProtectedContent,
6761 const MemoryProperties &memoryProperties,
6762 VkMemoryPropertyFlags flags,
6763 MemoryAllocationType allocationType)
6764 {
6765 Renderer *renderer = context->getRenderer();
6766 VkMemoryPropertyFlags outputFlags;
6767 VkDeviceSize outputSize;
6768
6769 if (hasProtectedContent)
6770 {
6771 flags |= VK_MEMORY_PROPERTY_PROTECTED_BIT;
6772 }
6773
6774 // Get memory requirements for the allocation.
6775 VkMemoryRequirements memoryRequirements;
6776 mImage.getMemoryRequirements(renderer->getDevice(), &memoryRequirements);
6777 bool allocateDedicatedMemory =
6778 renderer->getImageMemorySuballocator().needsDedicatedMemory(memoryRequirements.size);
6779
6780 ANGLE_VK_TRY(context,
6781 initMemory(context, memoryProperties, flags, 0, &memoryRequirements,
6782 allocateDedicatedMemory, allocationType, &outputFlags, &outputSize));
6783
6784 if (renderer->getFeatures().allocateNonZeroMemory.enabled)
6785 {
6786 ANGLE_TRY(initializeNonZeroMemory(context, hasProtectedContent, outputFlags, outputSize));
6787 }
6788 return angle::Result::Continue;
6789 }
6790
initExternalMemory(Context * context,const MemoryProperties & memoryProperties,const VkMemoryRequirements & memoryRequirements,uint32_t extraAllocationInfoCount,const void ** extraAllocationInfo,DeviceQueueIndex currentDeviceQueueIndex,VkMemoryPropertyFlags flags)6791 angle::Result ImageHelper::initExternalMemory(Context *context,
6792 const MemoryProperties &memoryProperties,
6793 const VkMemoryRequirements &memoryRequirements,
6794 uint32_t extraAllocationInfoCount,
6795 const void **extraAllocationInfo,
6796 DeviceQueueIndex currentDeviceQueueIndex,
6797 VkMemoryPropertyFlags flags)
6798 {
6799 // Vulkan allows up to 4 memory planes.
6800 constexpr size_t kMaxMemoryPlanes = 4;
6801 constexpr VkImageAspectFlagBits kMemoryPlaneAspects[kMaxMemoryPlanes] = {
6802 VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT,
6803 VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT,
6804 VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT,
6805 VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT,
6806 };
6807 ASSERT(extraAllocationInfoCount <= kMaxMemoryPlanes);
6808
6809 VkBindImagePlaneMemoryInfoKHR bindImagePlaneMemoryInfo = {};
6810 bindImagePlaneMemoryInfo.sType = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO;
6811
6812 const VkBindImagePlaneMemoryInfoKHR *bindImagePlaneMemoryInfoPtr =
6813 extraAllocationInfoCount == 1 ? nullptr : &bindImagePlaneMemoryInfo;
6814
6815 mAllocationSize = memoryRequirements.size;
6816 mMemoryAllocationType = MemoryAllocationType::ImageExternal;
6817
6818 for (uint32_t memoryPlane = 0; memoryPlane < extraAllocationInfoCount; ++memoryPlane)
6819 {
6820 bindImagePlaneMemoryInfo.planeAspect = kMemoryPlaneAspects[memoryPlane];
6821
6822 ANGLE_VK_TRY(context, AllocateImageMemoryWithRequirements(
6823 context, mMemoryAllocationType, flags, memoryRequirements,
6824 extraAllocationInfo[memoryPlane], bindImagePlaneMemoryInfoPtr,
6825 &mImage, &mMemoryTypeIndex, &mDeviceMemory));
6826 }
6827 mCurrentDeviceQueueIndex = currentDeviceQueueIndex;
6828 mIsReleasedToExternal = false;
6829
6830 return angle::Result::Continue;
6831 }
6832
initLayerImageView(Context * context,gl::TextureType textureType,VkImageAspectFlags aspectMask,const gl::SwizzleState & swizzleMap,ImageView * imageViewOut,LevelIndex baseMipLevelVk,uint32_t levelCount,uint32_t baseArrayLayer,uint32_t layerCount) const6833 angle::Result ImageHelper::initLayerImageView(Context *context,
6834 gl::TextureType textureType,
6835 VkImageAspectFlags aspectMask,
6836 const gl::SwizzleState &swizzleMap,
6837 ImageView *imageViewOut,
6838 LevelIndex baseMipLevelVk,
6839 uint32_t levelCount,
6840 uint32_t baseArrayLayer,
6841 uint32_t layerCount) const
6842 {
6843 return initLayerImageViewImpl(context, textureType, aspectMask, swizzleMap, imageViewOut,
6844 baseMipLevelVk, levelCount, baseArrayLayer, layerCount,
6845 GetVkFormatFromFormatID(context->getRenderer(), mActualFormatID),
6846 kDefaultImageViewUsageFlags, gl::YuvSamplingMode::Default);
6847 }
6848
initLayerImageViewWithUsage(Context * context,gl::TextureType textureType,VkImageAspectFlags aspectMask,const gl::SwizzleState & swizzleMap,ImageView * imageViewOut,LevelIndex baseMipLevelVk,uint32_t levelCount,uint32_t baseArrayLayer,uint32_t layerCount,VkImageUsageFlags imageUsageFlags) const6849 angle::Result ImageHelper::initLayerImageViewWithUsage(Context *context,
6850 gl::TextureType textureType,
6851 VkImageAspectFlags aspectMask,
6852 const gl::SwizzleState &swizzleMap,
6853 ImageView *imageViewOut,
6854 LevelIndex baseMipLevelVk,
6855 uint32_t levelCount,
6856 uint32_t baseArrayLayer,
6857 uint32_t layerCount,
6858 VkImageUsageFlags imageUsageFlags) const
6859 {
6860 return initLayerImageViewImpl(context, textureType, aspectMask, swizzleMap, imageViewOut,
6861 baseMipLevelVk, levelCount, baseArrayLayer, layerCount,
6862 GetVkFormatFromFormatID(context->getRenderer(), mActualFormatID),
6863 imageUsageFlags, gl::YuvSamplingMode::Default);
6864 }
6865
initLayerImageViewWithYuvModeOverride(Context * context,gl::TextureType textureType,VkImageAspectFlags aspectMask,const gl::SwizzleState & swizzleMap,ImageView * imageViewOut,LevelIndex baseMipLevelVk,uint32_t levelCount,uint32_t baseArrayLayer,uint32_t layerCount,gl::YuvSamplingMode yuvSamplingMode,VkImageUsageFlags imageUsageFlags) const6866 angle::Result ImageHelper::initLayerImageViewWithYuvModeOverride(
6867 Context *context,
6868 gl::TextureType textureType,
6869 VkImageAspectFlags aspectMask,
6870 const gl::SwizzleState &swizzleMap,
6871 ImageView *imageViewOut,
6872 LevelIndex baseMipLevelVk,
6873 uint32_t levelCount,
6874 uint32_t baseArrayLayer,
6875 uint32_t layerCount,
6876 gl::YuvSamplingMode yuvSamplingMode,
6877 VkImageUsageFlags imageUsageFlags) const
6878 {
6879 return initLayerImageViewImpl(context, textureType, aspectMask, swizzleMap, imageViewOut,
6880 baseMipLevelVk, levelCount, baseArrayLayer, layerCount,
6881 GetVkFormatFromFormatID(context->getRenderer(), mActualFormatID),
6882 imageUsageFlags, yuvSamplingMode);
6883 }
6884
initLayerImageViewImpl(Context * context,gl::TextureType textureType,VkImageAspectFlags aspectMask,const gl::SwizzleState & swizzleMap,ImageView * imageViewOut,LevelIndex baseMipLevelVk,uint32_t levelCount,uint32_t baseArrayLayer,uint32_t layerCount,VkFormat imageFormat,VkImageUsageFlags usageFlags,gl::YuvSamplingMode yuvSamplingMode) const6885 angle::Result ImageHelper::initLayerImageViewImpl(Context *context,
6886 gl::TextureType textureType,
6887 VkImageAspectFlags aspectMask,
6888 const gl::SwizzleState &swizzleMap,
6889 ImageView *imageViewOut,
6890 LevelIndex baseMipLevelVk,
6891 uint32_t levelCount,
6892 uint32_t baseArrayLayer,
6893 uint32_t layerCount,
6894 VkFormat imageFormat,
6895 VkImageUsageFlags usageFlags,
6896 gl::YuvSamplingMode yuvSamplingMode) const
6897 {
6898 VkImageViewCreateInfo viewInfo = {};
6899 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
6900 viewInfo.flags = 0;
6901 viewInfo.image = mImage.getHandle();
6902 viewInfo.viewType = gl_vk::GetImageViewType(textureType);
6903 viewInfo.format = imageFormat;
6904
6905 if (swizzleMap.swizzleRequired() && !mYcbcrConversionDesc.valid())
6906 {
6907 viewInfo.components.r = gl_vk::GetSwizzle(swizzleMap.swizzleRed);
6908 viewInfo.components.g = gl_vk::GetSwizzle(swizzleMap.swizzleGreen);
6909 viewInfo.components.b = gl_vk::GetSwizzle(swizzleMap.swizzleBlue);
6910 viewInfo.components.a = gl_vk::GetSwizzle(swizzleMap.swizzleAlpha);
6911 }
6912 else
6913 {
6914 viewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
6915 viewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
6916 viewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
6917 viewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
6918 }
6919 viewInfo.subresourceRange.aspectMask = aspectMask;
6920 viewInfo.subresourceRange.baseMipLevel = baseMipLevelVk.get();
6921 viewInfo.subresourceRange.levelCount = levelCount;
6922 viewInfo.subresourceRange.baseArrayLayer = baseArrayLayer;
6923 viewInfo.subresourceRange.layerCount = layerCount;
6924
6925 VkImageViewUsageCreateInfo imageViewUsageCreateInfo = {};
6926 if (usageFlags)
6927 {
6928 imageViewUsageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO;
6929 imageViewUsageCreateInfo.usage = usageFlags;
6930
6931 viewInfo.pNext = &imageViewUsageCreateInfo;
6932 }
6933
6934 VkSamplerYcbcrConversionInfo yuvConversionInfo = {};
6935
6936 auto conversionDesc =
6937 yuvSamplingMode == gl::YuvSamplingMode::Y2Y ? getY2YConversionDesc() : mYcbcrConversionDesc;
6938
6939 if (conversionDesc.valid())
6940 {
6941 ASSERT((context->getFeatures().supportsYUVSamplerConversion.enabled));
6942 yuvConversionInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO;
6943 yuvConversionInfo.pNext = nullptr;
6944 ANGLE_TRY(context->getRenderer()->getYuvConversionCache().getSamplerYcbcrConversion(
6945 context, conversionDesc, &yuvConversionInfo.conversion));
6946 AddToPNextChain(&viewInfo, &yuvConversionInfo);
6947
6948 // VUID-VkImageViewCreateInfo-image-02399
6949 // If image has an external format, format must be VK_FORMAT_UNDEFINED
6950 if (conversionDesc.getExternalFormat() != 0)
6951 {
6952 viewInfo.format = VK_FORMAT_UNDEFINED;
6953 }
6954 }
6955 ANGLE_VK_TRY(context, imageViewOut->init(context->getDevice(), viewInfo));
6956 return angle::Result::Continue;
6957 }
6958
initReinterpretedLayerImageView(Context * context,gl::TextureType textureType,VkImageAspectFlags aspectMask,const gl::SwizzleState & swizzleMap,ImageView * imageViewOut,LevelIndex baseMipLevelVk,uint32_t levelCount,uint32_t baseArrayLayer,uint32_t layerCount,VkImageUsageFlags imageUsageFlags,angle::FormatID imageViewFormat) const6959 angle::Result ImageHelper::initReinterpretedLayerImageView(Context *context,
6960 gl::TextureType textureType,
6961 VkImageAspectFlags aspectMask,
6962 const gl::SwizzleState &swizzleMap,
6963 ImageView *imageViewOut,
6964 LevelIndex baseMipLevelVk,
6965 uint32_t levelCount,
6966 uint32_t baseArrayLayer,
6967 uint32_t layerCount,
6968 VkImageUsageFlags imageUsageFlags,
6969 angle::FormatID imageViewFormat) const
6970 {
6971 VkImageUsageFlags usageFlags =
6972 imageUsageFlags & GetMaximalImageUsageFlags(context->getRenderer(), imageViewFormat);
6973
6974 return initLayerImageViewImpl(
6975 context, textureType, aspectMask, swizzleMap, imageViewOut, baseMipLevelVk, levelCount,
6976 baseArrayLayer, layerCount,
6977 vk::GetVkFormatFromFormatID(context->getRenderer(), imageViewFormat), usageFlags,
6978 gl::YuvSamplingMode::Default);
6979 }
6980
destroy(Renderer * renderer)6981 void ImageHelper::destroy(Renderer *renderer)
6982 {
6983 VkDevice device = renderer->getDevice();
6984
6985 // mDeviceMemory and mVmaAllocation should not be valid at the same time.
6986 ASSERT(!mDeviceMemory.valid() || !mVmaAllocation.valid());
6987 if (mDeviceMemory.valid())
6988 {
6989 renderer->onMemoryDealloc(mMemoryAllocationType, mAllocationSize, mMemoryTypeIndex,
6990 mDeviceMemory.getHandle());
6991 }
6992 if (mVmaAllocation.valid())
6993 {
6994 renderer->onMemoryDealloc(mMemoryAllocationType, mAllocationSize, mMemoryTypeIndex,
6995 mVmaAllocation.getHandle());
6996 }
6997
6998 mCurrentEvent.release(renderer);
6999 mLastNonShaderReadOnlyEvent.release(renderer);
7000 mImage.destroy(device);
7001 mDeviceMemory.destroy(device);
7002 mVmaAllocation.destroy(renderer->getAllocator());
7003 mCurrentLayout = ImageLayout::Undefined;
7004 mImageType = VK_IMAGE_TYPE_2D;
7005 mLayerCount = 0;
7006 mLevelCount = 0;
7007 mMemoryAllocationType = MemoryAllocationType::InvalidEnum;
7008
7009 setEntireContentUndefined();
7010 }
7011
init2DWeakReference(Context * context,VkImage handle,const gl::Extents & glExtents,bool rotatedAspectRatio,angle::FormatID intendedFormatID,angle::FormatID actualFormatID,VkImageCreateFlags createFlags,VkImageUsageFlags usage,GLint samples,bool isRobustResourceInitEnabled)7012 void ImageHelper::init2DWeakReference(Context *context,
7013 VkImage handle,
7014 const gl::Extents &glExtents,
7015 bool rotatedAspectRatio,
7016 angle::FormatID intendedFormatID,
7017 angle::FormatID actualFormatID,
7018 VkImageCreateFlags createFlags,
7019 VkImageUsageFlags usage,
7020 GLint samples,
7021 bool isRobustResourceInitEnabled)
7022 {
7023 ASSERT(!valid());
7024 ASSERT(!IsAnySubresourceContentDefined(mContentDefined));
7025 ASSERT(!IsAnySubresourceContentDefined(mStencilContentDefined));
7026 vk::Renderer *renderer = context->getRenderer();
7027
7028 gl_vk::GetExtent(glExtents, &mExtents);
7029 mRotatedAspectRatio = rotatedAspectRatio;
7030 mIntendedFormatID = intendedFormatID;
7031 mActualFormatID = actualFormatID;
7032 mCreateFlags = createFlags;
7033 mUsage = usage;
7034 mSamples = std::max(samples, 1);
7035 mImageSerial = renderer->getResourceSerialFactory().generateImageSerial();
7036 mCurrentDeviceQueueIndex = context->getDeviceQueueIndex();
7037 mIsReleasedToExternal = false;
7038 mCurrentLayout = ImageLayout::Undefined;
7039 mLayerCount = 1;
7040 mLevelCount = 1;
7041
7042 // The view formats and usage flags are used for imageless framebuffers. Here, the former is set
7043 // similar to deriveImageViewFormatFromCreateInfoPNext() when there is no pNext from a
7044 // VkImageCreateInfo object.
7045 setImageFormatsFromActualFormat(GetVkFormatFromFormatID(renderer, actualFormatID),
7046 mViewFormats);
7047
7048 mImage.setHandle(handle);
7049
7050 stageClearIfEmulatedFormat(isRobustResourceInitEnabled, false);
7051 }
7052
init2DStaging(Context * context,bool hasProtectedContent,const MemoryProperties & memoryProperties,const gl::Extents & glExtents,angle::FormatID intendedFormatID,angle::FormatID actualFormatID,VkImageUsageFlags usage,uint32_t layerCount)7053 angle::Result ImageHelper::init2DStaging(Context *context,
7054 bool hasProtectedContent,
7055 const MemoryProperties &memoryProperties,
7056 const gl::Extents &glExtents,
7057 angle::FormatID intendedFormatID,
7058 angle::FormatID actualFormatID,
7059 VkImageUsageFlags usage,
7060 uint32_t layerCount)
7061 {
7062 gl_vk::GetExtent(glExtents, &mExtents);
7063
7064 return initStaging(context, hasProtectedContent, memoryProperties, VK_IMAGE_TYPE_2D, mExtents,
7065 intendedFormatID, actualFormatID, 1, usage, 1, layerCount);
7066 }
7067
initStaging(Context * context,bool hasProtectedContent,const MemoryProperties & memoryProperties,VkImageType imageType,const VkExtent3D & extents,angle::FormatID intendedFormatID,angle::FormatID actualFormatID,GLint samples,VkImageUsageFlags usage,uint32_t mipLevels,uint32_t layerCount)7068 angle::Result ImageHelper::initStaging(Context *context,
7069 bool hasProtectedContent,
7070 const MemoryProperties &memoryProperties,
7071 VkImageType imageType,
7072 const VkExtent3D &extents,
7073 angle::FormatID intendedFormatID,
7074 angle::FormatID actualFormatID,
7075 GLint samples,
7076 VkImageUsageFlags usage,
7077 uint32_t mipLevels,
7078 uint32_t layerCount)
7079 {
7080 ASSERT(!valid());
7081 ASSERT(!IsAnySubresourceContentDefined(mContentDefined));
7082 ASSERT(!IsAnySubresourceContentDefined(mStencilContentDefined));
7083 vk::Renderer *renderer = context->getRenderer();
7084
7085 mImageType = imageType;
7086 mExtents = extents;
7087 mRotatedAspectRatio = false;
7088 mIntendedFormatID = intendedFormatID;
7089 mActualFormatID = actualFormatID;
7090 mSamples = std::max(samples, 1);
7091 mImageSerial = renderer->getResourceSerialFactory().generateImageSerial();
7092 mLayerCount = layerCount;
7093 mLevelCount = mipLevels;
7094 mUsage = usage;
7095
7096 // Validate that mLayerCount is compatible with the image type
7097 ASSERT(imageType != VK_IMAGE_TYPE_3D || mLayerCount == 1);
7098 ASSERT(imageType != VK_IMAGE_TYPE_2D || mExtents.depth == 1);
7099
7100 mCurrentLayout = ImageLayout::Undefined;
7101
7102 VkImageCreateInfo imageInfo = {};
7103 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
7104 imageInfo.flags = hasProtectedContent ? VK_IMAGE_CREATE_PROTECTED_BIT : 0;
7105 imageInfo.imageType = mImageType;
7106 imageInfo.format = GetVkFormatFromFormatID(renderer, actualFormatID);
7107 imageInfo.extent = mExtents;
7108 imageInfo.mipLevels = mLevelCount;
7109 imageInfo.arrayLayers = mLayerCount;
7110 imageInfo.samples =
7111 gl_vk::GetSamples(mSamples, context->getFeatures().limitSampleCountTo2.enabled);
7112 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
7113 imageInfo.usage = usage;
7114 imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
7115 imageInfo.queueFamilyIndexCount = 0;
7116 imageInfo.pQueueFamilyIndices = nullptr;
7117 imageInfo.initialLayout = getCurrentLayout(context->getRenderer());
7118
7119 ANGLE_VK_TRY(context, mImage.init(context->getDevice(), imageInfo));
7120
7121 mVkImageCreateInfo = imageInfo;
7122 mVkImageCreateInfo.pNext = nullptr;
7123 mVkImageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
7124
7125 // Allocate and bind device-local memory.
7126 VkMemoryPropertyFlags memoryPropertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
7127 if (hasProtectedContent)
7128 {
7129 memoryPropertyFlags |= VK_MEMORY_PROPERTY_PROTECTED_BIT;
7130 }
7131
7132 ANGLE_TRY(initMemoryAndNonZeroFillIfNeeded(context, hasProtectedContent, memoryProperties,
7133 memoryPropertyFlags,
7134 vk::MemoryAllocationType::StagingImage));
7135 return angle::Result::Continue;
7136 }
7137
initImplicitMultisampledRenderToTexture(Context * context,bool hasProtectedContent,const MemoryProperties & memoryProperties,gl::TextureType textureType,GLint samples,const ImageHelper & resolveImage,const VkExtent3D & multisampleImageExtents,bool isRobustResourceInitEnabled)7138 angle::Result ImageHelper::initImplicitMultisampledRenderToTexture(
7139 Context *context,
7140 bool hasProtectedContent,
7141 const MemoryProperties &memoryProperties,
7142 gl::TextureType textureType,
7143 GLint samples,
7144 const ImageHelper &resolveImage,
7145 const VkExtent3D &multisampleImageExtents,
7146 bool isRobustResourceInitEnabled)
7147 {
7148 ASSERT(!valid());
7149 ASSERT(samples > 1);
7150 ASSERT(!IsAnySubresourceContentDefined(mContentDefined));
7151 ASSERT(!IsAnySubresourceContentDefined(mStencilContentDefined));
7152
7153 // The image is used as either color or depth/stencil attachment. Additionally, its memory is
7154 // lazily allocated as the contents are discarded at the end of the renderpass and with tiling
7155 // GPUs no actual backing memory is required.
7156 //
7157 // Note that the Vulkan image is created with or without VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT
7158 // based on whether the memory that will be used to create the image would have
7159 // VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT. TRANSIENT is provided if there is any memory that
7160 // supports LAZILY_ALLOCATED. However, based on actual image requirements, such a memory may
7161 // not be suitable for the image. We don't support such a case, which will result in the
7162 // |initMemory| call below failing.
7163 const bool hasLazilyAllocatedMemory = memoryProperties.hasLazilyAllocatedMemory();
7164
7165 const VkImageUsageFlags kLazyFlags =
7166 hasLazilyAllocatedMemory ? VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT : 0;
7167 constexpr VkImageUsageFlags kColorFlags =
7168 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
7169 constexpr VkImageUsageFlags kDepthStencilFlags =
7170 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
7171
7172 const VkImageUsageFlags kMultisampledUsageFlags =
7173 kLazyFlags |
7174 (resolveImage.getAspectFlags() == VK_IMAGE_ASPECT_COLOR_BIT ? kColorFlags
7175 : kDepthStencilFlags);
7176 const VkImageCreateFlags kMultisampledCreateFlags =
7177 hasProtectedContent ? VK_IMAGE_CREATE_PROTECTED_BIT : 0;
7178
7179 // Multisampled images have only 1 level
7180 constexpr uint32_t kLevelCount = 1;
7181
7182 ANGLE_TRY(initExternal(context, textureType, multisampleImageExtents,
7183 resolveImage.getIntendedFormatID(), resolveImage.getActualFormatID(),
7184 samples, kMultisampledUsageFlags, kMultisampledCreateFlags,
7185 ImageLayout::Undefined, nullptr, resolveImage.getFirstAllocatedLevel(),
7186 kLevelCount, resolveImage.getLayerCount(), isRobustResourceInitEnabled,
7187 hasProtectedContent, YcbcrConversionDesc{}, nullptr));
7188
7189 // Remove the emulated format clear from the multisampled image if any. There is one already
7190 // staged on the resolve image if needed.
7191 removeStagedUpdates(context, getFirstAllocatedLevel(), getLastAllocatedLevel());
7192
7193 const VkMemoryPropertyFlags kMultisampledMemoryFlags =
7194 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
7195 (hasLazilyAllocatedMemory ? VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT : 0) |
7196 (hasProtectedContent ? VK_MEMORY_PROPERTY_PROTECTED_BIT : 0);
7197
7198 // If this ever fails, it can be retried without the LAZILY_ALLOCATED flag (which will probably
7199 // still fail), but ideally that means GL_EXT_multisampled_render_to_texture should not be
7200 // advertized on this platform in the first place.
7201 ANGLE_TRY(initMemoryAndNonZeroFillIfNeeded(
7202 context, hasProtectedContent, memoryProperties, kMultisampledMemoryFlags,
7203 vk::MemoryAllocationType::ImplicitMultisampledRenderToTextureImage));
7204 return angle::Result::Continue;
7205 }
7206
getAspectFlags() const7207 VkImageAspectFlags ImageHelper::getAspectFlags() const
7208 {
7209 return GetFormatAspectFlags(angle::Format::Get(mActualFormatID));
7210 }
7211
isCombinedDepthStencilFormat() const7212 bool ImageHelper::isCombinedDepthStencilFormat() const
7213 {
7214 return (getAspectFlags() & kDepthStencilAspects) == kDepthStencilAspects;
7215 }
7216
setCurrentImageLayout(Renderer * renderer,ImageLayout newLayout)7217 void ImageHelper::setCurrentImageLayout(Renderer *renderer, ImageLayout newLayout)
7218 {
7219 // Once you transition to ImageLayout::SharedPresent, you never transition out of it.
7220 if (mCurrentLayout == ImageLayout::SharedPresent)
7221 {
7222 return;
7223 }
7224
7225 const ImageMemoryBarrierData &transitionFrom =
7226 renderer->getImageMemoryBarrierData(mCurrentLayout);
7227 const ImageMemoryBarrierData &transitionTo = renderer->getImageMemoryBarrierData(newLayout);
7228 mLastNonShaderReadOnlyLayout =
7229 !IsShaderReadOnlyLayout(transitionFrom) ? mCurrentLayout : mLastNonShaderReadOnlyLayout;
7230 // Force the use of BarrierType::Pipeline in the next barrierImpl call
7231 mLastNonShaderReadOnlyEvent.release(renderer);
7232 mCurrentShaderReadStageMask =
7233 IsShaderReadOnlyLayout(transitionTo) ? transitionTo.dstStageMask : 0;
7234 mCurrentLayout = newLayout;
7235 }
7236
getCurrentLayout(Renderer * renderer) const7237 VkImageLayout ImageHelper::getCurrentLayout(Renderer *renderer) const
7238 {
7239 return ConvertImageLayoutToVkImageLayout(renderer, mCurrentLayout);
7240 }
7241
getLevelExtents(LevelIndex levelVk) const7242 gl::Extents ImageHelper::getLevelExtents(LevelIndex levelVk) const
7243 {
7244 // Level 0 should be the size of the extents, after that every time you increase a level
7245 // you shrink the extents by half.
7246 uint32_t width = std::max(mExtents.width >> levelVk.get(), 1u);
7247 uint32_t height = std::max(mExtents.height >> levelVk.get(), 1u);
7248 uint32_t depth = std::max(mExtents.depth >> levelVk.get(), 1u);
7249
7250 return gl::Extents(width, height, depth);
7251 }
7252
getLevelExtents2D(LevelIndex levelVk) const7253 gl::Extents ImageHelper::getLevelExtents2D(LevelIndex levelVk) const
7254 {
7255 gl::Extents extents = getLevelExtents(levelVk);
7256 extents.depth = 1;
7257 return extents;
7258 }
7259
getRotatedExtents() const7260 const VkExtent3D ImageHelper::getRotatedExtents() const
7261 {
7262 VkExtent3D extents = mExtents;
7263 if (mRotatedAspectRatio)
7264 {
7265 std::swap(extents.width, extents.height);
7266 }
7267 return extents;
7268 }
7269
getRotatedLevelExtents2D(LevelIndex levelVk) const7270 gl::Extents ImageHelper::getRotatedLevelExtents2D(LevelIndex levelVk) const
7271 {
7272 gl::Extents extents = getLevelExtents2D(levelVk);
7273 if (mRotatedAspectRatio)
7274 {
7275 std::swap(extents.width, extents.height);
7276 }
7277 return extents;
7278 }
7279
isDepthOrStencil() const7280 bool ImageHelper::isDepthOrStencil() const
7281 {
7282 return getActualFormat().hasDepthOrStencilBits();
7283 }
7284
setRenderPassUsageFlag(RenderPassUsage flag)7285 void ImageHelper::setRenderPassUsageFlag(RenderPassUsage flag)
7286 {
7287 mRenderPassUsageFlags.set(flag);
7288 }
7289
clearRenderPassUsageFlag(RenderPassUsage flag)7290 void ImageHelper::clearRenderPassUsageFlag(RenderPassUsage flag)
7291 {
7292 mRenderPassUsageFlags.reset(flag);
7293 }
7294
resetRenderPassUsageFlags()7295 void ImageHelper::resetRenderPassUsageFlags()
7296 {
7297 mRenderPassUsageFlags.reset();
7298 }
7299
hasRenderPassUsageFlag(RenderPassUsage flag) const7300 bool ImageHelper::hasRenderPassUsageFlag(RenderPassUsage flag) const
7301 {
7302 return mRenderPassUsageFlags.test(flag);
7303 }
7304
usedByCurrentRenderPassAsAttachmentAndSampler(RenderPassUsage textureSamplerUsage) const7305 bool ImageHelper::usedByCurrentRenderPassAsAttachmentAndSampler(
7306 RenderPassUsage textureSamplerUsage) const
7307 {
7308 return mRenderPassUsageFlags[RenderPassUsage::RenderTargetAttachment] &&
7309 mRenderPassUsageFlags[textureSamplerUsage];
7310 }
7311
isReadBarrierNecessary(Renderer * renderer,ImageLayout newLayout) const7312 bool ImageHelper::isReadBarrierNecessary(Renderer *renderer, ImageLayout newLayout) const
7313 {
7314 // If transitioning to a different layout, we need always need a barrier.
7315 if (mCurrentLayout != newLayout)
7316 {
7317 return true;
7318 }
7319
7320 // RAR (read-after-read) is not a hazard and doesn't require a barrier.
7321 //
7322 // RAW (read-after-write) hazards always require a memory barrier. This can only happen if the
7323 // layout (same as new layout) is writable which in turn is only possible if the image is
7324 // simultaneously bound for shader write (i.e. the layout is GENERAL or SHARED_PRESENT).
7325 const ImageMemoryBarrierData &layoutData = renderer->getImageMemoryBarrierData(mCurrentLayout);
7326 return HasResourceWriteAccess(layoutData.type);
7327 }
7328
isReadSubresourceBarrierNecessary(ImageLayout newLayout,gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount) const7329 bool ImageHelper::isReadSubresourceBarrierNecessary(ImageLayout newLayout,
7330 gl::LevelIndex levelStart,
7331 uint32_t levelCount,
7332 uint32_t layerStart,
7333 uint32_t layerCount) const
7334 {
7335 // In case an image has both read and write permissions, the written subresources since the last
7336 // barrier should be checked to avoid RAW and WAR hazards. However, if a layout change is
7337 // necessary regardless, there is no need to check the written subresources.
7338 if (mCurrentLayout != newLayout)
7339 {
7340 return true;
7341 }
7342
7343 ImageLayerWriteMask layerMask = GetImageLayerWriteMask(layerStart, layerCount);
7344 for (uint32_t levelOffset = 0; levelOffset < levelCount; levelOffset++)
7345 {
7346 uint32_t level = levelStart.get() + levelOffset;
7347 if (areLevelSubresourcesWrittenWithinMaskRange(level, layerMask))
7348 {
7349 return true;
7350 }
7351 }
7352
7353 return false;
7354 }
7355
isWriteBarrierNecessary(ImageLayout newLayout,gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount) const7356 bool ImageHelper::isWriteBarrierNecessary(ImageLayout newLayout,
7357 gl::LevelIndex levelStart,
7358 uint32_t levelCount,
7359 uint32_t layerStart,
7360 uint32_t layerCount) const
7361 {
7362 // If transitioning to a different layout, we need always need a barrier.
7363 if (mCurrentLayout != newLayout)
7364 {
7365 return true;
7366 }
7367
7368 if (layerCount >= kMaxParallelLayerWrites)
7369 {
7370 return true;
7371 }
7372
7373 // If we are writing to the same parts of the image (level/layer), we need a barrier. Otherwise,
7374 // it can be done in parallel.
7375 ImageLayerWriteMask layerMask = GetImageLayerWriteMask(layerStart, layerCount);
7376 for (uint32_t levelOffset = 0; levelOffset < levelCount; levelOffset++)
7377 {
7378 uint32_t level = levelStart.get() + levelOffset;
7379 if (areLevelSubresourcesWrittenWithinMaskRange(level, layerMask))
7380 {
7381 return true;
7382 }
7383 }
7384
7385 return false;
7386 }
7387
changeLayoutAndQueue(Context * context,VkImageAspectFlags aspectMask,ImageLayout newLayout,DeviceQueueIndex newDeviceQueueIndex,OutsideRenderPassCommandBuffer * commandBuffer)7388 void ImageHelper::changeLayoutAndQueue(Context *context,
7389 VkImageAspectFlags aspectMask,
7390 ImageLayout newLayout,
7391 DeviceQueueIndex newDeviceQueueIndex,
7392 OutsideRenderPassCommandBuffer *commandBuffer)
7393 {
7394 ASSERT(isQueueFamilyChangeNeccesary(newDeviceQueueIndex));
7395 VkSemaphore acquireNextImageSemaphore;
7396 // barrierImpl should detect there is queue switch and fall back to pipelineBarrier properly.
7397 barrierImpl(context, aspectMask, newLayout, newDeviceQueueIndex, nullptr, commandBuffer,
7398 &acquireNextImageSemaphore);
7399 // SwapChain image should not get here.
7400 ASSERT(acquireNextImageSemaphore == VK_NULL_HANDLE);
7401 }
7402
acquireFromExternal(Context * context,DeviceQueueIndex externalQueueIndex,DeviceQueueIndex newDeviceQueueIndex,ImageLayout currentLayout,OutsideRenderPassCommandBuffer * commandBuffer)7403 void ImageHelper::acquireFromExternal(Context *context,
7404 DeviceQueueIndex externalQueueIndex,
7405 DeviceQueueIndex newDeviceQueueIndex,
7406 ImageLayout currentLayout,
7407 OutsideRenderPassCommandBuffer *commandBuffer)
7408 {
7409 // The image must be newly allocated or have been released to the external
7410 // queue. If this is not the case, it's an application bug, so ASSERT might
7411 // eventually need to change to a warning.
7412 ASSERT(mCurrentLayout == ImageLayout::ExternalPreInitialized ||
7413 mCurrentDeviceQueueIndex.familyIndex() == externalQueueIndex.familyIndex());
7414
7415 mCurrentLayout = currentLayout;
7416 mCurrentDeviceQueueIndex = externalQueueIndex;
7417 mIsReleasedToExternal = false;
7418
7419 // Only change the layout and queue if the layout is anything by Undefined. If it is undefined,
7420 // leave it to transition out as the image is used later.
7421 if (currentLayout != ImageLayout::Undefined)
7422 {
7423 changeLayoutAndQueue(context, getAspectFlags(), mCurrentLayout, newDeviceQueueIndex,
7424 commandBuffer);
7425 }
7426
7427 // It is unknown how the external has modified the image, so assume every subresource has
7428 // defined content. That is unless the layout is Undefined.
7429 if (currentLayout == ImageLayout::Undefined)
7430 {
7431 setEntireContentUndefined();
7432 }
7433 else
7434 {
7435 setEntireContentDefined();
7436 }
7437 }
7438
releaseToExternal(Context * context,DeviceQueueIndex externalQueueIndex,ImageLayout desiredLayout,OutsideRenderPassCommandBuffer * commandBuffer)7439 void ImageHelper::releaseToExternal(Context *context,
7440 DeviceQueueIndex externalQueueIndex,
7441 ImageLayout desiredLayout,
7442 OutsideRenderPassCommandBuffer *commandBuffer)
7443 {
7444 ASSERT(!mIsReleasedToExternal);
7445
7446 // A layout change is unnecessary if the image that was previously acquired was never used by
7447 // GL!
7448 if (mCurrentDeviceQueueIndex.familyIndex() != externalQueueIndex.familyIndex() ||
7449 mCurrentLayout != desiredLayout)
7450 {
7451 changeLayoutAndQueue(context, getAspectFlags(), desiredLayout, externalQueueIndex,
7452 commandBuffer);
7453 }
7454
7455 mIsReleasedToExternal = true;
7456 }
7457
isReleasedToExternal() const7458 bool ImageHelper::isReleasedToExternal() const
7459 {
7460 return mIsReleasedToExternal;
7461 }
7462
toVkLevel(gl::LevelIndex levelIndexGL) const7463 LevelIndex ImageHelper::toVkLevel(gl::LevelIndex levelIndexGL) const
7464 {
7465 return gl_vk::GetLevelIndex(levelIndexGL, mFirstAllocatedLevel);
7466 }
7467
toGLLevel(LevelIndex levelIndexVk) const7468 gl::LevelIndex ImageHelper::toGLLevel(LevelIndex levelIndexVk) const
7469 {
7470 return vk_gl::GetLevelIndex(levelIndexVk, mFirstAllocatedLevel);
7471 }
7472
initImageMemoryBarrierStruct(Renderer * renderer,VkImageAspectFlags aspectMask,ImageLayout newLayout,uint32_t newQueueFamilyIndex,VkImageMemoryBarrier * imageMemoryBarrier) const7473 ANGLE_INLINE void ImageHelper::initImageMemoryBarrierStruct(
7474 Renderer *renderer,
7475 VkImageAspectFlags aspectMask,
7476 ImageLayout newLayout,
7477 uint32_t newQueueFamilyIndex,
7478 VkImageMemoryBarrier *imageMemoryBarrier) const
7479 {
7480 ASSERT(mCurrentDeviceQueueIndex.familyIndex() != QueueFamily::kInvalidIndex);
7481 ASSERT(newQueueFamilyIndex != QueueFamily::kInvalidIndex);
7482
7483 const ImageMemoryBarrierData &transitionFrom =
7484 renderer->getImageMemoryBarrierData(mCurrentLayout);
7485 const ImageMemoryBarrierData &transitionTo = renderer->getImageMemoryBarrierData(newLayout);
7486
7487 imageMemoryBarrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
7488 imageMemoryBarrier->srcAccessMask = transitionFrom.srcAccessMask;
7489 imageMemoryBarrier->dstAccessMask = transitionTo.dstAccessMask;
7490 imageMemoryBarrier->oldLayout = ConvertImageLayoutToVkImageLayout(renderer, mCurrentLayout);
7491 imageMemoryBarrier->newLayout = ConvertImageLayoutToVkImageLayout(renderer, newLayout);
7492 imageMemoryBarrier->srcQueueFamilyIndex = mCurrentDeviceQueueIndex.familyIndex();
7493 imageMemoryBarrier->dstQueueFamilyIndex = newQueueFamilyIndex;
7494 imageMemoryBarrier->image = mImage.getHandle();
7495
7496 // Transition the whole resource.
7497 imageMemoryBarrier->subresourceRange.aspectMask = aspectMask;
7498 imageMemoryBarrier->subresourceRange.baseMipLevel = 0;
7499 imageMemoryBarrier->subresourceRange.levelCount = mLevelCount;
7500 imageMemoryBarrier->subresourceRange.baseArrayLayer = 0;
7501 imageMemoryBarrier->subresourceRange.layerCount = mLayerCount;
7502 }
7503
7504 // Generalized to accept both "primary" and "secondary" command buffers.
7505 template <typename CommandBufferT>
barrierImpl(Context * context,VkImageAspectFlags aspectMask,ImageLayout newLayout,DeviceQueueIndex newDeviceQueueIndex,RefCountedEventCollector * eventCollector,CommandBufferT * commandBuffer,VkSemaphore * acquireNextImageSemaphoreOut)7506 void ImageHelper::barrierImpl(Context *context,
7507 VkImageAspectFlags aspectMask,
7508 ImageLayout newLayout,
7509 DeviceQueueIndex newDeviceQueueIndex,
7510 RefCountedEventCollector *eventCollector,
7511 CommandBufferT *commandBuffer,
7512 VkSemaphore *acquireNextImageSemaphoreOut)
7513 {
7514 Renderer *renderer = context->getRenderer();
7515 // mCurrentEvent must be invalid if useVkEventForImageBarrieris disabled.
7516 ASSERT(context->getFeatures().useVkEventForImageBarrier.enabled || !mCurrentEvent.valid());
7517
7518 // Release the ANI semaphore to caller to add to the command submission.
7519 ASSERT(acquireNextImageSemaphoreOut != nullptr || !mAcquireNextImageSemaphore.valid());
7520 if (acquireNextImageSemaphoreOut != nullptr)
7521 {
7522 *acquireNextImageSemaphoreOut = mAcquireNextImageSemaphore.release();
7523 }
7524
7525 if (mCurrentLayout == ImageLayout::SharedPresent)
7526 {
7527 // For now we always use pipelineBarrier for singlebuffer mode. We could use event here in
7528 // future.
7529 mCurrentEvent.release(context);
7530
7531 const ImageMemoryBarrierData &transition =
7532 renderer->getImageMemoryBarrierData(mCurrentLayout);
7533 VkMemoryBarrier memoryBarrier = {};
7534 memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
7535 memoryBarrier.srcAccessMask = transition.srcAccessMask;
7536 memoryBarrier.dstAccessMask = transition.dstAccessMask;
7537
7538 commandBuffer->memoryBarrier(transition.srcStageMask, transition.dstStageMask,
7539 memoryBarrier);
7540 return;
7541 }
7542
7543 // Make sure we never transition out of SharedPresent
7544 ASSERT(mCurrentLayout != ImageLayout::SharedPresent || newLayout == ImageLayout::SharedPresent);
7545
7546 const ImageMemoryBarrierData &transitionFrom =
7547 renderer->getImageMemoryBarrierData(mCurrentLayout);
7548 const ImageMemoryBarrierData &transitionTo = renderer->getImageMemoryBarrierData(newLayout);
7549
7550 VkImageMemoryBarrier imageMemoryBarrier = {};
7551 initImageMemoryBarrierStruct(renderer, aspectMask, newLayout, newDeviceQueueIndex.familyIndex(),
7552 &imageMemoryBarrier);
7553
7554 VkPipelineStageFlags dstStageMask = transitionTo.dstStageMask;
7555
7556 // Fallback to pipelineBarrier if there is no event tracking image.
7557 // VkCmdWaitEvent requires the srcQueueFamilyIndex and dstQueueFamilyIndex members of any
7558 // element of pBufferMemoryBarriers or pImageMemoryBarriers must be equal
7559 // (VUID-vkCmdWaitEvents-srcQueueFamilyIndex-02803).
7560 BarrierType barrierType =
7561 mCurrentEvent.valid() && mCurrentDeviceQueueIndex == newDeviceQueueIndex
7562 ? BarrierType::Event
7563 : BarrierType::Pipeline;
7564
7565 if (barrierType == BarrierType::Event)
7566 {
7567 // If there is an event, we use the waitEvent to do layout change. Once we have waited, the
7568 // event gets garbage collected (which is GPU completion tracked) to avoid waited again in
7569 // future. We always use DstStageMask since that is what setEvent used and
7570 // VUID-vkCmdWaitEvents-srcStageMask-01158 requires they must match.
7571 VkPipelineStageFlags srcStageMask =
7572 context->getRenderer()->getEventPipelineStageMask(mCurrentEvent);
7573 commandBuffer->imageWaitEvent(mCurrentEvent.getEvent().getHandle(), srcStageMask,
7574 dstStageMask, imageMemoryBarrier);
7575 eventCollector->emplace_back(std::move(mCurrentEvent));
7576 }
7577 else
7578 {
7579 // There might be other shaderRead operations there other than the current layout.
7580 VkPipelineStageFlags srcStageMask = transitionFrom.srcStageMask;
7581 if (mCurrentShaderReadStageMask)
7582 {
7583 srcStageMask |= mCurrentShaderReadStageMask;
7584 mCurrentShaderReadStageMask = 0;
7585 mLastNonShaderReadOnlyLayout = ImageLayout::Undefined;
7586 }
7587 commandBuffer->imageBarrier(srcStageMask, dstStageMask, imageMemoryBarrier);
7588 // We use pipelineBarrier here, no needs to wait for events any more.
7589 mCurrentEvent.release(context);
7590 }
7591
7592 mCurrentLayout = newLayout;
7593 mCurrentDeviceQueueIndex = newDeviceQueueIndex;
7594 resetSubresourcesWrittenSinceBarrier();
7595
7596 // We must release the event so that new event will be created and added. If we did not add new
7597 // event, because mCurrentEvent have been released, next barrier will automatically fallback to
7598 // pipelineBarrier. Otherwise if we keep mCurrentEvent here we may accidentally end up waiting
7599 // for an old event which creates sync hazard.
7600 ASSERT(!mCurrentEvent.valid());
7601 }
7602
7603 template void ImageHelper::barrierImpl<priv::CommandBuffer>(
7604 Context *context,
7605 VkImageAspectFlags aspectMask,
7606 ImageLayout newLayout,
7607 DeviceQueueIndex newDeviceQueueIndex,
7608 RefCountedEventCollector *eventCollector,
7609 priv::CommandBuffer *commandBuffer,
7610 VkSemaphore *acquireNextImageSemaphoreOut);
7611
setSubresourcesWrittenSinceBarrier(gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount)7612 void ImageHelper::setSubresourcesWrittenSinceBarrier(gl::LevelIndex levelStart,
7613 uint32_t levelCount,
7614 uint32_t layerStart,
7615 uint32_t layerCount)
7616 {
7617 for (uint32_t levelOffset = 0; levelOffset < levelCount; levelOffset++)
7618 {
7619 uint32_t level = levelStart.get() + levelOffset;
7620 if (layerCount >= kMaxParallelLayerWrites)
7621 {
7622 mSubresourcesWrittenSinceBarrier[level].set();
7623 }
7624 else
7625 {
7626 ImageLayerWriteMask layerMask = GetImageLayerWriteMask(layerStart, layerCount);
7627 mSubresourcesWrittenSinceBarrier[level] |= layerMask;
7628 }
7629 }
7630 }
7631
resetSubresourcesWrittenSinceBarrier()7632 void ImageHelper::resetSubresourcesWrittenSinceBarrier()
7633 {
7634 for (auto &layerWriteMask : mSubresourcesWrittenSinceBarrier)
7635 {
7636 layerWriteMask.reset();
7637 }
7638 }
7639
recordWriteBarrier(Context * context,VkImageAspectFlags aspectMask,ImageLayout newLayout,gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount,OutsideRenderPassCommandBufferHelper * commands)7640 void ImageHelper::recordWriteBarrier(Context *context,
7641 VkImageAspectFlags aspectMask,
7642 ImageLayout newLayout,
7643 gl::LevelIndex levelStart,
7644 uint32_t levelCount,
7645 uint32_t layerStart,
7646 uint32_t layerCount,
7647 OutsideRenderPassCommandBufferHelper *commands)
7648 {
7649 if (isWriteBarrierNecessary(newLayout, levelStart, levelCount, layerStart, layerCount))
7650 {
7651 ASSERT(!mCurrentEvent.valid() || !commands->hasSetEventPendingFlush(mCurrentEvent));
7652 VkSemaphore acquireNextImageSemaphore;
7653 barrierImpl(context, aspectMask, newLayout, context->getDeviceQueueIndex(),
7654 commands->getRefCountedEventCollector(), &commands->getCommandBuffer(),
7655 &acquireNextImageSemaphore);
7656
7657 if (acquireNextImageSemaphore != VK_NULL_HANDLE)
7658 {
7659 commands->setAcquireNextImageSemaphore(acquireNextImageSemaphore);
7660 }
7661 }
7662
7663 setSubresourcesWrittenSinceBarrier(levelStart, levelCount, layerStart, layerCount);
7664 }
7665
recordReadSubresourceBarrier(Context * context,VkImageAspectFlags aspectMask,ImageLayout newLayout,gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount,OutsideRenderPassCommandBufferHelper * commands)7666 void ImageHelper::recordReadSubresourceBarrier(Context *context,
7667 VkImageAspectFlags aspectMask,
7668 ImageLayout newLayout,
7669 gl::LevelIndex levelStart,
7670 uint32_t levelCount,
7671 uint32_t layerStart,
7672 uint32_t layerCount,
7673 OutsideRenderPassCommandBufferHelper *commands)
7674 {
7675 // This barrier is used for an image with both read/write permissions, including during mipmap
7676 // generation and self-copy.
7677 if (isReadSubresourceBarrierNecessary(newLayout, levelStart, levelCount, layerStart,
7678 layerCount))
7679 {
7680 ASSERT(!mCurrentEvent.valid() || !commands->hasSetEventPendingFlush(mCurrentEvent));
7681 VkSemaphore acquireNextImageSemaphore;
7682 barrierImpl(context, aspectMask, newLayout, context->getDeviceQueueIndex(),
7683 commands->getRefCountedEventCollector(), &commands->getCommandBuffer(),
7684 &acquireNextImageSemaphore);
7685
7686 if (acquireNextImageSemaphore != VK_NULL_HANDLE)
7687 {
7688 commands->setAcquireNextImageSemaphore(acquireNextImageSemaphore);
7689 }
7690 }
7691
7692 // Levels/layers being read from are also registered to avoid RAW and WAR hazards.
7693 setSubresourcesWrittenSinceBarrier(levelStart, levelCount, layerStart, layerCount);
7694 }
7695
recordReadBarrier(Context * context,VkImageAspectFlags aspectMask,ImageLayout newLayout,OutsideRenderPassCommandBufferHelper * commands)7696 void ImageHelper::recordReadBarrier(Context *context,
7697 VkImageAspectFlags aspectMask,
7698 ImageLayout newLayout,
7699 OutsideRenderPassCommandBufferHelper *commands)
7700 {
7701 if (!isReadBarrierNecessary(context->getRenderer(), newLayout))
7702 {
7703 return;
7704 }
7705
7706 ASSERT(!mCurrentEvent.valid() || !commands->hasSetEventPendingFlush(mCurrentEvent));
7707 VkSemaphore acquireNextImageSemaphore;
7708 barrierImpl(context, aspectMask, newLayout, context->getDeviceQueueIndex(),
7709 commands->getRefCountedEventCollector(), &commands->getCommandBuffer(),
7710 &acquireNextImageSemaphore);
7711
7712 if (acquireNextImageSemaphore != VK_NULL_HANDLE)
7713 {
7714 commands->setAcquireNextImageSemaphore(acquireNextImageSemaphore);
7715 }
7716 }
7717
updateLayoutAndBarrier(Context * context,VkImageAspectFlags aspectMask,ImageLayout newLayout,BarrierType barrierType,const QueueSerial & queueSerial,PipelineBarrierArray * pipelineBarriers,EventBarrierArray * eventBarriers,RefCountedEventCollector * eventCollector,VkSemaphore * semaphoreOut)7718 void ImageHelper::updateLayoutAndBarrier(Context *context,
7719 VkImageAspectFlags aspectMask,
7720 ImageLayout newLayout,
7721 BarrierType barrierType,
7722 const QueueSerial &queueSerial,
7723 PipelineBarrierArray *pipelineBarriers,
7724 EventBarrierArray *eventBarriers,
7725 RefCountedEventCollector *eventCollector,
7726 VkSemaphore *semaphoreOut)
7727 {
7728 Renderer *renderer = context->getRenderer();
7729 ASSERT(queueSerial.valid());
7730 ASSERT(!mBarrierQueueSerial.valid() ||
7731 mBarrierQueueSerial.getIndex() != queueSerial.getIndex() ||
7732 mBarrierQueueSerial.getSerial() <= queueSerial.getSerial());
7733 ASSERT(renderer->getImageMemoryBarrierData(newLayout).barrierIndex !=
7734 PipelineStage::InvalidEnum);
7735 // mCurrentEvent must be invalid if useVkEventForImageBarrieris disabled.
7736 ASSERT(renderer->getFeatures().useVkEventForImageBarrier.enabled || !mCurrentEvent.valid());
7737
7738 if (mCurrentDeviceQueueIndex != context->getDeviceQueueIndex())
7739 {
7740 // Fallback to pipelineBarrier if the VkQueue has changed.
7741 barrierType = BarrierType::Pipeline;
7742 mCurrentDeviceQueueIndex = context->getDeviceQueueIndex();
7743 }
7744 else if (!mCurrentEvent.valid())
7745 {
7746 // Fallback to pipelineBarrier if there is no event tracking image.
7747 barrierType = BarrierType::Pipeline;
7748 }
7749
7750 // Once you transition to ImageLayout::SharedPresent, you never transition out of it.
7751 if (mCurrentLayout == ImageLayout::SharedPresent)
7752 {
7753 newLayout = ImageLayout::SharedPresent;
7754 }
7755
7756 if (newLayout == mCurrentLayout)
7757 {
7758 if (mBarrierQueueSerial == queueSerial)
7759 {
7760 ASSERT(!mAcquireNextImageSemaphore.valid());
7761 // If there is no layout change and the previous layout change happened in the same
7762 // render pass, then early out do nothing. This can happen when the same image is
7763 // attached to the multiple attachments of the framebuffer.
7764 return;
7765 }
7766
7767 const ImageMemoryBarrierData &layoutData =
7768 renderer->getImageMemoryBarrierData(mCurrentLayout);
7769 // RAR is not a hazard and doesn't require a barrier, especially as the image layout hasn't
7770 // changed. The following asserts that such a barrier is not attempted.
7771 ASSERT(HasResourceWriteAccess(layoutData.type));
7772
7773 // No layout change, only memory barrier is required
7774 if (barrierType == BarrierType::Event)
7775 {
7776 eventBarriers->addMemoryEvent(renderer, mCurrentEvent, layoutData.dstStageMask,
7777 layoutData.dstAccessMask);
7778 // Garbage collect the event, which tracks GPU completion automatically.
7779 eventCollector->emplace_back(std::move(mCurrentEvent));
7780 }
7781 else
7782 {
7783 pipelineBarriers->mergeMemoryBarrier(layoutData.barrierIndex, layoutData.dstStageMask,
7784 layoutData.dstStageMask, layoutData.srcAccessMask,
7785 layoutData.dstAccessMask);
7786
7787 // Release it. No need to garbage collect since we did not use the event here. ALl
7788 // previous use of event should garbage tracked already.
7789 mCurrentEvent.release(context);
7790 }
7791 mBarrierQueueSerial = queueSerial;
7792 }
7793 else
7794 {
7795 const ImageMemoryBarrierData &transitionFrom =
7796 renderer->getImageMemoryBarrierData(mCurrentLayout);
7797 const ImageMemoryBarrierData &transitionTo = renderer->getImageMemoryBarrierData(newLayout);
7798 VkPipelineStageFlags srcStageMask = transitionFrom.srcStageMask;
7799 VkPipelineStageFlags dstStageMask = transitionTo.dstStageMask;
7800
7801 if (transitionFrom.layout == transitionTo.layout && IsShaderReadOnlyLayout(transitionTo) &&
7802 mBarrierQueueSerial == queueSerial)
7803 {
7804 // If we are switching between different shader stage reads of the same render pass,
7805 // then there is no actual layout change or access type change. We only need a barrier
7806 // if we are making a read that is from a new stage. Also note that we do barrier
7807 // against previous non-shaderRead layout. We do not barrier between one shaderRead and
7808 // another shaderRead.
7809 bool isNewReadStage = (mCurrentShaderReadStageMask & dstStageMask) != dstStageMask;
7810 if (!isNewReadStage)
7811 {
7812 ASSERT(!mAcquireNextImageSemaphore.valid());
7813 return;
7814 }
7815
7816 ASSERT(!mLastNonShaderReadOnlyEvent.valid() ||
7817 mLastNonShaderReadOnlyEvent.getEventStage() ==
7818 GetImageLayoutEventStage(mLastNonShaderReadOnlyLayout));
7819 if (!mLastNonShaderReadOnlyEvent.valid())
7820 {
7821 barrierType = BarrierType::Pipeline;
7822 }
7823
7824 if (barrierType == BarrierType::Event)
7825 {
7826 // If we already inserted a barrier in the same renderPass, we has to add
7827 // the new stage mask to the existing VkCmdWaitEvent call, otherwise VVL will
7828 // complain.
7829 eventBarriers->addAdditionalStageAccess(mLastNonShaderReadOnlyEvent, dstStageMask,
7830 transitionTo.dstAccessMask);
7831 eventCollector->emplace_back(mLastNonShaderReadOnlyEvent);
7832 }
7833 else
7834 {
7835 const ImageMemoryBarrierData &layoutData =
7836 renderer->getImageMemoryBarrierData(mLastNonShaderReadOnlyLayout);
7837 pipelineBarriers->mergeMemoryBarrier(
7838 transitionTo.barrierIndex, layoutData.srcStageMask, dstStageMask,
7839 layoutData.srcAccessMask, transitionTo.dstAccessMask);
7840 }
7841
7842 mBarrierQueueSerial = queueSerial;
7843 // Accumulate new read stage.
7844 mCurrentShaderReadStageMask |= dstStageMask;
7845
7846 // Since we used pipelineBarrier, release the event now to avoid wait for the
7847 // event again.
7848 if (mCurrentEvent.valid())
7849 {
7850 eventCollector->emplace_back(std::move(mCurrentEvent));
7851 }
7852 }
7853 else
7854 {
7855 VkImageMemoryBarrier imageMemoryBarrier = {};
7856 initImageMemoryBarrierStruct(renderer, aspectMask, newLayout,
7857 context->getDeviceQueueIndex().familyIndex(),
7858 &imageMemoryBarrier);
7859
7860 if (transitionFrom.layout == transitionTo.layout &&
7861 IsShaderReadOnlyLayout(transitionTo))
7862 {
7863 // If we are transiting within shaderReadOnly layout, i.e. reading from different
7864 // shader stages, VkEvent can't handle this right now. In order for VkEvent to
7865 // handle this properly we have to wait for the previous shaderReadOnly layout
7866 // transition event and add a new memoryBarrier. But we may have lost that event
7867 // already if it has been used in a new render pass (because we have to update the
7868 // event even if there is no barrier needed). To workaround this issue we fall back
7869 // to pipelineBarrier for now.
7870 barrierType = BarrierType::Pipeline;
7871 }
7872 else if (mBarrierQueueSerial == queueSerial)
7873 {
7874 // If we already inserted a barrier in this render pass, force to use
7875 // pipelineBarrier. Otherwise we will end up inserting a VkCmdWaitEvent that has not
7876 // been set (See https://issuetracker.google.com/333419317 for example).
7877 barrierType = BarrierType::Pipeline;
7878 }
7879
7880 // if we transition from shaderReadOnly, we must add in stashed shader stage masks since
7881 // there might be outstanding shader reads from stages other than current layout. We do
7882 // not insert barrier between one shaderRead to another shaderRead
7883 if (mCurrentShaderReadStageMask)
7884 {
7885 if ((mCurrentShaderReadStageMask & srcStageMask) != mCurrentShaderReadStageMask)
7886 {
7887 // mCurrentShaderReadStageMask has more bits than srcStageMask. This means it
7888 // has been used by more than one shader stage in the same render pass. These
7889 // two usages are tracked by two different ImageLayout, even though underline
7890 // VkImageLayout is the same. This means two different RefCountedEvents since
7891 // each RefCountedEvent is associated with one ImageLayout. When we transit out
7892 // of this layout, we must wait for all reads to finish. But Right now
7893 // ImageHelper only keep track of the last read. To workaround this problem we
7894 // use pipelineBarrier in this case.
7895 barrierType = BarrierType::Pipeline;
7896 srcStageMask |= mCurrentShaderReadStageMask;
7897 }
7898 mCurrentShaderReadStageMask = 0;
7899 mLastNonShaderReadOnlyLayout = ImageLayout::Undefined;
7900 if (mLastNonShaderReadOnlyEvent.valid())
7901 {
7902 mLastNonShaderReadOnlyEvent.release(context);
7903 }
7904 }
7905
7906 // If we are transition into shaderRead layout, remember the last
7907 // non-shaderRead layout here.
7908 const bool isShaderReadOnly = IsShaderReadOnlyLayout(transitionTo);
7909 if (isShaderReadOnly)
7910 {
7911 mLastNonShaderReadOnlyEvent.release(context);
7912 mLastNonShaderReadOnlyLayout = mCurrentLayout;
7913 mCurrentShaderReadStageMask = dstStageMask;
7914 }
7915
7916 if (barrierType == BarrierType::Event)
7917 {
7918 eventBarriers->addImageEvent(renderer, mCurrentEvent, dstStageMask,
7919 imageMemoryBarrier);
7920 if (isShaderReadOnly)
7921 {
7922 mLastNonShaderReadOnlyEvent = mCurrentEvent;
7923 }
7924 eventCollector->emplace_back(std::move(mCurrentEvent));
7925 }
7926 else
7927 {
7928 pipelineBarriers->mergeImageBarrier(transitionTo.barrierIndex, srcStageMask,
7929 dstStageMask, imageMemoryBarrier);
7930 mCurrentEvent.release(context);
7931 }
7932
7933 mBarrierQueueSerial = queueSerial;
7934 }
7935 mCurrentLayout = newLayout;
7936 }
7937
7938 *semaphoreOut = mAcquireNextImageSemaphore.release();
7939 // We must release the event so that new event will be created and added. If we did not add new
7940 // event, because mCurrentEvent have been released, next barrier will automatically fallback to
7941 // pipelineBarrier. Otherwise if we keep mCurrentEvent here we may accidentally end up waiting
7942 // for an old event which creates sync hazard.
7943 ASSERT(!mCurrentEvent.valid());
7944 }
7945
setCurrentRefCountedEvent(Context * context,EventMaps & eventMaps)7946 void ImageHelper::setCurrentRefCountedEvent(Context *context, EventMaps &eventMaps)
7947 {
7948 ASSERT(context->getFeatures().useVkEventForImageBarrier.enabled);
7949
7950 // If there is already an event, release it first.
7951 mCurrentEvent.release(context);
7952
7953 // VkCmdSetEvent can remove the unnecessary GPU pipeline bubble that comes from false dependency
7954 // between fragment and vertex/transfer/compute stages. But it also comes with higher overhead.
7955 // In order to strike the balance, we exclude the images that are only used by one group of
7956 // pipeline stages in the past N references, where N is the heuristic window that we keep track
7957 // of. Use of VkEvent will not be beneficial if it is only accessed by one group of stages since
7958 // execution within the group is expected to be non-overlap.
7959 if (mPipelineStageAccessHeuristic == kPipelineStageAccessFragmentOnly ||
7960 mPipelineStageAccessHeuristic == kPipelineStageAccessPreFragmentOnly ||
7961 mPipelineStageAccessHeuristic == kPipelineStageAccessComputeOnly)
7962 {
7963 return;
7964 }
7965
7966 // Create the event if we have not yet so. Otherwise just use the already created event. This
7967 // means all images used in the same render pass that has the same layout will be tracked by the
7968 // same event.
7969 EventStage stage = GetImageLayoutEventStage(mCurrentLayout);
7970 if (!eventMaps.map[stage].valid())
7971 {
7972 if (!eventMaps.map[stage].init(context, stage))
7973 {
7974 // If VkEvent creation fail, we fallback to pipelineBarrier
7975 return;
7976 }
7977 eventMaps.mask.set(stage);
7978 }
7979
7980 // Copy the event to mCurrentEvent so that we can wait for it in future. This will add extra
7981 // refcount to the underlying VkEvent.
7982 mCurrentEvent = eventMaps.map[stage];
7983 }
7984
updatePipelineStageAccessHistory()7985 void ImageHelper::updatePipelineStageAccessHistory()
7986 {
7987 const ImageMemoryBarrierData &barrierData = kImageMemoryBarrierData[mCurrentLayout];
7988 mPipelineStageAccessHeuristic.onAccess(barrierData.pipelineStageGroup);
7989 }
7990
clearColor(Renderer * renderer,const VkClearColorValue & color,LevelIndex baseMipLevelVk,uint32_t levelCount,uint32_t baseArrayLayer,uint32_t layerCount,OutsideRenderPassCommandBuffer * commandBuffer)7991 void ImageHelper::clearColor(Renderer *renderer,
7992 const VkClearColorValue &color,
7993 LevelIndex baseMipLevelVk,
7994 uint32_t levelCount,
7995 uint32_t baseArrayLayer,
7996 uint32_t layerCount,
7997 OutsideRenderPassCommandBuffer *commandBuffer)
7998 {
7999 ASSERT(valid());
8000
8001 ASSERT(mCurrentLayout == ImageLayout::TransferDst ||
8002 mCurrentLayout == ImageLayout::SharedPresent);
8003
8004 VkImageSubresourceRange range = {};
8005 range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8006 range.baseMipLevel = baseMipLevelVk.get();
8007 range.levelCount = levelCount;
8008 range.baseArrayLayer = baseArrayLayer;
8009 range.layerCount = layerCount;
8010
8011 if (mImageType == VK_IMAGE_TYPE_3D)
8012 {
8013 ASSERT(baseArrayLayer == 0);
8014 ASSERT(layerCount == 1 ||
8015 layerCount == static_cast<uint32_t>(getLevelExtents(baseMipLevelVk).depth));
8016 range.layerCount = 1;
8017 }
8018
8019 commandBuffer->clearColorImage(mImage, getCurrentLayout(renderer), color, 1, &range);
8020 }
8021
clearDepthStencil(Renderer * renderer,VkImageAspectFlags clearAspectFlags,const VkClearDepthStencilValue & depthStencil,LevelIndex baseMipLevelVk,uint32_t levelCount,uint32_t baseArrayLayer,uint32_t layerCount,OutsideRenderPassCommandBuffer * commandBuffer)8022 void ImageHelper::clearDepthStencil(Renderer *renderer,
8023 VkImageAspectFlags clearAspectFlags,
8024 const VkClearDepthStencilValue &depthStencil,
8025 LevelIndex baseMipLevelVk,
8026 uint32_t levelCount,
8027 uint32_t baseArrayLayer,
8028 uint32_t layerCount,
8029 OutsideRenderPassCommandBuffer *commandBuffer)
8030 {
8031 ASSERT(valid());
8032
8033 ASSERT(mCurrentLayout == ImageLayout::TransferDst);
8034
8035 VkImageSubresourceRange range = {};
8036 range.aspectMask = clearAspectFlags;
8037 range.baseMipLevel = baseMipLevelVk.get();
8038 range.levelCount = levelCount;
8039 range.baseArrayLayer = baseArrayLayer;
8040 range.layerCount = layerCount;
8041
8042 if (mImageType == VK_IMAGE_TYPE_3D)
8043 {
8044 ASSERT(baseArrayLayer == 0);
8045 ASSERT(layerCount == 1 ||
8046 layerCount == static_cast<uint32_t>(getLevelExtents(baseMipLevelVk).depth));
8047 range.layerCount = 1;
8048 }
8049
8050 commandBuffer->clearDepthStencilImage(mImage, getCurrentLayout(renderer), depthStencil, 1,
8051 &range);
8052 }
8053
clear(Renderer * renderer,VkImageAspectFlags aspectFlags,const VkClearValue & value,LevelIndex mipLevel,uint32_t baseArrayLayer,uint32_t layerCount,OutsideRenderPassCommandBuffer * commandBuffer)8054 void ImageHelper::clear(Renderer *renderer,
8055 VkImageAspectFlags aspectFlags,
8056 const VkClearValue &value,
8057 LevelIndex mipLevel,
8058 uint32_t baseArrayLayer,
8059 uint32_t layerCount,
8060 OutsideRenderPassCommandBuffer *commandBuffer)
8061 {
8062 const angle::Format &angleFormat = getActualFormat();
8063 bool isDepthStencil = angleFormat.hasDepthOrStencilBits();
8064
8065 if (isDepthStencil)
8066 {
8067 clearDepthStencil(renderer, aspectFlags, value.depthStencil, mipLevel, 1, baseArrayLayer,
8068 layerCount, commandBuffer);
8069 }
8070 else
8071 {
8072 ASSERT(!angleFormat.isBlock);
8073
8074 clearColor(renderer, value.color, mipLevel, 1, baseArrayLayer, layerCount, commandBuffer);
8075 }
8076 }
8077
clearEmulatedChannels(ContextVk * contextVk,VkColorComponentFlags colorMaskFlags,const VkClearValue & value,LevelIndex mipLevel,uint32_t baseArrayLayer,uint32_t layerCount)8078 angle::Result ImageHelper::clearEmulatedChannels(ContextVk *contextVk,
8079 VkColorComponentFlags colorMaskFlags,
8080 const VkClearValue &value,
8081 LevelIndex mipLevel,
8082 uint32_t baseArrayLayer,
8083 uint32_t layerCount)
8084 {
8085 const gl::Extents levelExtents = getLevelExtents(mipLevel);
8086
8087 if (levelExtents.depth > 1)
8088 {
8089 // Currently not implemented for 3D textures
8090 UNIMPLEMENTED();
8091 return angle::Result::Continue;
8092 }
8093
8094 UtilsVk::ClearImageParameters params = {};
8095 params.clearArea = {0, 0, levelExtents.width, levelExtents.height};
8096 params.dstMip = mipLevel;
8097 params.colorMaskFlags = colorMaskFlags;
8098 params.colorClearValue = value.color;
8099
8100 for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex)
8101 {
8102 params.dstLayer = baseArrayLayer + layerIndex;
8103
8104 ANGLE_TRY(contextVk->getUtils().clearImage(contextVk, this, params));
8105 }
8106
8107 return angle::Result::Continue;
8108 }
8109
8110 // static
Copy(Renderer * renderer,ImageHelper * srcImage,ImageHelper * dstImage,const gl::Offset & srcOffset,const gl::Offset & dstOffset,const gl::Extents & copySize,const VkImageSubresourceLayers & srcSubresource,const VkImageSubresourceLayers & dstSubresource,OutsideRenderPassCommandBuffer * commandBuffer)8111 void ImageHelper::Copy(Renderer *renderer,
8112 ImageHelper *srcImage,
8113 ImageHelper *dstImage,
8114 const gl::Offset &srcOffset,
8115 const gl::Offset &dstOffset,
8116 const gl::Extents ©Size,
8117 const VkImageSubresourceLayers &srcSubresource,
8118 const VkImageSubresourceLayers &dstSubresource,
8119 OutsideRenderPassCommandBuffer *commandBuffer)
8120 {
8121 ASSERT(commandBuffer->valid() && srcImage->valid() && dstImage->valid());
8122
8123 ASSERT(srcImage->getCurrentLayout(renderer) == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
8124 ASSERT(dstImage->getCurrentLayout(renderer) == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
8125
8126 VkImageCopy region = {};
8127 region.srcSubresource = srcSubresource;
8128 region.srcOffset.x = srcOffset.x;
8129 region.srcOffset.y = srcOffset.y;
8130 region.srcOffset.z = srcOffset.z;
8131 region.dstSubresource = dstSubresource;
8132 region.dstOffset.x = dstOffset.x;
8133 region.dstOffset.y = dstOffset.y;
8134 region.dstOffset.z = dstOffset.z;
8135 region.extent.width = copySize.width;
8136 region.extent.height = copySize.height;
8137 region.extent.depth = copySize.depth;
8138
8139 commandBuffer->copyImage(srcImage->getImage(), srcImage->getCurrentLayout(renderer),
8140 dstImage->getImage(), dstImage->getCurrentLayout(renderer), 1,
8141 ®ion);
8142 }
8143
8144 // static
CopyImageSubData(const gl::Context * context,ImageHelper * srcImage,GLint srcLevel,GLint srcX,GLint srcY,GLint srcZ,ImageHelper * dstImage,GLint dstLevel,GLint dstX,GLint dstY,GLint dstZ,GLsizei srcWidth,GLsizei srcHeight,GLsizei srcDepth)8145 angle::Result ImageHelper::CopyImageSubData(const gl::Context *context,
8146 ImageHelper *srcImage,
8147 GLint srcLevel,
8148 GLint srcX,
8149 GLint srcY,
8150 GLint srcZ,
8151 ImageHelper *dstImage,
8152 GLint dstLevel,
8153 GLint dstX,
8154 GLint dstY,
8155 GLint dstZ,
8156 GLsizei srcWidth,
8157 GLsizei srcHeight,
8158 GLsizei srcDepth)
8159 {
8160 ContextVk *contextVk = GetImpl(context);
8161 Renderer *renderer = contextVk->getRenderer();
8162
8163 VkImageTiling srcTilingMode = srcImage->getTilingMode();
8164 VkImageTiling destTilingMode = dstImage->getTilingMode();
8165
8166 const gl::LevelIndex srcLevelGL = gl::LevelIndex(srcLevel);
8167 const gl::LevelIndex dstLevelGL = gl::LevelIndex(dstLevel);
8168
8169 if (CanCopyWithTransferForCopyImage(renderer, srcImage, srcTilingMode, dstImage,
8170 destTilingMode))
8171 {
8172 bool isSrc3D = srcImage->getType() == VK_IMAGE_TYPE_3D;
8173 bool isDst3D = dstImage->getType() == VK_IMAGE_TYPE_3D;
8174 const VkImageAspectFlags aspectFlags = srcImage->getAspectFlags();
8175
8176 ASSERT(srcImage->getAspectFlags() == dstImage->getAspectFlags());
8177
8178 VkImageCopy region = {};
8179
8180 region.srcSubresource.aspectMask = aspectFlags;
8181 region.srcSubresource.mipLevel = srcImage->toVkLevel(srcLevelGL).get();
8182 region.srcSubresource.baseArrayLayer = isSrc3D ? 0 : srcZ;
8183 region.srcSubresource.layerCount = isSrc3D ? 1 : srcDepth;
8184
8185 region.dstSubresource.aspectMask = aspectFlags;
8186 region.dstSubresource.mipLevel = dstImage->toVkLevel(dstLevelGL).get();
8187 region.dstSubresource.baseArrayLayer = isDst3D ? 0 : dstZ;
8188 region.dstSubresource.layerCount = isDst3D ? 1 : srcDepth;
8189
8190 region.srcOffset.x = srcX;
8191 region.srcOffset.y = srcY;
8192 region.srcOffset.z = isSrc3D ? srcZ : 0;
8193 region.dstOffset.x = dstX;
8194 region.dstOffset.y = dstY;
8195 region.dstOffset.z = isDst3D ? dstZ : 0;
8196 region.extent.width = srcWidth;
8197 region.extent.height = srcHeight;
8198 region.extent.depth = (isSrc3D || isDst3D) ? srcDepth : 1;
8199
8200 CommandBufferAccess access;
8201 if (srcImage == dstImage)
8202 {
8203 access.onImageSelfCopy(srcLevelGL, 1, region.srcSubresource.baseArrayLayer,
8204 region.srcSubresource.layerCount, dstLevelGL, 1,
8205 region.dstSubresource.baseArrayLayer,
8206 region.dstSubresource.layerCount, aspectFlags, srcImage);
8207 }
8208 else
8209 {
8210 access.onImageTransferRead(aspectFlags, srcImage);
8211 access.onImageTransferWrite(dstLevelGL, 1, region.dstSubresource.baseArrayLayer,
8212 region.dstSubresource.layerCount, aspectFlags, dstImage);
8213 }
8214
8215 OutsideRenderPassCommandBuffer *commandBuffer;
8216 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
8217
8218 ASSERT(srcImage->valid() && dstImage->valid());
8219 ASSERT(srcImage->getCurrentLayout(renderer) == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL ||
8220 srcImage->getCurrentLayout(renderer) == VK_IMAGE_LAYOUT_GENERAL);
8221 ASSERT(dstImage->getCurrentLayout(renderer) == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL ||
8222 dstImage->getCurrentLayout(renderer) == VK_IMAGE_LAYOUT_GENERAL);
8223
8224 commandBuffer->copyImage(srcImage->getImage(), srcImage->getCurrentLayout(renderer),
8225 dstImage->getImage(), dstImage->getCurrentLayout(renderer), 1,
8226 ®ion);
8227 }
8228 else if (!srcImage->getIntendedFormat().isBlock && !dstImage->getIntendedFormat().isBlock)
8229 {
8230 // The source and destination image formats may be using a fallback in the case of RGB
8231 // images. A compute shader is used in such a case to perform the copy.
8232 UtilsVk &utilsVk = contextVk->getUtils();
8233
8234 UtilsVk::CopyImageBitsParameters params;
8235 params.srcOffset[0] = srcX;
8236 params.srcOffset[1] = srcY;
8237 params.srcOffset[2] = srcZ;
8238 params.srcLevel = srcLevelGL;
8239 params.dstOffset[0] = dstX;
8240 params.dstOffset[1] = dstY;
8241 params.dstOffset[2] = dstZ;
8242 params.dstLevel = dstLevelGL;
8243 params.copyExtents[0] = srcWidth;
8244 params.copyExtents[1] = srcHeight;
8245 params.copyExtents[2] = srcDepth;
8246
8247 ANGLE_TRY(utilsVk.copyImageBits(contextVk, dstImage, srcImage, params));
8248 }
8249 else
8250 {
8251 // No support for emulated compressed formats.
8252 UNIMPLEMENTED();
8253 ANGLE_VK_CHECK(contextVk, false, VK_ERROR_FEATURE_NOT_PRESENT);
8254 }
8255
8256 return angle::Result::Continue;
8257 }
8258
generateMipmapsWithBlit(ContextVk * contextVk,LevelIndex baseLevel,LevelIndex maxLevel)8259 angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk,
8260 LevelIndex baseLevel,
8261 LevelIndex maxLevel)
8262 {
8263 Renderer *renderer = contextVk->getRenderer();
8264
8265 CommandBufferAccess access;
8266 gl::LevelIndex baseLevelGL = toGLLevel(baseLevel);
8267 access.onImageTransferWrite(baseLevelGL + 1, maxLevel.get(), 0, mLayerCount,
8268 VK_IMAGE_ASPECT_COLOR_BIT, this);
8269
8270 OutsideRenderPassCommandBuffer *commandBuffer;
8271 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
8272
8273 // We are able to use blitImage since the image format we are using supports it.
8274 int32_t mipWidth = mExtents.width;
8275 int32_t mipHeight = mExtents.height;
8276 int32_t mipDepth = mExtents.depth;
8277
8278 // Manually manage the image memory barrier because it uses a lot more parameters than our
8279 // usual one.
8280 VkImageMemoryBarrier barrier = {};
8281 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
8282 barrier.image = mImage.getHandle();
8283 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
8284 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
8285 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8286 barrier.subresourceRange.baseArrayLayer = 0;
8287 barrier.subresourceRange.layerCount = mLayerCount;
8288 barrier.subresourceRange.levelCount = 1;
8289
8290 const VkFilter filter =
8291 gl_vk::GetFilter(CalculateGenerateMipmapFilter(contextVk, getActualFormatID()));
8292
8293 for (LevelIndex mipLevel(1); mipLevel <= LevelIndex(mLevelCount); ++mipLevel)
8294 {
8295 int32_t nextMipWidth = std::max<int32_t>(1, mipWidth >> 1);
8296 int32_t nextMipHeight = std::max<int32_t>(1, mipHeight >> 1);
8297 int32_t nextMipDepth = std::max<int32_t>(1, mipDepth >> 1);
8298
8299 if (mipLevel > baseLevel && mipLevel <= maxLevel)
8300 {
8301 barrier.subresourceRange.baseMipLevel = mipLevel.get() - 1;
8302 barrier.oldLayout = getCurrentLayout(renderer);
8303 barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
8304 barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
8305 barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
8306
8307 // We can do it for all layers at once.
8308 commandBuffer->imageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
8309 VK_PIPELINE_STAGE_TRANSFER_BIT, barrier);
8310 VkImageBlit blit = {};
8311 blit.srcOffsets[0] = {0, 0, 0};
8312 blit.srcOffsets[1] = {mipWidth, mipHeight, mipDepth};
8313 blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8314 blit.srcSubresource.mipLevel = mipLevel.get() - 1;
8315 blit.srcSubresource.baseArrayLayer = 0;
8316 blit.srcSubresource.layerCount = mLayerCount;
8317 blit.dstOffsets[0] = {0, 0, 0};
8318 blit.dstOffsets[1] = {nextMipWidth, nextMipHeight, nextMipDepth};
8319 blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8320 blit.dstSubresource.mipLevel = mipLevel.get();
8321 blit.dstSubresource.baseArrayLayer = 0;
8322 blit.dstSubresource.layerCount = mLayerCount;
8323
8324 commandBuffer->blitImage(mImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, mImage,
8325 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, filter);
8326 }
8327 mipWidth = nextMipWidth;
8328 mipHeight = nextMipHeight;
8329 mipDepth = nextMipDepth;
8330 }
8331
8332 // Transition all mip level to the same layout so we can declare our whole image layout to one
8333 // ImageLayout. FragmentShaderReadOnly is picked here since this is the most reasonable usage
8334 // after glGenerateMipmap call.
8335 barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
8336 barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
8337 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
8338 if (baseLevel.get() > 0)
8339 {
8340 // [0:baseLevel-1] from TRANSFER_DST to SHADER_READ
8341 barrier.subresourceRange.baseMipLevel = 0;
8342 barrier.subresourceRange.levelCount = baseLevel.get();
8343 commandBuffer->imageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
8344 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, barrier);
8345 }
8346 // [maxLevel:mLevelCount-1] from TRANSFER_DST to SHADER_READ
8347 ASSERT(mLevelCount > maxLevel.get());
8348 barrier.subresourceRange.baseMipLevel = maxLevel.get();
8349 barrier.subresourceRange.levelCount = mLevelCount - maxLevel.get();
8350 commandBuffer->imageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
8351 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, barrier);
8352 // [baseLevel:maxLevel-1] from TRANSFER_SRC to SHADER_READ
8353 barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
8354 barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
8355 barrier.subresourceRange.baseMipLevel = baseLevel.get();
8356 barrier.subresourceRange.levelCount = maxLevel.get() - baseLevel.get();
8357 commandBuffer->imageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
8358 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, barrier);
8359
8360 // This is just changing the internal state of the image helper so that the next call
8361 // to changeLayout will use this layout as the "oldLayout" argument.
8362 // mLastNonShaderReadOnlyLayout is used to ensure previous write are made visible to reads,
8363 // since the only write here is transfer, hence mLastNonShaderReadOnlyLayout is set to
8364 // ImageLayout::TransferDst.
8365 setCurrentImageLayout(renderer, ImageLayout::FragmentShaderReadOnly);
8366
8367 contextVk->trackImageWithOutsideRenderPassEvent(this);
8368
8369 return angle::Result::Continue;
8370 }
8371
resolve(ImageHelper * dst,const VkImageResolve & region,OutsideRenderPassCommandBuffer * commandBuffer)8372 void ImageHelper::resolve(ImageHelper *dst,
8373 const VkImageResolve ®ion,
8374 OutsideRenderPassCommandBuffer *commandBuffer)
8375 {
8376 ASSERT(mCurrentLayout == ImageLayout::TransferSrc ||
8377 mCurrentLayout == ImageLayout::SharedPresent);
8378 commandBuffer->resolveImage(getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst->getImage(),
8379 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
8380 }
8381
removeSingleSubresourceStagedUpdates(ContextVk * contextVk,gl::LevelIndex levelIndexGL,uint32_t layerIndex,uint32_t layerCount)8382 void ImageHelper::removeSingleSubresourceStagedUpdates(ContextVk *contextVk,
8383 gl::LevelIndex levelIndexGL,
8384 uint32_t layerIndex,
8385 uint32_t layerCount)
8386 {
8387 mCurrentSingleClearValue.reset();
8388
8389 // Find any staged updates for this index and remove them from the pending list.
8390 std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(levelIndexGL);
8391 if (levelUpdates == nullptr)
8392 {
8393 return;
8394 }
8395
8396 for (size_t index = 0; index < levelUpdates->size();)
8397 {
8398 auto update = levelUpdates->begin() + index;
8399 if (update->matchesLayerRange(layerIndex, layerCount))
8400 {
8401 // Update total staging buffer size
8402 mTotalStagedBufferUpdateSize -= update->updateSource == UpdateSource::Buffer
8403 ? update->data.buffer.bufferHelper->getSize()
8404 : 0;
8405 update->release(contextVk->getRenderer());
8406 levelUpdates->erase(update);
8407 }
8408 else
8409 {
8410 index++;
8411 }
8412 }
8413 }
8414
removeSingleStagedClearAfterInvalidate(gl::LevelIndex levelIndexGL,uint32_t layerIndex,uint32_t layerCount)8415 void ImageHelper::removeSingleStagedClearAfterInvalidate(gl::LevelIndex levelIndexGL,
8416 uint32_t layerIndex,
8417 uint32_t layerCount)
8418 {
8419 // When this function is called, it's expected that there may be at most one
8420 // ClearAfterInvalidate update pending to this subresource, and that's a color clear due to
8421 // emulated channels after invalidate. This function removes that update.
8422
8423 std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(levelIndexGL);
8424 if (levelUpdates == nullptr)
8425 {
8426 return;
8427 }
8428
8429 for (size_t index = 0; index < levelUpdates->size(); ++index)
8430 {
8431 auto update = levelUpdates->begin() + index;
8432 if (update->updateSource == UpdateSource::ClearAfterInvalidate &&
8433 update->matchesLayerRange(layerIndex, layerCount))
8434 {
8435 // It's a clear, so doesn't need to be released.
8436 levelUpdates->erase(update);
8437 // There's only one such clear possible.
8438 return;
8439 }
8440 }
8441 }
8442
removeStagedUpdates(Context * context,gl::LevelIndex levelGLStart,gl::LevelIndex levelGLEnd)8443 void ImageHelper::removeStagedUpdates(Context *context,
8444 gl::LevelIndex levelGLStart,
8445 gl::LevelIndex levelGLEnd)
8446 {
8447 ASSERT(validateSubresourceUpdateRefCountsConsistent());
8448
8449 // Remove all updates to levels [start, end].
8450 for (gl::LevelIndex level = levelGLStart; level <= levelGLEnd; ++level)
8451 {
8452 std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(level);
8453 if (levelUpdates == nullptr)
8454 {
8455 ASSERT(static_cast<size_t>(level.get()) >= mSubresourceUpdates.size());
8456 return;
8457 }
8458
8459 for (SubresourceUpdate &update : *levelUpdates)
8460 {
8461 // Update total staging buffer size
8462 mTotalStagedBufferUpdateSize -= update.updateSource == UpdateSource::Buffer
8463 ? update.data.buffer.bufferHelper->getSize()
8464 : 0;
8465 update.release(context->getRenderer());
8466 }
8467
8468 levelUpdates->clear();
8469 }
8470
8471 ASSERT(validateSubresourceUpdateRefCountsConsistent());
8472 }
8473
stageSubresourceUpdateImpl(ContextVk * contextVk,const gl::ImageIndex & index,const gl::Extents & glExtents,const gl::Offset & offset,const gl::InternalFormat & formatInfo,const gl::PixelUnpackState & unpack,GLenum type,const uint8_t * pixels,const Format & vkFormat,ImageAccess access,const GLuint inputRowPitch,const GLuint inputDepthPitch,const GLuint inputSkipBytes,ApplyImageUpdate applyUpdate,bool * updateAppliedImmediatelyOut)8474 angle::Result ImageHelper::stageSubresourceUpdateImpl(ContextVk *contextVk,
8475 const gl::ImageIndex &index,
8476 const gl::Extents &glExtents,
8477 const gl::Offset &offset,
8478 const gl::InternalFormat &formatInfo,
8479 const gl::PixelUnpackState &unpack,
8480 GLenum type,
8481 const uint8_t *pixels,
8482 const Format &vkFormat,
8483 ImageAccess access,
8484 const GLuint inputRowPitch,
8485 const GLuint inputDepthPitch,
8486 const GLuint inputSkipBytes,
8487 ApplyImageUpdate applyUpdate,
8488 bool *updateAppliedImmediatelyOut)
8489 {
8490 *updateAppliedImmediatelyOut = false;
8491
8492 const angle::Format &storageFormat = vkFormat.getActualImageFormat(access);
8493
8494 size_t outputRowPitch;
8495 size_t outputDepthPitch;
8496 size_t stencilAllocationSize = 0;
8497 uint32_t bufferRowLength;
8498 uint32_t bufferImageHeight;
8499 size_t allocationSize;
8500
8501 LoadImageFunctionInfo loadFunctionInfo = vkFormat.getTextureLoadFunction(access, type);
8502 LoadImageFunction stencilLoadFunction = nullptr;
8503
8504 bool useComputeTransCoding = false;
8505 if (storageFormat.isBlock)
8506 {
8507 const gl::InternalFormat &storageFormatInfo = vkFormat.getInternalFormatInfo(type);
8508 GLuint rowPitch;
8509 GLuint depthPitch;
8510 GLuint totalSize;
8511
8512 ANGLE_VK_CHECK_MATH(contextVk, storageFormatInfo.computeCompressedImageRowPitch(
8513 glExtents.width, &rowPitch));
8514 ANGLE_VK_CHECK_MATH(contextVk, storageFormatInfo.computeCompressedImageDepthPitch(
8515 glExtents.height, rowPitch, &depthPitch));
8516
8517 ANGLE_VK_CHECK_MATH(contextVk,
8518 storageFormatInfo.computeCompressedImageSize(glExtents, &totalSize));
8519
8520 outputRowPitch = rowPitch;
8521 outputDepthPitch = depthPitch;
8522 allocationSize = totalSize;
8523
8524 ANGLE_VK_CHECK_MATH(
8525 contextVk, storageFormatInfo.computeBufferRowLength(glExtents.width, &bufferRowLength));
8526 ANGLE_VK_CHECK_MATH(contextVk, storageFormatInfo.computeBufferImageHeight(
8527 glExtents.height, &bufferImageHeight));
8528
8529 if (contextVk->getFeatures().supportsComputeTranscodeEtcToBc.enabled &&
8530 IsETCFormat(vkFormat.getIntendedFormatID()) && IsBCFormat(storageFormat.id))
8531 {
8532 useComputeTransCoding =
8533 shouldUseComputeForTransCoding(vk::LevelIndex(index.getLevelIndex()));
8534 if (!useComputeTransCoding)
8535 {
8536 loadFunctionInfo = GetEtcToBcTransCodingFunc(vkFormat.getIntendedFormatID());
8537 }
8538 }
8539 }
8540 else
8541 {
8542 ASSERT(storageFormat.pixelBytes != 0);
8543 const bool stencilOnly = formatInfo.sizedInternalFormat == GL_STENCIL_INDEX8;
8544
8545 if (!stencilOnly && storageFormat.id == angle::FormatID::D24_UNORM_S8_UINT)
8546 {
8547 switch (type)
8548 {
8549 case GL_UNSIGNED_INT_24_8:
8550 stencilLoadFunction = angle::LoadX24S8ToS8;
8551 break;
8552 case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
8553 stencilLoadFunction = angle::LoadX32S8ToS8;
8554 break;
8555 }
8556 }
8557 if (!stencilOnly && storageFormat.id == angle::FormatID::D32_FLOAT_S8X24_UINT)
8558 {
8559 // If depth is D32FLOAT_S8, we must pack D32F tightly (no stencil) for CopyBufferToImage
8560 outputRowPitch = sizeof(float) * glExtents.width;
8561
8562 // The generic load functions don't handle tightly packing D32FS8 to D32F & S8 so call
8563 // special case load functions.
8564 switch (type)
8565 {
8566 case GL_UNSIGNED_INT:
8567 loadFunctionInfo.loadFunction = angle::LoadD32ToD32F;
8568 stencilLoadFunction = nullptr;
8569 break;
8570 case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
8571 loadFunctionInfo.loadFunction = angle::LoadD32FS8X24ToD32F;
8572 stencilLoadFunction = angle::LoadX32S8ToS8;
8573 break;
8574 case GL_UNSIGNED_INT_24_8:
8575 loadFunctionInfo.loadFunction = angle::LoadD24S8ToD32F;
8576 stencilLoadFunction = angle::LoadX24S8ToS8;
8577 break;
8578 default:
8579 UNREACHABLE();
8580 }
8581 }
8582 else if (!stencilOnly)
8583 {
8584 outputRowPitch = storageFormat.pixelBytes * glExtents.width;
8585 }
8586 else
8587 {
8588 // Some Vulkan implementations do not support S8_UINT, so stencil-only data is
8589 // uploaded using one of combined depth-stencil formats there. Since the uploaded
8590 // stencil data must be tightly packed, the actual storage format should be ignored
8591 // with regards to its load function and output row pitch.
8592 loadFunctionInfo.loadFunction = angle::LoadToNative<GLubyte, 1>;
8593 outputRowPitch = glExtents.width;
8594 }
8595 outputDepthPitch = outputRowPitch * glExtents.height;
8596
8597 bufferRowLength = glExtents.width;
8598 bufferImageHeight = glExtents.height;
8599
8600 allocationSize = outputDepthPitch * glExtents.depth;
8601
8602 // Note: because the LoadImageFunctionInfo functions are limited to copying a single
8603 // component, we have to special case packed depth/stencil use and send the stencil as a
8604 // separate chunk.
8605 if (storageFormat.hasDepthAndStencilBits() && formatInfo.depthBits > 0 &&
8606 formatInfo.stencilBits > 0)
8607 {
8608 // Note: Stencil is always one byte
8609 stencilAllocationSize = glExtents.width * glExtents.height * glExtents.depth;
8610 allocationSize += stencilAllocationSize;
8611 }
8612 }
8613
8614 const uint8_t *source = pixels + static_cast<ptrdiff_t>(inputSkipBytes);
8615
8616 // If possible, copy the buffer to the image directly on the host, to avoid having to use a temp
8617 // image (and do a double copy).
8618 if (applyUpdate != ApplyImageUpdate::Defer && !loadFunctionInfo.requiresConversion &&
8619 inputRowPitch == outputRowPitch && inputDepthPitch == outputDepthPitch)
8620 {
8621 bool copied = false;
8622 ANGLE_TRY(updateSubresourceOnHost(contextVk, applyUpdate, index, glExtents, offset, source,
8623 bufferRowLength, bufferImageHeight, &copied));
8624 if (copied)
8625 {
8626 *updateAppliedImmediatelyOut = true;
8627 return angle::Result::Continue;
8628 }
8629 }
8630
8631 std::unique_ptr<RefCounted<BufferHelper>> stagingBuffer =
8632 std::make_unique<RefCounted<BufferHelper>>();
8633 BufferHelper *currentBuffer = &stagingBuffer->get();
8634
8635 uint8_t *stagingPointer;
8636 VkDeviceSize stagingOffset;
8637 ANGLE_TRY(contextVk->initBufferForImageCopy(currentBuffer, allocationSize,
8638 MemoryCoherency::CachedNonCoherent,
8639 storageFormat.id, &stagingOffset, &stagingPointer));
8640
8641 loadFunctionInfo.loadFunction(
8642 contextVk->getImageLoadContext(), glExtents.width, glExtents.height, glExtents.depth,
8643 source, inputRowPitch, inputDepthPitch, stagingPointer, outputRowPitch, outputDepthPitch);
8644
8645 // YUV formats need special handling.
8646 if (storageFormat.isYUV)
8647 {
8648 gl::YuvFormatInfo yuvInfo(formatInfo.internalFormat, glExtents);
8649
8650 constexpr VkImageAspectFlagBits kPlaneAspectFlags[3] = {
8651 VK_IMAGE_ASPECT_PLANE_0_BIT, VK_IMAGE_ASPECT_PLANE_1_BIT, VK_IMAGE_ASPECT_PLANE_2_BIT};
8652
8653 // We only support mip level 0 and layerCount of 1 for YUV formats.
8654 ASSERT(index.getLevelIndex() == 0);
8655 ASSERT(index.getLayerCount() == 1);
8656
8657 for (uint32_t plane = 0; plane < yuvInfo.planeCount; plane++)
8658 {
8659 VkBufferImageCopy copy = {};
8660 copy.bufferOffset = stagingOffset + yuvInfo.planeOffset[plane];
8661 copy.bufferRowLength = 0;
8662 copy.bufferImageHeight = 0;
8663 copy.imageSubresource.mipLevel = 0;
8664 copy.imageSubresource.layerCount = 1;
8665 gl_vk::GetOffset(offset, ©.imageOffset);
8666 gl_vk::GetExtent(yuvInfo.planeExtent[plane], ©.imageExtent);
8667 copy.imageSubresource.baseArrayLayer = 0;
8668 copy.imageSubresource.aspectMask = kPlaneAspectFlags[plane];
8669 appendSubresourceUpdate(
8670 gl::LevelIndex(0),
8671 SubresourceUpdate(stagingBuffer.get(), currentBuffer, copy, storageFormat.id));
8672 }
8673
8674 stagingBuffer.release();
8675 return angle::Result::Continue;
8676 }
8677
8678 VkBufferImageCopy copy = {};
8679 VkImageAspectFlags aspectFlags = GetFormatAspectFlags(storageFormat);
8680
8681 copy.bufferOffset = stagingOffset;
8682 copy.bufferRowLength = bufferRowLength;
8683 copy.bufferImageHeight = bufferImageHeight;
8684
8685 gl::LevelIndex updateLevelGL(index.getLevelIndex());
8686 copy.imageSubresource.mipLevel = updateLevelGL.get();
8687 copy.imageSubresource.layerCount = index.getLayerCount();
8688
8689 gl_vk::GetOffset(offset, ©.imageOffset);
8690 gl_vk::GetExtent(glExtents, ©.imageExtent);
8691
8692 if (gl::IsArrayTextureType(index.getType()))
8693 {
8694 copy.imageSubresource.baseArrayLayer = offset.z;
8695 copy.imageOffset.z = 0;
8696 copy.imageExtent.depth = 1;
8697 }
8698 else
8699 {
8700 copy.imageSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0;
8701 }
8702
8703 if (stencilAllocationSize > 0)
8704 {
8705 // Note: Stencil is always one byte
8706 ASSERT((aspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) != 0);
8707
8708 // Skip over depth data.
8709 stagingPointer += outputDepthPitch * glExtents.depth;
8710 stagingOffset += outputDepthPitch * glExtents.depth;
8711
8712 // recompute pitch for stencil data
8713 outputRowPitch = glExtents.width;
8714 outputDepthPitch = outputRowPitch * glExtents.height;
8715
8716 ASSERT(stencilLoadFunction != nullptr);
8717 stencilLoadFunction(contextVk->getImageLoadContext(), glExtents.width, glExtents.height,
8718 glExtents.depth, source, inputRowPitch, inputDepthPitch, stagingPointer,
8719 outputRowPitch, outputDepthPitch);
8720
8721 VkBufferImageCopy stencilCopy = {};
8722
8723 stencilCopy.bufferOffset = stagingOffset;
8724 stencilCopy.bufferRowLength = bufferRowLength;
8725 stencilCopy.bufferImageHeight = bufferImageHeight;
8726 stencilCopy.imageSubresource.mipLevel = copy.imageSubresource.mipLevel;
8727 stencilCopy.imageSubresource.baseArrayLayer = copy.imageSubresource.baseArrayLayer;
8728 stencilCopy.imageSubresource.layerCount = copy.imageSubresource.layerCount;
8729 stencilCopy.imageOffset = copy.imageOffset;
8730 stencilCopy.imageExtent = copy.imageExtent;
8731 stencilCopy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
8732 appendSubresourceUpdate(updateLevelGL, SubresourceUpdate(stagingBuffer.get(), currentBuffer,
8733 stencilCopy, storageFormat.id));
8734
8735 aspectFlags &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
8736 }
8737
8738 if (HasBothDepthAndStencilAspects(aspectFlags))
8739 {
8740 // We still have both depth and stencil aspect bits set. That means we have a destination
8741 // buffer that is packed depth stencil and that the application is only loading one aspect.
8742 // Figure out which aspect the user is touching and remove the unused aspect bit.
8743 if (formatInfo.stencilBits > 0)
8744 {
8745 aspectFlags &= ~VK_IMAGE_ASPECT_DEPTH_BIT;
8746 }
8747 else
8748 {
8749 aspectFlags &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
8750 }
8751 }
8752
8753 if (aspectFlags)
8754 {
8755 copy.imageSubresource.aspectMask = aspectFlags;
8756 appendSubresourceUpdate(
8757 updateLevelGL, SubresourceUpdate(stagingBuffer.get(), currentBuffer, copy,
8758 useComputeTransCoding ? vkFormat.getIntendedFormatID()
8759 : storageFormat.id));
8760 pruneSupersededUpdatesForLevel(contextVk, updateLevelGL, PruneReason::MemoryOptimization);
8761 }
8762
8763 stagingBuffer.release();
8764 return angle::Result::Continue;
8765 }
8766
updateSubresourceOnHost(Context * context,ApplyImageUpdate applyUpdate,const gl::ImageIndex & index,const gl::Extents & glExtents,const gl::Offset & offset,const uint8_t * source,const GLuint memoryRowLength,const GLuint memoryImageHeight,bool * copiedOut)8767 angle::Result ImageHelper::updateSubresourceOnHost(Context *context,
8768 ApplyImageUpdate applyUpdate,
8769 const gl::ImageIndex &index,
8770 const gl::Extents &glExtents,
8771 const gl::Offset &offset,
8772 const uint8_t *source,
8773 const GLuint memoryRowLength,
8774 const GLuint memoryImageHeight,
8775 bool *copiedOut)
8776 {
8777 // If the image is not set up for host copy, it can't be done.
8778 if (!valid() || (mUsage & VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT) == 0)
8779 {
8780 return angle::Result::Continue;
8781 }
8782
8783 Renderer *renderer = context->getRenderer();
8784 const VkPhysicalDeviceHostImageCopyPropertiesEXT &hostImageCopyProperties =
8785 renderer->getPhysicalDeviceHostImageCopyProperties();
8786
8787 // The image should be unused by the GPU.
8788 if (!renderer->hasResourceUseFinished(getResourceUse()))
8789 {
8790 ANGLE_TRY(renderer->checkCompletedCommandsAndCleanup(context));
8791 if (!renderer->hasResourceUseFinished(getResourceUse()))
8792 {
8793 return angle::Result::Continue;
8794 }
8795 }
8796
8797 // The image should not have any pending updates to this subresource.
8798 //
8799 // TODO: if there are any pending updates, see if they can be pruned given the incoming update.
8800 // This would most likely be the case where a clear is automatically staged for robustness or
8801 // other reasons, which would now be superseded by the data upload. http://anglebug.com/42266771
8802 const gl::LevelIndex updateLevelGL(index.getLevelIndex());
8803 const uint32_t layerIndex = index.hasLayer() ? index.getLayerIndex() : 0;
8804 const uint32_t layerCount = index.getLayerCount();
8805 if (hasStagedUpdatesForSubresource(updateLevelGL, layerIndex, layerCount))
8806 {
8807 return angle::Result::Continue;
8808 }
8809
8810 // The image should be in a layout this is copiable. If UNDEFINED, it can be transitioned to a
8811 // layout that is copyable.
8812 const VkImageAspectFlags aspectMask = getAspectFlags();
8813 if (mCurrentLayout == ImageLayout::Undefined)
8814 {
8815 VkHostImageLayoutTransitionInfoEXT transition = {};
8816 transition.sType = VK_STRUCTURE_TYPE_HOST_IMAGE_LAYOUT_TRANSITION_INFO_EXT;
8817 transition.image = mImage.getHandle();
8818 transition.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
8819 // The GENERAL layout is always guaranteed to be in
8820 // VkPhysicalDeviceHostImageCopyPropertiesEXT::pCopyDstLayouts
8821 transition.newLayout = VK_IMAGE_LAYOUT_GENERAL;
8822 transition.subresourceRange.aspectMask = aspectMask;
8823 transition.subresourceRange.baseMipLevel = 0;
8824 transition.subresourceRange.levelCount = mLevelCount;
8825 transition.subresourceRange.baseArrayLayer = 0;
8826 transition.subresourceRange.layerCount = mLayerCount;
8827
8828 ANGLE_VK_TRY(context, vkTransitionImageLayoutEXT(renderer->getDevice(), 1, &transition));
8829 mCurrentLayout = ImageLayout::HostCopy;
8830 }
8831 else if (mCurrentLayout != ImageLayout::HostCopy &&
8832 !IsAnyLayout(getCurrentLayout(renderer), hostImageCopyProperties.pCopyDstLayouts,
8833 hostImageCopyProperties.copyDstLayoutCount))
8834 {
8835 return angle::Result::Continue;
8836 }
8837
8838 const bool isArray = gl::IsArrayTextureType(index.getType());
8839 const uint32_t baseArrayLayer = isArray ? offset.z : layerIndex;
8840
8841 onWrite(updateLevelGL, 1, baseArrayLayer, layerCount, aspectMask);
8842 *copiedOut = true;
8843
8844 // Perform the copy without holding the lock. This is important for applications that perform
8845 // the copy on a separate thread, and doing all the work while holding the lock effectively
8846 // destroys all parallelism. Note that the texture may not be used by the other thread without
8847 // appropriate synchronization (such as through glFenceSync), and because the copy is happening
8848 // in this call (just without holding the lock), the sync function won't be called until the
8849 // copy is done.
8850 auto doCopy = [context, image = mImage.getHandle(), source, memoryRowLength, memoryImageHeight,
8851 aspectMask, levelVk = toVkLevel(updateLevelGL), isArray, baseArrayLayer,
8852 layerCount, offset, glExtents,
8853 layout = getCurrentLayout(renderer)](void *resultOut) {
8854 ANGLE_TRACE_EVENT0("gpu.angle", "Upload image data on host");
8855 ANGLE_UNUSED_VARIABLE(resultOut);
8856
8857 VkMemoryToImageCopyEXT copyRegion = {};
8858 copyRegion.sType = VK_STRUCTURE_TYPE_MEMORY_TO_IMAGE_COPY_EXT;
8859 copyRegion.pHostPointer = source;
8860 copyRegion.memoryRowLength = memoryRowLength;
8861 copyRegion.memoryImageHeight = memoryImageHeight;
8862 copyRegion.imageSubresource.aspectMask = aspectMask;
8863 copyRegion.imageSubresource.mipLevel = levelVk.get();
8864 copyRegion.imageSubresource.baseArrayLayer = baseArrayLayer;
8865 copyRegion.imageSubresource.layerCount = layerCount;
8866 gl_vk::GetOffset(offset, ©Region.imageOffset);
8867 gl_vk::GetExtent(glExtents, ©Region.imageExtent);
8868
8869 if (isArray)
8870 {
8871 copyRegion.imageOffset.z = 0;
8872 copyRegion.imageExtent.depth = 1;
8873 }
8874
8875 VkCopyMemoryToImageInfoEXT copyInfo = {};
8876 copyInfo.sType = VK_STRUCTURE_TYPE_COPY_MEMORY_TO_IMAGE_INFO_EXT;
8877 copyInfo.dstImage = image;
8878 copyInfo.dstImageLayout = layout;
8879 copyInfo.regionCount = 1;
8880 copyInfo.pRegions = ©Region;
8881
8882 VkResult result = vkCopyMemoryToImageEXT(context->getDevice(), ©Info);
8883 if (result != VK_SUCCESS)
8884 {
8885 context->handleError(result, __FILE__, ANGLE_FUNCTION, __LINE__);
8886 }
8887 };
8888
8889 switch (applyUpdate)
8890 {
8891 // If possible, perform the copy in an unlocked tail call. Then the other threads of the
8892 // application are free to draw.
8893 case ApplyImageUpdate::ImmediatelyInUnlockedTailCall:
8894 egl::Display::GetCurrentThreadUnlockedTailCall()->add(doCopy);
8895 break;
8896
8897 // In some cases, the copy cannot be delayed. For example because the contents are
8898 // immediately needed (such as when the generate mipmap hint is set), or because unlocked
8899 // tail calls are not allowed (this is the case with incomplete textures which are lazily
8900 // created at draw, but unlocked tail calls are avoided on draw calls due to overhead).
8901 case ApplyImageUpdate::Immediately:
8902 doCopy(nullptr);
8903 break;
8904
8905 default:
8906 UNREACHABLE();
8907 doCopy(nullptr);
8908 }
8909
8910 return angle::Result::Continue;
8911 }
8912
reformatStagedBufferUpdates(ContextVk * contextVk,angle::FormatID srcFormatID,angle::FormatID dstFormatID)8913 angle::Result ImageHelper::reformatStagedBufferUpdates(ContextVk *contextVk,
8914 angle::FormatID srcFormatID,
8915 angle::FormatID dstFormatID)
8916 {
8917 Renderer *renderer = contextVk->getRenderer();
8918 const angle::Format &srcFormat = angle::Format::Get(srcFormatID);
8919 const angle::Format &dstFormat = angle::Format::Get(dstFormatID);
8920 const gl::InternalFormat &dstFormatInfo =
8921 gl::GetSizedInternalFormatInfo(dstFormat.glInternalFormat);
8922
8923 for (std::vector<SubresourceUpdate> &levelUpdates : mSubresourceUpdates)
8924 {
8925 for (SubresourceUpdate &update : levelUpdates)
8926 {
8927 // Right now whenever we stage update from a source image, the formats always match.
8928 ASSERT(valid() || update.updateSource != UpdateSource::Image ||
8929 update.data.image.formatID == srcFormatID);
8930
8931 if (update.updateSource == UpdateSource::Buffer &&
8932 update.data.buffer.formatID == srcFormatID)
8933 {
8934 const VkBufferImageCopy © = update.data.buffer.copyRegion;
8935
8936 // Source and dst data are tightly packed
8937 GLuint srcDataRowPitch = copy.imageExtent.width * srcFormat.pixelBytes;
8938 GLuint dstDataRowPitch = copy.imageExtent.width * dstFormat.pixelBytes;
8939
8940 GLuint srcDataDepthPitch = srcDataRowPitch * copy.imageExtent.height;
8941 GLuint dstDataDepthPitch = dstDataRowPitch * copy.imageExtent.height;
8942
8943 // Retrieve source buffer
8944 vk::BufferHelper *srcBuffer = update.data.buffer.bufferHelper;
8945 ASSERT(srcBuffer->isMapped());
8946 // The bufferOffset is relative to the buffer block. We have to use the buffer
8947 // block's memory pointer to get the source data pointer.
8948 uint8_t *srcData = srcBuffer->getBlockMemory() + copy.bufferOffset;
8949
8950 // Allocate memory with dstFormat
8951 std::unique_ptr<RefCounted<BufferHelper>> stagingBuffer =
8952 std::make_unique<RefCounted<BufferHelper>>();
8953 BufferHelper *dstBuffer = &stagingBuffer->get();
8954
8955 uint8_t *dstData;
8956 VkDeviceSize dstBufferOffset;
8957 size_t dstBufferSize = dstDataDepthPitch * copy.imageExtent.depth;
8958 ANGLE_TRY(contextVk->initBufferForImageCopy(
8959 dstBuffer, dstBufferSize, MemoryCoherency::CachedNonCoherent, dstFormatID,
8960 &dstBufferOffset, &dstData));
8961
8962 rx::PixelReadFunction pixelReadFunction = srcFormat.pixelReadFunction;
8963 rx::PixelWriteFunction pixelWriteFunction = dstFormat.pixelWriteFunction;
8964
8965 CopyImageCHROMIUM(srcData, srcDataRowPitch, srcFormat.pixelBytes, srcDataDepthPitch,
8966 pixelReadFunction, dstData, dstDataRowPitch, dstFormat.pixelBytes,
8967 dstDataDepthPitch, pixelWriteFunction, dstFormatInfo.format,
8968 dstFormatInfo.componentType, copy.imageExtent.width,
8969 copy.imageExtent.height, copy.imageExtent.depth, false, false,
8970 false);
8971
8972 // Replace srcBuffer with dstBuffer
8973 update.data.buffer.bufferHelper = dstBuffer;
8974 update.data.buffer.formatID = dstFormatID;
8975 update.data.buffer.copyRegion.bufferOffset = dstBufferOffset;
8976
8977 // Update total staging buffer size
8978 mTotalStagedBufferUpdateSize -= srcBuffer->getSize();
8979 mTotalStagedBufferUpdateSize += dstBuffer->getSize();
8980
8981 // Let update structure owns the staging buffer
8982 if (update.refCounted.buffer)
8983 {
8984 update.refCounted.buffer->releaseRef();
8985 if (!update.refCounted.buffer->isReferenced())
8986 {
8987 update.refCounted.buffer->get().release(renderer);
8988 SafeDelete(update.refCounted.buffer);
8989 }
8990 }
8991 update.refCounted.buffer = stagingBuffer.release();
8992 update.refCounted.buffer->addRef();
8993 }
8994 }
8995 }
8996
8997 return angle::Result::Continue;
8998 }
8999
CalculateBufferInfo(ContextVk * contextVk,const gl::Extents & glExtents,const gl::InternalFormat & formatInfo,const gl::PixelUnpackState & unpack,GLenum type,bool is3D,GLuint * inputRowPitch,GLuint * inputDepthPitch,GLuint * inputSkipBytes)9000 angle::Result ImageHelper::CalculateBufferInfo(ContextVk *contextVk,
9001 const gl::Extents &glExtents,
9002 const gl::InternalFormat &formatInfo,
9003 const gl::PixelUnpackState &unpack,
9004 GLenum type,
9005 bool is3D,
9006 GLuint *inputRowPitch,
9007 GLuint *inputDepthPitch,
9008 GLuint *inputSkipBytes)
9009 {
9010 // YUV formats need special handling.
9011 if (gl::IsYuvFormat(formatInfo.internalFormat))
9012 {
9013 gl::YuvFormatInfo yuvInfo(formatInfo.internalFormat, glExtents);
9014
9015 // row pitch = Y plane row pitch
9016 *inputRowPitch = yuvInfo.planePitch[0];
9017 // depth pitch = Y plane size + chroma plane size
9018 *inputDepthPitch = yuvInfo.planeSize[0] + yuvInfo.planeSize[1] + yuvInfo.planeSize[2];
9019 *inputSkipBytes = 0;
9020
9021 return angle::Result::Continue;
9022 }
9023
9024 ANGLE_VK_CHECK_MATH(contextVk,
9025 formatInfo.computeRowPitch(type, glExtents.width, unpack.alignment,
9026 unpack.rowLength, inputRowPitch));
9027
9028 ANGLE_VK_CHECK_MATH(contextVk,
9029 formatInfo.computeDepthPitch(glExtents.height, unpack.imageHeight,
9030 *inputRowPitch, inputDepthPitch));
9031
9032 ANGLE_VK_CHECK_MATH(
9033 contextVk, formatInfo.computeSkipBytes(type, *inputRowPitch, *inputDepthPitch, unpack, is3D,
9034 inputSkipBytes));
9035
9036 return angle::Result::Continue;
9037 }
9038
onRenderPassAttach(const QueueSerial & queueSerial)9039 void ImageHelper::onRenderPassAttach(const QueueSerial &queueSerial)
9040 {
9041 setQueueSerial(queueSerial);
9042 // updatePipelineStageAccessHistory uses mCurrentLayout which we dont know yet (deferred until
9043 // endRenderPass time). So update it directly since we know attachment will be accessed by
9044 // fragment and attachment stages.
9045 mPipelineStageAccessHeuristic.onAccess(PipelineStageGroup::FragmentOnly);
9046 }
9047
onWrite(gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags)9048 void ImageHelper::onWrite(gl::LevelIndex levelStart,
9049 uint32_t levelCount,
9050 uint32_t layerStart,
9051 uint32_t layerCount,
9052 VkImageAspectFlags aspectFlags)
9053 {
9054 mCurrentSingleClearValue.reset();
9055
9056 // Mark contents of the given subresource as defined.
9057 setContentDefined(toVkLevel(levelStart), levelCount, layerStart, layerCount, aspectFlags);
9058 }
9059
hasSubresourceDefinedContent(gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount) const9060 bool ImageHelper::hasSubresourceDefinedContent(gl::LevelIndex level,
9061 uint32_t layerIndex,
9062 uint32_t layerCount) const
9063 {
9064 if (layerIndex >= kMaxContentDefinedLayerCount)
9065 {
9066 return true;
9067 }
9068
9069 uint8_t layerRangeBits =
9070 GetContentDefinedLayerRangeBits(layerIndex, layerCount, kMaxContentDefinedLayerCount);
9071 return (getLevelContentDefined(toVkLevel(level)) & LevelContentDefinedMask(layerRangeBits))
9072 .any();
9073 }
9074
hasSubresourceDefinedStencilContent(gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount) const9075 bool ImageHelper::hasSubresourceDefinedStencilContent(gl::LevelIndex level,
9076 uint32_t layerIndex,
9077 uint32_t layerCount) const
9078 {
9079 if (layerIndex >= kMaxContentDefinedLayerCount)
9080 {
9081 return true;
9082 }
9083
9084 uint8_t layerRangeBits =
9085 GetContentDefinedLayerRangeBits(layerIndex, layerCount, kMaxContentDefinedLayerCount);
9086 return (getLevelStencilContentDefined(toVkLevel(level)) &
9087 LevelContentDefinedMask(layerRangeBits))
9088 .any();
9089 }
9090
invalidateSubresourceContent(ContextVk * contextVk,gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount,bool * preferToKeepContentsDefinedOut)9091 void ImageHelper::invalidateSubresourceContent(ContextVk *contextVk,
9092 gl::LevelIndex level,
9093 uint32_t layerIndex,
9094 uint32_t layerCount,
9095 bool *preferToKeepContentsDefinedOut)
9096 {
9097 invalidateSubresourceContentImpl(
9098 contextVk, level, layerIndex, layerCount,
9099 static_cast<VkImageAspectFlagBits>(getAspectFlags() & ~VK_IMAGE_ASPECT_STENCIL_BIT),
9100 &getLevelContentDefined(toVkLevel(level)), preferToKeepContentsDefinedOut);
9101 }
9102
invalidateSubresourceStencilContent(ContextVk * contextVk,gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount,bool * preferToKeepContentsDefinedOut)9103 void ImageHelper::invalidateSubresourceStencilContent(ContextVk *contextVk,
9104 gl::LevelIndex level,
9105 uint32_t layerIndex,
9106 uint32_t layerCount,
9107 bool *preferToKeepContentsDefinedOut)
9108 {
9109 invalidateSubresourceContentImpl(
9110 contextVk, level, layerIndex, layerCount, VK_IMAGE_ASPECT_STENCIL_BIT,
9111 &getLevelStencilContentDefined(toVkLevel(level)), preferToKeepContentsDefinedOut);
9112 }
9113
invalidateSubresourceContentImpl(ContextVk * contextVk,gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount,VkImageAspectFlagBits aspect,LevelContentDefinedMask * contentDefinedMask,bool * preferToKeepContentsDefinedOut)9114 void ImageHelper::invalidateSubresourceContentImpl(ContextVk *contextVk,
9115 gl::LevelIndex level,
9116 uint32_t layerIndex,
9117 uint32_t layerCount,
9118 VkImageAspectFlagBits aspect,
9119 LevelContentDefinedMask *contentDefinedMask,
9120 bool *preferToKeepContentsDefinedOut)
9121 {
9122 // If the aspect being invalidated doesn't exist, skip invalidation altogether.
9123 if ((getAspectFlags() & aspect) == 0)
9124 {
9125 if (preferToKeepContentsDefinedOut)
9126 {
9127 // Let the caller know that this invalidate request was ignored.
9128 *preferToKeepContentsDefinedOut = true;
9129 }
9130 return;
9131 }
9132
9133 // If the color format is emulated and has extra channels, those channels need to stay cleared.
9134 // On some devices, it's cheaper to skip invalidating the framebuffer attachment, while on
9135 // others it's cheaper to invalidate but then re-clear the image.
9136 //
9137 // For depth/stencil formats, each channel is separately invalidated, so the invalidate is
9138 // simply skipped for the emulated channel on all devices.
9139 const bool hasEmulatedChannels = hasEmulatedImageChannels();
9140 bool skip = false;
9141 switch (aspect)
9142 {
9143 case VK_IMAGE_ASPECT_DEPTH_BIT:
9144 skip = hasEmulatedDepthChannel();
9145 break;
9146 case VK_IMAGE_ASPECT_STENCIL_BIT:
9147 skip = hasEmulatedStencilChannel();
9148 break;
9149 case VK_IMAGE_ASPECT_COLOR_BIT:
9150 skip = hasEmulatedChannels &&
9151 contextVk->getFeatures().preferSkippingInvalidateForEmulatedFormats.enabled;
9152 break;
9153 default:
9154 UNREACHABLE();
9155 skip = true;
9156 }
9157
9158 if (preferToKeepContentsDefinedOut)
9159 {
9160 *preferToKeepContentsDefinedOut = skip;
9161 }
9162 if (skip)
9163 {
9164 return;
9165 }
9166
9167 if (layerIndex >= kMaxContentDefinedLayerCount)
9168 {
9169 const char *aspectName = "color";
9170 if (aspect == VK_IMAGE_ASPECT_DEPTH_BIT)
9171 {
9172 aspectName = "depth";
9173 }
9174 else if (aspect == VK_IMAGE_ASPECT_STENCIL_BIT)
9175 {
9176 aspectName = "stencil";
9177 }
9178 ANGLE_VK_PERF_WARNING(
9179 contextVk, GL_DEBUG_SEVERITY_LOW,
9180 "glInvalidateFramebuffer (%s) ineffective on attachments with layer >= 8", aspectName);
9181 return;
9182 }
9183
9184 uint8_t layerRangeBits =
9185 GetContentDefinedLayerRangeBits(layerIndex, layerCount, kMaxContentDefinedLayerCount);
9186 *contentDefinedMask &= static_cast<uint8_t>(~layerRangeBits);
9187
9188 // If there are emulated channels, stage a clear to make sure those channels continue to contain
9189 // valid values.
9190 if (hasEmulatedChannels && aspect == VK_IMAGE_ASPECT_COLOR_BIT)
9191 {
9192 VkClearValue clearValue;
9193 clearValue.color = kEmulatedInitColorValue;
9194
9195 prependSubresourceUpdate(
9196 level, SubresourceUpdate(aspect, clearValue, level, layerIndex, layerCount));
9197 mSubresourceUpdates[level.get()].front().updateSource = UpdateSource::ClearAfterInvalidate;
9198 }
9199 }
9200
restoreSubresourceContent(gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount)9201 void ImageHelper::restoreSubresourceContent(gl::LevelIndex level,
9202 uint32_t layerIndex,
9203 uint32_t layerCount)
9204 {
9205 restoreSubresourceContentImpl(
9206 level, layerIndex, layerCount,
9207 static_cast<VkImageAspectFlagBits>(getAspectFlags() & ~VK_IMAGE_ASPECT_STENCIL_BIT),
9208 &getLevelContentDefined(toVkLevel(level)));
9209 }
9210
restoreSubresourceStencilContent(gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount)9211 void ImageHelper::restoreSubresourceStencilContent(gl::LevelIndex level,
9212 uint32_t layerIndex,
9213 uint32_t layerCount)
9214 {
9215 restoreSubresourceContentImpl(level, layerIndex, layerCount, VK_IMAGE_ASPECT_STENCIL_BIT,
9216 &getLevelStencilContentDefined(toVkLevel(level)));
9217 }
9218
restoreSubresourceContentImpl(gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount,VkImageAspectFlagBits aspect,LevelContentDefinedMask * contentDefinedMask)9219 void ImageHelper::restoreSubresourceContentImpl(gl::LevelIndex level,
9220 uint32_t layerIndex,
9221 uint32_t layerCount,
9222 VkImageAspectFlagBits aspect,
9223 LevelContentDefinedMask *contentDefinedMask)
9224 {
9225 if (layerIndex >= kMaxContentDefinedLayerCount)
9226 {
9227 return;
9228 }
9229
9230 uint8_t layerRangeBits =
9231 GetContentDefinedLayerRangeBits(layerIndex, layerCount, kMaxContentDefinedLayerCount);
9232
9233 switch (aspect)
9234 {
9235 case VK_IMAGE_ASPECT_DEPTH_BIT:
9236 // Emulated depth channel should never have been marked invalid, so it can retain its
9237 // cleared value.
9238 ASSERT(!hasEmulatedDepthChannel() ||
9239 (contentDefinedMask->bits() & layerRangeBits) == layerRangeBits);
9240 break;
9241 case VK_IMAGE_ASPECT_STENCIL_BIT:
9242 // Emulated stencil channel should never have been marked invalid, so it can retain its
9243 // cleared value.
9244 ASSERT(!hasEmulatedStencilChannel() ||
9245 (contentDefinedMask->bits() & layerRangeBits) == layerRangeBits);
9246 break;
9247 case VK_IMAGE_ASPECT_COLOR_BIT:
9248 // This function is called on attachments during a render pass when it's determined that
9249 // they should no longer be considered invalidated. For an attachment with emulated
9250 // format that has extra channels, invalidateSubresourceContentImpl may have proactively
9251 // inserted a clear so that the extra channels continue to have defined values. That
9252 // clear should be removed.
9253 if (hasEmulatedImageChannels())
9254 {
9255 removeSingleStagedClearAfterInvalidate(level, layerIndex, layerCount);
9256 }
9257 break;
9258 default:
9259 UNREACHABLE();
9260 break;
9261 }
9262
9263 // Additionally, as the resource has been rewritten to in the render pass, its no longer cleared
9264 // to the cached value.
9265 mCurrentSingleClearValue.reset();
9266
9267 *contentDefinedMask |= layerRangeBits;
9268 }
9269
stagePartialClear(ContextVk * contextVk,const gl::Box & clearArea,const ClearTextureMode clearMode,gl::TextureType textureType,uint32_t levelIndex,uint32_t layerIndex,uint32_t layerCount,GLenum type,const gl::InternalFormat & formatInfo,const Format & vkFormat,ImageAccess access,const uint8_t * data)9270 angle::Result ImageHelper::stagePartialClear(ContextVk *contextVk,
9271 const gl::Box &clearArea,
9272 const ClearTextureMode clearMode,
9273 gl::TextureType textureType,
9274 uint32_t levelIndex,
9275 uint32_t layerIndex,
9276 uint32_t layerCount,
9277 GLenum type,
9278 const gl::InternalFormat &formatInfo,
9279 const Format &vkFormat,
9280 ImageAccess access,
9281 const uint8_t *data)
9282 {
9283 // If the input data pointer is null, the texture is filled with zeros.
9284 const angle::Format &intendedFormat = vkFormat.getIntendedFormat();
9285 const angle::Format &actualFormat = vkFormat.getActualImageFormat(access);
9286 auto intendedPixelSize = static_cast<uint32_t>(intendedFormat.pixelBytes);
9287 auto actualPixelSize = static_cast<uint32_t>(actualFormat.pixelBytes);
9288
9289 uint8_t intendedData[16] = {0};
9290 if (data != nullptr)
9291 {
9292 memcpy(intendedData, data, intendedPixelSize);
9293 }
9294
9295 // The appropriate loading function is used to take the original value as a single pixel and
9296 // convert it into the format actually used for this image.
9297 std::vector<uint8_t> actualData(actualPixelSize, 0);
9298 LoadImageFunctionInfo loadFunctionInfo = vkFormat.getTextureLoadFunction(access, type);
9299
9300 bool stencilOnly = formatInfo.sizedInternalFormat == GL_STENCIL_INDEX8;
9301 if (stencilOnly)
9302 {
9303 // Some Vulkan implementations do not support S8_UINT, so stencil-only data is
9304 // uploaded using one of combined depth-stencil formats there. Since the uploaded
9305 // stencil data must be tightly packed, the actual storage format should be ignored
9306 // with regards to its load function and output row pitch.
9307 loadFunctionInfo.loadFunction = angle::LoadToNative<GLubyte, 1>;
9308 }
9309
9310 loadFunctionInfo.loadFunction(contextVk->getImageLoadContext(), 1, 1, 1, intendedData, 1, 1,
9311 actualData.data(), 1, 1);
9312
9313 // VkClearValue is used for renderable images.
9314 VkClearValue clearValue = {};
9315 if (formatInfo.isDepthOrStencil())
9316 {
9317 GetVkClearDepthStencilValueFromBytes(intendedData, intendedFormat, &clearValue);
9318 }
9319 else
9320 {
9321 GetVkClearColorValueFromBytes(actualData.data(), actualFormat, &clearValue);
9322 }
9323
9324 // Stage a ClearPartial update.
9325 VkImageAspectFlags aspectFlags = 0;
9326 if (!formatInfo.isDepthOrStencil())
9327 {
9328 aspectFlags |= VK_IMAGE_ASPECT_COLOR_BIT;
9329 }
9330 else
9331 {
9332 aspectFlags |= formatInfo.depthBits > 0 ? VK_IMAGE_ASPECT_DEPTH_BIT : 0;
9333 aspectFlags |= formatInfo.stencilBits > 0 ? VK_IMAGE_ASPECT_STENCIL_BIT : 0;
9334 }
9335
9336 if (clearMode == ClearTextureMode::FullClear)
9337 {
9338 bool useLayerAsDepth = textureType == gl::TextureType::CubeMap ||
9339 textureType == gl::TextureType::CubeMapArray ||
9340 textureType == gl::TextureType::_2DArray ||
9341 textureType == gl::TextureType::_2DMultisampleArray;
9342 const gl::ImageIndex index = gl::ImageIndex::MakeFromType(
9343 textureType, levelIndex, 0, useLayerAsDepth ? clearArea.depth : 1);
9344
9345 appendSubresourceUpdate(gl::LevelIndex(levelIndex),
9346 SubresourceUpdate(aspectFlags, clearValue, index));
9347 }
9348 else
9349 {
9350 appendSubresourceUpdate(gl::LevelIndex(levelIndex),
9351 SubresourceUpdate(aspectFlags, clearValue, textureType, levelIndex,
9352 layerIndex, layerCount, clearArea));
9353 }
9354 return angle::Result::Continue;
9355 }
9356
stageSubresourceUpdate(ContextVk * contextVk,const gl::ImageIndex & index,const gl::Extents & glExtents,const gl::Offset & offset,const gl::InternalFormat & formatInfo,const gl::PixelUnpackState & unpack,GLenum type,const uint8_t * pixels,const Format & vkFormat,ImageAccess access,ApplyImageUpdate applyUpdate,bool * updateAppliedImmediatelyOut)9357 angle::Result ImageHelper::stageSubresourceUpdate(ContextVk *contextVk,
9358 const gl::ImageIndex &index,
9359 const gl::Extents &glExtents,
9360 const gl::Offset &offset,
9361 const gl::InternalFormat &formatInfo,
9362 const gl::PixelUnpackState &unpack,
9363 GLenum type,
9364 const uint8_t *pixels,
9365 const Format &vkFormat,
9366 ImageAccess access,
9367 ApplyImageUpdate applyUpdate,
9368 bool *updateAppliedImmediatelyOut)
9369 {
9370 GLuint inputRowPitch = 0;
9371 GLuint inputDepthPitch = 0;
9372 GLuint inputSkipBytes = 0;
9373 ANGLE_TRY(CalculateBufferInfo(contextVk, glExtents, formatInfo, unpack, type, index.usesTex3D(),
9374 &inputRowPitch, &inputDepthPitch, &inputSkipBytes));
9375
9376 ANGLE_TRY(stageSubresourceUpdateImpl(
9377 contextVk, index, glExtents, offset, formatInfo, unpack, type, pixels, vkFormat, access,
9378 inputRowPitch, inputDepthPitch, inputSkipBytes, applyUpdate, updateAppliedImmediatelyOut));
9379
9380 return angle::Result::Continue;
9381 }
9382
stageSubresourceUpdateAndGetData(ContextVk * contextVk,size_t allocationSize,const gl::ImageIndex & imageIndex,const gl::Extents & glExtents,const gl::Offset & offset,uint8_t ** dstData,angle::FormatID formatID)9383 angle::Result ImageHelper::stageSubresourceUpdateAndGetData(ContextVk *contextVk,
9384 size_t allocationSize,
9385 const gl::ImageIndex &imageIndex,
9386 const gl::Extents &glExtents,
9387 const gl::Offset &offset,
9388 uint8_t **dstData,
9389 angle::FormatID formatID)
9390 {
9391 std::unique_ptr<RefCounted<BufferHelper>> stagingBuffer =
9392 std::make_unique<RefCounted<BufferHelper>>();
9393 BufferHelper *currentBuffer = &stagingBuffer->get();
9394
9395 VkDeviceSize stagingOffset;
9396 ANGLE_TRY(contextVk->initBufferForImageCopy(currentBuffer, allocationSize,
9397 MemoryCoherency::CachedNonCoherent, formatID,
9398 &stagingOffset, dstData));
9399
9400 gl::LevelIndex updateLevelGL(imageIndex.getLevelIndex());
9401
9402 VkBufferImageCopy copy = {};
9403 copy.bufferOffset = stagingOffset;
9404 copy.bufferRowLength = glExtents.width;
9405 copy.bufferImageHeight = glExtents.height;
9406 copy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
9407 copy.imageSubresource.mipLevel = updateLevelGL.get();
9408 copy.imageSubresource.baseArrayLayer = imageIndex.hasLayer() ? imageIndex.getLayerIndex() : 0;
9409 copy.imageSubresource.layerCount = imageIndex.getLayerCount();
9410
9411 // Note: Only support color now
9412 ASSERT((mActualFormatID == angle::FormatID::NONE) ||
9413 (getAspectFlags() == VK_IMAGE_ASPECT_COLOR_BIT));
9414
9415 gl_vk::GetOffset(offset, ©.imageOffset);
9416 gl_vk::GetExtent(glExtents, ©.imageExtent);
9417
9418 appendSubresourceUpdate(
9419 updateLevelGL, SubresourceUpdate(stagingBuffer.release(), currentBuffer, copy, formatID));
9420 return angle::Result::Continue;
9421 }
9422
stageSubresourceUpdateFromFramebuffer(const gl::Context * context,const gl::ImageIndex & index,const gl::Rectangle & sourceArea,const gl::Offset & dstOffset,const gl::Extents & dstExtent,const gl::InternalFormat & formatInfo,ImageAccess access,FramebufferVk * framebufferVk)9423 angle::Result ImageHelper::stageSubresourceUpdateFromFramebuffer(
9424 const gl::Context *context,
9425 const gl::ImageIndex &index,
9426 const gl::Rectangle &sourceArea,
9427 const gl::Offset &dstOffset,
9428 const gl::Extents &dstExtent,
9429 const gl::InternalFormat &formatInfo,
9430 ImageAccess access,
9431 FramebufferVk *framebufferVk)
9432 {
9433 ContextVk *contextVk = GetImpl(context);
9434
9435 // If the extents and offset is outside the source image, we need to clip.
9436 gl::Rectangle clippedRectangle;
9437 const gl::Extents readExtents = framebufferVk->getReadImageExtents();
9438 if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, readExtents.width, readExtents.height),
9439 &clippedRectangle))
9440 {
9441 // Empty source area, nothing to do.
9442 return angle::Result::Continue;
9443 }
9444
9445 bool isViewportFlipEnabled = contextVk->isViewportFlipEnabledForDrawFBO();
9446 if (isViewportFlipEnabled)
9447 {
9448 clippedRectangle.y = readExtents.height - clippedRectangle.y - clippedRectangle.height;
9449 }
9450
9451 // 1- obtain a buffer handle to copy to
9452 Renderer *renderer = contextVk->getRenderer();
9453
9454 const Format &vkFormat = renderer->getFormat(formatInfo.sizedInternalFormat);
9455 const angle::Format &storageFormat = vkFormat.getActualImageFormat(access);
9456 LoadImageFunctionInfo loadFunction = vkFormat.getTextureLoadFunction(access, formatInfo.type);
9457
9458 size_t outputRowPitch = storageFormat.pixelBytes * clippedRectangle.width;
9459 size_t outputDepthPitch = outputRowPitch * clippedRectangle.height;
9460
9461 std::unique_ptr<RefCounted<BufferHelper>> stagingBuffer =
9462 std::make_unique<RefCounted<BufferHelper>>();
9463 BufferHelper *currentBuffer = &stagingBuffer->get();
9464
9465 uint8_t *stagingPointer;
9466 VkDeviceSize stagingOffset;
9467
9468 // The destination is only one layer deep.
9469 size_t allocationSize = outputDepthPitch;
9470 ANGLE_TRY(contextVk->initBufferForImageCopy(currentBuffer, allocationSize,
9471 MemoryCoherency::CachedNonCoherent,
9472 storageFormat.id, &stagingOffset, &stagingPointer));
9473
9474 const angle::Format ©Format =
9475 GetFormatFromFormatType(formatInfo.internalFormat, formatInfo.type);
9476 PackPixelsParams params(clippedRectangle, copyFormat, static_cast<GLuint>(outputRowPitch),
9477 isViewportFlipEnabled, nullptr, 0);
9478
9479 RenderTargetVk *readRenderTarget = framebufferVk->getColorReadRenderTarget();
9480
9481 // 2- copy the source image region to the pixel buffer using a cpu readback
9482 if (loadFunction.requiresConversion)
9483 {
9484 // When a conversion is required, we need to use the loadFunction to read from a temporary
9485 // buffer instead so its an even slower path.
9486 size_t bufferSize =
9487 storageFormat.pixelBytes * clippedRectangle.width * clippedRectangle.height;
9488 angle::MemoryBuffer *memoryBuffer = nullptr;
9489 ANGLE_VK_CHECK_ALLOC(contextVk, context->getScratchBuffer(bufferSize, &memoryBuffer));
9490
9491 // Read into the scratch buffer
9492 ANGLE_TRY(framebufferVk->readPixelsImpl(contextVk, clippedRectangle, params,
9493 VK_IMAGE_ASPECT_COLOR_BIT, readRenderTarget,
9494 memoryBuffer->data()));
9495
9496 // Load from scratch buffer to our pixel buffer
9497 loadFunction.loadFunction(contextVk->getImageLoadContext(), clippedRectangle.width,
9498 clippedRectangle.height, 1, memoryBuffer->data(), outputRowPitch,
9499 0, stagingPointer, outputRowPitch, 0);
9500 }
9501 else
9502 {
9503 // We read directly from the framebuffer into our pixel buffer.
9504 ANGLE_TRY(framebufferVk->readPixelsImpl(contextVk, clippedRectangle, params,
9505 VK_IMAGE_ASPECT_COLOR_BIT, readRenderTarget,
9506 stagingPointer));
9507 }
9508
9509 gl::LevelIndex updateLevelGL(index.getLevelIndex());
9510
9511 // 3- enqueue the destination image subresource update
9512 VkBufferImageCopy copyToImage = {};
9513 copyToImage.bufferOffset = static_cast<VkDeviceSize>(stagingOffset);
9514 copyToImage.bufferRowLength = 0; // Tightly packed data can be specified as 0.
9515 copyToImage.bufferImageHeight = clippedRectangle.height;
9516 copyToImage.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
9517 copyToImage.imageSubresource.mipLevel = updateLevelGL.get();
9518 copyToImage.imageSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0;
9519 copyToImage.imageSubresource.layerCount = index.getLayerCount();
9520 gl_vk::GetOffset(dstOffset, ©ToImage.imageOffset);
9521 gl_vk::GetExtent(dstExtent, ©ToImage.imageExtent);
9522
9523 // 3- enqueue the destination image subresource update
9524 appendSubresourceUpdate(updateLevelGL, SubresourceUpdate(stagingBuffer.release(), currentBuffer,
9525 copyToImage, storageFormat.id));
9526
9527 return angle::Result::Continue;
9528 }
9529
stageSubresourceUpdateFromImage(RefCounted<ImageHelper> * image,const gl::ImageIndex & index,LevelIndex srcMipLevel,const gl::Offset & destOffset,const gl::Extents & glExtents,const VkImageType imageType)9530 void ImageHelper::stageSubresourceUpdateFromImage(RefCounted<ImageHelper> *image,
9531 const gl::ImageIndex &index,
9532 LevelIndex srcMipLevel,
9533 const gl::Offset &destOffset,
9534 const gl::Extents &glExtents,
9535 const VkImageType imageType)
9536 {
9537 gl::LevelIndex updateLevelGL(index.getLevelIndex());
9538 VkImageAspectFlags imageAspectFlags = vk::GetFormatAspectFlags(image->get().getActualFormat());
9539
9540 VkImageCopy copyToImage = {};
9541 copyToImage.srcSubresource.aspectMask = imageAspectFlags;
9542 copyToImage.srcSubresource.mipLevel = srcMipLevel.get();
9543 copyToImage.srcSubresource.layerCount = index.getLayerCount();
9544 copyToImage.dstSubresource.aspectMask = imageAspectFlags;
9545 copyToImage.dstSubresource.mipLevel = updateLevelGL.get();
9546
9547 if (imageType == VK_IMAGE_TYPE_3D)
9548 {
9549 // These values must be set explicitly to follow the Vulkan spec:
9550 // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VkImageCopy.html
9551 // If either of the calling command's srcImage or dstImage parameters are of VkImageType
9552 // VK_IMAGE_TYPE_3D, the baseArrayLayer and layerCount members of the corresponding
9553 // subresource must be 0 and 1, respectively
9554 copyToImage.dstSubresource.baseArrayLayer = 0;
9555 copyToImage.dstSubresource.layerCount = 1;
9556 // Preserve the assumption that destOffset.z == "dstSubresource.baseArrayLayer"
9557 ASSERT(destOffset.z == (index.hasLayer() ? index.getLayerIndex() : 0));
9558 }
9559 else
9560 {
9561 copyToImage.dstSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0;
9562 copyToImage.dstSubresource.layerCount = index.getLayerCount();
9563 }
9564
9565 gl_vk::GetOffset(destOffset, ©ToImage.dstOffset);
9566 gl_vk::GetExtent(glExtents, ©ToImage.extent);
9567
9568 appendSubresourceUpdate(
9569 updateLevelGL, SubresourceUpdate(image, copyToImage, image->get().getActualFormatID()));
9570 }
9571
stageSubresourceUpdatesFromAllImageLevels(RefCounted<ImageHelper> * image,gl::LevelIndex baseLevel)9572 void ImageHelper::stageSubresourceUpdatesFromAllImageLevels(RefCounted<ImageHelper> *image,
9573 gl::LevelIndex baseLevel)
9574 {
9575 for (LevelIndex levelVk(0); levelVk < LevelIndex(image->get().getLevelCount()); ++levelVk)
9576 {
9577 const gl::LevelIndex levelGL = vk_gl::GetLevelIndex(levelVk, baseLevel);
9578 const gl::ImageIndex index =
9579 gl::ImageIndex::Make2DArrayRange(levelGL.get(), 0, image->get().getLayerCount());
9580
9581 stageSubresourceUpdateFromImage(image, index, levelVk, gl::kOffsetZero,
9582 image->get().getLevelExtents(levelVk),
9583 image->get().getType());
9584 }
9585 }
9586
stageClear(const gl::ImageIndex & index,VkImageAspectFlags aspectFlags,const VkClearValue & clearValue)9587 void ImageHelper::stageClear(const gl::ImageIndex &index,
9588 VkImageAspectFlags aspectFlags,
9589 const VkClearValue &clearValue)
9590 {
9591 gl::LevelIndex updateLevelGL(index.getLevelIndex());
9592 appendSubresourceUpdate(updateLevelGL, SubresourceUpdate(aspectFlags, clearValue, index));
9593 }
9594
stageRobustResourceClear(const gl::ImageIndex & index)9595 void ImageHelper::stageRobustResourceClear(const gl::ImageIndex &index)
9596 {
9597 const VkImageAspectFlags aspectFlags = getAspectFlags();
9598
9599 ASSERT(mActualFormatID != angle::FormatID::NONE);
9600 VkClearValue clearValue = GetRobustResourceClearValue(getIntendedFormat(), getActualFormat());
9601
9602 gl::LevelIndex updateLevelGL(index.getLevelIndex());
9603 appendSubresourceUpdate(updateLevelGL, SubresourceUpdate(aspectFlags, clearValue, index));
9604 }
9605
stageResourceClearWithFormat(ContextVk * contextVk,const gl::ImageIndex & index,const gl::Extents & glExtents,const angle::Format & intendedFormat,const angle::Format & imageFormat,const VkClearValue & clearValue)9606 angle::Result ImageHelper::stageResourceClearWithFormat(ContextVk *contextVk,
9607 const gl::ImageIndex &index,
9608 const gl::Extents &glExtents,
9609 const angle::Format &intendedFormat,
9610 const angle::Format &imageFormat,
9611 const VkClearValue &clearValue)
9612 {
9613 // Robust clears must only be staged if we do not have any prior data for this subresource.
9614 ASSERT(!hasStagedUpdatesForSubresource(gl::LevelIndex(index.getLevelIndex()),
9615 index.getLayerIndex(), index.getLayerCount()));
9616
9617 const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(imageFormat);
9618
9619 gl::LevelIndex updateLevelGL(index.getLevelIndex());
9620
9621 if (imageFormat.isBlock)
9622 {
9623 // This only supports doing an initial clear to 0, not clearing to a specific encoded RGBA
9624 // value
9625 ASSERT((clearValue.color.int32[0] == 0) && (clearValue.color.int32[1] == 0) &&
9626 (clearValue.color.int32[2] == 0) && (clearValue.color.int32[3] == 0));
9627
9628 const gl::InternalFormat &formatInfo =
9629 gl::GetSizedInternalFormatInfo(imageFormat.glInternalFormat);
9630 GLuint totalSize;
9631 ANGLE_VK_CHECK_MATH(contextVk,
9632 formatInfo.computeCompressedImageSize(glExtents, &totalSize));
9633
9634 std::unique_ptr<RefCounted<BufferHelper>> stagingBuffer =
9635 std::make_unique<RefCounted<BufferHelper>>();
9636 BufferHelper *currentBuffer = &stagingBuffer->get();
9637
9638 uint8_t *stagingPointer;
9639 VkDeviceSize stagingOffset;
9640 ANGLE_TRY(contextVk->initBufferForImageCopy(
9641 currentBuffer, totalSize, MemoryCoherency::CachedNonCoherent, imageFormat.id,
9642 &stagingOffset, &stagingPointer));
9643 memset(stagingPointer, 0, totalSize);
9644
9645 VkBufferImageCopy copyRegion = {};
9646 copyRegion.bufferOffset = stagingOffset;
9647 copyRegion.imageExtent.width = glExtents.width;
9648 copyRegion.imageExtent.height = glExtents.height;
9649 copyRegion.imageExtent.depth = glExtents.depth;
9650 copyRegion.imageSubresource.mipLevel = updateLevelGL.get();
9651 copyRegion.imageSubresource.aspectMask = aspectFlags;
9652 copyRegion.imageSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0;
9653 copyRegion.imageSubresource.layerCount = index.getLayerCount();
9654
9655 // The update structure owns the staging buffer.
9656 appendSubresourceUpdate(
9657 updateLevelGL,
9658 SubresourceUpdate(stagingBuffer.release(), currentBuffer, copyRegion, imageFormat.id));
9659 }
9660 else
9661 {
9662 appendSubresourceUpdate(updateLevelGL, SubresourceUpdate(aspectFlags, clearValue, index));
9663 }
9664
9665 return angle::Result::Continue;
9666 }
9667
stageRobustResourceClearWithFormat(ContextVk * contextVk,const gl::ImageIndex & index,const gl::Extents & glExtents,const angle::Format & intendedFormat,const angle::Format & imageFormat)9668 angle::Result ImageHelper::stageRobustResourceClearWithFormat(ContextVk *contextVk,
9669 const gl::ImageIndex &index,
9670 const gl::Extents &glExtents,
9671 const angle::Format &intendedFormat,
9672 const angle::Format &imageFormat)
9673 {
9674 VkClearValue clearValue = GetRobustResourceClearValue(intendedFormat, imageFormat);
9675 gl::ImageIndex fullResourceIndex = index;
9676 gl::Extents fullResourceExtents = glExtents;
9677
9678 if (gl::IsArrayTextureType(index.getType()))
9679 {
9680 // For 2Darray textures gl::Extents::depth is the layer count.
9681 fullResourceIndex = gl::ImageIndex::MakeFromType(
9682 index.getType(), index.getLevelIndex(), gl::ImageIndex::kEntireLevel, glExtents.depth);
9683 // Vulkan requires depth of 1 for 2Darray textures.
9684 fullResourceExtents.depth = 1;
9685 }
9686
9687 return stageResourceClearWithFormat(contextVk, fullResourceIndex, fullResourceExtents,
9688 intendedFormat, imageFormat, clearValue);
9689 }
9690
stageClearIfEmulatedFormat(bool isRobustResourceInitEnabled,bool isExternalImage)9691 void ImageHelper::stageClearIfEmulatedFormat(bool isRobustResourceInitEnabled, bool isExternalImage)
9692 {
9693 // Skip staging extra clears if robust resource init is enabled.
9694 if (!hasEmulatedImageChannels() || isRobustResourceInitEnabled)
9695 {
9696 return;
9697 }
9698
9699 VkClearValue clearValue = {};
9700 if (getIntendedFormat().hasDepthOrStencilBits())
9701 {
9702 clearValue.depthStencil = kRobustInitDepthStencilValue;
9703 }
9704 else
9705 {
9706 clearValue.color = kEmulatedInitColorValue;
9707 }
9708
9709 const VkImageAspectFlags aspectFlags = getAspectFlags();
9710
9711 // If the image has an emulated channel and robust resource init is not enabled, always clear
9712 // it. These channels will be masked out in future writes, and shouldn't contain uninitialized
9713 // values.
9714 //
9715 // For external images, we cannot clear the image entirely, as it may contain data in the
9716 // non-emulated channels. For depth/stencil images, clear is already per aspect, but for color
9717 // images we would need to take a special path where we only clear the emulated channels.
9718
9719 // Block images are not cleared, since no emulated channels are present if decoded.
9720 if (isExternalImage && getIntendedFormat().isBlock)
9721 {
9722 return;
9723 }
9724
9725 const bool clearOnlyEmulatedChannels =
9726 isExternalImage && !getIntendedFormat().hasDepthOrStencilBits();
9727 const VkColorComponentFlags colorMaskFlags =
9728 clearOnlyEmulatedChannels ? getEmulatedChannelsMask() : 0;
9729
9730 for (LevelIndex level(0); level < LevelIndex(mLevelCount); ++level)
9731 {
9732 gl::LevelIndex updateLevelGL = toGLLevel(level);
9733 gl::ImageIndex index =
9734 gl::ImageIndex::Make2DArrayRange(updateLevelGL.get(), 0, mLayerCount);
9735
9736 if (clearOnlyEmulatedChannels)
9737 {
9738 prependSubresourceUpdate(updateLevelGL,
9739 SubresourceUpdate(colorMaskFlags, clearValue.color, index));
9740 }
9741 else
9742 {
9743 prependSubresourceUpdate(updateLevelGL,
9744 SubresourceUpdate(aspectFlags, clearValue, index));
9745 }
9746 }
9747 }
9748
verifyEmulatedClearsAreBeforeOtherUpdates(const std::vector<SubresourceUpdate> & updates)9749 bool ImageHelper::verifyEmulatedClearsAreBeforeOtherUpdates(
9750 const std::vector<SubresourceUpdate> &updates)
9751 {
9752 bool isIteratingEmulatedClears = true;
9753
9754 for (const SubresourceUpdate &update : updates)
9755 {
9756 // If anything other than ClearEmulatedChannelsOnly is visited, there cannot be any
9757 // ClearEmulatedChannelsOnly updates after that.
9758 if (update.updateSource != UpdateSource::ClearEmulatedChannelsOnly)
9759 {
9760 isIteratingEmulatedClears = false;
9761 }
9762 else if (!isIteratingEmulatedClears)
9763 {
9764 // If ClearEmulatedChannelsOnly is visited after another update, that's an error.
9765 return false;
9766 }
9767 }
9768
9769 // Additionally, verify that emulated clear is not applied multiple times.
9770 if (updates.size() >= 2 && updates[1].updateSource == UpdateSource::ClearEmulatedChannelsOnly)
9771 {
9772 return false;
9773 }
9774
9775 return true;
9776 }
9777
stageSelfAsSubresourceUpdates(ContextVk * contextVk,uint32_t levelCount,gl::TextureType textureType,const gl::CubeFaceArray<gl::TexLevelMask> & skipLevels)9778 void ImageHelper::stageSelfAsSubresourceUpdates(
9779 ContextVk *contextVk,
9780 uint32_t levelCount,
9781 gl::TextureType textureType,
9782 const gl::CubeFaceArray<gl::TexLevelMask> &skipLevels)
9783
9784 {
9785 // Nothing to do if every level must be skipped
9786 const gl::TexLevelMask levelsMask(angle::BitMask<uint32_t>(levelCount)
9787 << mFirstAllocatedLevel.get());
9788 const gl::TexLevelMask skipLevelsAllFaces = AggregateSkipLevels(skipLevels);
9789
9790 if ((~skipLevelsAllFaces & levelsMask).none())
9791 {
9792 return;
9793 }
9794
9795 // Because we are cloning this object to another object, we must finalize the layout if it is
9796 // being used by current renderpass as attachment. Otherwise we are copying the incorrect layout
9797 // since it is determined at endRenderPass time.
9798 contextVk->finalizeImageLayout(this, {});
9799
9800 std::unique_ptr<RefCounted<ImageHelper>> prevImage =
9801 std::make_unique<RefCounted<ImageHelper>>();
9802
9803 // Move the necessary information for staged update to work, and keep the rest as part of this
9804 // object.
9805
9806 // Usage info
9807 prevImage->get().Resource::operator=(std::move(*this));
9808
9809 // Vulkan objects
9810 prevImage->get().mImage = std::move(mImage);
9811 prevImage->get().mDeviceMemory = std::move(mDeviceMemory);
9812 prevImage->get().mVmaAllocation = std::move(mVmaAllocation);
9813
9814 // Barrier information. Note: mLevelCount is set to levelCount so that only the necessary
9815 // levels are transitioned when flushing the update.
9816 prevImage->get().mIntendedFormatID = mIntendedFormatID;
9817 prevImage->get().mActualFormatID = mActualFormatID;
9818 prevImage->get().mCurrentLayout = mCurrentLayout;
9819 prevImage->get().mCurrentDeviceQueueIndex = mCurrentDeviceQueueIndex;
9820 prevImage->get().mLastNonShaderReadOnlyLayout = mLastNonShaderReadOnlyLayout;
9821 prevImage->get().mCurrentShaderReadStageMask = mCurrentShaderReadStageMask;
9822 prevImage->get().mLevelCount = levelCount;
9823 prevImage->get().mLayerCount = mLayerCount;
9824 prevImage->get().mImageSerial = mImageSerial;
9825 prevImage->get().mAllocationSize = mAllocationSize;
9826 prevImage->get().mMemoryAllocationType = mMemoryAllocationType;
9827 prevImage->get().mMemoryTypeIndex = mMemoryTypeIndex;
9828
9829 // Reset information for current (invalid) image.
9830 mCurrentLayout = ImageLayout::Undefined;
9831 mCurrentDeviceQueueIndex = kInvalidDeviceQueueIndex;
9832 mIsReleasedToExternal = false;
9833 mLastNonShaderReadOnlyLayout = ImageLayout::Undefined;
9834 mCurrentShaderReadStageMask = 0;
9835 mImageSerial = kInvalidImageSerial;
9836 mMemoryAllocationType = MemoryAllocationType::InvalidEnum;
9837
9838 setEntireContentUndefined();
9839
9840 // Stage updates from the previous image.
9841 for (LevelIndex levelVk(0); levelVk < LevelIndex(levelCount); ++levelVk)
9842 {
9843 gl::LevelIndex levelGL = toGLLevel(levelVk);
9844 if (!skipLevelsAllFaces.test(levelGL.get()))
9845 {
9846 const gl::ImageIndex index =
9847 gl::ImageIndex::Make2DArrayRange(levelGL.get(), 0, mLayerCount);
9848
9849 stageSubresourceUpdateFromImage(prevImage.get(), index, levelVk, gl::kOffsetZero,
9850 getLevelExtents(levelVk), mImageType);
9851 }
9852 else if (textureType == gl::TextureType::CubeMap)
9853 {
9854 for (uint32_t face = 0; face < gl::kCubeFaceCount; ++face)
9855 {
9856 if (!skipLevels[face][levelGL.get()])
9857 {
9858 const gl::ImageIndex index =
9859 gl::ImageIndex::Make2DArrayRange(levelGL.get(), face, 1);
9860
9861 stageSubresourceUpdateFromImage(prevImage.get(), index, levelVk,
9862 gl::kOffsetZero, getLevelExtents(levelVk),
9863 mImageType);
9864 }
9865 }
9866 }
9867 }
9868
9869 ASSERT(levelCount > 0);
9870 prevImage.release();
9871 }
9872
flushSingleSubresourceStagedUpdates(ContextVk * contextVk,gl::LevelIndex levelGL,uint32_t layer,uint32_t layerCount,ClearValuesArray * deferredClears,uint32_t deferredClearIndex)9873 angle::Result ImageHelper::flushSingleSubresourceStagedUpdates(ContextVk *contextVk,
9874 gl::LevelIndex levelGL,
9875 uint32_t layer,
9876 uint32_t layerCount,
9877 ClearValuesArray *deferredClears,
9878 uint32_t deferredClearIndex)
9879 {
9880 std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(levelGL);
9881 if (levelUpdates == nullptr || levelUpdates->empty())
9882 {
9883 return angle::Result::Continue;
9884 }
9885
9886 // Handle deferred clears. Search the updates list for a matching clear index.
9887 if (deferredClears)
9888 {
9889 Optional<size_t> foundClear;
9890
9891 for (size_t updateIndex = 0; updateIndex < levelUpdates->size(); ++updateIndex)
9892 {
9893 SubresourceUpdate &update = (*levelUpdates)[updateIndex];
9894
9895 if (update.intersectsLayerRange(layer, layerCount))
9896 {
9897 // On any data update or the clear does not match exact layer range, we'll need to
9898 // do a full upload.
9899 const bool isClear = IsClearOfAllChannels(update.updateSource);
9900 if (isClear && update.matchesLayerRange(layer, layerCount))
9901 {
9902 foundClear = updateIndex;
9903 }
9904 else
9905 {
9906 foundClear.reset();
9907 break;
9908 }
9909 }
9910 }
9911
9912 // If we have a valid index we defer the clear using the clear reference.
9913 if (foundClear.valid())
9914 {
9915 size_t foundIndex = foundClear.value();
9916 const ClearUpdate &update = (*levelUpdates)[foundIndex].data.clear;
9917
9918 // Note that this set command handles combined or separate depth/stencil clears.
9919 deferredClears->store(deferredClearIndex, update.aspectFlags, update.value);
9920
9921 // Do not call onWrite as it removes mCurrentSingleClearValue, but instead call
9922 // setContentDefined directly.
9923 setContentDefined(toVkLevel(levelGL), 1, layer, layerCount, update.aspectFlags);
9924
9925 // We process the updates again to erase any clears for this level.
9926 removeSingleSubresourceStagedUpdates(contextVk, levelGL, layer, layerCount);
9927 return angle::Result::Continue;
9928 }
9929
9930 // Otherwise we proceed with a normal update.
9931 }
9932
9933 return flushStagedUpdates(contextVk, levelGL, levelGL + 1, layer, layer + layerCount, {});
9934 }
9935
flushStagedClearEmulatedChannelsUpdates(ContextVk * contextVk,gl::LevelIndex levelGLStart,gl::LevelIndex levelGLLimit,bool * otherUpdatesToFlushOut)9936 angle::Result ImageHelper::flushStagedClearEmulatedChannelsUpdates(ContextVk *contextVk,
9937 gl::LevelIndex levelGLStart,
9938 gl::LevelIndex levelGLLimit,
9939 bool *otherUpdatesToFlushOut)
9940 {
9941 *otherUpdatesToFlushOut = false;
9942 for (gl::LevelIndex updateMipLevelGL = levelGLStart; updateMipLevelGL < levelGLLimit;
9943 ++updateMipLevelGL)
9944 {
9945 // It is expected that the checked mip levels in this loop do not surpass the size of
9946 // mSubresourceUpdates.
9947 std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(updateMipLevelGL);
9948 ASSERT(levelUpdates != nullptr);
9949
9950 // The levels with no updates should be skipped.
9951 if (levelUpdates->empty())
9952 {
9953 continue;
9954 }
9955
9956 // Since ClearEmulatedChannelsOnly is expected in the beginning and there cannot be more
9957 // than one such update type, we can process the first update and move on if there is
9958 // another update type in the list.
9959 ASSERT(verifyEmulatedClearsAreBeforeOtherUpdates(*levelUpdates));
9960 std::vector<SubresourceUpdate>::iterator update = (*levelUpdates).begin();
9961
9962 if (update->updateSource != UpdateSource::ClearEmulatedChannelsOnly)
9963 {
9964 *otherUpdatesToFlushOut = true;
9965 continue;
9966 }
9967
9968 // If found, ClearEmulatedChannelsOnly should be flushed before the others and removed from
9969 // the update list.
9970 ASSERT(update->updateSource == UpdateSource::ClearEmulatedChannelsOnly);
9971 uint32_t updateBaseLayer, updateLayerCount;
9972 update->getDestSubresource(mLayerCount, &updateBaseLayer, &updateLayerCount);
9973
9974 const LevelIndex updateMipLevelVk = toVkLevel(updateMipLevelGL);
9975 update->data.clear.levelIndex = updateMipLevelVk.get();
9976 ANGLE_TRY(clearEmulatedChannels(contextVk, update->data.clear.colorMaskFlags,
9977 update->data.clear.value, updateMipLevelVk, updateBaseLayer,
9978 updateLayerCount));
9979 // Do not call onWrite. Even though some channels of the image are cleared, don't consider
9980 // the contents defined. Also, since clearing emulated channels is a one-time thing that's
9981 // superseded by Clears, |mCurrentSingleClearValue| is irrelevant and can't have a value.
9982 ASSERT(!mCurrentSingleClearValue.valid());
9983
9984 levelUpdates->erase(update);
9985 if (!levelUpdates->empty())
9986 {
9987 ASSERT(levelUpdates->begin()->updateSource != UpdateSource::ClearEmulatedChannelsOnly);
9988 *otherUpdatesToFlushOut = true;
9989 }
9990 }
9991
9992 return angle::Result::Continue;
9993 }
9994
flushStagedUpdatesImpl(ContextVk * contextVk,gl::LevelIndex levelGLStart,gl::LevelIndex levelGLEnd,uint32_t layerStart,uint32_t layerEnd,const gl::TexLevelMask & skipLevelsAllFaces)9995 angle::Result ImageHelper::flushStagedUpdatesImpl(ContextVk *contextVk,
9996 gl::LevelIndex levelGLStart,
9997 gl::LevelIndex levelGLEnd,
9998 uint32_t layerStart,
9999 uint32_t layerEnd,
10000 const gl::TexLevelMask &skipLevelsAllFaces)
10001 {
10002 Renderer *renderer = contextVk->getRenderer();
10003
10004 const angle::FormatID &actualformat = getActualFormatID();
10005 const angle::FormatID &intendedFormat = getIntendedFormatID();
10006
10007 const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(getActualFormat());
10008
10009 // Start in TransferDst. Don't yet mark any subresource as having defined contents; that is
10010 // done with fine granularity as updates are applied. This is achieved by specifying a layer
10011 // that is outside the tracking range. Under some circumstances, ComputeWrite is also required.
10012 // This need not be applied if the only updates are ClearEmulatedChannels.
10013 CommandBufferAccess transferAccess;
10014 OutsideRenderPassCommandBufferHelper *commandBuffer = nullptr;
10015 bool transCoding = renderer->getFeatures().supportsComputeTranscodeEtcToBc.enabled &&
10016 IsETCFormat(intendedFormat) && IsBCFormat(actualformat);
10017
10018 if (transCoding)
10019 {
10020 transferAccess.onImageTransferDstAndComputeWrite(
10021 levelGLStart, 1, kMaxContentDefinedLayerCount, 0, aspectFlags, this);
10022 }
10023 else
10024 {
10025 transferAccess.onImageTransferWrite(levelGLStart, 1, kMaxContentDefinedLayerCount, 0,
10026 aspectFlags, this);
10027 }
10028 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBufferHelper(transferAccess, &commandBuffer));
10029
10030 // Flush the staged updates in each mip level.
10031 for (gl::LevelIndex updateMipLevelGL = levelGLStart; updateMipLevelGL < levelGLEnd;
10032 ++updateMipLevelGL)
10033 {
10034 // If updates to this level are specifically asked to be skipped, skip
10035 // them. This can happen when recreating an image that has been partially incompatibly
10036 // redefined, in which case only updates to the levels that haven't been redefined
10037 // should be flushed.
10038 if (skipLevelsAllFaces.test(updateMipLevelGL.get()))
10039 {
10040 continue;
10041 }
10042
10043 // It is expected that the checked mip levels in this loop do not surpass the size of
10044 // mSubresourceUpdates.
10045 std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(updateMipLevelGL);
10046 std::vector<SubresourceUpdate> updatesToKeep;
10047 ASSERT(levelUpdates != nullptr);
10048
10049 // Because updates may have overlapping layer ranges, we must first figure out the actual
10050 // layer ranges that will be flushed. The updatesToKeep list must compare against this
10051 // adjusted layer range. Otherwise you may end up keeping the update even though it is
10052 // overlapped with the update that gets flushed, and then content gets overwritten when
10053 // updatesToKeep gets flushed out.
10054 uint32_t adjustedLayerStart = layerStart, adjustedLayerEnd = layerEnd;
10055 if (levelUpdates->size() > 1)
10056 {
10057 adjustLayerRange(*levelUpdates, &adjustedLayerStart, &adjustedLayerEnd);
10058 }
10059
10060 for (SubresourceUpdate &update : *levelUpdates)
10061 {
10062 ASSERT(IsClearOfAllChannels(update.updateSource) ||
10063 (update.updateSource == UpdateSource::ClearPartial) ||
10064 (update.updateSource == UpdateSource::Buffer &&
10065 update.data.buffer.bufferHelper != nullptr) ||
10066 (update.updateSource == UpdateSource::Image &&
10067 update.refCounted.image != nullptr && update.refCounted.image->isReferenced() &&
10068 update.refCounted.image->get().valid()));
10069
10070 uint32_t updateBaseLayer, updateLayerCount;
10071 update.getDestSubresource(mLayerCount, &updateBaseLayer, &updateLayerCount);
10072
10073 // If the update layers don't intersect the requested layers, skip the update.
10074 const bool areUpdateLayersOutsideRange =
10075 updateBaseLayer + updateLayerCount <= adjustedLayerStart ||
10076 updateBaseLayer >= adjustedLayerEnd;
10077 if (areUpdateLayersOutsideRange)
10078 {
10079 updatesToKeep.emplace_back(std::move(update));
10080 continue;
10081 }
10082
10083 const LevelIndex updateMipLevelVk = toVkLevel(updateMipLevelGL);
10084
10085 // It seems we haven't fully support glCopyImageSubData
10086 // when compressed format emulated by uncompressed format.
10087 // make assumption that there is no data source come from image.
10088 ASSERT(!transCoding || (transCoding && update.updateSource == UpdateSource::Buffer));
10089 // The updates were holding gl::LevelIndex values so that they would not need
10090 // modification when the base level of the texture changes. Now that the update is
10091 // about to take effect, we need to change miplevel to LevelIndex.
10092 switch (update.updateSource)
10093 {
10094 case UpdateSource::Clear:
10095 case UpdateSource::ClearAfterInvalidate:
10096 {
10097 update.data.clear.levelIndex = updateMipLevelVk.get();
10098 break;
10099 }
10100 case UpdateSource::ClearPartial:
10101 {
10102 update.data.clearPartial.levelIndex = updateMipLevelVk.get();
10103 break;
10104 }
10105 case UpdateSource::Buffer:
10106 {
10107 if (!transCoding && !isDataFormatMatchForCopy(update.data.buffer.formatID))
10108 {
10109 // TODO: http://anglebug.com/42264884, we should handle this in higher level
10110 // code. If we have incompatible updates, skip but keep it.
10111 updatesToKeep.emplace_back(std::move(update));
10112 continue;
10113 }
10114 update.data.buffer.copyRegion.imageSubresource.mipLevel =
10115 updateMipLevelVk.get();
10116 break;
10117 }
10118 case UpdateSource::Image:
10119 {
10120 if (!isDataFormatMatchForCopy(update.data.image.formatID))
10121 {
10122 // If we have incompatible updates, skip but keep it.
10123 updatesToKeep.emplace_back(std::move(update));
10124 continue;
10125 }
10126 update.data.image.copyRegion.dstSubresource.mipLevel = updateMipLevelVk.get();
10127 break;
10128 }
10129 default:
10130 {
10131 UNREACHABLE();
10132 break;
10133 }
10134 }
10135
10136 // When a barrier is necessary when uploading updates to a level, we could instead move
10137 // to the next level and continue uploads in parallel. Once all levels need a barrier,
10138 // a single barrier can be issued and we could continue with the rest of the updates
10139 // from the first level. In case of multiple layer updates within the same level, a
10140 // barrier might be needed if there are multiple updates in the same parts of the image.
10141 ImageLayout barrierLayout =
10142 transCoding ? ImageLayout::TransferDstAndComputeWrite : ImageLayout::TransferDst;
10143 if (updateLayerCount >= kMaxParallelLayerWrites)
10144 {
10145 // If there are more subresources than bits we can track, always insert a barrier.
10146 recordWriteBarrier(contextVk, aspectFlags, barrierLayout, updateMipLevelGL, 1,
10147 updateBaseLayer, updateLayerCount, commandBuffer);
10148 mSubresourcesWrittenSinceBarrier[updateMipLevelGL.get()].set();
10149 }
10150 else
10151 {
10152 ImageLayerWriteMask subresourceHash =
10153 GetImageLayerWriteMask(updateBaseLayer, updateLayerCount);
10154
10155 if (areLevelSubresourcesWrittenWithinMaskRange(updateMipLevelGL.get(),
10156 subresourceHash))
10157 {
10158 // If there's overlap in subresource upload, issue a barrier.
10159 recordWriteBarrier(contextVk, aspectFlags, barrierLayout, updateMipLevelGL, 1,
10160 updateBaseLayer, updateLayerCount, commandBuffer);
10161 mSubresourcesWrittenSinceBarrier[updateMipLevelGL.get()].reset();
10162 }
10163 mSubresourcesWrittenSinceBarrier[updateMipLevelGL.get()] |= subresourceHash;
10164 }
10165
10166 // Add the necessary commands to the outside command buffer.
10167 switch (update.updateSource)
10168 {
10169 case UpdateSource::Clear:
10170 case UpdateSource::ClearAfterInvalidate:
10171 {
10172 clear(renderer, update.data.clear.aspectFlags, update.data.clear.value,
10173 updateMipLevelVk, updateBaseLayer, updateLayerCount,
10174 &commandBuffer->getCommandBuffer());
10175 contextVk->getPerfCounters().fullImageClears++;
10176 // Remember the latest operation is a clear call.
10177 mCurrentSingleClearValue = update.data.clear;
10178
10179 // Do not call onWrite as it removes mCurrentSingleClearValue, but instead call
10180 // setContentDefined directly.
10181 setContentDefined(updateMipLevelVk, 1, updateBaseLayer, updateLayerCount,
10182 update.data.clear.aspectFlags);
10183 break;
10184 }
10185 case UpdateSource::ClearPartial:
10186 {
10187 ClearPartialUpdate &clearPartialUpdate = update.data.clearPartial;
10188 gl::Box clearArea =
10189 gl::Box(clearPartialUpdate.offset, clearPartialUpdate.extent);
10190
10191 // clearTexture() uses LOAD_OP_CLEAR in a render pass to clear the texture. If
10192 // the texture has the depth dimension or multiple layers, the clear will be
10193 // performed layer by layer. In case of the former, the z-dimension will be used
10194 // as the layer index.
10195 UtilsVk::ClearTextureParameters params = {};
10196 params.aspectFlags = clearPartialUpdate.aspectFlags;
10197 params.level = updateMipLevelVk;
10198 params.clearArea = clearArea;
10199 params.clearValue = clearPartialUpdate.clearValue;
10200
10201 bool shouldUseDepthAsLayer =
10202 clearPartialUpdate.textureType == gl::TextureType::_3D;
10203 uint32_t clearBaseLayer =
10204 shouldUseDepthAsLayer ? clearArea.z : clearPartialUpdate.layerIndex;
10205 uint32_t clearLayerCount =
10206 shouldUseDepthAsLayer ? clearArea.depth : clearPartialUpdate.layerCount;
10207
10208 for (uint32_t layerIndex = clearBaseLayer;
10209 layerIndex < clearBaseLayer + clearLayerCount; ++layerIndex)
10210 {
10211 params.layer = layerIndex;
10212 ANGLE_TRY(contextVk->getUtils().clearTexture(contextVk, this, params));
10213 }
10214
10215 // Queue serial index becomes invalid after starting render pass for the op
10216 // above. Therefore, the outside command buffer should be re-acquired.
10217 ANGLE_TRY(
10218 contextVk->getOutsideRenderPassCommandBufferHelper({}, &commandBuffer));
10219 setContentDefined(updateMipLevelVk, 1, updateBaseLayer, updateLayerCount,
10220 clearPartialUpdate.aspectFlags);
10221 break;
10222 }
10223 case UpdateSource::Buffer:
10224 {
10225 BufferUpdate &bufferUpdate = update.data.buffer;
10226
10227 BufferHelper *currentBuffer = bufferUpdate.bufferHelper;
10228 ASSERT(currentBuffer && currentBuffer->valid());
10229 ANGLE_TRY(currentBuffer->flush(renderer));
10230
10231 CommandBufferAccess bufferAccess;
10232 VkBufferImageCopy *copyRegion = &update.data.buffer.copyRegion;
10233
10234 if (transCoding && update.data.buffer.formatID != actualformat)
10235 {
10236 bufferAccess.onBufferComputeShaderRead(currentBuffer);
10237 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBufferHelper(
10238 bufferAccess, &commandBuffer));
10239 ANGLE_TRY(contextVk->getUtils().transCodeEtcToBc(contextVk, currentBuffer,
10240 this, copyRegion));
10241 }
10242 else
10243 {
10244 bufferAccess.onBufferTransferRead(currentBuffer);
10245 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBufferHelper(
10246 bufferAccess, &commandBuffer));
10247 commandBuffer->getCommandBuffer().copyBufferToImage(
10248 currentBuffer->getBuffer().getHandle(), mImage,
10249 getCurrentLayout(renderer), 1, copyRegion);
10250 }
10251 bool commandBufferWasFlushed = false;
10252 ANGLE_TRY(contextVk->onCopyUpdate(currentBuffer->getSize(),
10253 &commandBufferWasFlushed));
10254 onWrite(updateMipLevelGL, 1, updateBaseLayer, updateLayerCount,
10255 copyRegion->imageSubresource.aspectMask);
10256
10257 // Update total staging buffer size.
10258 mTotalStagedBufferUpdateSize -= bufferUpdate.bufferHelper->getSize();
10259
10260 if (commandBufferWasFlushed)
10261 {
10262 ANGLE_TRY(
10263 contextVk->getOutsideRenderPassCommandBufferHelper({}, &commandBuffer));
10264 }
10265 break;
10266 }
10267 case UpdateSource::Image:
10268 {
10269 CommandBufferAccess imageAccess;
10270 imageAccess.onImageTransferRead(aspectFlags, &update.refCounted.image->get());
10271 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBufferHelper(imageAccess,
10272 &commandBuffer));
10273
10274 VkImageCopy *copyRegion = &update.data.image.copyRegion;
10275 commandBuffer->getCommandBuffer().copyImage(
10276 update.refCounted.image->get().getImage(),
10277 update.refCounted.image->get().getCurrentLayout(renderer), mImage,
10278 getCurrentLayout(renderer), 1, copyRegion);
10279 onWrite(updateMipLevelGL, 1, updateBaseLayer, updateLayerCount,
10280 copyRegion->dstSubresource.aspectMask);
10281 break;
10282 }
10283 default:
10284 {
10285 UNREACHABLE();
10286 break;
10287 }
10288 }
10289
10290 update.release(renderer);
10291 }
10292
10293 // Only remove the updates that were actually applied to the image.
10294 *levelUpdates = std::move(updatesToKeep);
10295 }
10296
10297 // After applying the updates, the image serial should match the current queue serial of the
10298 // outside command buffer.
10299 if (mUse.getSerials()[commandBuffer->getQueueSerial().getIndex()] !=
10300 commandBuffer->getQueueSerial().getSerial())
10301 {
10302 // There has been a submission after the retainImage() call. Update the queue serial again.
10303 setQueueSerial(commandBuffer->getQueueSerial());
10304 }
10305
10306 return angle::Result::Continue;
10307 }
10308
flushStagedUpdates(ContextVk * contextVk,gl::LevelIndex levelGLStart,gl::LevelIndex levelGLEnd,uint32_t layerStart,uint32_t layerEnd,const gl::CubeFaceArray<gl::TexLevelMask> & skipLevels)10309 angle::Result ImageHelper::flushStagedUpdates(ContextVk *contextVk,
10310 gl::LevelIndex levelGLStart,
10311 gl::LevelIndex levelGLEnd,
10312 uint32_t layerStart,
10313 uint32_t layerEnd,
10314 const gl::CubeFaceArray<gl::TexLevelMask> &skipLevels)
10315 {
10316 Renderer *renderer = contextVk->getRenderer();
10317
10318 if (!hasStagedUpdatesInLevels(levelGLStart, levelGLEnd))
10319 {
10320 return angle::Result::Continue;
10321 }
10322
10323 const gl::TexLevelMask skipLevelsAllFaces = AggregateSkipLevels(skipLevels);
10324 removeSupersededUpdates(contextVk, skipLevelsAllFaces);
10325
10326 // If a clear is requested and we know it was previously cleared with the same value, we drop
10327 // the clear.
10328 if (mCurrentSingleClearValue.valid())
10329 {
10330 std::vector<SubresourceUpdate> *levelUpdates =
10331 getLevelUpdates(gl::LevelIndex(mCurrentSingleClearValue.value().levelIndex));
10332 if (levelUpdates && levelUpdates->size() == 1)
10333 {
10334 SubresourceUpdate &update = (*levelUpdates)[0];
10335 if (IsClearOfAllChannels(update.updateSource) &&
10336 mCurrentSingleClearValue.value() == update.data.clear)
10337 {
10338 ASSERT(levelGLStart + 1 == levelGLEnd);
10339 setContentDefined(toVkLevel(levelGLStart), 1, layerStart, layerEnd - layerStart,
10340 update.data.clear.aspectFlags);
10341 ANGLE_VK_PERF_WARNING(contextVk, GL_DEBUG_SEVERITY_LOW,
10342 "Repeated Clear on framebuffer attachment dropped");
10343 update.release(renderer);
10344 levelUpdates->clear();
10345 return angle::Result::Continue;
10346 }
10347 }
10348 }
10349
10350 ASSERT(validateSubresourceUpdateRefCountsConsistent());
10351
10352 // Process the clear emulated channels from the updates first. They are expected to be at the
10353 // beginning of the level updates.
10354 bool otherUpdatesToFlushOut = false;
10355 clipLevelToUpdateListUpperLimit(&levelGLEnd);
10356 ANGLE_TRY(flushStagedClearEmulatedChannelsUpdates(contextVk, levelGLStart, levelGLEnd,
10357 &otherUpdatesToFlushOut));
10358
10359 // If updates remain after processing ClearEmulatedChannelsOnly updates, we should acquire the
10360 // outside command buffer and apply the necessary barriers. Otherwise, this function can return
10361 // early, skipping the next loop.
10362 if (otherUpdatesToFlushOut)
10363 {
10364 ANGLE_TRY(flushStagedUpdatesImpl(contextVk, levelGLStart, levelGLEnd, layerStart, layerEnd,
10365 skipLevelsAllFaces));
10366 }
10367
10368 // Compact mSubresourceUpdates, then check if there are any updates left.
10369 size_t compactSize;
10370 for (compactSize = mSubresourceUpdates.size(); compactSize > 0; --compactSize)
10371 {
10372 if (!mSubresourceUpdates[compactSize - 1].empty())
10373 {
10374 break;
10375 }
10376 }
10377 mSubresourceUpdates.resize(compactSize);
10378
10379 ASSERT(validateSubresourceUpdateRefCountsConsistent());
10380
10381 // If no updates left, release the staging buffers to save memory.
10382 if (mSubresourceUpdates.empty())
10383 {
10384 ASSERT(mTotalStagedBufferUpdateSize == 0);
10385 onStateChange(angle::SubjectMessage::InitializationComplete);
10386 }
10387
10388 return angle::Result::Continue;
10389 }
10390
flushAllStagedUpdates(ContextVk * contextVk)10391 angle::Result ImageHelper::flushAllStagedUpdates(ContextVk *contextVk)
10392 {
10393 return flushStagedUpdates(contextVk, mFirstAllocatedLevel, mFirstAllocatedLevel + mLevelCount,
10394 0, mLayerCount, {});
10395 }
10396
hasStagedUpdatesForSubresource(gl::LevelIndex levelGL,uint32_t layer,uint32_t layerCount) const10397 bool ImageHelper::hasStagedUpdatesForSubresource(gl::LevelIndex levelGL,
10398 uint32_t layer,
10399 uint32_t layerCount) const
10400 {
10401 // Check to see if any updates are staged for the given level and layer
10402
10403 const std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(levelGL);
10404 if (levelUpdates == nullptr || levelUpdates->empty())
10405 {
10406 return false;
10407 }
10408
10409 for (const SubresourceUpdate &update : *levelUpdates)
10410 {
10411 uint32_t updateBaseLayer, updateLayerCount;
10412 update.getDestSubresource(mLayerCount, &updateBaseLayer, &updateLayerCount);
10413
10414 const uint32_t updateLayerEnd = updateBaseLayer + updateLayerCount;
10415 const uint32_t layerEnd = layer + layerCount;
10416
10417 if ((layer >= updateBaseLayer && layer < updateLayerEnd) ||
10418 (layerEnd > updateBaseLayer && layerEnd <= updateLayerEnd))
10419 {
10420 // The layers intersect with the update range
10421 return true;
10422 }
10423 }
10424
10425 return false;
10426 }
10427
removeStagedClearUpdatesAndReturnColor(gl::LevelIndex levelGL,const VkClearColorValue ** color)10428 bool ImageHelper::removeStagedClearUpdatesAndReturnColor(gl::LevelIndex levelGL,
10429 const VkClearColorValue **color)
10430 {
10431 std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(levelGL);
10432 if (levelUpdates == nullptr || levelUpdates->empty())
10433 {
10434 return false;
10435 }
10436
10437 bool result = false;
10438
10439 for (size_t index = 0; index < levelUpdates->size();)
10440 {
10441 auto update = levelUpdates->begin() + index;
10442 if (IsClearOfAllChannels(update->updateSource))
10443 {
10444 if (color != nullptr)
10445 {
10446 *color = &update->data.clear.value.color;
10447 }
10448 levelUpdates->erase(update);
10449 result = true;
10450 }
10451 }
10452
10453 return result;
10454 }
10455
adjustLayerRange(const std::vector<SubresourceUpdate> & levelUpdates,uint32_t * layerStart,uint32_t * layerEnd)10456 void ImageHelper::adjustLayerRange(const std::vector<SubresourceUpdate> &levelUpdates,
10457 uint32_t *layerStart,
10458 uint32_t *layerEnd)
10459 {
10460 for (const SubresourceUpdate &update : levelUpdates)
10461 {
10462 uint32_t updateBaseLayer, updateLayerCount;
10463 update.getDestSubresource(mLayerCount, &updateBaseLayer, &updateLayerCount);
10464 uint32_t updateLayerEnd = updateBaseLayer + updateLayerCount;
10465
10466 // In some cases, the update has the bigger layer range than the request. If the update
10467 // layers intersect the requested layers, then expand the layer range to the maximum from
10468 // the update and from the request.
10469 const bool areUpdateLayersWithinRange =
10470 updateBaseLayer < *layerEnd && updateLayerEnd > *layerStart;
10471 if (areUpdateLayersWithinRange)
10472 {
10473 *layerStart = std::min(*layerStart, updateBaseLayer);
10474 *layerEnd = std::max(*layerEnd, updateLayerEnd);
10475 }
10476 }
10477 }
10478
getLastAllocatedLevel() const10479 gl::LevelIndex ImageHelper::getLastAllocatedLevel() const
10480 {
10481 return mFirstAllocatedLevel + mLevelCount - 1;
10482 }
10483
hasStagedUpdatesInAllocatedLevels() const10484 bool ImageHelper::hasStagedUpdatesInAllocatedLevels() const
10485 {
10486 return hasStagedUpdatesInLevels(mFirstAllocatedLevel, getLastAllocatedLevel() + 1);
10487 }
10488
hasStagedUpdatesInLevels(gl::LevelIndex levelStart,gl::LevelIndex levelEnd) const10489 bool ImageHelper::hasStagedUpdatesInLevels(gl::LevelIndex levelStart, gl::LevelIndex levelEnd) const
10490 {
10491 for (gl::LevelIndex level = levelStart; level < levelEnd; ++level)
10492 {
10493 const std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(level);
10494 if (levelUpdates == nullptr)
10495 {
10496 ASSERT(static_cast<size_t>(level.get()) >= mSubresourceUpdates.size());
10497 return false;
10498 }
10499
10500 if (!levelUpdates->empty())
10501 {
10502 return true;
10503 }
10504 }
10505 return false;
10506 }
10507
hasStagedImageUpdatesWithMismatchedFormat(gl::LevelIndex levelStart,gl::LevelIndex levelEnd,angle::FormatID formatID) const10508 bool ImageHelper::hasStagedImageUpdatesWithMismatchedFormat(gl::LevelIndex levelStart,
10509 gl::LevelIndex levelEnd,
10510 angle::FormatID formatID) const
10511 {
10512 for (gl::LevelIndex level = levelStart; level < levelEnd; ++level)
10513 {
10514 const std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(level);
10515 if (levelUpdates == nullptr)
10516 {
10517 continue;
10518 }
10519
10520 for (const SubresourceUpdate &update : *levelUpdates)
10521 {
10522 if (update.updateSource == UpdateSource::Image &&
10523 update.data.image.formatID != formatID)
10524 {
10525 return true;
10526 }
10527 }
10528 }
10529 return false;
10530 }
10531
hasBufferSourcedStagedUpdatesInAllLevels() const10532 bool ImageHelper::hasBufferSourcedStagedUpdatesInAllLevels() const
10533 {
10534 for (gl::LevelIndex level = mFirstAllocatedLevel; level <= getLastAllocatedLevel(); ++level)
10535 {
10536 const std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(level);
10537 if (levelUpdates == nullptr || levelUpdates->empty())
10538 {
10539 return false;
10540 }
10541
10542 bool hasUpdateSourceWithBufferOrPartialClear = false;
10543 for (const SubresourceUpdate &update : *levelUpdates)
10544 {
10545 if (update.updateSource == UpdateSource::Buffer ||
10546 update.updateSource == UpdateSource::ClearPartial)
10547 {
10548 hasUpdateSourceWithBufferOrPartialClear = true;
10549 break;
10550 }
10551 }
10552 if (!hasUpdateSourceWithBufferOrPartialClear)
10553 {
10554 return false;
10555 }
10556 }
10557 return true;
10558 }
10559
validateSubresourceUpdateBufferRefConsistent(RefCounted<BufferHelper> * buffer) const10560 bool ImageHelper::validateSubresourceUpdateBufferRefConsistent(
10561 RefCounted<BufferHelper> *buffer) const
10562 {
10563 if (buffer == nullptr)
10564 {
10565 return true;
10566 }
10567
10568 uint32_t refs = 0;
10569
10570 for (const std::vector<SubresourceUpdate> &levelUpdates : mSubresourceUpdates)
10571 {
10572 for (const SubresourceUpdate &update : levelUpdates)
10573 {
10574 if (update.updateSource == UpdateSource::Buffer && update.refCounted.buffer == buffer)
10575 {
10576 ++refs;
10577 }
10578 }
10579 }
10580
10581 return buffer->isRefCountAsExpected(refs);
10582 }
10583
validateSubresourceUpdateImageRefConsistent(RefCounted<ImageHelper> * image) const10584 bool ImageHelper::validateSubresourceUpdateImageRefConsistent(RefCounted<ImageHelper> *image) const
10585 {
10586 if (image == nullptr)
10587 {
10588 return true;
10589 }
10590
10591 uint32_t refs = 0;
10592
10593 for (const std::vector<SubresourceUpdate> &levelUpdates : mSubresourceUpdates)
10594 {
10595 for (const SubresourceUpdate &update : levelUpdates)
10596 {
10597 if (update.updateSource == UpdateSource::Image && update.refCounted.image == image)
10598 {
10599 ++refs;
10600 }
10601 }
10602 }
10603
10604 return image->isRefCountAsExpected(refs);
10605 }
10606
validateSubresourceUpdateRefCountsConsistent() const10607 bool ImageHelper::validateSubresourceUpdateRefCountsConsistent() const
10608 {
10609 for (const std::vector<SubresourceUpdate> &levelUpdates : mSubresourceUpdates)
10610 {
10611 for (const SubresourceUpdate &update : levelUpdates)
10612 {
10613 if (update.updateSource == UpdateSource::Image)
10614 {
10615 if (!validateSubresourceUpdateImageRefConsistent(update.refCounted.image))
10616 {
10617 return false;
10618 }
10619 }
10620 else if (update.updateSource == UpdateSource::Buffer)
10621 {
10622 if (!validateSubresourceUpdateBufferRefConsistent(update.refCounted.buffer))
10623 {
10624 return false;
10625 }
10626 }
10627 }
10628 }
10629
10630 return true;
10631 }
10632
pruneSupersededUpdatesForLevel(ContextVk * contextVk,const gl::LevelIndex level,const PruneReason reason)10633 void ImageHelper::pruneSupersededUpdatesForLevel(ContextVk *contextVk,
10634 const gl::LevelIndex level,
10635 const PruneReason reason)
10636 {
10637 constexpr VkDeviceSize kSubresourceUpdateSizeBeforePruning = 16 * 1024 * 1024; // 16 MB
10638 constexpr int kUpdateCountThreshold = 1024;
10639 std::vector<ImageHelper::SubresourceUpdate> *levelUpdates = getLevelUpdates(level);
10640
10641 // If we are below pruning threshold, nothing to do.
10642 const int updateCount = static_cast<int>(levelUpdates->size());
10643 const bool withinThreshold = updateCount < kUpdateCountThreshold &&
10644 mTotalStagedBufferUpdateSize < kSubresourceUpdateSizeBeforePruning;
10645 if (updateCount == 1 || (reason == PruneReason::MemoryOptimization && withinThreshold))
10646 {
10647 return;
10648 }
10649
10650 // Start from the most recent update and define a boundingBox that covers the region to be
10651 // updated. Walk through all earlier updates and if its update region is contained within the
10652 // boundingBox, mark it as superseded, otherwise reset the boundingBox and continue.
10653 //
10654 // Color, depth and stencil are the only types supported for now. The boundingBox for color and
10655 // depth types is at index 0 and index 1 has the boundingBox for stencil type.
10656 VkDeviceSize supersededUpdateSize = 0;
10657 std::array<gl::Box, 2> boundingBox = {gl::Box(gl::kOffsetZero, gl::Extents())};
10658
10659 auto canDropUpdate = [this, contextVk, level, &supersededUpdateSize,
10660 &boundingBox](SubresourceUpdate &update) {
10661 VkDeviceSize updateSize = 0;
10662 VkImageAspectFlags aspectMask = update.getDestAspectFlags();
10663 gl::Box currentUpdateBox(gl::kOffsetZero, gl::Extents());
10664
10665 const bool isColor =
10666 (aspectMask & (VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_PLANE_0_BIT |
10667 VK_IMAGE_ASPECT_PLANE_1_BIT | VK_IMAGE_ASPECT_PLANE_2_BIT)) != 0;
10668 const bool isDepth = (aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) != 0;
10669 const bool isStencil = (aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) != 0;
10670 ASSERT(isColor || isDepth || isStencil);
10671 int aspectIndex = (isColor || isDepth) ? 0 : 1;
10672
10673 if (update.updateSource == UpdateSource::Buffer)
10674 {
10675 currentUpdateBox = gl::Box(update.data.buffer.copyRegion.imageOffset,
10676 update.data.buffer.copyRegion.imageExtent);
10677 updateSize = update.data.buffer.bufferHelper->getSize();
10678 }
10679 else if (update.updateSource == UpdateSource::Image)
10680 {
10681 currentUpdateBox = gl::Box(update.data.image.copyRegion.dstOffset,
10682 update.data.image.copyRegion.extent);
10683 }
10684 else if (update.updateSource == UpdateSource::ClearPartial)
10685 {
10686 currentUpdateBox = gl::Box(
10687 update.data.clearPartial.offset.x, update.data.clearPartial.offset.z,
10688 update.data.clearPartial.offset.z, update.data.clearPartial.extent.width,
10689 update.data.clearPartial.extent.height, update.data.clearPartial.extent.depth);
10690 }
10691 else
10692 {
10693 ASSERT(IsClear(update.updateSource));
10694 currentUpdateBox = gl::Box(gl::kOffsetZero, getLevelExtents(toVkLevel(level)));
10695 }
10696
10697 // Account for updates to layered images
10698 uint32_t layerIndex = 0;
10699 uint32_t layerCount = 0;
10700 update.getDestSubresource(mLayerCount, &layerIndex, &layerCount);
10701 if (layerIndex > 0 || layerCount > 1)
10702 {
10703 currentUpdateBox.z = layerIndex;
10704 currentUpdateBox.depth = layerCount;
10705 }
10706
10707 // Check if current update region is superseded by the accumulated update region
10708 if (boundingBox[aspectIndex].contains(currentUpdateBox))
10709 {
10710 ANGLE_VK_PERF_WARNING(contextVk, GL_DEBUG_SEVERITY_LOW,
10711 "Dropped texture update that is superseded by a more recent one");
10712
10713 // Release the superseded update
10714 update.release(contextVk->getRenderer());
10715
10716 // Update pruning size
10717 supersededUpdateSize += updateSize;
10718
10719 return true;
10720 }
10721 else
10722 {
10723 // Extend boundingBox to best accommodate current update's box.
10724 boundingBox[aspectIndex].extend(currentUpdateBox);
10725 // If the volume of the current update box is larger than the extended boundingBox
10726 // use that as the new boundingBox instead.
10727 if (currentUpdateBox.volume() > boundingBox[aspectIndex].volume())
10728 {
10729 boundingBox[aspectIndex] = currentUpdateBox;
10730 }
10731 return false;
10732 }
10733 };
10734
10735 levelUpdates->erase(
10736 levelUpdates->begin(),
10737 std::remove_if(levelUpdates->rbegin(), levelUpdates->rend(), canDropUpdate).base());
10738
10739 // Update total staging buffer size
10740 mTotalStagedBufferUpdateSize -= supersededUpdateSize;
10741 }
10742
removeSupersededUpdates(ContextVk * contextVk,const gl::TexLevelMask skipLevelsAllFaces)10743 void ImageHelper::removeSupersededUpdates(ContextVk *contextVk,
10744 const gl::TexLevelMask skipLevelsAllFaces)
10745 {
10746 ASSERT(validateSubresourceUpdateRefCountsConsistent());
10747
10748 for (LevelIndex levelVk(0); levelVk < LevelIndex(mLevelCount); ++levelVk)
10749 {
10750 gl::LevelIndex levelGL = toGLLevel(levelVk);
10751 std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(levelGL);
10752 if (levelUpdates == nullptr || levelUpdates->size() == 0 ||
10753 skipLevelsAllFaces.test(levelGL.get()))
10754 {
10755 // There are no valid updates to process, continue.
10756 continue;
10757 }
10758
10759 // ClearEmulatedChannelsOnly updates can only be in the beginning of the list of updates.
10760 // They don't entirely clear the image, so they cannot supersede any update.
10761 ASSERT(verifyEmulatedClearsAreBeforeOtherUpdates(*levelUpdates));
10762
10763 pruneSupersededUpdatesForLevel(contextVk, levelGL, PruneReason::MinimizeWorkBeforeFlush);
10764 }
10765
10766 ASSERT(validateSubresourceUpdateRefCountsConsistent());
10767 }
10768
copyImageDataToBuffer(ContextVk * contextVk,gl::LevelIndex sourceLevelGL,uint32_t layerCount,uint32_t baseLayer,const gl::Box & sourceArea,BufferHelper * dstBuffer,uint8_t ** outDataPtr)10769 angle::Result ImageHelper::copyImageDataToBuffer(ContextVk *contextVk,
10770 gl::LevelIndex sourceLevelGL,
10771 uint32_t layerCount,
10772 uint32_t baseLayer,
10773 const gl::Box &sourceArea,
10774 BufferHelper *dstBuffer,
10775 uint8_t **outDataPtr)
10776 {
10777 ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::copyImageDataToBuffer");
10778 Renderer *renderer = contextVk->getRenderer();
10779
10780 const angle::Format &imageFormat = getActualFormat();
10781
10782 // As noted in the OpenGL ES 3.2 specs, table 8.13, CopyTexImage cannot
10783 // be used for depth textures. There is no way for the image or buffer
10784 // used in this function to be of some combined depth and stencil format.
10785 ASSERT(getAspectFlags() == VK_IMAGE_ASPECT_COLOR_BIT);
10786
10787 uint32_t pixelBytes = imageFormat.pixelBytes;
10788 size_t bufferSize =
10789 sourceArea.width * sourceArea.height * sourceArea.depth * pixelBytes * layerCount;
10790
10791 const VkImageAspectFlags aspectFlags = getAspectFlags();
10792
10793 // Allocate staging buffer prefer coherent
10794 ASSERT(dstBuffer != nullptr && !dstBuffer->valid());
10795 VkDeviceSize dstOffset;
10796 ANGLE_TRY(contextVk->initBufferForImageCopy(dstBuffer, bufferSize,
10797 MemoryCoherency::CachedPreferCoherent,
10798 imageFormat.id, &dstOffset, outDataPtr));
10799 ANGLE_TRY(dstBuffer->flush(contextVk->getRenderer()));
10800
10801 VkBuffer bufferHandle = dstBuffer->getBuffer().getHandle();
10802
10803 LevelIndex sourceLevelVk = toVkLevel(sourceLevelGL);
10804
10805 VkBufferImageCopy regions = {};
10806 uint32_t regionCount = 1;
10807 // Default to non-combined DS case
10808 regions.bufferOffset = dstOffset;
10809 regions.bufferRowLength = 0;
10810 regions.bufferImageHeight = 0;
10811 regions.imageExtent.width = sourceArea.width;
10812 regions.imageExtent.height = sourceArea.height;
10813 regions.imageExtent.depth = sourceArea.depth;
10814 regions.imageOffset.x = sourceArea.x;
10815 regions.imageOffset.y = sourceArea.y;
10816 regions.imageOffset.z = sourceArea.z;
10817 regions.imageSubresource.aspectMask = aspectFlags;
10818 regions.imageSubresource.baseArrayLayer = baseLayer;
10819 regions.imageSubresource.layerCount = layerCount;
10820 regions.imageSubresource.mipLevel = sourceLevelVk.get();
10821
10822 CommandBufferAccess access;
10823 access.onBufferTransferWrite(dstBuffer);
10824 access.onImageTransferRead(aspectFlags, this);
10825
10826 OutsideRenderPassCommandBuffer *commandBuffer;
10827 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
10828
10829 commandBuffer->copyImageToBuffer(mImage, getCurrentLayout(renderer), bufferHandle, regionCount,
10830 ®ions);
10831
10832 return angle::Result::Continue;
10833 }
10834
copySurfaceImageToBuffer(DisplayVk * displayVk,gl::LevelIndex sourceLevelGL,uint32_t layerCount,uint32_t baseLayer,const gl::Box & sourceArea,vk::BufferHelper * bufferHelper)10835 angle::Result ImageHelper::copySurfaceImageToBuffer(DisplayVk *displayVk,
10836 gl::LevelIndex sourceLevelGL,
10837 uint32_t layerCount,
10838 uint32_t baseLayer,
10839 const gl::Box &sourceArea,
10840 vk::BufferHelper *bufferHelper)
10841 {
10842 ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::copySurfaceImageToBuffer");
10843
10844 Renderer *renderer = displayVk->getRenderer();
10845
10846 VkBufferImageCopy region = {};
10847 region.bufferOffset = 0;
10848 region.bufferRowLength = 0;
10849 region.bufferImageHeight = 0;
10850 region.imageExtent.width = sourceArea.width;
10851 region.imageExtent.height = sourceArea.height;
10852 region.imageExtent.depth = sourceArea.depth;
10853 region.imageOffset.x = sourceArea.x;
10854 region.imageOffset.y = sourceArea.y;
10855 region.imageOffset.z = sourceArea.z;
10856 region.imageSubresource.aspectMask = getAspectFlags();
10857 region.imageSubresource.baseArrayLayer = baseLayer;
10858 region.imageSubresource.layerCount = layerCount;
10859 region.imageSubresource.mipLevel = toVkLevel(sourceLevelGL).get();
10860
10861 // We may have a valid event here but we do not have a collector to collect it. Release the
10862 // event here to force pipelineBarrier.
10863 mCurrentEvent.release(displayVk->getRenderer());
10864
10865 PrimaryCommandBuffer primaryCommandBuffer;
10866 ANGLE_TRY(renderer->getCommandBufferOneOff(displayVk, ProtectionType::Unprotected,
10867 &primaryCommandBuffer));
10868
10869 VkSemaphore acquireNextImageSemaphore;
10870 barrierImpl(displayVk, getAspectFlags(), ImageLayout::TransferSrc,
10871 displayVk->getDeviceQueueIndex(), nullptr, &primaryCommandBuffer,
10872 &acquireNextImageSemaphore);
10873 primaryCommandBuffer.copyImageToBuffer(mImage, getCurrentLayout(renderer),
10874 bufferHelper->getBuffer().getHandle(), 1, ®ion);
10875
10876 ANGLE_VK_TRY(displayVk, primaryCommandBuffer.end());
10877
10878 QueueSerial submitQueueSerial;
10879 ANGLE_TRY(renderer->queueSubmitOneOff(
10880 displayVk, std::move(primaryCommandBuffer), ProtectionType::Unprotected,
10881 egl::ContextPriority::Medium, acquireNextImageSemaphore,
10882 kSwapchainAcquireImageWaitStageFlags, vk::SubmitPolicy::AllowDeferred, &submitQueueSerial));
10883
10884 return renderer->finishQueueSerial(displayVk, submitQueueSerial);
10885 }
10886
copyBufferToSurfaceImage(DisplayVk * displayVk,gl::LevelIndex sourceLevelGL,uint32_t layerCount,uint32_t baseLayer,const gl::Box & sourceArea,vk::BufferHelper * bufferHelper)10887 angle::Result ImageHelper::copyBufferToSurfaceImage(DisplayVk *displayVk,
10888 gl::LevelIndex sourceLevelGL,
10889 uint32_t layerCount,
10890 uint32_t baseLayer,
10891 const gl::Box &sourceArea,
10892 vk::BufferHelper *bufferHelper)
10893 {
10894 ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::copyBufferToSurfaceImage");
10895
10896 Renderer *renderer = displayVk->getRenderer();
10897
10898 VkBufferImageCopy region = {};
10899 region.bufferOffset = 0;
10900 region.bufferRowLength = 0;
10901 region.bufferImageHeight = 0;
10902 region.imageExtent.width = sourceArea.width;
10903 region.imageExtent.height = sourceArea.height;
10904 region.imageExtent.depth = sourceArea.depth;
10905 region.imageOffset.x = sourceArea.x;
10906 region.imageOffset.y = sourceArea.y;
10907 region.imageOffset.z = sourceArea.z;
10908 region.imageSubresource.aspectMask = getAspectFlags();
10909 region.imageSubresource.baseArrayLayer = baseLayer;
10910 region.imageSubresource.layerCount = layerCount;
10911 region.imageSubresource.mipLevel = toVkLevel(sourceLevelGL).get();
10912
10913 // We may have a valid event here but we do not have a collector to collect it. Release the
10914 // event here to force pipelineBarrier.
10915 mCurrentEvent.release(displayVk->getRenderer());
10916
10917 PrimaryCommandBuffer commandBuffer;
10918 ANGLE_TRY(
10919 renderer->getCommandBufferOneOff(displayVk, ProtectionType::Unprotected, &commandBuffer));
10920
10921 VkSemaphore acquireNextImageSemaphore;
10922 barrierImpl(displayVk, getAspectFlags(), ImageLayout::TransferDst,
10923 displayVk->getDeviceQueueIndex(), nullptr, &commandBuffer,
10924 &acquireNextImageSemaphore);
10925 commandBuffer.copyBufferToImage(bufferHelper->getBuffer().getHandle(), mImage,
10926 getCurrentLayout(renderer), 1, ®ion);
10927
10928 ANGLE_VK_TRY(displayVk, commandBuffer.end());
10929
10930 QueueSerial submitQueueSerial;
10931 ANGLE_TRY(renderer->queueSubmitOneOff(
10932 displayVk, std::move(commandBuffer), ProtectionType::Unprotected,
10933 egl::ContextPriority::Medium, acquireNextImageSemaphore,
10934 kSwapchainAcquireImageWaitStageFlags, vk::SubmitPolicy::AllowDeferred, &submitQueueSerial));
10935
10936 return renderer->finishQueueSerial(displayVk, submitQueueSerial);
10937 }
10938
10939 // static
GetReadPixelsParams(ContextVk * contextVk,const gl::PixelPackState & packState,gl::Buffer * packBuffer,GLenum format,GLenum type,const gl::Rectangle & area,const gl::Rectangle & clippedArea,PackPixelsParams * paramsOut,GLuint * skipBytesOut)10940 angle::Result ImageHelper::GetReadPixelsParams(ContextVk *contextVk,
10941 const gl::PixelPackState &packState,
10942 gl::Buffer *packBuffer,
10943 GLenum format,
10944 GLenum type,
10945 const gl::Rectangle &area,
10946 const gl::Rectangle &clippedArea,
10947 PackPixelsParams *paramsOut,
10948 GLuint *skipBytesOut)
10949 {
10950 const gl::InternalFormat &sizedFormatInfo = gl::GetInternalFormatInfo(format, type);
10951
10952 GLuint outputPitch = 0;
10953 ANGLE_VK_CHECK_MATH(contextVk,
10954 sizedFormatInfo.computeRowPitch(type, area.width, packState.alignment,
10955 packState.rowLength, &outputPitch));
10956 ANGLE_VK_CHECK_MATH(contextVk, sizedFormatInfo.computeSkipBytes(type, outputPitch, 0, packState,
10957 false, skipBytesOut));
10958
10959 ANGLE_TRY(GetPackPixelsParams(sizedFormatInfo, outputPitch, packState, packBuffer, area,
10960 clippedArea, paramsOut, skipBytesOut));
10961 return angle::Result::Continue;
10962 }
10963
readPixelsForGetImage(ContextVk * contextVk,const gl::PixelPackState & packState,gl::Buffer * packBuffer,gl::LevelIndex levelGL,uint32_t layer,uint32_t layerCount,GLenum format,GLenum type,void * pixels)10964 angle::Result ImageHelper::readPixelsForGetImage(ContextVk *contextVk,
10965 const gl::PixelPackState &packState,
10966 gl::Buffer *packBuffer,
10967 gl::LevelIndex levelGL,
10968 uint32_t layer,
10969 uint32_t layerCount,
10970 GLenum format,
10971 GLenum type,
10972 void *pixels)
10973 {
10974 const angle::Format &angleFormat = GetFormatFromFormatType(format, type);
10975
10976 VkImageAspectFlagBits aspectFlags = {};
10977 if (angleFormat.redBits > 0 || angleFormat.blueBits > 0 || angleFormat.greenBits > 0 ||
10978 angleFormat.alphaBits > 0 || angleFormat.luminanceBits > 0)
10979 {
10980 aspectFlags = static_cast<VkImageAspectFlagBits>(aspectFlags | VK_IMAGE_ASPECT_COLOR_BIT);
10981 }
10982 else
10983 {
10984 if (angleFormat.depthBits > 0)
10985 {
10986 aspectFlags =
10987 static_cast<VkImageAspectFlagBits>(aspectFlags | VK_IMAGE_ASPECT_DEPTH_BIT);
10988 }
10989 if (angleFormat.stencilBits > 0)
10990 {
10991 aspectFlags =
10992 static_cast<VkImageAspectFlagBits>(aspectFlags | VK_IMAGE_ASPECT_STENCIL_BIT);
10993 }
10994 }
10995
10996 ASSERT(aspectFlags != 0);
10997
10998 PackPixelsParams params;
10999 GLuint outputSkipBytes = 0;
11000
11001 const LevelIndex levelVk = toVkLevel(levelGL);
11002 const gl::Extents mipExtents = getLevelExtents(levelVk);
11003 gl::Rectangle area(0, 0, mipExtents.width, mipExtents.height);
11004
11005 ANGLE_TRY(GetReadPixelsParams(contextVk, packState, packBuffer, format, type, area, area,
11006 ¶ms, &outputSkipBytes));
11007
11008 if (mExtents.depth > 1 || layerCount > 1)
11009 {
11010 ASSERT(layer == 0);
11011 ASSERT(layerCount == 1 || mipExtents.depth == 1);
11012
11013 uint32_t lastLayer = std::max(static_cast<uint32_t>(mipExtents.depth), layerCount);
11014
11015 // Depth > 1 means this is a 3D texture and we need to copy all layers
11016 for (uint32_t mipLayer = 0; mipLayer < lastLayer; mipLayer++)
11017 {
11018 ANGLE_TRY(readPixels(contextVk, area, params, aspectFlags, levelGL, mipLayer,
11019 static_cast<uint8_t *>(pixels) + outputSkipBytes));
11020
11021 outputSkipBytes += mipExtents.width * mipExtents.height *
11022 gl::GetInternalFormatInfo(format, type).pixelBytes;
11023 }
11024 }
11025 else
11026 {
11027 ANGLE_TRY(readPixels(contextVk, area, params, aspectFlags, levelGL, layer,
11028 static_cast<uint8_t *>(pixels) + outputSkipBytes));
11029 }
11030
11031 return angle::Result::Continue;
11032 }
11033
readPixelsForCompressedGetImage(ContextVk * contextVk,const gl::PixelPackState & packState,gl::Buffer * packBuffer,gl::LevelIndex levelGL,uint32_t layer,uint32_t layerCount,void * pixels)11034 angle::Result ImageHelper::readPixelsForCompressedGetImage(ContextVk *contextVk,
11035 const gl::PixelPackState &packState,
11036 gl::Buffer *packBuffer,
11037 gl::LevelIndex levelGL,
11038 uint32_t layer,
11039 uint32_t layerCount,
11040 void *pixels)
11041 {
11042 PackPixelsParams params;
11043 GLuint outputSkipBytes = 0;
11044
11045 const LevelIndex levelVk = toVkLevel(levelGL);
11046 gl::Extents mipExtents = getLevelExtents(levelVk);
11047 gl::Rectangle area(0, 0, mipExtents.width, mipExtents.height);
11048
11049 VkImageAspectFlagBits aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT;
11050
11051 const angle::Format *readFormat = &getActualFormat();
11052
11053 // TODO(anglebug.com/42264702): Implement encoding for emuluated compression formats
11054 ANGLE_VK_CHECK(contextVk, readFormat->isBlock, VK_ERROR_FORMAT_NOT_SUPPORTED);
11055
11056 if (mExtents.depth > 1 || layerCount > 1)
11057 {
11058 ASSERT(layer == 0);
11059 ASSERT(layerCount == 1 || mipExtents.depth == 1);
11060
11061 uint32_t lastLayer = std::max(static_cast<uint32_t>(mipExtents.depth), layerCount);
11062
11063 const vk::Format &vkFormat = contextVk->getRenderer()->getFormat(readFormat->id);
11064 const gl::InternalFormat &storageFormatInfo =
11065 vkFormat.getInternalFormatInfo(readFormat->componentType);
11066
11067 // Calculate size for one layer
11068 mipExtents.depth = 1;
11069 GLuint layerSize;
11070 ANGLE_VK_CHECK_MATH(contextVk,
11071 storageFormatInfo.computeCompressedImageSize(mipExtents, &layerSize));
11072
11073 // Depth > 1 means this is a 3D texture and we need to copy all layers
11074 for (uint32_t mipLayer = 0; mipLayer < lastLayer; mipLayer++)
11075 {
11076 ANGLE_TRY(readPixels(contextVk, area, params, aspectFlags, levelGL, mipLayer,
11077 static_cast<uint8_t *>(pixels) + outputSkipBytes));
11078 outputSkipBytes += layerSize;
11079 }
11080 }
11081 else
11082 {
11083 ANGLE_TRY(readPixels(contextVk, area, params, aspectFlags, levelGL, layer,
11084 static_cast<uint8_t *>(pixels) + outputSkipBytes));
11085 }
11086
11087 return angle::Result::Continue;
11088 }
11089
readPixelsWithCompute(ContextVk * contextVk,ImageHelper * src,const PackPixelsParams & packPixelsParams,const VkOffset3D & srcOffset,const VkExtent3D & srcExtent,ptrdiff_t pixelsOffset,const VkImageSubresourceLayers & srcSubresource)11090 angle::Result ImageHelper::readPixelsWithCompute(ContextVk *contextVk,
11091 ImageHelper *src,
11092 const PackPixelsParams &packPixelsParams,
11093 const VkOffset3D &srcOffset,
11094 const VkExtent3D &srcExtent,
11095 ptrdiff_t pixelsOffset,
11096 const VkImageSubresourceLayers &srcSubresource)
11097 {
11098 ASSERT(srcOffset.z == 0 || srcSubresource.baseArrayLayer == 0);
11099
11100 UtilsVk::CopyImageToBufferParameters params = {};
11101 params.srcOffset[0] = srcOffset.x;
11102 params.srcOffset[1] = srcOffset.y;
11103 params.srcLayer = std::max<uint32_t>(srcOffset.z, srcSubresource.baseArrayLayer);
11104 params.srcMip = LevelIndex(srcSubresource.mipLevel);
11105 params.size[0] = srcExtent.width;
11106 params.size[1] = srcExtent.height;
11107 params.outputOffset = packPixelsParams.offset + pixelsOffset;
11108 params.outputPitch = packPixelsParams.outputPitch;
11109 params.reverseRowOrder = packPixelsParams.reverseRowOrder;
11110 params.outputFormat = packPixelsParams.destFormat;
11111
11112 BufferHelper &packBuffer = GetImpl(packPixelsParams.packBuffer)->getBuffer();
11113
11114 return contextVk->getUtils().copyImageToBuffer(contextVk, &packBuffer, src, params);
11115 }
11116
canCopyWithTransformForReadPixels(const PackPixelsParams & packPixelsParams,const VkExtent3D & srcExtent,const angle::Format * readFormat,ptrdiff_t pixelsOffset)11117 bool ImageHelper::canCopyWithTransformForReadPixels(const PackPixelsParams &packPixelsParams,
11118 const VkExtent3D &srcExtent,
11119 const angle::Format *readFormat,
11120 ptrdiff_t pixelsOffset)
11121 {
11122 ASSERT(mActualFormatID != angle::FormatID::NONE && mIntendedFormatID != angle::FormatID::NONE);
11123
11124 // Only allow copies to PBOs with identical format.
11125 const bool isSameFormatCopy = *readFormat == *packPixelsParams.destFormat;
11126
11127 // Disallow any transformation.
11128 const bool needsTransformation =
11129 packPixelsParams.rotation != SurfaceRotation::Identity || packPixelsParams.reverseRowOrder;
11130
11131 // Disallow copies when the output pitch cannot be correctly specified in Vulkan.
11132 const bool isPitchMultipleOfTexelSize =
11133 packPixelsParams.outputPitch % readFormat->pixelBytes == 0;
11134
11135 // Disallow copies when PBO offset violates Vulkan bufferOffset alignment requirements.
11136 const BufferHelper &packBuffer = GetImpl(packPixelsParams.packBuffer)->getBuffer();
11137 const VkDeviceSize offset = packBuffer.getOffset() + packPixelsParams.offset + pixelsOffset;
11138 const bool isOffsetMultipleOfTexelSize = offset % readFormat->pixelBytes == 0;
11139
11140 // Disallow copies when PBO row length is smaller than the source area width.
11141 const bool isRowLengthEnough =
11142 packPixelsParams.outputPitch >= srcExtent.width * readFormat->pixelBytes;
11143
11144 // Don't allow copies from emulated formats for simplicity.
11145 return !hasEmulatedImageFormat() && isSameFormatCopy && !needsTransformation &&
11146 isPitchMultipleOfTexelSize && isOffsetMultipleOfTexelSize && isRowLengthEnough;
11147 }
11148
canCopyWithComputeForReadPixels(const PackPixelsParams & packPixelsParams,const VkExtent3D & srcExtent,const angle::Format * readFormat,ptrdiff_t pixelsOffset)11149 bool ImageHelper::canCopyWithComputeForReadPixels(const PackPixelsParams &packPixelsParams,
11150 const VkExtent3D &srcExtent,
11151 const angle::Format *readFormat,
11152 ptrdiff_t pixelsOffset)
11153 {
11154 ASSERT(mActualFormatID != angle::FormatID::NONE && mIntendedFormatID != angle::FormatID::NONE);
11155 const angle::Format *writeFormat = packPixelsParams.destFormat;
11156
11157 // For now, only float formats are supported with 4-byte 4-channel normalized pixels for output.
11158 const bool isFloat =
11159 !readFormat->isSint() && !readFormat->isUint() && !readFormat->hasDepthOrStencilBits();
11160 const bool isFourByteOutput = writeFormat->pixelBytes == 4 && writeFormat->channelCount == 4;
11161 const bool isNormalizedOutput = writeFormat->isUnorm() || writeFormat->isSnorm();
11162
11163 // Disallow rotation.
11164 const bool needsTransformation = packPixelsParams.rotation != SurfaceRotation::Identity;
11165
11166 // Disallow copies when the output pitch cannot be correctly specified in Vulkan.
11167 const bool isPitchMultipleOfTexelSize =
11168 packPixelsParams.outputPitch % readFormat->pixelBytes == 0;
11169
11170 // Disallow copies when the output offset is not aligned to uint32_t
11171 const bool isOffsetMultipleOfUint =
11172 (packPixelsParams.offset + pixelsOffset) % readFormat->pixelBytes == 0;
11173
11174 // Disallow copies when PBO row length is smaller than the source area width.
11175 const bool isRowLengthEnough =
11176 packPixelsParams.outputPitch >= srcExtent.width * readFormat->pixelBytes;
11177
11178 return isFloat && isFourByteOutput && isNormalizedOutput && !needsTransformation &&
11179 isPitchMultipleOfTexelSize && isOffsetMultipleOfUint && isRowLengthEnough;
11180 }
11181
readPixels(ContextVk * contextVk,const gl::Rectangle & area,const PackPixelsParams & packPixelsParams,VkImageAspectFlagBits copyAspectFlags,gl::LevelIndex levelGL,uint32_t layer,void * pixels)11182 angle::Result ImageHelper::readPixels(ContextVk *contextVk,
11183 const gl::Rectangle &area,
11184 const PackPixelsParams &packPixelsParams,
11185 VkImageAspectFlagBits copyAspectFlags,
11186 gl::LevelIndex levelGL,
11187 uint32_t layer,
11188 void *pixels)
11189 {
11190 ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::readPixels");
11191
11192 const angle::Format &readFormat = getActualFormat();
11193
11194 if (readFormat.depthBits == 0)
11195 {
11196 copyAspectFlags =
11197 static_cast<VkImageAspectFlagBits>(copyAspectFlags & ~VK_IMAGE_ASPECT_DEPTH_BIT);
11198 }
11199 if (readFormat.stencilBits == 0)
11200 {
11201 copyAspectFlags =
11202 static_cast<VkImageAspectFlagBits>(copyAspectFlags & ~VK_IMAGE_ASPECT_STENCIL_BIT);
11203 }
11204
11205 if (copyAspectFlags == IMAGE_ASPECT_DEPTH_STENCIL)
11206 {
11207 const angle::Format &depthFormat =
11208 GetDepthStencilImageToBufferFormat(readFormat, VK_IMAGE_ASPECT_DEPTH_BIT);
11209 const angle::Format &stencilFormat =
11210 GetDepthStencilImageToBufferFormat(readFormat, VK_IMAGE_ASPECT_STENCIL_BIT);
11211
11212 int depthOffset = 0;
11213 int stencilOffset = 0;
11214 switch (readFormat.id)
11215 {
11216 case angle::FormatID::D24_UNORM_S8_UINT:
11217 depthOffset = 1;
11218 stencilOffset = 0;
11219 break;
11220
11221 case angle::FormatID::D32_FLOAT_S8X24_UINT:
11222 depthOffset = 0;
11223 stencilOffset = 4;
11224 break;
11225
11226 default:
11227 UNREACHABLE();
11228 }
11229
11230 ASSERT(depthOffset > 0 || stencilOffset > 0);
11231 ASSERT(depthOffset + depthFormat.depthBits / 8 <= readFormat.pixelBytes);
11232 ASSERT(stencilOffset + stencilFormat.stencilBits / 8 <= readFormat.pixelBytes);
11233
11234 // Read the depth values, tightly-packed
11235 angle::MemoryBuffer depthBuffer;
11236 ANGLE_VK_CHECK_ALLOC(contextVk,
11237 depthBuffer.resize(depthFormat.pixelBytes * area.width * area.height));
11238 ANGLE_TRY(
11239 readPixelsImpl(contextVk, area,
11240 PackPixelsParams(area, depthFormat, depthFormat.pixelBytes * area.width,
11241 false, nullptr, 0),
11242 VK_IMAGE_ASPECT_DEPTH_BIT, levelGL, layer, depthBuffer.data()));
11243
11244 // Read the stencil values, tightly-packed
11245 angle::MemoryBuffer stencilBuffer;
11246 ANGLE_VK_CHECK_ALLOC(
11247 contextVk, stencilBuffer.resize(stencilFormat.pixelBytes * area.width * area.height));
11248 ANGLE_TRY(readPixelsImpl(
11249 contextVk, area,
11250 PackPixelsParams(area, stencilFormat, stencilFormat.pixelBytes * area.width, false,
11251 nullptr, 0),
11252 VK_IMAGE_ASPECT_STENCIL_BIT, levelGL, layer, stencilBuffer.data()));
11253
11254 // Interleave them together
11255 angle::MemoryBuffer readPixelBuffer;
11256 ANGLE_VK_CHECK_ALLOC(
11257 contextVk, readPixelBuffer.resize(readFormat.pixelBytes * area.width * area.height));
11258 readPixelBuffer.fill(0);
11259 for (int i = 0; i < area.width * area.height; i++)
11260 {
11261 uint8_t *readPixel = readPixelBuffer.data() + i * readFormat.pixelBytes;
11262 memcpy(readPixel + depthOffset, depthBuffer.data() + i * depthFormat.pixelBytes,
11263 depthFormat.depthBits / 8);
11264 memcpy(readPixel + stencilOffset, stencilBuffer.data() + i * stencilFormat.pixelBytes,
11265 stencilFormat.stencilBits / 8);
11266 }
11267
11268 // Pack the interleaved depth and stencil into user-provided
11269 // destination, per user's pack pixels params
11270
11271 // The compressed format path in packReadPixelBuffer isn't applicable
11272 // to our case, let's make extra sure we won't hit it
11273 ASSERT(!readFormat.isBlock);
11274 return packReadPixelBuffer(contextVk, area, packPixelsParams, readFormat, readFormat,
11275 readPixelBuffer.data(), levelGL, pixels);
11276 }
11277
11278 return readPixelsImpl(contextVk, area, packPixelsParams, copyAspectFlags, levelGL, layer,
11279 pixels);
11280 }
11281
readPixelsImpl(ContextVk * contextVk,const gl::Rectangle & area,const PackPixelsParams & packPixelsParams,VkImageAspectFlagBits copyAspectFlags,gl::LevelIndex levelGL,uint32_t layer,void * pixels)11282 angle::Result ImageHelper::readPixelsImpl(ContextVk *contextVk,
11283 const gl::Rectangle &area,
11284 const PackPixelsParams &packPixelsParams,
11285 VkImageAspectFlagBits copyAspectFlags,
11286 gl::LevelIndex levelGL,
11287 uint32_t layer,
11288 void *pixels)
11289 {
11290 ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::readPixelsImpl");
11291
11292 Renderer *renderer = contextVk->getRenderer();
11293
11294 bool isExternalFormat = getExternalFormat() != 0;
11295 ASSERT(!isExternalFormat || (mActualFormatID >= angle::FormatID::EXTERNAL0 &&
11296 mActualFormatID <= angle::FormatID::EXTERNAL7));
11297
11298 // If the source image is multisampled, we need to resolve it into a temporary image before
11299 // performing a readback.
11300 bool isMultisampled = mSamples > 1;
11301 RendererScoped<ImageHelper> resolvedImage(contextVk->getRenderer());
11302
11303 ImageHelper *src = this;
11304
11305 ASSERT(!hasStagedUpdatesForSubresource(levelGL, layer, 1));
11306
11307 if (isMultisampled)
11308 {
11309 ANGLE_TRY(resolvedImage.get().init2DStaging(
11310 contextVk, contextVk->getState().hasProtectedContent(), renderer->getMemoryProperties(),
11311 gl::Extents(area.width, area.height, 1), mIntendedFormatID, mActualFormatID,
11312 VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
11313 VK_IMAGE_USAGE_SAMPLED_BIT,
11314 1));
11315 }
11316 else if (isExternalFormat)
11317 {
11318 ANGLE_TRY(resolvedImage.get().init2DStaging(
11319 contextVk, contextVk->getState().hasProtectedContent(), renderer->getMemoryProperties(),
11320 gl::Extents(area.width, area.height, 1), angle::FormatID::R8G8B8A8_UNORM,
11321 angle::FormatID::R8G8B8A8_UNORM,
11322 VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
11323 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
11324 1));
11325 }
11326
11327 VkImageAspectFlags layoutChangeAspectFlags = src->getAspectFlags();
11328
11329 const angle::Format *rgbaFormat = &angle::Format::Get(angle::FormatID::R8G8B8A8_UNORM);
11330 const angle::Format *readFormat = isExternalFormat ? rgbaFormat : &getActualFormat();
11331 const vk::Format &vkFormat = contextVk->getRenderer()->getFormat(readFormat->id);
11332 const gl::InternalFormat &storageFormatInfo =
11333 vkFormat.getInternalFormatInfo(readFormat->componentType);
11334
11335 if (copyAspectFlags != VK_IMAGE_ASPECT_COLOR_BIT)
11336 {
11337 readFormat = &GetDepthStencilImageToBufferFormat(*readFormat, copyAspectFlags);
11338 }
11339
11340 VkOffset3D srcOffset = {area.x, area.y, 0};
11341
11342 VkImageSubresourceLayers srcSubresource = {};
11343 srcSubresource.aspectMask = copyAspectFlags;
11344 srcSubresource.mipLevel = toVkLevel(levelGL).get();
11345 srcSubresource.baseArrayLayer = layer;
11346 srcSubresource.layerCount = 1;
11347
11348 VkExtent3D srcExtent = {static_cast<uint32_t>(area.width), static_cast<uint32_t>(area.height),
11349 1};
11350
11351 if (mExtents.depth > 1)
11352 {
11353 // Depth > 1 means this is a 3D texture and we need special handling
11354 srcOffset.z = layer;
11355 srcSubresource.baseArrayLayer = 0;
11356 }
11357
11358 if (isExternalFormat)
11359 {
11360 CommandBufferAccess access;
11361 access.onImageTransferRead(layoutChangeAspectFlags, this);
11362 OutsideRenderPassCommandBuffer *commandBuffer;
11363 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
11364
11365 // Create some temp views because copyImage works in terms of them
11366 gl::TextureType textureType = Get2DTextureType(1, resolvedImage.get().getSamples());
11367
11368 // Surely we have a view of this already!
11369 vk::ImageView srcView;
11370 ANGLE_TRY(src->initLayerImageView(contextVk, textureType, VK_IMAGE_ASPECT_COLOR_BIT,
11371 gl::SwizzleState(), &srcView, vk::LevelIndex(0), 1, 0,
11372 mLayerCount));
11373 vk::ImageView stagingView;
11374 ANGLE_TRY(resolvedImage.get().initLayerImageView(
11375 contextVk, textureType, VK_IMAGE_ASPECT_COLOR_BIT, gl::SwizzleState(), &stagingView,
11376 vk::LevelIndex(0), 1, 0, mLayerCount));
11377
11378 UtilsVk::CopyImageParameters params = {};
11379 params.srcOffset[0] = srcOffset.x;
11380 params.srcOffset[1] = srcOffset.y;
11381 params.srcExtents[0] = srcExtent.width;
11382 params.srcExtents[1] = srcExtent.height;
11383 params.srcHeight = srcExtent.height;
11384 ANGLE_TRY(contextVk->getUtils().copyImage(contextVk, &resolvedImage.get(), &stagingView,
11385 src, &srcView, params));
11386
11387 CommandBufferAccess readAccess;
11388 readAccess.onImageTransferRead(layoutChangeAspectFlags, &resolvedImage.get());
11389 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(readAccess, &commandBuffer));
11390
11391 // Make the resolved image the target of buffer copy
11392 src = &resolvedImage.get();
11393 srcOffset = {0, 0, 0};
11394 srcSubresource.baseArrayLayer = 0;
11395 srcSubresource.layerCount = 1;
11396 srcSubresource.mipLevel = 0;
11397
11398 // Mark our temp views as garbage immediately
11399 contextVk->addGarbage(&srcView);
11400 contextVk->addGarbage(&stagingView);
11401 }
11402
11403 if (isMultisampled)
11404 {
11405 CommandBufferAccess access;
11406 access.onImageTransferRead(layoutChangeAspectFlags, this);
11407 access.onImageTransferWrite(gl::LevelIndex(0), 1, 0, 1, layoutChangeAspectFlags,
11408 &resolvedImage.get());
11409
11410 OutsideRenderPassCommandBuffer *commandBuffer;
11411 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
11412
11413 // Note: resolve only works on color images (not depth/stencil).
11414 ASSERT(copyAspectFlags == VK_IMAGE_ASPECT_COLOR_BIT);
11415
11416 VkImageResolve resolveRegion = {};
11417 resolveRegion.srcSubresource = srcSubresource;
11418 resolveRegion.srcOffset = srcOffset;
11419 resolveRegion.dstSubresource.aspectMask = copyAspectFlags;
11420 resolveRegion.dstSubresource.mipLevel = 0;
11421 resolveRegion.dstSubresource.baseArrayLayer = 0;
11422 resolveRegion.dstSubresource.layerCount = 1;
11423 resolveRegion.dstOffset = {};
11424 resolveRegion.extent = srcExtent;
11425
11426 resolve(&resolvedImage.get(), resolveRegion, commandBuffer);
11427
11428 // Make the resolved image the target of buffer copy.
11429 src = &resolvedImage.get();
11430 srcOffset = {0, 0, 0};
11431 srcSubresource.baseArrayLayer = 0;
11432 srcSubresource.layerCount = 1;
11433 srcSubresource.mipLevel = 0;
11434 }
11435
11436 // If PBO and if possible, copy directly on the GPU.
11437 if (packPixelsParams.packBuffer)
11438 {
11439 ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::readPixelsImpl - PBO");
11440
11441 const ptrdiff_t pixelsOffset = reinterpret_cast<ptrdiff_t>(pixels);
11442 if (canCopyWithTransformForReadPixels(packPixelsParams, srcExtent, readFormat,
11443 pixelsOffset))
11444 {
11445 BufferHelper &packBuffer = GetImpl(packPixelsParams.packBuffer)->getBuffer();
11446 VkDeviceSize packBufferOffset = packBuffer.getOffset();
11447
11448 CommandBufferAccess copyAccess;
11449 copyAccess.onBufferTransferWrite(&packBuffer);
11450 copyAccess.onImageTransferRead(layoutChangeAspectFlags, src);
11451
11452 OutsideRenderPassCommandBuffer *copyCommandBuffer;
11453 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(copyAccess, ©CommandBuffer));
11454
11455 ASSERT(packPixelsParams.outputPitch % readFormat->pixelBytes == 0);
11456
11457 VkBufferImageCopy region = {};
11458 region.bufferImageHeight = srcExtent.height;
11459 region.bufferOffset = packBufferOffset + packPixelsParams.offset + pixelsOffset;
11460 region.bufferRowLength = packPixelsParams.outputPitch / readFormat->pixelBytes;
11461 region.imageExtent = srcExtent;
11462 region.imageOffset = srcOffset;
11463 region.imageSubresource = srcSubresource;
11464
11465 copyCommandBuffer->copyImageToBuffer(src->getImage(), src->getCurrentLayout(renderer),
11466 packBuffer.getBuffer().getHandle(), 1, ®ion);
11467 return angle::Result::Continue;
11468 }
11469 if (canCopyWithComputeForReadPixels(packPixelsParams, srcExtent, readFormat, pixelsOffset))
11470 {
11471 ANGLE_TRY(readPixelsWithCompute(contextVk, src, packPixelsParams, srcOffset, srcExtent,
11472 pixelsOffset, srcSubresource));
11473 return angle::Result::Continue;
11474 }
11475 }
11476
11477 ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::readPixelsImpl - CPU Readback");
11478
11479 RendererScoped<vk::BufferHelper> readBuffer(renderer);
11480 vk::BufferHelper *stagingBuffer = &readBuffer.get();
11481
11482 uint8_t *readPixelBuffer = nullptr;
11483 VkDeviceSize stagingOffset = 0;
11484 size_t allocationSize = readFormat->pixelBytes * area.width * area.height;
11485
11486 ANGLE_TRY(contextVk->initBufferForImageCopy(stagingBuffer, allocationSize,
11487 MemoryCoherency::CachedPreferCoherent,
11488 readFormat->id, &stagingOffset, &readPixelBuffer));
11489 ANGLE_TRY(stagingBuffer->flush(renderer));
11490 VkBuffer bufferHandle = stagingBuffer->getBuffer().getHandle();
11491
11492 VkBufferImageCopy region = {};
11493 region.bufferImageHeight = srcExtent.height;
11494 region.bufferOffset = stagingOffset;
11495 region.bufferRowLength = srcExtent.width;
11496 region.imageExtent = srcExtent;
11497 region.imageOffset = srcOffset;
11498 region.imageSubresource = srcSubresource;
11499
11500 // For compressed textures, vkCmdCopyImageToBuffer requires
11501 // a region that is a multiple of the block size.
11502 if (readFormat->isBlock)
11503 {
11504 region.bufferRowLength =
11505 roundUp(region.bufferRowLength, storageFormatInfo.compressedBlockWidth);
11506 region.bufferImageHeight =
11507 roundUp(region.bufferImageHeight, storageFormatInfo.compressedBlockHeight);
11508 }
11509
11510 CommandBufferAccess readbackAccess;
11511 readbackAccess.onBufferTransferWrite(stagingBuffer);
11512 readbackAccess.onImageTransferRead(layoutChangeAspectFlags, src);
11513
11514 OutsideRenderPassCommandBuffer *readbackCommandBuffer;
11515 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(readbackAccess, &readbackCommandBuffer));
11516
11517 readbackCommandBuffer->copyImageToBuffer(src->getImage(), src->getCurrentLayout(renderer),
11518 bufferHandle, 1, ®ion);
11519
11520 ANGLE_VK_PERF_WARNING(contextVk, GL_DEBUG_SEVERITY_HIGH, "GPU stall due to ReadPixels");
11521
11522 // Triggers a full finish.
11523 ANGLE_TRY(contextVk->finishImpl(RenderPassClosureReason::GLReadPixels));
11524 // invalidate must be called after wait for finish.
11525 ANGLE_TRY(stagingBuffer->invalidate(renderer));
11526
11527 return packReadPixelBuffer(contextVk, area, packPixelsParams, getActualFormat(), *readFormat,
11528 readPixelBuffer, levelGL, pixels);
11529 }
11530
packReadPixelBuffer(ContextVk * contextVk,const gl::Rectangle & area,const PackPixelsParams & packPixelsParams,const angle::Format & readFormat,const angle::Format & aspectFormat,const uint8_t * readPixelBuffer,gl::LevelIndex levelGL,void * pixels)11531 angle::Result ImageHelper::packReadPixelBuffer(ContextVk *contextVk,
11532 const gl::Rectangle &area,
11533 const PackPixelsParams &packPixelsParams,
11534 const angle::Format &readFormat,
11535 const angle::Format &aspectFormat,
11536 const uint8_t *readPixelBuffer,
11537 gl::LevelIndex levelGL,
11538 void *pixels)
11539 {
11540 const vk::Format &vkFormat = contextVk->getRenderer()->getFormat(readFormat.id);
11541 const gl::InternalFormat &storageFormatInfo =
11542 vkFormat.getInternalFormatInfo(readFormat.componentType);
11543
11544 if (readFormat.isBlock)
11545 {
11546 ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::packReadPixelBuffer - Block");
11547
11548 ASSERT(readFormat == aspectFormat);
11549
11550 const LevelIndex levelVk = toVkLevel(levelGL);
11551 gl::Extents levelExtents = getLevelExtents(levelVk);
11552
11553 // Calculate size of one layer
11554 levelExtents.depth = 1;
11555 GLuint layerSize;
11556 ANGLE_VK_CHECK_MATH(contextVk,
11557 storageFormatInfo.computeCompressedImageSize(levelExtents, &layerSize));
11558 memcpy(pixels, readPixelBuffer, layerSize);
11559 }
11560 else if (packPixelsParams.packBuffer)
11561 {
11562 ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::packReadPixelBuffer - PBO");
11563
11564 // Must map the PBO in order to read its contents (and then unmap it later)
11565 BufferVk *packBufferVk = GetImpl(packPixelsParams.packBuffer);
11566 void *mapPtr = nullptr;
11567 ANGLE_TRY(packBufferVk->mapImpl(contextVk, GL_MAP_WRITE_BIT, &mapPtr));
11568 uint8_t *dst = static_cast<uint8_t *>(mapPtr) + reinterpret_cast<ptrdiff_t>(pixels);
11569 PackPixels(packPixelsParams, aspectFormat, area.width * aspectFormat.pixelBytes,
11570 readPixelBuffer, dst);
11571 ANGLE_TRY(packBufferVk->unmapImpl(contextVk));
11572 }
11573 else
11574 {
11575 PackPixels(packPixelsParams, aspectFormat, area.width * aspectFormat.pixelBytes,
11576 readPixelBuffer, static_cast<uint8_t *>(pixels));
11577 }
11578
11579 return angle::Result::Continue;
11580 }
11581
11582 // ImageHelper::SubresourceUpdate implementation
SubresourceUpdate()11583 ImageHelper::SubresourceUpdate::SubresourceUpdate() : updateSource(UpdateSource::Buffer)
11584 {
11585 data.buffer.bufferHelper = nullptr;
11586 refCounted.buffer = nullptr;
11587 }
11588
SubresourceUpdate(const VkImageAspectFlags aspectFlags,const VkClearValue & clearValue,const gl::TextureType textureType,const uint32_t levelIndex,const uint32_t layerIndex,const uint32_t layerCount,const gl::Box & clearArea)11589 ImageHelper::SubresourceUpdate::SubresourceUpdate(const VkImageAspectFlags aspectFlags,
11590 const VkClearValue &clearValue,
11591 const gl::TextureType textureType,
11592 const uint32_t levelIndex,
11593 const uint32_t layerIndex,
11594 const uint32_t layerCount,
11595 const gl::Box &clearArea)
11596 : updateSource(UpdateSource::ClearPartial)
11597 {
11598 data.clearPartial.aspectFlags = aspectFlags;
11599 data.clearPartial.levelIndex = levelIndex;
11600 data.clearPartial.textureType = textureType;
11601 data.clearPartial.layerIndex = layerIndex;
11602 data.clearPartial.layerCount = layerCount;
11603 data.clearPartial.offset = {clearArea.x, clearArea.y, clearArea.z};
11604 data.clearPartial.extent = {static_cast<uint32_t>(clearArea.width),
11605 static_cast<uint32_t>(clearArea.height),
11606 static_cast<uint32_t>(clearArea.depth)};
11607 data.clearPartial.clearValue = clearValue;
11608 }
11609
~SubresourceUpdate()11610 ImageHelper::SubresourceUpdate::~SubresourceUpdate() {}
11611
SubresourceUpdate(RefCounted<BufferHelper> * bufferIn,BufferHelper * bufferHelperIn,const VkBufferImageCopy & copyRegionIn,angle::FormatID formatID)11612 ImageHelper::SubresourceUpdate::SubresourceUpdate(RefCounted<BufferHelper> *bufferIn,
11613 BufferHelper *bufferHelperIn,
11614 const VkBufferImageCopy ©RegionIn,
11615 angle::FormatID formatID)
11616 : updateSource(UpdateSource::Buffer)
11617 {
11618 refCounted.buffer = bufferIn;
11619 if (refCounted.buffer != nullptr)
11620 {
11621 refCounted.buffer->addRef();
11622 }
11623 data.buffer.bufferHelper = bufferHelperIn;
11624 data.buffer.copyRegion = copyRegionIn;
11625 data.buffer.formatID = formatID;
11626 }
11627
SubresourceUpdate(RefCounted<ImageHelper> * imageIn,const VkImageCopy & copyRegionIn,angle::FormatID formatID)11628 ImageHelper::SubresourceUpdate::SubresourceUpdate(RefCounted<ImageHelper> *imageIn,
11629 const VkImageCopy ©RegionIn,
11630 angle::FormatID formatID)
11631 : updateSource(UpdateSource::Image)
11632 {
11633 refCounted.image = imageIn;
11634 refCounted.image->addRef();
11635 data.image.copyRegion = copyRegionIn;
11636 data.image.formatID = formatID;
11637 }
11638
SubresourceUpdate(VkImageAspectFlags aspectFlags,const VkClearValue & clearValue,const gl::ImageIndex & imageIndex)11639 ImageHelper::SubresourceUpdate::SubresourceUpdate(VkImageAspectFlags aspectFlags,
11640 const VkClearValue &clearValue,
11641 const gl::ImageIndex &imageIndex)
11642 : SubresourceUpdate(
11643 aspectFlags,
11644 clearValue,
11645 gl::LevelIndex(imageIndex.getLevelIndex()),
11646 imageIndex.hasLayer() ? imageIndex.getLayerIndex() : 0,
11647 imageIndex.hasLayer() ? imageIndex.getLayerCount() : VK_REMAINING_ARRAY_LAYERS)
11648 {}
11649
SubresourceUpdate(VkImageAspectFlags aspectFlags,const VkClearValue & clearValue,gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount)11650 ImageHelper::SubresourceUpdate::SubresourceUpdate(VkImageAspectFlags aspectFlags,
11651 const VkClearValue &clearValue,
11652 gl::LevelIndex level,
11653 uint32_t layerIndex,
11654 uint32_t layerCount)
11655 : updateSource(UpdateSource::Clear)
11656 {
11657 refCounted.image = nullptr;
11658 data.clear.aspectFlags = aspectFlags;
11659 data.clear.value = clearValue;
11660 data.clear.levelIndex = level.get();
11661 data.clear.layerIndex = layerIndex;
11662 data.clear.layerCount = layerCount;
11663 data.clear.colorMaskFlags = 0;
11664 }
11665
SubresourceUpdate(VkColorComponentFlags colorMaskFlags,const VkClearColorValue & clearValue,const gl::ImageIndex & imageIndex)11666 ImageHelper::SubresourceUpdate::SubresourceUpdate(VkColorComponentFlags colorMaskFlags,
11667 const VkClearColorValue &clearValue,
11668 const gl::ImageIndex &imageIndex)
11669 : updateSource(UpdateSource::ClearEmulatedChannelsOnly)
11670 {
11671 refCounted.image = nullptr;
11672 data.clear.aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT;
11673 data.clear.value.color = clearValue;
11674 data.clear.levelIndex = imageIndex.getLevelIndex();
11675 data.clear.layerIndex = imageIndex.hasLayer() ? imageIndex.getLayerIndex() : 0;
11676 data.clear.layerCount =
11677 imageIndex.hasLayer() ? imageIndex.getLayerCount() : VK_REMAINING_ARRAY_LAYERS;
11678 data.clear.colorMaskFlags = colorMaskFlags;
11679 }
11680
SubresourceUpdate(SubresourceUpdate && other)11681 ImageHelper::SubresourceUpdate::SubresourceUpdate(SubresourceUpdate &&other)
11682 : updateSource(other.updateSource)
11683 {
11684 switch (updateSource)
11685 {
11686 case UpdateSource::Clear:
11687 case UpdateSource::ClearEmulatedChannelsOnly:
11688 case UpdateSource::ClearAfterInvalidate:
11689 data.clear = other.data.clear;
11690 refCounted.buffer = nullptr;
11691 break;
11692 case UpdateSource::ClearPartial:
11693 data.clearPartial = other.data.clearPartial;
11694 break;
11695 case UpdateSource::Buffer:
11696 data.buffer = other.data.buffer;
11697 refCounted.buffer = other.refCounted.buffer;
11698 other.refCounted.buffer = nullptr;
11699 break;
11700 case UpdateSource::Image:
11701 data.image = other.data.image;
11702 refCounted.image = other.refCounted.image;
11703 other.refCounted.image = nullptr;
11704 break;
11705 default:
11706 UNREACHABLE();
11707 }
11708 }
11709
operator =(SubresourceUpdate && other)11710 ImageHelper::SubresourceUpdate &ImageHelper::SubresourceUpdate::operator=(SubresourceUpdate &&other)
11711 {
11712 // Given that the update is a union of three structs, we can't use std::swap on the fields. For
11713 // example, |this| may be an Image update and |other| may be a Buffer update.
11714 // The following could work:
11715 //
11716 // SubresourceUpdate oldThis;
11717 // Set oldThis to this->field based on updateSource
11718 // Set this->otherField to other.otherField based on other.updateSource
11719 // Set other.field to oldThis->field based on updateSource
11720 // std::Swap(updateSource, other.updateSource);
11721 //
11722 // It's much simpler to just swap the memory instead.
11723
11724 SubresourceUpdate oldThis;
11725 memcpy(&oldThis, this, sizeof(*this));
11726 memcpy(this, &other, sizeof(*this));
11727 memcpy(&other, &oldThis, sizeof(*this));
11728
11729 return *this;
11730 }
11731
release(Renderer * renderer)11732 void ImageHelper::SubresourceUpdate::release(Renderer *renderer)
11733 {
11734 if (updateSource == UpdateSource::Image)
11735 {
11736 refCounted.image->releaseRef();
11737
11738 if (!refCounted.image->isReferenced())
11739 {
11740 // Staging images won't be used in render pass attachments.
11741 refCounted.image->get().releaseImage(renderer);
11742 refCounted.image->get().releaseStagedUpdates(renderer);
11743 SafeDelete(refCounted.image);
11744 }
11745
11746 refCounted.image = nullptr;
11747 }
11748 else if (updateSource == UpdateSource::Buffer && refCounted.buffer != nullptr)
11749 {
11750 refCounted.buffer->releaseRef();
11751
11752 if (!refCounted.buffer->isReferenced())
11753 {
11754 refCounted.buffer->get().release(renderer);
11755 SafeDelete(refCounted.buffer);
11756 }
11757
11758 refCounted.buffer = nullptr;
11759 }
11760 }
11761
matchesLayerRange(uint32_t layerIndex,uint32_t layerCount) const11762 bool ImageHelper::SubresourceUpdate::matchesLayerRange(uint32_t layerIndex,
11763 uint32_t layerCount) const
11764 {
11765 uint32_t updateBaseLayer, updateLayerCount;
11766 getDestSubresource(gl::ImageIndex::kEntireLevel, &updateBaseLayer, &updateLayerCount);
11767
11768 return updateBaseLayer == layerIndex &&
11769 (updateLayerCount == layerCount || updateLayerCount == VK_REMAINING_ARRAY_LAYERS);
11770 }
11771
intersectsLayerRange(uint32_t layerIndex,uint32_t layerCount) const11772 bool ImageHelper::SubresourceUpdate::intersectsLayerRange(uint32_t layerIndex,
11773 uint32_t layerCount) const
11774 {
11775 uint32_t updateBaseLayer, updateLayerCount;
11776 getDestSubresource(gl::ImageIndex::kEntireLevel, &updateBaseLayer, &updateLayerCount);
11777 uint32_t updateLayerEnd = updateBaseLayer + updateLayerCount;
11778
11779 return updateBaseLayer < (layerIndex + layerCount) && updateLayerEnd > layerIndex;
11780 }
11781
getDestSubresource(uint32_t imageLayerCount,uint32_t * baseLayerOut,uint32_t * layerCountOut) const11782 void ImageHelper::SubresourceUpdate::getDestSubresource(uint32_t imageLayerCount,
11783 uint32_t *baseLayerOut,
11784 uint32_t *layerCountOut) const
11785 {
11786 if (IsClear(updateSource))
11787 {
11788 *baseLayerOut = data.clear.layerIndex;
11789 *layerCountOut = data.clear.layerCount;
11790
11791 if (*layerCountOut == static_cast<uint32_t>(gl::ImageIndex::kEntireLevel))
11792 {
11793 *layerCountOut = imageLayerCount;
11794 }
11795 }
11796 else if (updateSource == UpdateSource::ClearPartial)
11797 {
11798 *baseLayerOut = data.clearPartial.layerIndex;
11799 *layerCountOut = data.clearPartial.layerCount;
11800
11801 if (*layerCountOut == static_cast<uint32_t>(gl::ImageIndex::kEntireLevel))
11802 {
11803 *layerCountOut = imageLayerCount;
11804 }
11805 }
11806 else
11807 {
11808 const VkImageSubresourceLayers &dstSubresource =
11809 updateSource == UpdateSource::Buffer ? data.buffer.copyRegion.imageSubresource
11810 : data.image.copyRegion.dstSubresource;
11811 *baseLayerOut = dstSubresource.baseArrayLayer;
11812 *layerCountOut = dstSubresource.layerCount;
11813
11814 ASSERT(*layerCountOut != static_cast<uint32_t>(gl::ImageIndex::kEntireLevel));
11815 }
11816 }
11817
getDestAspectFlags() const11818 VkImageAspectFlags ImageHelper::SubresourceUpdate::getDestAspectFlags() const
11819 {
11820 if (IsClear(updateSource))
11821 {
11822 return data.clear.aspectFlags;
11823 }
11824 else if (updateSource == UpdateSource::ClearPartial)
11825 {
11826 return data.clearPartial.aspectFlags;
11827 }
11828 else if (updateSource == UpdateSource::Buffer)
11829 {
11830 return data.buffer.copyRegion.imageSubresource.aspectMask;
11831 }
11832 else
11833 {
11834 ASSERT(updateSource == UpdateSource::Image);
11835 return data.image.copyRegion.dstSubresource.aspectMask;
11836 }
11837 }
11838
getLevelUpdateCount(gl::LevelIndex level) const11839 size_t ImageHelper::getLevelUpdateCount(gl::LevelIndex level) const
11840 {
11841 return static_cast<size_t>(level.get()) < mSubresourceUpdates.size()
11842 ? mSubresourceUpdates[level.get()].size()
11843 : 0;
11844 }
11845
clipLevelToUpdateListUpperLimit(gl::LevelIndex * level) const11846 void ImageHelper::clipLevelToUpdateListUpperLimit(gl::LevelIndex *level) const
11847 {
11848 gl::LevelIndex levelLimit(static_cast<int>(mSubresourceUpdates.size()));
11849 *level = std::min(*level, levelLimit);
11850 }
11851
getLevelUpdates(gl::LevelIndex level)11852 std::vector<ImageHelper::SubresourceUpdate> *ImageHelper::getLevelUpdates(gl::LevelIndex level)
11853 {
11854 return static_cast<size_t>(level.get()) < mSubresourceUpdates.size()
11855 ? &mSubresourceUpdates[level.get()]
11856 : nullptr;
11857 }
11858
getLevelUpdates(gl::LevelIndex level) const11859 const std::vector<ImageHelper::SubresourceUpdate> *ImageHelper::getLevelUpdates(
11860 gl::LevelIndex level) const
11861 {
11862 return static_cast<size_t>(level.get()) < mSubresourceUpdates.size()
11863 ? &mSubresourceUpdates[level.get()]
11864 : nullptr;
11865 }
11866
appendSubresourceUpdate(gl::LevelIndex level,SubresourceUpdate && update)11867 void ImageHelper::appendSubresourceUpdate(gl::LevelIndex level, SubresourceUpdate &&update)
11868 {
11869 if (mSubresourceUpdates.size() <= static_cast<size_t>(level.get()))
11870 {
11871 mSubresourceUpdates.resize(level.get() + 1);
11872 }
11873 // Update total staging buffer size
11874 mTotalStagedBufferUpdateSize += update.updateSource == UpdateSource::Buffer
11875 ? update.data.buffer.bufferHelper->getSize()
11876 : 0;
11877 mSubresourceUpdates[level.get()].emplace_back(std::move(update));
11878 onStateChange(angle::SubjectMessage::SubjectChanged);
11879 }
11880
prependSubresourceUpdate(gl::LevelIndex level,SubresourceUpdate && update)11881 void ImageHelper::prependSubresourceUpdate(gl::LevelIndex level, SubresourceUpdate &&update)
11882 {
11883 if (mSubresourceUpdates.size() <= static_cast<size_t>(level.get()))
11884 {
11885 mSubresourceUpdates.resize(level.get() + 1);
11886 }
11887
11888 // Update total staging buffer size
11889 mTotalStagedBufferUpdateSize += update.updateSource == UpdateSource::Buffer
11890 ? update.data.buffer.bufferHelper->getSize()
11891 : 0;
11892 mSubresourceUpdates[level.get()].insert(mSubresourceUpdates[level.get()].begin(),
11893 std::move(update));
11894 onStateChange(angle::SubjectMessage::SubjectChanged);
11895 }
11896
hasEmulatedImageChannels() const11897 bool ImageHelper::hasEmulatedImageChannels() const
11898 {
11899 const angle::Format &angleFmt = getIntendedFormat();
11900 const angle::Format &textureFmt = getActualFormat();
11901
11902 // Block formats may be decoded and emulated with a non-block format.
11903 if (angleFmt.isBlock)
11904 {
11905 return !textureFmt.isBlock;
11906 }
11907
11908 // The red channel is never emulated.
11909 ASSERT((angleFmt.redBits != 0 || angleFmt.luminanceBits != 0 || angleFmt.alphaBits != 0) ==
11910 (textureFmt.redBits != 0));
11911
11912 return (angleFmt.alphaBits == 0 && textureFmt.alphaBits > 0) ||
11913 (angleFmt.blueBits == 0 && textureFmt.blueBits > 0) ||
11914 (angleFmt.greenBits == 0 && textureFmt.greenBits > 0) ||
11915 (angleFmt.depthBits == 0 && textureFmt.depthBits > 0) ||
11916 (angleFmt.stencilBits == 0 && textureFmt.stencilBits > 0);
11917 }
11918
hasEmulatedDepthChannel() const11919 bool ImageHelper::hasEmulatedDepthChannel() const
11920 {
11921 return getIntendedFormat().depthBits == 0 && getActualFormat().depthBits > 0;
11922 }
11923
hasEmulatedStencilChannel() const11924 bool ImageHelper::hasEmulatedStencilChannel() const
11925 {
11926 return getIntendedFormat().stencilBits == 0 && getActualFormat().stencilBits > 0;
11927 }
11928
hasInefficientlyEmulatedImageFormat() const11929 bool ImageHelper::hasInefficientlyEmulatedImageFormat() const
11930 {
11931 if (hasEmulatedImageFormat())
11932 {
11933 // ETC2 compression is compatible with ETC1
11934 return !(mIntendedFormatID == angle::FormatID::ETC1_R8G8B8_UNORM_BLOCK &&
11935 mActualFormatID == angle::FormatID::ETC2_R8G8B8_UNORM_BLOCK);
11936 }
11937 return false;
11938 }
11939
getEmulatedChannelsMask() const11940 VkColorComponentFlags ImageHelper::getEmulatedChannelsMask() const
11941 {
11942 const angle::Format &angleFmt = getIntendedFormat();
11943 const angle::Format &textureFmt = getActualFormat();
11944
11945 ASSERT(!angleFmt.hasDepthOrStencilBits());
11946
11947 VkColorComponentFlags emulatedChannelsMask = 0;
11948
11949 if (angleFmt.alphaBits == 0 && textureFmt.alphaBits > 0)
11950 {
11951 emulatedChannelsMask |= VK_COLOR_COMPONENT_A_BIT;
11952 }
11953 if (angleFmt.blueBits == 0 && textureFmt.blueBits > 0)
11954 {
11955 emulatedChannelsMask |= VK_COLOR_COMPONENT_B_BIT;
11956 }
11957 if (angleFmt.greenBits == 0 && textureFmt.greenBits > 0)
11958 {
11959 emulatedChannelsMask |= VK_COLOR_COMPONENT_G_BIT;
11960 }
11961
11962 // The red channel is never emulated.
11963 ASSERT((angleFmt.redBits != 0 || angleFmt.luminanceBits != 0 || angleFmt.alphaBits != 0) ==
11964 (textureFmt.redBits != 0));
11965
11966 return emulatedChannelsMask;
11967 }
11968
getCompressionFixedRate(VkImageCompressionControlEXT * compressionInfo,VkImageCompressionFixedRateFlagsEXT * compressionRates,GLenum glCompressionRate) const11969 bool ImageHelper::getCompressionFixedRate(VkImageCompressionControlEXT *compressionInfo,
11970 VkImageCompressionFixedRateFlagsEXT *compressionRates,
11971 GLenum glCompressionRate) const
11972 {
11973 bool rtn = true;
11974 ASSERT(compressionInfo->sType == VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT);
11975 compressionInfo->compressionControlPlaneCount = 1;
11976
11977 if (glCompressionRate == GL_SURFACE_COMPRESSION_FIXED_RATE_NONE_EXT)
11978 {
11979 compressionInfo->flags = VK_IMAGE_COMPRESSION_DISABLED_EXT;
11980 }
11981 else if (glCompressionRate == GL_SURFACE_COMPRESSION_FIXED_RATE_DEFAULT_EXT)
11982 {
11983 compressionInfo->flags = VK_IMAGE_COMPRESSION_FIXED_RATE_DEFAULT_EXT;
11984 }
11985 else if (glCompressionRate >= GL_SURFACE_COMPRESSION_FIXED_RATE_1BPC_EXT &&
11986 glCompressionRate <= GL_SURFACE_COMPRESSION_FIXED_RATE_12BPC_EXT)
11987 {
11988 int offset = glCompressionRate - GL_SURFACE_COMPRESSION_FIXED_RATE_1BPC_EXT;
11989 compressionInfo->flags = VK_IMAGE_COMPRESSION_FIXED_RATE_EXPLICIT_EXT;
11990 *compressionRates = 1u << offset;
11991 compressionInfo->pFixedRateFlags = compressionRates;
11992 }
11993 else
11994 {
11995 // Invalid value
11996 rtn = false;
11997 }
11998
11999 return rtn;
12000 }
12001
GetLayerMode(const vk::ImageHelper & image,uint32_t layerCount)12002 LayerMode GetLayerMode(const vk::ImageHelper &image, uint32_t layerCount)
12003 {
12004 const uint32_t imageLayerCount = GetImageLayerCountForView(image);
12005 const bool allLayers = layerCount == imageLayerCount;
12006
12007 ASSERT(allLayers || (layerCount > 0 && layerCount <= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS));
12008 return allLayers ? LayerMode::All : static_cast<LayerMode>(layerCount);
12009 }
12010
GetComputePipelineOptions(vk::PipelineRobustness robustness,vk::PipelineProtectedAccess protectedAccess)12011 ComputePipelineOptions GetComputePipelineOptions(vk::PipelineRobustness robustness,
12012 vk::PipelineProtectedAccess protectedAccess)
12013 {
12014 vk::ComputePipelineOptions pipelineOptions = {};
12015
12016 if (robustness == vk::PipelineRobustness::Robust)
12017 {
12018 pipelineOptions.robustness = 1;
12019 }
12020 if (protectedAccess == vk::PipelineProtectedAccess::Protected)
12021 {
12022 pipelineOptions.protectedAccess = 1;
12023 }
12024
12025 return pipelineOptions;
12026 }
12027
12028 // ImageViewHelper implementation.
ImageViewHelper()12029 ImageViewHelper::ImageViewHelper()
12030 : mCurrentBaseMaxLevelHash(0),
12031 mReadColorspace(ImageViewColorspace::Invalid),
12032 mWriteColorspace(ImageViewColorspace::Invalid)
12033 {}
12034
ImageViewHelper(ImageViewHelper && other)12035 ImageViewHelper::ImageViewHelper(ImageViewHelper &&other)
12036 {
12037 std::swap(mCurrentBaseMaxLevelHash, other.mCurrentBaseMaxLevelHash);
12038 std::swap(mReadColorspace, other.mReadColorspace);
12039 std::swap(mWriteColorspace, other.mWriteColorspace);
12040 std::swap(mColorspaceState, other.mColorspaceState);
12041
12042 std::swap(mPerLevelRangeLinearReadImageViews, other.mPerLevelRangeLinearReadImageViews);
12043 std::swap(mPerLevelRangeSRGBReadImageViews, other.mPerLevelRangeSRGBReadImageViews);
12044 std::swap(mPerLevelRangeLinearCopyImageViews, other.mPerLevelRangeLinearCopyImageViews);
12045 std::swap(mPerLevelRangeSRGBCopyImageViews, other.mPerLevelRangeSRGBCopyImageViews);
12046 std::swap(mPerLevelRangeStencilReadImageViews, other.mPerLevelRangeStencilReadImageViews);
12047 std::swap(mPerLevelRangeSamplerExternal2DY2YEXTImageViews,
12048 other.mPerLevelRangeSamplerExternal2DY2YEXTImageViews);
12049
12050 std::swap(mLayerLevelDrawImageViews, other.mLayerLevelDrawImageViews);
12051 std::swap(mLayerLevelDrawImageViewsLinear, other.mLayerLevelDrawImageViewsLinear);
12052 std::swap(mSubresourceDrawImageViews, other.mSubresourceDrawImageViews);
12053
12054 std::swap(mLayerLevelDepthOnlyImageViews, other.mLayerLevelDepthOnlyImageViews);
12055 std::swap(mLayerLevelStencilOnlyImageViews, other.mLayerLevelStencilOnlyImageViews);
12056 std::swap(mSubresourceDepthOnlyImageViews, other.mSubresourceDepthOnlyImageViews);
12057 std::swap(mSubresourceStencilOnlyImageViews, other.mSubresourceStencilOnlyImageViews);
12058
12059 std::swap(mLevelStorageImageViews, other.mLevelStorageImageViews);
12060 std::swap(mLayerLevelStorageImageViews, other.mLayerLevelStorageImageViews);
12061 std::swap(mFragmentShadingRateImageView, other.mFragmentShadingRateImageView);
12062 std::swap(mImageViewSerial, other.mImageViewSerial);
12063 }
12064
~ImageViewHelper()12065 ImageViewHelper::~ImageViewHelper() {}
12066
init(Renderer * renderer)12067 void ImageViewHelper::init(Renderer *renderer)
12068 {
12069 if (!mImageViewSerial.valid())
12070 {
12071 mImageViewSerial = renderer->getResourceSerialFactory().generateImageOrBufferViewSerial();
12072 }
12073 }
12074
release(Renderer * renderer,const ResourceUse & use)12075 void ImageViewHelper::release(Renderer *renderer, const ResourceUse &use)
12076 {
12077 mCurrentBaseMaxLevelHash = 0;
12078 mReadColorspace = ImageViewColorspace::Invalid;
12079 mWriteColorspace = ImageViewColorspace::Invalid;
12080 mColorspaceState.reset();
12081
12082 std::vector<vk::GarbageObject> garbage;
12083 // Release the read views
12084 ReleaseImageViews(&mPerLevelRangeLinearReadImageViews, &garbage);
12085 ReleaseImageViews(&mPerLevelRangeSRGBReadImageViews, &garbage);
12086 ReleaseImageViews(&mPerLevelRangeLinearCopyImageViews, &garbage);
12087 ReleaseImageViews(&mPerLevelRangeSRGBCopyImageViews, &garbage);
12088 ReleaseImageViews(&mPerLevelRangeStencilReadImageViews, &garbage);
12089 ReleaseImageViews(&mPerLevelRangeSamplerExternal2DY2YEXTImageViews, &garbage);
12090
12091 // Release the draw views
12092 ReleaseLayerLevelImageViews(&mLayerLevelDrawImageViews, &garbage);
12093 ReleaseLayerLevelImageViews(&mLayerLevelDrawImageViewsLinear, &garbage);
12094 ReleaseSubresourceImageViews(&mSubresourceDrawImageViews, &garbage);
12095
12096 // Release the depth-xor-stencil input views
12097 ReleaseLayerLevelImageViews(&mLayerLevelDepthOnlyImageViews, &garbage);
12098 ReleaseLayerLevelImageViews(&mLayerLevelStencilOnlyImageViews, &garbage);
12099 ReleaseSubresourceImageViews(&mSubresourceDepthOnlyImageViews, &garbage);
12100 ReleaseSubresourceImageViews(&mSubresourceStencilOnlyImageViews, &garbage);
12101
12102 // Release the storage views
12103 ReleaseImageViews(&mLevelStorageImageViews, &garbage);
12104 ReleaseLayerLevelImageViews(&mLayerLevelStorageImageViews, &garbage);
12105
12106 // Release fragment shading rate view
12107 if (mFragmentShadingRateImageView.valid())
12108 {
12109 garbage.emplace_back(GetGarbage(&mFragmentShadingRateImageView));
12110 }
12111
12112 if (!garbage.empty())
12113 {
12114 renderer->collectGarbage(use, std::move(garbage));
12115 }
12116
12117 // Update image view serial.
12118 mImageViewSerial = renderer->getResourceSerialFactory().generateImageOrBufferViewSerial();
12119 }
12120
isImageViewGarbageEmpty() const12121 bool ImageViewHelper::isImageViewGarbageEmpty() const
12122 {
12123 return mPerLevelRangeLinearReadImageViews.empty() &&
12124 mPerLevelRangeLinearCopyImageViews.empty() && mPerLevelRangeSRGBReadImageViews.empty() &&
12125 mPerLevelRangeSRGBCopyImageViews.empty() &&
12126 mPerLevelRangeStencilReadImageViews.empty() &&
12127 mPerLevelRangeSamplerExternal2DY2YEXTImageViews.empty() &&
12128 mLayerLevelDrawImageViews.empty() && mLayerLevelDrawImageViewsLinear.empty() &&
12129 mSubresourceDrawImageViews.empty() && mLayerLevelDepthOnlyImageViews.empty() &&
12130 mLayerLevelStencilOnlyImageViews.empty() && mSubresourceDepthOnlyImageViews.empty() &&
12131 mSubresourceStencilOnlyImageViews.empty() && mLayerLevelStorageImageViews.empty();
12132 }
12133
destroy(VkDevice device)12134 void ImageViewHelper::destroy(VkDevice device)
12135 {
12136 mCurrentBaseMaxLevelHash = 0;
12137 mReadColorspace = ImageViewColorspace::Invalid;
12138 mWriteColorspace = ImageViewColorspace::Invalid;
12139 mColorspaceState.reset();
12140
12141 // Release the read views
12142 DestroyImageViews(&mPerLevelRangeLinearReadImageViews, device);
12143 DestroyImageViews(&mPerLevelRangeSRGBReadImageViews, device);
12144 DestroyImageViews(&mPerLevelRangeLinearCopyImageViews, device);
12145 DestroyImageViews(&mPerLevelRangeSRGBCopyImageViews, device);
12146 DestroyImageViews(&mPerLevelRangeStencilReadImageViews, device);
12147 DestroyImageViews(&mPerLevelRangeSamplerExternal2DY2YEXTImageViews, device);
12148
12149 // Release the draw views
12150 DestroyLayerLevelImageViews(&mLayerLevelDrawImageViews, device);
12151 DestroyLayerLevelImageViews(&mLayerLevelDrawImageViewsLinear, device);
12152 DestroySubresourceImageViews(&mSubresourceDrawImageViews, device);
12153
12154 // Release the depth-xor-stencil input views
12155 DestroyLayerLevelImageViews(&mLayerLevelDepthOnlyImageViews, device);
12156 DestroyLayerLevelImageViews(&mLayerLevelStencilOnlyImageViews, device);
12157 DestroySubresourceImageViews(&mSubresourceDepthOnlyImageViews, device);
12158 DestroySubresourceImageViews(&mSubresourceStencilOnlyImageViews, device);
12159
12160 // Release the storage views
12161 DestroyImageViews(&mLevelStorageImageViews, device);
12162 DestroyLayerLevelImageViews(&mLayerLevelStorageImageViews, device);
12163
12164 // Destroy fragment shading rate view
12165 mFragmentShadingRateImageView.destroy(device);
12166
12167 mImageViewSerial = kInvalidImageOrBufferViewSerial;
12168 }
12169
initReadViews(ContextVk * contextVk,gl::TextureType viewType,const ImageHelper & image,const gl::SwizzleState & formatSwizzle,const gl::SwizzleState & readSwizzle,LevelIndex baseLevel,uint32_t levelCount,uint32_t baseLayer,uint32_t layerCount,bool requiresSRGBViews,VkImageUsageFlags imageUsageFlags)12170 angle::Result ImageViewHelper::initReadViews(ContextVk *contextVk,
12171 gl::TextureType viewType,
12172 const ImageHelper &image,
12173 const gl::SwizzleState &formatSwizzle,
12174 const gl::SwizzleState &readSwizzle,
12175 LevelIndex baseLevel,
12176 uint32_t levelCount,
12177 uint32_t baseLayer,
12178 uint32_t layerCount,
12179 bool requiresSRGBViews,
12180 VkImageUsageFlags imageUsageFlags)
12181 {
12182 ASSERT(levelCount > 0);
12183
12184 const uint32_t maxLevel = levelCount - 1;
12185 ASSERT(maxLevel < 16);
12186 ASSERT(baseLevel.get() < 16);
12187 mCurrentBaseMaxLevelHash = static_cast<uint8_t>(baseLevel.get() << 4 | maxLevel);
12188 updateColorspace(image);
12189
12190 if (mCurrentBaseMaxLevelHash >= mPerLevelRangeLinearReadImageViews.size())
12191 {
12192 const uint32_t maxViewCount = mCurrentBaseMaxLevelHash + 1;
12193
12194 mPerLevelRangeLinearReadImageViews.resize(maxViewCount);
12195 mPerLevelRangeSRGBReadImageViews.resize(maxViewCount);
12196 mPerLevelRangeLinearCopyImageViews.resize(maxViewCount);
12197 mPerLevelRangeSRGBCopyImageViews.resize(maxViewCount);
12198 mPerLevelRangeStencilReadImageViews.resize(maxViewCount);
12199 mPerLevelRangeSamplerExternal2DY2YEXTImageViews.resize(maxViewCount);
12200 }
12201
12202 // Determine if we already have ImageViews for the new max level
12203 if (getReadImageView().valid())
12204 {
12205 return angle::Result::Continue;
12206 }
12207
12208 // Since we don't have a readImageView, we must create ImageViews for the new max level
12209 if (requiresSRGBViews)
12210 {
12211 // Initialize image views for both linear and srgb colorspaces
12212 ANGLE_TRY(initLinearAndSrgbReadViewsImpl(contextVk, viewType, image, formatSwizzle,
12213 readSwizzle, baseLevel, levelCount, baseLayer,
12214 layerCount, imageUsageFlags));
12215 }
12216 else
12217 {
12218 // Initialize image view for image's format's colorspace
12219 ANGLE_TRY(initReadViewsImpl(contextVk, viewType, image, formatSwizzle, readSwizzle,
12220 baseLevel, levelCount, baseLayer, layerCount, imageUsageFlags));
12221 }
12222
12223 return angle::Result::Continue;
12224 }
12225
initReadViewsImpl(ContextVk * contextVk,gl::TextureType viewType,const ImageHelper & image,const gl::SwizzleState & formatSwizzle,const gl::SwizzleState & readSwizzle,LevelIndex baseLevel,uint32_t levelCount,uint32_t baseLayer,uint32_t layerCount,VkImageUsageFlags imageUsageFlags)12226 angle::Result ImageViewHelper::initReadViewsImpl(ContextVk *contextVk,
12227 gl::TextureType viewType,
12228 const ImageHelper &image,
12229 const gl::SwizzleState &formatSwizzle,
12230 const gl::SwizzleState &readSwizzle,
12231 LevelIndex baseLevel,
12232 uint32_t levelCount,
12233 uint32_t baseLayer,
12234 uint32_t layerCount,
12235 VkImageUsageFlags imageUsageFlags)
12236 {
12237 ASSERT(mImageViewSerial.valid());
12238 ASSERT(mReadColorspace != ImageViewColorspace::Invalid);
12239
12240 const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(image.getIntendedFormat());
12241
12242 if (HasBothDepthAndStencilAspects(aspectFlags))
12243 {
12244 ANGLE_TRY(image.initLayerImageViewWithUsage(
12245 contextVk, viewType, VK_IMAGE_ASPECT_DEPTH_BIT, readSwizzle, &getReadImageView(),
12246 baseLevel, levelCount, baseLayer, layerCount, imageUsageFlags));
12247 ANGLE_TRY(image.initLayerImageViewWithUsage(
12248 contextVk, viewType, VK_IMAGE_ASPECT_STENCIL_BIT, readSwizzle,
12249 &mPerLevelRangeStencilReadImageViews[mCurrentBaseMaxLevelHash], baseLevel, levelCount,
12250 baseLayer, layerCount, imageUsageFlags));
12251 }
12252 else
12253 {
12254 ANGLE_TRY(image.initLayerImageViewWithUsage(contextVk, viewType, aspectFlags, readSwizzle,
12255 &getReadImageView(), baseLevel, levelCount,
12256 baseLayer, layerCount, imageUsageFlags));
12257
12258 if (image.getActualFormat().isYUV)
12259 {
12260 ANGLE_TRY(image.initLayerImageViewWithYuvModeOverride(
12261 contextVk, viewType, aspectFlags, readSwizzle,
12262 &getSamplerExternal2DY2YEXTImageView(), baseLevel, levelCount, baseLayer,
12263 layerCount, gl::YuvSamplingMode::Y2Y, imageUsageFlags));
12264 }
12265 }
12266
12267 gl::TextureType fetchType = viewType;
12268 if (viewType == gl::TextureType::CubeMap || viewType == gl::TextureType::_2DArray ||
12269 viewType == gl::TextureType::_2DMultisampleArray)
12270 {
12271 fetchType = Get2DTextureType(layerCount, image.getSamples());
12272 }
12273
12274 if (!image.getActualFormat().isBlock)
12275 {
12276 ANGLE_TRY(image.initLayerImageViewWithUsage(
12277 contextVk, fetchType, aspectFlags, formatSwizzle, &getCopyImageView(), baseLevel,
12278 levelCount, baseLayer, layerCount, imageUsageFlags));
12279 }
12280 return angle::Result::Continue;
12281 }
12282
initLinearAndSrgbReadViewsImpl(ContextVk * contextVk,gl::TextureType viewType,const ImageHelper & image,const gl::SwizzleState & formatSwizzle,const gl::SwizzleState & readSwizzle,LevelIndex baseLevel,uint32_t levelCount,uint32_t baseLayer,uint32_t layerCount,VkImageUsageFlags imageUsageFlags)12283 angle::Result ImageViewHelper::initLinearAndSrgbReadViewsImpl(ContextVk *contextVk,
12284 gl::TextureType viewType,
12285 const ImageHelper &image,
12286 const gl::SwizzleState &formatSwizzle,
12287 const gl::SwizzleState &readSwizzle,
12288 LevelIndex baseLevel,
12289 uint32_t levelCount,
12290 uint32_t baseLayer,
12291 uint32_t layerCount,
12292 VkImageUsageFlags imageUsageFlags)
12293 {
12294 ASSERT(mReadColorspace != ImageViewColorspace::Invalid);
12295
12296 // When we select the linear/srgb counterpart formats, we must first make sure they're
12297 // actually supported by the ICD. If they are not supported by the ICD, then we treat that as if
12298 // there is no counterpart format.
12299 const bool imageFormatIsSrgb = image.getActualFormat().isSRGB;
12300 const angle::FormatID imageFormat = image.getActualFormatID();
12301 angle::FormatID srgbFormat = imageFormatIsSrgb ? imageFormat : ConvertToSRGB(imageFormat);
12302 if (srgbFormat != angle::FormatID::NONE &&
12303 !HasNonRenderableTextureFormatSupport(contextVk->getRenderer(), srgbFormat))
12304 {
12305 srgbFormat = angle::FormatID::NONE;
12306 }
12307
12308 angle::FormatID linearFormat = !imageFormatIsSrgb ? imageFormat : ConvertToLinear(imageFormat);
12309 ASSERT(linearFormat != angle::FormatID::NONE);
12310
12311 const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(image.getIntendedFormat());
12312
12313 if (HasBothDepthAndStencilAspects(aspectFlags))
12314 {
12315 ANGLE_TRY(image.initReinterpretedLayerImageView(
12316 contextVk, viewType, VK_IMAGE_ASPECT_DEPTH_BIT, readSwizzle,
12317 &mPerLevelRangeLinearReadImageViews[mCurrentBaseMaxLevelHash], baseLevel, levelCount,
12318 baseLayer, layerCount, imageUsageFlags, linearFormat));
12319
12320 ANGLE_TRY(image.initReinterpretedLayerImageView(
12321 contextVk, viewType, VK_IMAGE_ASPECT_STENCIL_BIT, readSwizzle,
12322 &mPerLevelRangeStencilReadImageViews[mCurrentBaseMaxLevelHash], baseLevel, levelCount,
12323 baseLayer, layerCount, imageUsageFlags, linearFormat));
12324 }
12325 else
12326 {
12327 if (!mPerLevelRangeLinearReadImageViews[mCurrentBaseMaxLevelHash].valid())
12328 {
12329 ANGLE_TRY(image.initReinterpretedLayerImageView(
12330 contextVk, viewType, aspectFlags, readSwizzle,
12331 &mPerLevelRangeLinearReadImageViews[mCurrentBaseMaxLevelHash], baseLevel,
12332 levelCount, baseLayer, layerCount, imageUsageFlags, linearFormat));
12333 }
12334
12335 if (srgbFormat != angle::FormatID::NONE &&
12336 !mPerLevelRangeSRGBReadImageViews[mCurrentBaseMaxLevelHash].valid())
12337 {
12338 ANGLE_TRY(image.initReinterpretedLayerImageView(
12339 contextVk, viewType, aspectFlags, readSwizzle,
12340 &mPerLevelRangeSRGBReadImageViews[mCurrentBaseMaxLevelHash], baseLevel, levelCount,
12341 baseLayer, layerCount, imageUsageFlags, srgbFormat));
12342 }
12343
12344 if (image.getActualFormat().isYUV)
12345 {
12346 ANGLE_TRY(image.initLayerImageViewWithYuvModeOverride(
12347 contextVk, viewType, aspectFlags, readSwizzle,
12348 &getSamplerExternal2DY2YEXTImageView(), baseLevel, levelCount, baseLayer,
12349 layerCount, gl::YuvSamplingMode::Y2Y, imageUsageFlags));
12350 }
12351 }
12352
12353 gl::TextureType fetchType = viewType;
12354
12355 if (viewType == gl::TextureType::CubeMap || viewType == gl::TextureType::_2DArray ||
12356 viewType == gl::TextureType::_2DMultisampleArray)
12357 {
12358 fetchType = Get2DTextureType(layerCount, image.getSamples());
12359 }
12360
12361 if (!image.getActualFormat().isBlock)
12362 {
12363 if (!mPerLevelRangeLinearCopyImageViews[mCurrentBaseMaxLevelHash].valid())
12364 {
12365 ANGLE_TRY(image.initReinterpretedLayerImageView(
12366 contextVk, fetchType, aspectFlags, formatSwizzle,
12367 &mPerLevelRangeLinearCopyImageViews[mCurrentBaseMaxLevelHash], baseLevel,
12368 levelCount, baseLayer, layerCount, imageUsageFlags, linearFormat));
12369 }
12370 if (srgbFormat != angle::FormatID::NONE &&
12371 !mPerLevelRangeSRGBCopyImageViews[mCurrentBaseMaxLevelHash].valid())
12372 {
12373 ANGLE_TRY(image.initReinterpretedLayerImageView(
12374 contextVk, fetchType, aspectFlags, formatSwizzle,
12375 &mPerLevelRangeSRGBCopyImageViews[mCurrentBaseMaxLevelHash], baseLevel, levelCount,
12376 baseLayer, layerCount, imageUsageFlags, srgbFormat));
12377 }
12378 }
12379
12380 return angle::Result::Continue;
12381 }
12382
getLevelStorageImageView(Context * context,gl::TextureType viewType,const ImageHelper & image,LevelIndex levelVk,uint32_t layer,VkImageUsageFlags imageUsageFlags,angle::FormatID formatID,const ImageView ** imageViewOut)12383 angle::Result ImageViewHelper::getLevelStorageImageView(Context *context,
12384 gl::TextureType viewType,
12385 const ImageHelper &image,
12386 LevelIndex levelVk,
12387 uint32_t layer,
12388 VkImageUsageFlags imageUsageFlags,
12389 angle::FormatID formatID,
12390 const ImageView **imageViewOut)
12391 {
12392 ASSERT(mImageViewSerial.valid());
12393
12394 ImageView *imageView =
12395 GetLevelImageView(&mLevelStorageImageViews, levelVk, image.getLevelCount());
12396
12397 *imageViewOut = imageView;
12398 if (imageView->valid())
12399 {
12400 return angle::Result::Continue;
12401 }
12402
12403 // Create the view. Note that storage images are not affected by swizzle parameters.
12404 return image.initReinterpretedLayerImageView(context, viewType, image.getAspectFlags(),
12405 gl::SwizzleState(), imageView, levelVk, 1, layer,
12406 image.getLayerCount(), imageUsageFlags, formatID);
12407 }
12408
getLevelLayerStorageImageView(Context * contextVk,const ImageHelper & image,LevelIndex levelVk,uint32_t layer,VkImageUsageFlags imageUsageFlags,angle::FormatID formatID,const ImageView ** imageViewOut)12409 angle::Result ImageViewHelper::getLevelLayerStorageImageView(Context *contextVk,
12410 const ImageHelper &image,
12411 LevelIndex levelVk,
12412 uint32_t layer,
12413 VkImageUsageFlags imageUsageFlags,
12414 angle::FormatID formatID,
12415 const ImageView **imageViewOut)
12416 {
12417 ASSERT(image.valid());
12418 ASSERT(mImageViewSerial.valid());
12419 ASSERT(!image.getActualFormat().isBlock);
12420
12421 ImageView *imageView =
12422 GetLevelLayerImageView(&mLayerLevelStorageImageViews, levelVk, layer, image.getLevelCount(),
12423 GetImageLayerCountForView(image));
12424 *imageViewOut = imageView;
12425
12426 if (imageView->valid())
12427 {
12428 return angle::Result::Continue;
12429 }
12430
12431 // Create the view. Note that storage images are not affected by swizzle parameters.
12432 gl::TextureType viewType = Get2DTextureType(1, image.getSamples());
12433 return image.initReinterpretedLayerImageView(contextVk, viewType, image.getAspectFlags(),
12434 gl::SwizzleState(), imageView, levelVk, 1, layer,
12435 1, imageUsageFlags, formatID);
12436 }
12437
getLevelLayerDrawImageViewImpl(Context * context,const ImageHelper & image,LevelIndex levelVk,uint32_t layer,uint32_t layerCount,ImageView * imageViewOut)12438 angle::Result ImageViewHelper::getLevelLayerDrawImageViewImpl(Context *context,
12439 const ImageHelper &image,
12440 LevelIndex levelVk,
12441 uint32_t layer,
12442 uint32_t layerCount,
12443 ImageView *imageViewOut)
12444 {
12445 ASSERT(imageViewOut != nullptr);
12446
12447 // If we are initializing an imageview for use with EXT_srgb_write_control, we need to override
12448 // the format to its linear counterpart. Formats that cannot be reinterpreted are exempt from
12449 // this requirement.
12450 angle::FormatID actualFormat = image.getActualFormatID();
12451 angle::FormatID linearFormat = ConvertToLinear(actualFormat);
12452 angle::FormatID sRGBFormat = ConvertToSRGB(actualFormat);
12453 if (mWriteColorspace == ImageViewColorspace::Linear && linearFormat != angle::FormatID::NONE)
12454 {
12455 actualFormat = linearFormat;
12456 }
12457 else if (mWriteColorspace == ImageViewColorspace::SRGB && sRGBFormat != angle::FormatID::NONE)
12458 {
12459 actualFormat = sRGBFormat;
12460 }
12461
12462 // Note that these views are specifically made to be used as framebuffer attachments, and
12463 // therefore don't have swizzle.
12464 return image.initReinterpretedLayerImageView(
12465 context, Get2DTextureType(layerCount, image.getSamples()), image.getAspectFlags(),
12466 gl::SwizzleState(), imageViewOut, levelVk, 1, layer, layerCount,
12467 vk::ImageHelper::kDefaultImageViewUsageFlags, actualFormat);
12468 }
12469
getLevelDrawImageView(Context * context,const ImageHelper & image,LevelIndex levelVk,uint32_t layer,uint32_t layerCount,const ImageView ** imageViewOut)12470 angle::Result ImageViewHelper::getLevelDrawImageView(Context *context,
12471 const ImageHelper &image,
12472 LevelIndex levelVk,
12473 uint32_t layer,
12474 uint32_t layerCount,
12475 const ImageView **imageViewOut)
12476 {
12477 ASSERT(image.valid());
12478 ASSERT(mImageViewSerial.valid());
12479 ASSERT(!image.getActualFormat().isBlock);
12480
12481 if (mWriteColorspace == ImageViewColorspace::Invalid)
12482 {
12483 updateColorspace(image);
12484 }
12485 ASSERT(mWriteColorspace != ImageViewColorspace::Invalid);
12486
12487 ImageSubresourceRange range = MakeImageSubresourceDrawRange(image.toGLLevel(levelVk), layer,
12488 GetLayerMode(image, layerCount),
12489 mReadColorspace, mWriteColorspace);
12490
12491 std::unique_ptr<ImageView> &view = mSubresourceDrawImageViews[range];
12492 if (view)
12493 {
12494 *imageViewOut = view.get();
12495 return angle::Result::Continue;
12496 }
12497
12498 view = std::make_unique<ImageView>();
12499 *imageViewOut = view.get();
12500
12501 return getLevelLayerDrawImageViewImpl(context, image, levelVk, layer, layerCount, view.get());
12502 }
12503
getLevelLayerDrawImageView(Context * context,const ImageHelper & image,LevelIndex levelVk,uint32_t layer,const ImageView ** imageViewOut)12504 angle::Result ImageViewHelper::getLevelLayerDrawImageView(Context *context,
12505 const ImageHelper &image,
12506 LevelIndex levelVk,
12507 uint32_t layer,
12508 const ImageView **imageViewOut)
12509 {
12510 ASSERT(image.valid());
12511 ASSERT(mImageViewSerial.valid());
12512 ASSERT(!image.getActualFormat().isBlock);
12513
12514 if (mWriteColorspace == ImageViewColorspace::Invalid)
12515 {
12516 updateColorspace(image);
12517 }
12518 ASSERT(mWriteColorspace != ImageViewColorspace::Invalid);
12519
12520 LayerLevelImageViewVector &imageViews = (mWriteColorspace == ImageViewColorspace::Linear)
12521 ? mLayerLevelDrawImageViewsLinear
12522 : mLayerLevelDrawImageViews;
12523
12524 // Lazily allocate the storage for image views
12525 ImageView *imageView = GetLevelLayerImageView(
12526 &imageViews, levelVk, layer, image.getLevelCount(), GetImageLayerCountForView(image));
12527 *imageViewOut = imageView;
12528
12529 if (imageView->valid())
12530 {
12531 return angle::Result::Continue;
12532 }
12533
12534 return getLevelLayerDrawImageViewImpl(context, image, levelVk, layer, 1, imageView);
12535 }
12536
getLevelDepthOrStencilImageView(Context * context,const ImageHelper & image,LevelIndex levelVk,uint32_t layer,uint32_t layerCount,VkImageAspectFlagBits aspect,const ImageView ** imageViewOut)12537 angle::Result ImageViewHelper::getLevelDepthOrStencilImageView(Context *context,
12538 const ImageHelper &image,
12539 LevelIndex levelVk,
12540 uint32_t layer,
12541 uint32_t layerCount,
12542 VkImageAspectFlagBits aspect,
12543 const ImageView **imageViewOut)
12544 {
12545 ASSERT(image.valid());
12546 ASSERT(mImageViewSerial.valid());
12547 ASSERT((image.getAspectFlags() & aspect) != 0);
12548
12549 ImageSubresourceRange range = MakeImageSubresourceDrawRange(
12550 image.toGLLevel(levelVk), layer, GetLayerMode(image, layerCount),
12551 ImageViewColorspace::Linear, ImageViewColorspace::Linear);
12552
12553 SubresourceImageViewMap &imageViews = aspect == VK_IMAGE_ASPECT_DEPTH_BIT
12554 ? mSubresourceDepthOnlyImageViews
12555 : mSubresourceStencilOnlyImageViews;
12556
12557 std::unique_ptr<ImageView> &view = imageViews[range];
12558 if (view)
12559 {
12560 *imageViewOut = view.get();
12561 return angle::Result::Continue;
12562 }
12563
12564 view = std::make_unique<ImageView>();
12565 *imageViewOut = view.get();
12566
12567 return getLevelLayerDepthOrStencilImageViewImpl(context, image, levelVk, layer, layerCount,
12568 aspect, view.get());
12569 }
12570
getLevelLayerDepthOrStencilImageView(Context * context,const ImageHelper & image,LevelIndex levelVk,uint32_t layer,VkImageAspectFlagBits aspect,const ImageView ** imageViewOut)12571 angle::Result ImageViewHelper::getLevelLayerDepthOrStencilImageView(Context *context,
12572 const ImageHelper &image,
12573 LevelIndex levelVk,
12574 uint32_t layer,
12575 VkImageAspectFlagBits aspect,
12576 const ImageView **imageViewOut)
12577 {
12578 ASSERT(image.valid());
12579 ASSERT(mImageViewSerial.valid());
12580 ASSERT((image.getAspectFlags() & aspect) != 0);
12581
12582 LayerLevelImageViewVector &imageViews = aspect == VK_IMAGE_ASPECT_DEPTH_BIT
12583 ? mLayerLevelDepthOnlyImageViews
12584 : mLayerLevelStencilOnlyImageViews;
12585
12586 // Lazily allocate the storage for image views
12587 ImageView *imageView = GetLevelLayerImageView(
12588 &imageViews, levelVk, layer, image.getLevelCount(), GetImageLayerCountForView(image));
12589 *imageViewOut = imageView;
12590
12591 if (imageView->valid())
12592 {
12593 return angle::Result::Continue;
12594 }
12595
12596 return getLevelLayerDepthOrStencilImageViewImpl(context, image, levelVk, layer, 1, aspect,
12597 imageView);
12598 }
12599
getLevelLayerDepthOrStencilImageViewImpl(Context * context,const ImageHelper & image,LevelIndex levelVk,uint32_t layer,uint32_t layerCount,VkImageAspectFlagBits aspect,ImageView * imageViewOut)12600 angle::Result ImageViewHelper::getLevelLayerDepthOrStencilImageViewImpl(
12601 Context *context,
12602 const ImageHelper &image,
12603 LevelIndex levelVk,
12604 uint32_t layer,
12605 uint32_t layerCount,
12606 VkImageAspectFlagBits aspect,
12607 ImageView *imageViewOut)
12608 {
12609 // Note that these views are specifically made to be used as input attachments, and
12610 // therefore don't have swizzle.
12611 return image.initReinterpretedLayerImageView(
12612 context, Get2DTextureType(layerCount, image.getSamples()), aspect, gl::SwizzleState(),
12613 imageViewOut, levelVk, 1, layer, layerCount, vk::ImageHelper::kDefaultImageViewUsageFlags,
12614 image.getActualFormatID());
12615 }
12616
initFragmentShadingRateView(ContextVk * contextVk,ImageHelper * image)12617 angle::Result ImageViewHelper::initFragmentShadingRateView(ContextVk *contextVk, ImageHelper *image)
12618 {
12619 ASSERT(image->valid());
12620 ASSERT(mImageViewSerial.valid());
12621
12622 // Determine if we already have ImageView
12623 if (mFragmentShadingRateImageView.valid())
12624 {
12625 return angle::Result::Continue;
12626 }
12627
12628 // Fragment shading rate image view always have -
12629 // - gl::TextureType == gl::TextureType::_2D
12630 // - VkImageAspectFlags == VK_IMAGE_ASPECT_COLOR_BIT
12631 // - gl::SwizzleState == gl::SwizzleState()
12632 // - baseMipLevelVk == vk::LevelIndex(0)
12633 // - levelCount == 1
12634 // - baseArrayLayer == 0
12635 // - layerCount == 1
12636 return image->initLayerImageViewWithUsage(
12637 contextVk, gl::TextureType::_2D, VK_IMAGE_ASPECT_COLOR_BIT, gl::SwizzleState(),
12638 &mFragmentShadingRateImageView, vk::LevelIndex(0), 1, 0, 1, image->getUsage());
12639 }
12640
getColorspaceOverrideFormatForWrite(angle::FormatID format) const12641 angle::FormatID ImageViewHelper::getColorspaceOverrideFormatForWrite(angle::FormatID format) const
12642 {
12643 ASSERT(mWriteColorspace != ImageViewColorspace::Invalid);
12644
12645 angle::FormatID colorspaceOverrideFormat = format;
12646 angle::FormatID linearFormat = ConvertToLinear(format);
12647 angle::FormatID sRGBFormat = ConvertToSRGB(format);
12648 if (mWriteColorspace == ImageViewColorspace::Linear && linearFormat != angle::FormatID::NONE)
12649 {
12650 colorspaceOverrideFormat = linearFormat;
12651 }
12652 else if (mWriteColorspace == ImageViewColorspace::SRGB && sRGBFormat != angle::FormatID::NONE)
12653 {
12654 colorspaceOverrideFormat = sRGBFormat;
12655 }
12656
12657 return colorspaceOverrideFormat;
12658 }
12659
updateColorspace(const ImageHelper & image) const12660 void ImageViewHelper::updateColorspace(const ImageHelper &image) const
12661 {
12662 const angle::Format &imageFormat = image.getActualFormat();
12663 ImageViewColorspace imageViewColorspace = ImageViewColorspace::Invalid;
12664 mReadColorspace = ImageViewColorspace::Invalid;
12665 mWriteColorspace = ImageViewColorspace::Invalid;
12666
12667 // Initialize colorspace based on image's format's colorspace
12668 imageViewColorspace =
12669 imageFormat.isSRGB ? ImageViewColorspace::SRGB : ImageViewColorspace::Linear;
12670
12671 // Process EGL image colorspace override state
12672 if (!imageFormat.isSRGB && mColorspaceState.eglImageColorspace == egl::ImageColorspace::SRGB)
12673 {
12674 imageViewColorspace = ImageViewColorspace::SRGB;
12675 }
12676 else if (imageFormat.isSRGB &&
12677 mColorspaceState.eglImageColorspace == egl::ImageColorspace::Linear)
12678 {
12679 imageViewColorspace = ImageViewColorspace::Linear;
12680 }
12681 ASSERT(imageViewColorspace != ImageViewColorspace::Invalid);
12682
12683 mReadColorspace = imageViewColorspace;
12684 mWriteColorspace = imageViewColorspace;
12685
12686 // Process srgb decode and srgb override state
12687 if (mReadColorspace == ImageViewColorspace::Linear)
12688 {
12689 if (mColorspaceState.srgbOverride == gl::SrgbOverride::SRGB &&
12690 rx::ConvertToSRGB(imageFormat.id) != angle::FormatID::NONE &&
12691 mColorspaceState.srgbDecode != gl::SrgbDecode::Skip)
12692 {
12693 mReadColorspace = ImageViewColorspace::SRGB;
12694 }
12695 }
12696 else
12697 {
12698 ASSERT(mReadColorspace == ImageViewColorspace::SRGB);
12699
12700 if (mColorspaceState.srgbDecode == gl::SrgbDecode::Skip &&
12701 !mColorspaceState.hasStaticTexelFetchAccess)
12702 {
12703 mReadColorspace = ImageViewColorspace::Linear;
12704 }
12705 }
12706
12707 // Process srgb write control state
12708 if (mWriteColorspace == ImageViewColorspace::SRGB &&
12709 mColorspaceState.srgbWriteControl == gl::SrgbWriteControlMode::Linear)
12710 {
12711 mWriteColorspace = ImageViewColorspace::Linear;
12712 }
12713
12714 ASSERT(mReadColorspace != ImageViewColorspace::Invalid);
12715 ASSERT(mWriteColorspace != ImageViewColorspace::Invalid);
12716 }
12717
getSubresourceSerial(gl::LevelIndex levelGL,uint32_t levelCount,uint32_t layer,LayerMode layerMode) const12718 ImageOrBufferViewSubresourceSerial ImageViewHelper::getSubresourceSerial(gl::LevelIndex levelGL,
12719 uint32_t levelCount,
12720 uint32_t layer,
12721 LayerMode layerMode) const
12722 {
12723 return getSubresourceSerialForColorspace(levelGL, levelCount, layer, layerMode,
12724 mReadColorspace);
12725 }
12726
getSubresourceSerialForColorspace(gl::LevelIndex levelGL,uint32_t levelCount,uint32_t layer,LayerMode layerMode,ImageViewColorspace readColorspace) const12727 ImageOrBufferViewSubresourceSerial ImageViewHelper::getSubresourceSerialForColorspace(
12728 gl::LevelIndex levelGL,
12729 uint32_t levelCount,
12730 uint32_t layer,
12731 LayerMode layerMode,
12732 ImageViewColorspace readColorspace) const
12733 {
12734 ASSERT(mImageViewSerial.valid());
12735
12736 ImageOrBufferViewSubresourceSerial serial;
12737 serial.viewSerial = mImageViewSerial;
12738 serial.subresource = MakeImageSubresourceReadRange(levelGL, levelCount, layer, layerMode,
12739 readColorspace, mWriteColorspace);
12740 return serial;
12741 }
12742
getSubresourceDrawRange(gl::LevelIndex level,uint32_t layer,LayerMode layerMode) const12743 ImageSubresourceRange ImageViewHelper::getSubresourceDrawRange(gl::LevelIndex level,
12744 uint32_t layer,
12745 LayerMode layerMode) const
12746 {
12747 return MakeImageSubresourceDrawRange(level, layer, layerMode, mReadColorspace,
12748 mWriteColorspace);
12749 }
12750
12751 // BufferViewHelper implementation.
BufferViewHelper()12752 BufferViewHelper::BufferViewHelper() : mInitialized(false), mOffset(0), mSize(0) {}
12753
BufferViewHelper(BufferViewHelper && other)12754 BufferViewHelper::BufferViewHelper(BufferViewHelper &&other) : Resource(std::move(other))
12755 {
12756 std::swap(mInitialized, other.mInitialized);
12757 std::swap(mOffset, other.mOffset);
12758 std::swap(mSize, other.mSize);
12759 std::swap(mViews, other.mViews);
12760 std::swap(mViewSerial, other.mViewSerial);
12761 }
12762
~BufferViewHelper()12763 BufferViewHelper::~BufferViewHelper() {}
12764
init(Renderer * renderer,VkDeviceSize offset,VkDeviceSize size)12765 void BufferViewHelper::init(Renderer *renderer, VkDeviceSize offset, VkDeviceSize size)
12766 {
12767 ASSERT(mViews.empty());
12768
12769 mOffset = offset;
12770 mSize = size;
12771
12772 if (!mViewSerial.valid())
12773 {
12774 mViewSerial = renderer->getResourceSerialFactory().generateImageOrBufferViewSerial();
12775 }
12776
12777 mInitialized = true;
12778 }
12779
release(Renderer * renderer)12780 void BufferViewHelper::release(Renderer *renderer)
12781 {
12782 if (!mInitialized)
12783 {
12784 return;
12785 }
12786
12787 GarbageObjects garbage;
12788
12789 for (auto &formatAndView : mViews)
12790 {
12791 BufferView &view = formatAndView.second;
12792 ASSERT(view.valid());
12793
12794 garbage.emplace_back(GetGarbage(&view));
12795 }
12796
12797 if (!garbage.empty())
12798 {
12799 renderer->collectGarbage(mUse, std::move(garbage));
12800 // Update image view serial.
12801 mViewSerial = renderer->getResourceSerialFactory().generateImageOrBufferViewSerial();
12802 }
12803
12804 mUse.reset();
12805 mViews.clear();
12806 mOffset = 0;
12807 mSize = 0;
12808 mInitialized = false;
12809 }
12810
release(ContextVk * contextVk)12811 void BufferViewHelper::release(ContextVk *contextVk)
12812 {
12813 if (!mInitialized)
12814 {
12815 return;
12816 }
12817
12818 contextVk->flushDescriptorSetUpdates();
12819 return release(contextVk->getRenderer());
12820 }
12821
destroy(VkDevice device)12822 void BufferViewHelper::destroy(VkDevice device)
12823 {
12824 for (auto &formatAndView : mViews)
12825 {
12826 BufferView &view = formatAndView.second;
12827 view.destroy(device);
12828 }
12829
12830 mViews.clear();
12831
12832 mOffset = 0;
12833 mSize = 0;
12834
12835 mViewSerial = kInvalidImageOrBufferViewSerial;
12836 }
12837
getView(Context * context,const BufferHelper & buffer,VkDeviceSize bufferOffset,const Format & format,const BufferView ** viewOut)12838 angle::Result BufferViewHelper::getView(Context *context,
12839 const BufferHelper &buffer,
12840 VkDeviceSize bufferOffset,
12841 const Format &format,
12842 const BufferView **viewOut)
12843 {
12844 ASSERT(format.valid());
12845
12846 vk::Renderer *renderer = context->getRenderer();
12847 VkFormat viewVkFormat = format.getActualBufferVkFormat(renderer, false);
12848
12849 auto iter = mViews.find(viewVkFormat);
12850 if (iter != mViews.end())
12851 {
12852 *viewOut = &iter->second;
12853 return angle::Result::Continue;
12854 }
12855
12856 // If the size is not a multiple of pixelBytes, remove the extra bytes. The last element cannot
12857 // be read anyway, and this is a requirement of Vulkan (for size to be a multiple of format
12858 // texel block size).
12859 const angle::Format &bufferFormat = format.getActualBufferFormat(false);
12860 const GLuint pixelBytes = bufferFormat.pixelBytes;
12861 VkDeviceSize size = mSize - mSize % pixelBytes;
12862
12863 VkBufferViewCreateInfo viewCreateInfo = {};
12864 viewCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO;
12865 viewCreateInfo.buffer = buffer.getBuffer().getHandle();
12866 viewCreateInfo.format = viewVkFormat;
12867 viewCreateInfo.offset = mOffset + bufferOffset;
12868 viewCreateInfo.range = size;
12869
12870 BufferView view;
12871 ANGLE_VK_TRY(context, view.init(context->getDevice(), viewCreateInfo));
12872
12873 // Cache the view
12874 auto insertIter = mViews.insert({viewVkFormat, std::move(view)});
12875 *viewOut = &insertIter.first->second;
12876 ASSERT(insertIter.second);
12877
12878 return angle::Result::Continue;
12879 }
12880
getSerial() const12881 ImageOrBufferViewSubresourceSerial BufferViewHelper::getSerial() const
12882 {
12883 ASSERT(mViewSerial.valid());
12884
12885 ImageOrBufferViewSubresourceSerial serial = {};
12886 serial.viewSerial = mViewSerial;
12887 return serial;
12888 }
12889
12890 // ShaderProgramHelper implementation.
12891 ShaderProgramHelper::ShaderProgramHelper() = default;
12892 ShaderProgramHelper::~ShaderProgramHelper() = default;
12893
valid(const gl::ShaderType shaderType) const12894 bool ShaderProgramHelper::valid(const gl::ShaderType shaderType) const
12895 {
12896 return mShaders[shaderType];
12897 }
12898
destroy(Renderer * renderer)12899 void ShaderProgramHelper::destroy(Renderer *renderer)
12900 {
12901 for (ShaderModulePtr &shader : mShaders)
12902 {
12903 shader.reset();
12904 }
12905 }
12906
release(ContextVk * contextVk)12907 void ShaderProgramHelper::release(ContextVk *contextVk)
12908 {
12909 for (ShaderModulePtr &shader : mShaders)
12910 {
12911 shader.reset();
12912 }
12913 }
12914
setShader(gl::ShaderType shaderType,const ShaderModulePtr & shader)12915 void ShaderProgramHelper::setShader(gl::ShaderType shaderType, const ShaderModulePtr &shader)
12916 {
12917 // The shaders must be set once and are not expected to change.
12918 ASSERT(!mShaders[shaderType]);
12919 ASSERT(shader && shader->valid());
12920 mShaders[shaderType] = shader;
12921 }
12922
createMonolithicPipelineCreationTask(vk::Context * context,PipelineCacheAccess * pipelineCache,const GraphicsPipelineDesc & desc,const PipelineLayout & pipelineLayout,const SpecializationConstants & specConsts,PipelineHelper * pipeline) const12923 void ShaderProgramHelper::createMonolithicPipelineCreationTask(
12924 vk::Context *context,
12925 PipelineCacheAccess *pipelineCache,
12926 const GraphicsPipelineDesc &desc,
12927 const PipelineLayout &pipelineLayout,
12928 const SpecializationConstants &specConsts,
12929 PipelineHelper *pipeline) const
12930 {
12931 std::shared_ptr<CreateMonolithicPipelineTask> monolithicPipelineCreationTask =
12932 std::make_shared<CreateMonolithicPipelineTask>(context->getRenderer(), *pipelineCache,
12933 pipelineLayout, mShaders, specConsts, desc);
12934
12935 pipeline->setMonolithicPipelineCreationTask(std::move(monolithicPipelineCreationTask));
12936 }
12937
getOrCreateComputePipeline(vk::Context * context,ComputePipelineCache * computePipelines,PipelineCacheAccess * pipelineCache,const PipelineLayout & pipelineLayout,ComputePipelineOptions pipelineOptions,PipelineSource source,PipelineHelper ** pipelineOut,const char * shaderName,VkSpecializationInfo * specializationInfo) const12938 angle::Result ShaderProgramHelper::getOrCreateComputePipeline(
12939 vk::Context *context,
12940 ComputePipelineCache *computePipelines,
12941 PipelineCacheAccess *pipelineCache,
12942 const PipelineLayout &pipelineLayout,
12943 ComputePipelineOptions pipelineOptions,
12944 PipelineSource source,
12945 PipelineHelper **pipelineOut,
12946 const char *shaderName,
12947 VkSpecializationInfo *specializationInfo) const
12948 {
12949 PipelineHelper *computePipeline = &(*computePipelines)[pipelineOptions.permutationIndex];
12950
12951 if (computePipeline->valid())
12952 {
12953 *pipelineOut = computePipeline;
12954 return angle::Result::Continue;
12955 }
12956
12957 VkPipelineShaderStageCreateInfo shaderStage = {};
12958 VkComputePipelineCreateInfo createInfo = {};
12959
12960 shaderStage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
12961 shaderStage.flags = 0;
12962 shaderStage.stage = VK_SHADER_STAGE_COMPUTE_BIT;
12963 shaderStage.module = mShaders[gl::ShaderType::Compute]->getHandle();
12964 shaderStage.pName = shaderName ? shaderName : "main";
12965 shaderStage.pSpecializationInfo = specializationInfo;
12966
12967 createInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
12968 createInfo.flags = 0;
12969 createInfo.stage = shaderStage;
12970 createInfo.layout = pipelineLayout.getHandle();
12971 createInfo.basePipelineHandle = VK_NULL_HANDLE;
12972 createInfo.basePipelineIndex = 0;
12973
12974 VkPipelineRobustnessCreateInfoEXT robustness = {};
12975 robustness.sType = VK_STRUCTURE_TYPE_PIPELINE_ROBUSTNESS_CREATE_INFO_EXT;
12976
12977 // Enable robustness on the pipeline if needed. Note that the global robustBufferAccess feature
12978 // must be disabled by default.
12979 if (pipelineOptions.robustness != 0)
12980 {
12981 ASSERT(context->getFeatures().supportsPipelineRobustness.enabled);
12982
12983 robustness.storageBuffers = VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_EXT;
12984 robustness.uniformBuffers = VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_EXT;
12985 robustness.vertexInputs = VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DEVICE_DEFAULT_EXT;
12986 robustness.images = VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_DEVICE_DEFAULT_EXT;
12987
12988 AddToPNextChain(&createInfo, &robustness);
12989 }
12990
12991 // Restrict pipeline to protected or unprotected command buffers if possible.
12992 if (pipelineOptions.protectedAccess != 0)
12993 {
12994 ASSERT(context->getFeatures().supportsPipelineProtectedAccess.enabled);
12995 createInfo.flags |= VK_PIPELINE_CREATE_PROTECTED_ACCESS_ONLY_BIT_EXT;
12996 }
12997 else if (context->getFeatures().supportsPipelineProtectedAccess.enabled)
12998 {
12999 createInfo.flags |= VK_PIPELINE_CREATE_NO_PROTECTED_ACCESS_BIT_EXT;
13000 }
13001
13002 VkPipelineCreationFeedback feedback = {};
13003 VkPipelineCreationFeedback perStageFeedback = {};
13004 VkPipelineCreationFeedbackCreateInfo feedbackInfo = {};
13005 feedbackInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO;
13006 feedbackInfo.pPipelineCreationFeedback = &feedback;
13007 // Note: see comment in GraphicsPipelineDesc::initializePipeline about why per-stage feedback is
13008 // specified even though unused.
13009 feedbackInfo.pipelineStageCreationFeedbackCount = 1;
13010 feedbackInfo.pPipelineStageCreationFeedbacks = &perStageFeedback;
13011
13012 const bool supportsFeedback = context->getFeatures().supportsPipelineCreationFeedback.enabled;
13013 if (supportsFeedback)
13014 {
13015 AddToPNextChain(&createInfo, &feedbackInfo);
13016 }
13017
13018 vk::Pipeline pipeline;
13019 ANGLE_VK_TRY(context, pipelineCache->createComputePipeline(context, createInfo, &pipeline));
13020
13021 vk::CacheLookUpFeedback lookUpFeedback = CacheLookUpFeedback::None;
13022
13023 if (supportsFeedback)
13024 {
13025 const bool cacheHit =
13026 (feedback.flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT) !=
13027 0;
13028
13029 lookUpFeedback = cacheHit ? CacheLookUpFeedback::Hit : CacheLookUpFeedback::Miss;
13030 ApplyPipelineCreationFeedback(context, feedback);
13031 }
13032
13033 computePipeline->setComputePipeline(std::move(pipeline), lookUpFeedback);
13034
13035 *pipelineOut = computePipeline;
13036 return angle::Result::Continue;
13037 }
13038
13039 // ActiveHandleCounter implementation.
ActiveHandleCounter()13040 ActiveHandleCounter::ActiveHandleCounter() : mActiveCounts{}, mAllocatedCounts{} {}
13041
13042 ActiveHandleCounter::~ActiveHandleCounter() = default;
13043
13044 // CommandBufferAccess implementation.
13045 CommandBufferAccess::CommandBufferAccess() = default;
13046 CommandBufferAccess::~CommandBufferAccess() = default;
13047
onBufferRead(VkAccessFlags readAccessType,PipelineStage readStage,BufferHelper * buffer)13048 void CommandBufferAccess::onBufferRead(VkAccessFlags readAccessType,
13049 PipelineStage readStage,
13050 BufferHelper *buffer)
13051 {
13052 ASSERT(!buffer->isReleasedToExternal());
13053 mReadBuffers.emplace_back(buffer, readAccessType, readStage);
13054 }
13055
onBufferWrite(VkAccessFlags writeAccessType,PipelineStage writeStage,BufferHelper * buffer)13056 void CommandBufferAccess::onBufferWrite(VkAccessFlags writeAccessType,
13057 PipelineStage writeStage,
13058 BufferHelper *buffer)
13059 {
13060 ASSERT(!buffer->isReleasedToExternal());
13061 mWriteBuffers.emplace_back(buffer, writeAccessType, writeStage);
13062 }
13063
onImageRead(VkImageAspectFlags aspectFlags,ImageLayout imageLayout,ImageHelper * image)13064 void CommandBufferAccess::onImageRead(VkImageAspectFlags aspectFlags,
13065 ImageLayout imageLayout,
13066 ImageHelper *image)
13067 {
13068 ASSERT(!image->isReleasedToExternal());
13069 ASSERT(image->getImageSerial().valid());
13070 mReadImages.emplace_back(image, aspectFlags, imageLayout);
13071 }
13072
onImageWrite(gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,ImageHelper * image)13073 void CommandBufferAccess::onImageWrite(gl::LevelIndex levelStart,
13074 uint32_t levelCount,
13075 uint32_t layerStart,
13076 uint32_t layerCount,
13077 VkImageAspectFlags aspectFlags,
13078 ImageLayout imageLayout,
13079 ImageHelper *image)
13080 {
13081 ASSERT(!image->isReleasedToExternal());
13082 ASSERT(image->getImageSerial().valid());
13083 mWriteImages.emplace_back(CommandBufferImageAccess{image, aspectFlags, imageLayout}, levelStart,
13084 levelCount, layerStart, layerCount);
13085 }
13086
onImageReadSubresources(gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,ImageHelper * image)13087 void CommandBufferAccess::onImageReadSubresources(gl::LevelIndex levelStart,
13088 uint32_t levelCount,
13089 uint32_t layerStart,
13090 uint32_t layerCount,
13091 VkImageAspectFlags aspectFlags,
13092 ImageLayout imageLayout,
13093 ImageHelper *image)
13094 {
13095 ASSERT(!image->isReleasedToExternal());
13096 ASSERT(image->getImageSerial().valid());
13097 mReadImageSubresources.emplace_back(CommandBufferImageAccess{image, aspectFlags, imageLayout},
13098 levelStart, levelCount, layerStart, layerCount);
13099 }
13100
onBufferExternalAcquireRelease(BufferHelper * buffer)13101 void CommandBufferAccess::onBufferExternalAcquireRelease(BufferHelper *buffer)
13102 {
13103 mExternalAcquireReleaseBuffers.emplace_back(CommandBufferBufferExternalAcquireRelease{buffer});
13104 }
13105
onResourceAccess(Resource * resource)13106 void CommandBufferAccess::onResourceAccess(Resource *resource)
13107 {
13108 mAccessResources.emplace_back(CommandBufferResourceAccess{resource});
13109 }
13110
13111 // DescriptorMetaCache implementation.
13112 MetaDescriptorPool::MetaDescriptorPool() = default;
13113
~MetaDescriptorPool()13114 MetaDescriptorPool::~MetaDescriptorPool()
13115 {
13116 ASSERT(mPayload.empty());
13117 }
13118
destroy(Renderer * renderer)13119 void MetaDescriptorPool::destroy(Renderer *renderer)
13120 {
13121 for (auto &iter : mPayload)
13122 {
13123 DynamicDescriptorPoolPointer &pool = iter.second;
13124 ASSERT(pool.unique());
13125 }
13126 mPayload.clear();
13127 }
13128
bindCachedDescriptorPool(Context * context,const DescriptorSetLayoutDesc & descriptorSetLayoutDesc,uint32_t descriptorCountMultiplier,DescriptorSetLayoutCache * descriptorSetLayoutCache,DynamicDescriptorPoolPointer * dynamicDescriptorPoolOut)13129 angle::Result MetaDescriptorPool::bindCachedDescriptorPool(
13130 Context *context,
13131 const DescriptorSetLayoutDesc &descriptorSetLayoutDesc,
13132 uint32_t descriptorCountMultiplier,
13133 DescriptorSetLayoutCache *descriptorSetLayoutCache,
13134 DynamicDescriptorPoolPointer *dynamicDescriptorPoolOut)
13135 {
13136 if (descriptorSetLayoutDesc.empty())
13137 {
13138 // No need for descriptorSet pool.
13139 return angle::Result::Continue;
13140 }
13141
13142 auto cacheIter = mPayload.find(descriptorSetLayoutDesc);
13143 if (cacheIter != mPayload.end())
13144 {
13145 *dynamicDescriptorPoolOut = cacheIter->second;
13146 return angle::Result::Continue;
13147 }
13148
13149 DescriptorSetLayoutPtr descriptorSetLayout;
13150 ANGLE_TRY(descriptorSetLayoutCache->getDescriptorSetLayout(context, descriptorSetLayoutDesc,
13151 &descriptorSetLayout));
13152
13153 DynamicDescriptorPool newDescriptorPool;
13154 ANGLE_TRY(InitDynamicDescriptorPool(context, descriptorSetLayoutDesc, *descriptorSetLayout,
13155 descriptorCountMultiplier, &newDescriptorPool));
13156
13157 ASSERT(newDescriptorPool.valid());
13158 DynamicDescriptorPoolPointer newDynamicDescriptorPoolPtr(context->getDevice(),
13159 std::move(newDescriptorPool));
13160 mPayload.emplace(descriptorSetLayoutDesc, newDynamicDescriptorPoolPtr);
13161 *dynamicDescriptorPoolOut = std::move(newDynamicDescriptorPoolPtr);
13162
13163 return angle::Result::Continue;
13164 }
13165
13166 static_assert(static_cast<uint32_t>(PresentMode::ImmediateKHR) == VK_PRESENT_MODE_IMMEDIATE_KHR,
13167 "PresentMode must be updated");
13168 static_assert(static_cast<uint32_t>(PresentMode::MailboxKHR) == VK_PRESENT_MODE_MAILBOX_KHR,
13169 "PresentMode must be updated");
13170 static_assert(static_cast<uint32_t>(PresentMode::FifoKHR) == VK_PRESENT_MODE_FIFO_KHR,
13171 "PresentMode must be updated");
13172 static_assert(static_cast<uint32_t>(PresentMode::FifoRelaxedKHR) ==
13173 VK_PRESENT_MODE_FIFO_RELAXED_KHR,
13174 "PresentMode must be updated");
13175 static_assert(static_cast<uint32_t>(PresentMode::SharedDemandRefreshKHR) ==
13176 VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR,
13177 "PresentMode must be updated");
13178 static_assert(static_cast<uint32_t>(PresentMode::SharedContinuousRefreshKHR) ==
13179 VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR,
13180 "PresentMode must be updated");
13181
ConvertPresentModeToVkPresentMode(PresentMode presentMode)13182 VkPresentModeKHR ConvertPresentModeToVkPresentMode(PresentMode presentMode)
13183 {
13184 return static_cast<VkPresentModeKHR>(presentMode);
13185 }
13186
ConvertVkPresentModeToPresentMode(VkPresentModeKHR vkPresentMode)13187 PresentMode ConvertVkPresentModeToPresentMode(VkPresentModeKHR vkPresentMode)
13188 {
13189 return static_cast<PresentMode>(vkPresentMode);
13190 }
13191
13192 } // namespace vk
13193 } // namespace rx
13194