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