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