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