1 //
2 // Copyright 2018 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // vk_helpers:
7 // Helper utility classes that manage Vulkan resources.
8
9 #include "libANGLE/renderer/vulkan/vk_helpers.h"
10
11 #include "common/aligned_memory.h"
12 #include "common/utilities.h"
13 #include "common/vulkan/vk_headers.h"
14 #include "image_util/loadimage.h"
15 #include "libANGLE/Context.h"
16 #include "libANGLE/Display.h"
17 #include "libANGLE/renderer/driver_utils.h"
18 #include "libANGLE/renderer/renderer_utils.h"
19 #include "libANGLE/renderer/vulkan/BufferVk.h"
20 #include "libANGLE/renderer/vulkan/ContextVk.h"
21 #include "libANGLE/renderer/vulkan/DisplayVk.h"
22 #include "libANGLE/renderer/vulkan/FramebufferVk.h"
23 #include "libANGLE/renderer/vulkan/RenderTargetVk.h"
24 #include "libANGLE/renderer/vulkan/android/vk_android_utils.h"
25 #include "libANGLE/renderer/vulkan/vk_ref_counted_event.h"
26 #include "libANGLE/renderer/vulkan/vk_renderer.h"
27 #include "libANGLE/renderer/vulkan/vk_utils.h"
28
29 namespace rx
30 {
31 namespace vk
32 {
33 namespace
34 {
35 // During descriptorSet cache eviction, we keep it in the cache only if it is recently used. If it
36 // has not been used in the past kDescriptorSetCacheRetireAge frames, it will be evicted.
37 constexpr uint32_t kDescriptorSetCacheRetireAge = 10;
38
39 // ANGLE_robust_resource_initialization requires color textures to be initialized to zero.
40 constexpr VkClearColorValue kRobustInitColorValue = {{0, 0, 0, 0}};
41 // When emulating a texture, we want the emulated channels to be 0, with alpha 1.
42 constexpr VkClearColorValue kEmulatedInitColorValue = {{0, 0, 0, 1.0f}};
43 // ANGLE_robust_resource_initialization requires depth to be initialized to 1 and stencil to 0.
44 // We are fine with these values for emulated depth/stencil textures too.
45 constexpr VkClearDepthStencilValue kRobustInitDepthStencilValue = {1.0f, 0};
46
47 constexpr VkImageAspectFlags kDepthStencilAspects =
48 VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_DEPTH_BIT;
49
50 // Information useful for buffer related barriers
51 struct BufferMemoryBarrierData
52 {
53 VkPipelineStageFlags pipelineStageFlags;
54 // EventStage::InvalidEnum indicates don't use VkEvent for barrier(i.e., use pipelineBarrier
55 // instead)
56 EventStage eventStage;
57 };
58 // clang-format off
59 constexpr angle::PackedEnumMap<PipelineStage, BufferMemoryBarrierData> kBufferMemoryBarrierData = {
60 {PipelineStage::TopOfPipe, {VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, EventStage::InvalidEnum}},
61 {PipelineStage::DrawIndirect, {VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, EventStage::VertexInput}},
62 {PipelineStage::VertexInput, {VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, EventStage::VertexInput}},
63 {PipelineStage::VertexShader, {VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, EventStage::VertexShader}},
64 {PipelineStage::TessellationControl, {VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT, EventStage::InvalidEnum}},
65 {PipelineStage::TessellationEvaluation, {VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT, EventStage::InvalidEnum}},
66 {PipelineStage::GeometryShader, {VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT, EventStage::InvalidEnum}},
67 {PipelineStage::TransformFeedback, {VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT, EventStage::TransformFeedbackWrite}},
68 {PipelineStage::FragmentShadingRate, {0, EventStage::InvalidEnum}},
69 {PipelineStage::EarlyFragmentTest, {0, EventStage::InvalidEnum}},
70 {PipelineStage::FragmentShader, {VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, EventStage::FragmentShader}},
71 {PipelineStage::LateFragmentTest, {0, EventStage::InvalidEnum}},
72 {PipelineStage::ColorAttachmentOutput, {0, EventStage::InvalidEnum}},
73 {PipelineStage::ComputeShader, {VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, EventStage::ComputeShader}},
74 {PipelineStage::Transfer, {VK_PIPELINE_STAGE_TRANSFER_BIT, EventStage::InvalidEnum}},
75 {PipelineStage::BottomOfPipe, BufferMemoryBarrierData{VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, EventStage::InvalidEnum}},
76 {PipelineStage::Host, {VK_PIPELINE_STAGE_HOST_BIT, EventStage::InvalidEnum}},
77 };
78
79 constexpr gl::ShaderMap<PipelineStage> kPipelineStageShaderMap = {
80 {gl::ShaderType::Vertex, PipelineStage::VertexShader},
81 {gl::ShaderType::TessControl, PipelineStage::TessellationControl},
82 {gl::ShaderType::TessEvaluation, PipelineStage::TessellationEvaluation},
83 {gl::ShaderType::Geometry, PipelineStage::GeometryShader},
84 {gl::ShaderType::Fragment, PipelineStage::FragmentShader},
85 {gl::ShaderType::Compute, PipelineStage::ComputeShader},
86 };
87
88 constexpr ImageLayoutToMemoryBarrierDataMap kImageMemoryBarrierData = {
89 {
90 ImageLayout::Undefined,
91 ImageMemoryBarrierData{
92 "Undefined",
93 VK_IMAGE_LAYOUT_UNDEFINED,
94 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
95 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
96 // Transition to: we don't expect to transition into Undefined.
97 0,
98 // Transition from: there's no data in the image to care about.
99 0,
100 ResourceAccess::ReadOnly,
101 PipelineStage::InvalidEnum,
102 // We do not directly use this layout in SetEvent. We transit to other layout before using
103 EventStage::InvalidEnum,
104 PipelineStageGroup::Other,
105 },
106 },
107 {
108 ImageLayout::ColorWrite,
109 ImageMemoryBarrierData{
110 "ColorWrite",
111 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
112 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
113 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
114 // Transition to: all reads and writes must happen after barrier.
115 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
116 // Transition from: all writes must finish before barrier.
117 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
118 ResourceAccess::ReadWrite,
119 PipelineStage::ColorAttachmentOutput,
120 EventStage::Attachment,
121 PipelineStageGroup::FragmentOnly,
122 },
123 },
124 {
125 ImageLayout::ColorWriteAndInput,
126 ImageMemoryBarrierData{
127 "ColorWriteAndInput",
128 VK_IMAGE_LAYOUT_RENDERING_LOCAL_READ_KHR,
129 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
130 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
131 // Transition to: all reads and writes must happen after barrier.
132 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
133 // Transition from: all writes must finish before barrier.
134 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
135 ResourceAccess::ReadWrite,
136 PipelineStage::ColorAttachmentOutput,
137 EventStage::Attachment,
138 PipelineStageGroup::FragmentOnly,
139 },
140 },
141 {
142 ImageLayout::MSRTTEmulationColorUnresolveAndResolve,
143 ImageMemoryBarrierData{
144 "MSRTTEmulationColorUnresolveAndResolve",
145 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
146 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
147 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
148 // Transition to: all reads and writes must happen after barrier.
149 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT,
150 // Transition from: all writes must finish before barrier.
151 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
152 ResourceAccess::ReadWrite,
153 PipelineStage::FragmentShader,
154 EventStage::AttachmentAndFragmentShader,
155 PipelineStageGroup::FragmentOnly,
156 },
157 },
158 {
159 ImageLayout::DepthWriteStencilWrite,
160 ImageMemoryBarrierData{
161 "DepthWriteStencilWrite",
162 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
163 kAllDepthStencilPipelineStageFlags,
164 kAllDepthStencilPipelineStageFlags,
165 // Transition to: all reads and writes must happen after barrier.
166 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
167 // Transition from: all writes must finish before barrier.
168 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
169 ResourceAccess::ReadWrite,
170 PipelineStage::EarlyFragmentTest,
171 EventStage::Attachment,
172 PipelineStageGroup::FragmentOnly,
173 },
174 },
175 {
176 ImageLayout::DepthStencilWriteAndInput,
177 ImageMemoryBarrierData{
178 "DepthStencilWriteAndInput",
179 VK_IMAGE_LAYOUT_RENDERING_LOCAL_READ_KHR,
180 kAllDepthStencilPipelineStageFlags,
181 kAllDepthStencilPipelineStageFlags,
182 // Transition to: all reads and writes must happen after barrier.
183 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
184 // Transition from: all writes must finish before barrier.
185 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
186 ResourceAccess::ReadWrite,
187 PipelineStage::EarlyFragmentTest,
188 EventStage::Attachment,
189 PipelineStageGroup::FragmentOnly,
190 },
191 },
192 {
193 ImageLayout::DepthWriteStencilRead,
194 ImageMemoryBarrierData{
195 "DepthWriteStencilRead",
196 VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL,
197 kAllDepthStencilPipelineStageFlags,
198 kAllDepthStencilPipelineStageFlags,
199 // Transition to: all reads and writes must happen after barrier.
200 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
201 // Transition from: all writes must finish before barrier.
202 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
203 ResourceAccess::ReadWrite,
204 PipelineStage::EarlyFragmentTest,
205 EventStage::Attachment,
206 PipelineStageGroup::FragmentOnly,
207 },
208 },
209 {
210 ImageLayout::DepthWriteStencilReadFragmentShaderStencilRead,
211 ImageMemoryBarrierData{
212 "DepthWriteStencilReadFragmentShaderStencilRead",
213 VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL,
214 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | kAllDepthStencilPipelineStageFlags,
215 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | kAllDepthStencilPipelineStageFlags,
216 // Transition to: all reads and writes must happen after barrier.
217 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
218 // Transition from: all writes must finish before barrier.
219 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
220 ResourceAccess::ReadWrite,
221 PipelineStage::EarlyFragmentTest,
222 EventStage::AttachmentAndFragmentShader,
223 PipelineStageGroup::FragmentOnly,
224 },
225 },
226 {
227 ImageLayout::DepthWriteStencilReadAllShadersStencilRead,
228 ImageMemoryBarrierData{
229 "DepthWriteStencilReadAllShadersStencilRead",
230 VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL,
231 kAllShadersPipelineStageFlags | kAllDepthStencilPipelineStageFlags,
232 kAllShadersPipelineStageFlags | kAllDepthStencilPipelineStageFlags,
233 // Transition to: all reads and writes must happen after barrier.
234 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
235 // Transition from: all writes must finish before barrier.
236 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
237 ResourceAccess::ReadWrite,
238 PipelineStage::VertexShader,
239 EventStage::AttachmentAndAllShaders,
240 PipelineStageGroup::Other,
241 },
242 },
243 {
244 ImageLayout::DepthReadStencilWrite,
245 ImageMemoryBarrierData{
246 "DepthReadStencilWrite",
247 VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL,
248 kAllDepthStencilPipelineStageFlags,
249 kAllDepthStencilPipelineStageFlags,
250 // Transition to: all reads and writes must happen after barrier.
251 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
252 // Transition from: all writes must finish before barrier.
253 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
254 ResourceAccess::ReadWrite,
255 PipelineStage::EarlyFragmentTest,
256 EventStage::Attachment,
257 PipelineStageGroup::FragmentOnly,
258 },
259 },
260 {
261 ImageLayout::DepthReadStencilWriteFragmentShaderDepthRead,
262 ImageMemoryBarrierData{
263 "DepthReadStencilWriteFragmentShaderDepthRead",
264 VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL,
265 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | kAllDepthStencilPipelineStageFlags,
266 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | kAllDepthStencilPipelineStageFlags,
267 // Transition to: all reads and writes must happen after barrier.
268 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
269 // Transition from: all writes must finish before barrier.
270 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
271 ResourceAccess::ReadWrite,
272 PipelineStage::EarlyFragmentTest,
273 EventStage::AttachmentAndFragmentShader,
274 PipelineStageGroup::FragmentOnly,
275 },
276 },
277 {
278 ImageLayout::DepthReadStencilWriteAllShadersDepthRead,
279 ImageMemoryBarrierData{
280 "DepthReadStencilWriteAllShadersDepthRead",
281 VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL,
282 kAllShadersPipelineStageFlags | kAllDepthStencilPipelineStageFlags,
283 kAllShadersPipelineStageFlags | kAllDepthStencilPipelineStageFlags,
284 // Transition to: all reads and writes must happen after barrier.
285 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
286 // Transition from: all writes must finish before barrier.
287 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
288 ResourceAccess::ReadWrite,
289 PipelineStage::VertexShader,
290 EventStage::AttachmentAndAllShaders,
291 PipelineStageGroup::Other,
292 },
293 },
294 {
295 ImageLayout::DepthReadStencilRead,
296 ImageMemoryBarrierData{
297 "DepthReadStencilRead",
298 VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
299 kAllDepthStencilPipelineStageFlags,
300 kAllDepthStencilPipelineStageFlags,
301 // Transition to: all reads must happen after barrier.
302 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
303 // Transition from: RAR and WAR don't need memory barrier.
304 0,
305 ResourceAccess::ReadOnly,
306 PipelineStage::EarlyFragmentTest,
307 EventStage::Attachment,
308 PipelineStageGroup::FragmentOnly,
309 },
310 },
311
312 {
313 ImageLayout::DepthReadStencilReadFragmentShaderRead,
314 ImageMemoryBarrierData{
315 "DepthReadStencilReadFragmentShaderRead",
316 VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
317 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | kAllDepthStencilPipelineStageFlags,
318 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | kAllDepthStencilPipelineStageFlags,
319 // Transition to: all reads must happen after barrier.
320 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
321 // Transition from: RAR and WAR don't need memory barrier.
322 0,
323 ResourceAccess::ReadOnly,
324 PipelineStage::EarlyFragmentTest,
325 EventStage::AttachmentAndFragmentShader,
326 PipelineStageGroup::FragmentOnly,
327 },
328 },
329 {
330 ImageLayout::DepthReadStencilReadAllShadersRead,
331 ImageMemoryBarrierData{
332 "DepthReadStencilReadAllShadersRead",
333 VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
334 kAllShadersPipelineStageFlags | kAllDepthStencilPipelineStageFlags,
335 kAllShadersPipelineStageFlags | kAllDepthStencilPipelineStageFlags,
336 // Transition to: all reads must happen after barrier.
337 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
338 // Transition from: RAR and WAR don't need memory barrier.
339 0,
340 ResourceAccess::ReadOnly,
341 PipelineStage::VertexShader,
342 EventStage::AttachmentAndAllShaders,
343 PipelineStageGroup::Other,
344 },
345 },
346 {
347 ImageLayout::ColorWriteFragmentShaderFeedback,
348 ImageMemoryBarrierData{
349 "ColorWriteFragmentShaderFeedback",
350 VK_IMAGE_LAYOUT_GENERAL,
351 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
352 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
353 // Transition to: all reads and writes must happen after barrier.
354 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT,
355 // Transition from: all writes must finish before barrier.
356 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
357 ResourceAccess::ReadWrite,
358 PipelineStage::FragmentShader,
359 EventStage::AttachmentAndFragmentShader,
360 PipelineStageGroup::FragmentOnly,
361 },
362 },
363 {
364 ImageLayout::ColorWriteAllShadersFeedback,
365 ImageMemoryBarrierData{
366 "ColorWriteAllShadersFeedback",
367 VK_IMAGE_LAYOUT_GENERAL,
368 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | kAllShadersPipelineStageFlags,
369 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | kAllShadersPipelineStageFlags,
370 // Transition to: all reads and writes must happen after barrier.
371 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT,
372 // Transition from: all writes must finish before barrier.
373 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
374 ResourceAccess::ReadWrite,
375 // In case of multiple destination stages, We barrier the earliest stage
376 PipelineStage::VertexShader,
377 EventStage::AttachmentAndAllShaders,
378 PipelineStageGroup::Other,
379 },
380 },
381 {
382 ImageLayout::DepthStencilFragmentShaderFeedback,
383 ImageMemoryBarrierData{
384 "DepthStencilFragmentShaderFeedback",
385 VK_IMAGE_LAYOUT_GENERAL,
386 kAllDepthStencilPipelineStageFlags | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
387 kAllDepthStencilPipelineStageFlags | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
388 // Transition to: all reads and writes must happen after barrier.
389 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT,
390 // Transition from: all writes must finish before barrier.
391 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
392 ResourceAccess::ReadWrite,
393 PipelineStage::FragmentShader,
394 EventStage::AttachmentAndFragmentShader,
395 PipelineStageGroup::FragmentOnly,
396 },
397 },
398 {
399 ImageLayout::DepthStencilAllShadersFeedback,
400 ImageMemoryBarrierData{
401 "DepthStencilAllShadersFeedback",
402 VK_IMAGE_LAYOUT_GENERAL,
403 kAllDepthStencilPipelineStageFlags | kAllShadersPipelineStageFlags,
404 kAllDepthStencilPipelineStageFlags | kAllShadersPipelineStageFlags,
405 // Transition to: all reads and writes must happen after barrier.
406 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT,
407 // Transition from: all writes must finish before barrier.
408 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
409 ResourceAccess::ReadWrite,
410 // In case of multiple destination stages, We barrier the earliest stage
411 PipelineStage::VertexShader,
412 EventStage::AttachmentAndAllShaders,
413 PipelineStageGroup::Other,
414 },
415 },
416 {
417 ImageLayout::DepthStencilResolve,
418 ImageMemoryBarrierData{
419 "DepthStencilResolve",
420 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
421 // Note: depth/stencil resolve uses color output stage and mask!
422 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
423 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
424 // Transition to: all reads and writes must happen after barrier.
425 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
426 // Transition from: all writes must finish before barrier.
427 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
428 ResourceAccess::ReadWrite,
429 PipelineStage::ColorAttachmentOutput,
430 EventStage::Attachment,
431 PipelineStageGroup::FragmentOnly,
432 },
433 },
434 {
435 ImageLayout::MSRTTEmulationDepthStencilUnresolveAndResolve,
436 ImageMemoryBarrierData{
437 "MSRTTEmulationDepthStencilUnresolveAndResolve",
438 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
439 // Note: depth/stencil resolve uses color output stage and mask!
440 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
441 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
442 // Transition to: all reads and writes must happen after barrier.
443 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT,
444 // Transition from: all writes must finish before barrier.
445 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
446 ResourceAccess::ReadWrite,
447 PipelineStage::FragmentShader,
448 EventStage::AttachmentAndFragmentShader,
449 PipelineStageGroup::FragmentOnly,
450 },
451 },
452 {
453 ImageLayout::Present,
454 ImageMemoryBarrierData{
455 "Present",
456 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
457 // Transition to: do not delay execution of commands in the second synchronization
458 // scope. Allow layout transition to be delayed until present semaphore is signaled.
459 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
460 // Transition from: use same stages as in Acquire Image Semaphore stage mask in order to
461 // build a dependency chain from the Acquire Image Semaphore to the layout transition's
462 // first synchronization scope.
463 kSwapchainAcquireImageWaitStageFlags,
464 // Transition to: vkQueuePresentKHR automatically performs the appropriate memory barriers:
465 //
466 // > Any writes to memory backing the images referenced by the pImageIndices and
467 // > pSwapchains members of pPresentInfo, that are available before vkQueuePresentKHR
468 // > is executed, are automatically made visible to the read access performed by the
469 // > presentation engine.
470 0,
471 // Transition from: RAR and WAR don't need memory barrier.
472 0,
473 ResourceAccess::ReadOnly,
474 PipelineStage::BottomOfPipe,
475 // We do not directly use this layout in SetEvent.
476 EventStage::InvalidEnum,
477 PipelineStageGroup::Other,
478 },
479 },
480 {
481 ImageLayout::SharedPresent,
482 ImageMemoryBarrierData{
483 "SharedPresent",
484 VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR,
485 // All currently possible stages for SharedPresent
486 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
487 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
488 // Transition to: all reads and writes must happen after barrier.
489 VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
490 // Transition from: all writes must finish before barrier.
491 VK_ACCESS_MEMORY_WRITE_BIT,
492 ResourceAccess::ReadWrite,
493 PipelineStage::BottomOfPipe,
494 EventStage::AttachmentAndFragmentShaderAndTransfer,
495 PipelineStageGroup::Other,
496 },
497 },
498 {
499 ImageLayout::ExternalPreInitialized,
500 ImageMemoryBarrierData{
501 "ExternalPreInitialized",
502 // Binding a VkImage with an initial layout of VK_IMAGE_LAYOUT_UNDEFINED to external
503 // memory whose content has already been defined does not make the content undefined
504 // (see 12.8.1. External Resource Sharing).
505 //
506 // Note that for external memory objects, if the content is already defined, the
507 // ownership rules imply that the first operation on the texture must be a call to
508 // glWaitSemaphoreEXT that grants ownership of the image and informs us of the true
509 // layout. If the content is not already defined, the first operation may not be a
510 // glWaitSemaphore, but in this case undefined layout is appropriate.
511 VK_IMAGE_LAYOUT_UNDEFINED,
512 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
513 VK_PIPELINE_STAGE_HOST_BIT | VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
514 // Transition to: we don't expect to transition into PreInitialized.
515 0,
516 // Transition from: all writes must finish before barrier.
517 VK_ACCESS_MEMORY_WRITE_BIT,
518 ResourceAccess::ReadOnly,
519 PipelineStage::InvalidEnum,
520 // We do not directly use this layout in SetEvent. We transit to internal layout before using
521 EventStage::InvalidEnum,
522 PipelineStageGroup::Other,
523 },
524 },
525 {
526 ImageLayout::ExternalShadersReadOnly,
527 ImageMemoryBarrierData{
528 "ExternalShadersReadOnly",
529 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
530 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
531 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
532 // Transition to: all reads must happen after barrier.
533 VK_ACCESS_SHADER_READ_BIT,
534 // Transition from: RAR and WAR don't need memory barrier.
535 0,
536 ResourceAccess::ReadOnly,
537 // In case of multiple destination stages, We barrier the earliest stage
538 PipelineStage::TopOfPipe,
539 // We do not directly use this layout in SetEvent. We transit to internal layout before using
540 EventStage::InvalidEnum,
541 PipelineStageGroup::Other,
542 },
543 },
544 {
545 ImageLayout::ExternalShadersWrite,
546 ImageMemoryBarrierData{
547 "ExternalShadersWrite",
548 VK_IMAGE_LAYOUT_GENERAL,
549 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
550 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
551 // Transition to: all reads and writes must happen after barrier.
552 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
553 // Transition from: all writes must finish before barrier.
554 VK_ACCESS_SHADER_WRITE_BIT,
555 ResourceAccess::ReadWrite,
556 // In case of multiple destination stages, We barrier the earliest stage
557 PipelineStage::TopOfPipe,
558 // We do not directly use this layout in SetEvent. We transit to internal layout before using
559 EventStage::InvalidEnum,
560 PipelineStageGroup::Other,
561 },
562 },
563 {
564 ImageLayout::ForeignAccess,
565 ImageMemoryBarrierData{
566 "ForeignAccess",
567 VK_IMAGE_LAYOUT_GENERAL,
568 // Transition to: we don't expect to transition into ForeignAccess, that's done at
569 // submission time by the CommandQueue; the following value doesn't matter.
570 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
571 VK_PIPELINE_STAGE_HOST_BIT | VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
572 // Transition to: see dstStageMask
573 0,
574 // Transition from: all writes must finish before barrier; it is unknown how the foreign
575 // entity has access the memory.
576 VK_ACCESS_MEMORY_WRITE_BIT,
577 ResourceAccess::ReadWrite,
578 // In case of multiple destination stages, We barrier the earliest stage
579 PipelineStage::TopOfPipe,
580 // We do not directly use this layout in SetEvent. We transit to internal layout before using
581 EventStage::InvalidEnum,
582 PipelineStageGroup::Other,
583 },
584 },
585 {
586 ImageLayout::TransferSrc,
587 ImageMemoryBarrierData{
588 "TransferSrc",
589 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
590 VK_PIPELINE_STAGE_TRANSFER_BIT,
591 VK_PIPELINE_STAGE_TRANSFER_BIT,
592 // Transition to: all reads must happen after barrier.
593 VK_ACCESS_TRANSFER_READ_BIT,
594 // Transition from: RAR and WAR don't need memory barrier.
595 0,
596 ResourceAccess::ReadOnly,
597 PipelineStage::Transfer,
598 EventStage::Transfer,
599 PipelineStageGroup::Other,
600 },
601 },
602 {
603 ImageLayout::TransferDst,
604 ImageMemoryBarrierData{
605 "TransferDst",
606 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
607 VK_PIPELINE_STAGE_TRANSFER_BIT,
608 VK_PIPELINE_STAGE_TRANSFER_BIT,
609 // Transition to: all writes must happen after barrier.
610 VK_ACCESS_TRANSFER_WRITE_BIT,
611 // Transition from: all writes must finish before barrier.
612 VK_ACCESS_TRANSFER_WRITE_BIT,
613 ResourceAccess::ReadWrite,
614 PipelineStage::Transfer,
615 EventStage::Transfer,
616 PipelineStageGroup::Other,
617 },
618 },
619 {
620 ImageLayout::TransferSrcDst,
621 ImageMemoryBarrierData{
622 "TransferSrcDst",
623 VK_IMAGE_LAYOUT_GENERAL,
624 VK_PIPELINE_STAGE_TRANSFER_BIT,
625 VK_PIPELINE_STAGE_TRANSFER_BIT,
626 // Transition to: all reads and writes must happen after barrier.
627 VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
628 // Transition from: all writes must finish before barrier.
629 VK_ACCESS_TRANSFER_WRITE_BIT,
630 ResourceAccess::ReadWrite,
631 PipelineStage::Transfer,
632 EventStage::Transfer,
633 PipelineStageGroup::Other,
634 },
635 },
636 {
637 ImageLayout::HostCopy,
638 ImageMemoryBarrierData{
639 "HostCopy",
640 VK_IMAGE_LAYOUT_GENERAL,
641 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
642 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
643 // Transition to: we don't expect to transition into HostCopy on the GPU.
644 0,
645 // Transition from: the data was initialized in the image by the host. Note that we
646 // only transition to this layout if the image was previously in UNDEFINED, in which
647 // case it didn't contain any data prior to the host copy either.
648 0,
649 ResourceAccess::ReadOnly,
650 PipelineStage::InvalidEnum,
651 // We do not directly use this layout in SetEvent.
652 EventStage::InvalidEnum,
653 PipelineStageGroup::Other,
654 },
655 },
656 {
657 ImageLayout::VertexShaderReadOnly,
658 ImageMemoryBarrierData{
659 "VertexShaderReadOnly",
660 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
661 VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
662 VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
663 // Transition to: all reads must happen after barrier.
664 VK_ACCESS_SHADER_READ_BIT,
665 // Transition from: RAR and WAR don't need memory barrier.
666 0,
667 ResourceAccess::ReadOnly,
668 PipelineStage::VertexShader,
669 EventStage::VertexShader,
670 PipelineStageGroup::PreFragmentOnly,
671 },
672 },
673 {
674 ImageLayout::VertexShaderWrite,
675 ImageMemoryBarrierData{
676 "VertexShaderWrite",
677 VK_IMAGE_LAYOUT_GENERAL,
678 VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
679 VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
680 // Transition to: all reads and writes must happen after barrier.
681 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
682 // Transition from: all writes must finish before barrier.
683 VK_ACCESS_SHADER_WRITE_BIT,
684 ResourceAccess::ReadWrite,
685 PipelineStage::VertexShader,
686 EventStage::VertexShader,
687 PipelineStageGroup::PreFragmentOnly,
688 },
689 },
690 {
691 ImageLayout::PreFragmentShadersReadOnly,
692 ImageMemoryBarrierData{
693 "PreFragmentShadersReadOnly",
694 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
695 kPreFragmentStageFlags,
696 kPreFragmentStageFlags,
697 // Transition to: all reads must happen after barrier.
698 VK_ACCESS_SHADER_READ_BIT,
699 // Transition from: RAR and WAR don't need memory barrier.
700 0,
701 ResourceAccess::ReadOnly,
702 // In case of multiple destination stages, We barrier the earliest stage
703 PipelineStage::VertexShader,
704 EventStage::PreFragmentShaders,
705 PipelineStageGroup::PreFragmentOnly,
706 },
707 },
708 {
709 ImageLayout::PreFragmentShadersWrite,
710 ImageMemoryBarrierData{
711 "PreFragmentShadersWrite",
712 VK_IMAGE_LAYOUT_GENERAL,
713 kPreFragmentStageFlags,
714 kPreFragmentStageFlags,
715 // Transition to: all reads and writes must happen after barrier.
716 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
717 // Transition from: all writes must finish before barrier.
718 VK_ACCESS_SHADER_WRITE_BIT,
719 ResourceAccess::ReadWrite,
720 // In case of multiple destination stages, We barrier the earliest stage
721 PipelineStage::VertexShader,
722 EventStage::PreFragmentShaders,
723 PipelineStageGroup::PreFragmentOnly,
724 },
725 },
726 {
727 ImageLayout::FragmentShadingRateAttachmentReadOnly,
728 ImageMemoryBarrierData{
729 "FragmentShadingRateAttachmentReadOnly",
730 VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR,
731 VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR,
732 VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR,
733 // Transition to: all reads must happen after barrier.
734 VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR,
735 // Transition from: RAR and WAR don't need memory barrier.
736 0,
737 ResourceAccess::ReadOnly,
738 PipelineStage::FragmentShadingRate,
739 EventStage::FragmentShadingRate,
740 PipelineStageGroup::Other,
741 },
742 },
743 {
744 ImageLayout::FragmentShaderReadOnly,
745 ImageMemoryBarrierData{
746 "FragmentShaderReadOnly",
747 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
748 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
749 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
750 // Transition to: all reads must happen after barrier.
751 VK_ACCESS_SHADER_READ_BIT,
752 // Transition from: RAR and WAR don't need memory barrier.
753 0,
754 ResourceAccess::ReadOnly,
755 PipelineStage::FragmentShader,
756 EventStage::FragmentShader,
757 PipelineStageGroup::FragmentOnly,
758 },
759 },
760 {
761 ImageLayout::FragmentShaderWrite,
762 ImageMemoryBarrierData{
763 "FragmentShaderWrite",
764 VK_IMAGE_LAYOUT_GENERAL,
765 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
766 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
767 // Transition to: all reads and writes must happen after barrier.
768 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
769 // Transition from: all writes must finish before barrier.
770 VK_ACCESS_SHADER_WRITE_BIT,
771 ResourceAccess::ReadWrite,
772 PipelineStage::FragmentShader,
773 EventStage::FragmentShader,
774 PipelineStageGroup::FragmentOnly,
775 },
776 },
777 {
778 ImageLayout::ComputeShaderReadOnly,
779 ImageMemoryBarrierData{
780 "ComputeShaderReadOnly",
781 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
782 VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
783 VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
784 // Transition to: all reads must happen after barrier.
785 VK_ACCESS_SHADER_READ_BIT,
786 // Transition from: RAR and WAR don't need memory barrier.
787 0,
788 ResourceAccess::ReadOnly,
789 PipelineStage::ComputeShader,
790 EventStage::ComputeShader,
791 PipelineStageGroup::ComputeOnly,
792 },
793 },
794 {
795 ImageLayout::ComputeShaderWrite,
796 ImageMemoryBarrierData{
797 "ComputeShaderWrite",
798 VK_IMAGE_LAYOUT_GENERAL,
799 VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
800 VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
801 // Transition to: all reads and writes must happen after barrier.
802 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
803 // Transition from: all writes must finish before barrier.
804 VK_ACCESS_SHADER_WRITE_BIT,
805 ResourceAccess::ReadWrite,
806 PipelineStage::ComputeShader,
807 EventStage::ComputeShader,
808 PipelineStageGroup::ComputeOnly,
809 },
810 },
811 {
812 ImageLayout::AllGraphicsShadersReadOnly,
813 ImageMemoryBarrierData{
814 "AllGraphicsShadersReadOnly",
815 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
816 kAllShadersPipelineStageFlags,
817 kAllShadersPipelineStageFlags,
818 // Transition to: all reads must happen after barrier.
819 VK_ACCESS_SHADER_READ_BIT,
820 // Transition from: RAR and WAR don't need memory barrier.
821 0,
822 ResourceAccess::ReadOnly,
823 // In case of multiple destination stages, We barrier the earliest stage
824 PipelineStage::VertexShader,
825 EventStage::AllShaders,
826 PipelineStageGroup::Other,
827 },
828 },
829 {
830 ImageLayout::AllGraphicsShadersWrite,
831 ImageMemoryBarrierData{
832 "AllGraphicsShadersWrite",
833 VK_IMAGE_LAYOUT_GENERAL,
834 kAllShadersPipelineStageFlags,
835 kAllShadersPipelineStageFlags,
836 // Transition to: all reads and writes must happen after barrier.
837 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
838 // Transition from: all writes must finish before barrier.
839 VK_ACCESS_SHADER_WRITE_BIT,
840 ResourceAccess::ReadWrite,
841 // In case of multiple destination stages, We barrier the earliest stage
842 PipelineStage::VertexShader,
843 EventStage::AllShaders,
844 PipelineStageGroup::Other,
845 },
846 },
847 {
848 ImageLayout::TransferDstAndComputeWrite,
849 ImageMemoryBarrierData{
850 "TransferDstAndComputeWrite",
851 VK_IMAGE_LAYOUT_GENERAL,
852 VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT,
853 VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT,
854 // Transition to: all reads and writes must happen after barrier.
855 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT,
856 // Transition from: all writes must finish before barrier.
857 VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
858 ResourceAccess::ReadWrite,
859 // In case of multiple destination stages, We barrier the earliest stage
860 PipelineStage::ComputeShader,
861 EventStage::TransferAndComputeShader,
862 PipelineStageGroup::Other,
863 },
864 },
865 };
866 // clang-format on
867
GetImageLayoutEventStage(ImageLayout layout)868 EventStage GetImageLayoutEventStage(ImageLayout layout)
869 {
870 const ImageMemoryBarrierData &barrierData = kImageMemoryBarrierData[layout];
871 return barrierData.eventStage;
872 }
873
HasBothDepthAndStencilAspects(VkImageAspectFlags aspectFlags)874 bool HasBothDepthAndStencilAspects(VkImageAspectFlags aspectFlags)
875 {
876 return IsMaskFlagSet(aspectFlags, kDepthStencilAspects);
877 }
878
GetContentDefinedLayerRangeBits(uint32_t layerStart,uint32_t layerCount,uint32_t maxLayerCount)879 uint8_t GetContentDefinedLayerRangeBits(uint32_t layerStart,
880 uint32_t layerCount,
881 uint32_t maxLayerCount)
882 {
883 uint8_t layerRangeBits = layerCount >= maxLayerCount ? static_cast<uint8_t>(~0u)
884 : angle::BitMask<uint8_t>(layerCount);
885 layerRangeBits <<= layerStart;
886
887 return layerRangeBits;
888 }
889
GetImageLayerCountForView(const ImageHelper & image)890 uint32_t GetImageLayerCountForView(const ImageHelper &image)
891 {
892 // Depth > 1 means this is a 3D texture and depth is our layer count
893 return image.getExtents().depth > 1 ? image.getExtents().depth : image.getLayerCount();
894 }
895
ReleaseImageViews(ImageViewVector * imageViewVector,GarbageObjects * garbage)896 void ReleaseImageViews(ImageViewVector *imageViewVector, GarbageObjects *garbage)
897 {
898 for (ImageView &imageView : *imageViewVector)
899 {
900 if (imageView.valid())
901 {
902 garbage->emplace_back(GetGarbage(&imageView));
903 }
904 }
905 imageViewVector->clear();
906 }
907
DestroyImageViews(ImageViewVector * imageViewVector,VkDevice device)908 void DestroyImageViews(ImageViewVector *imageViewVector, VkDevice device)
909 {
910 for (ImageView &imageView : *imageViewVector)
911 {
912 imageView.destroy(device);
913 }
914 imageViewVector->clear();
915 }
916
ReleaseLayerLevelImageViews(LayerLevelImageViewVector * imageViewVector,GarbageObjects * garbage)917 void ReleaseLayerLevelImageViews(LayerLevelImageViewVector *imageViewVector,
918 GarbageObjects *garbage)
919 {
920 for (ImageViewVector &layerViews : *imageViewVector)
921 {
922 for (ImageView &imageView : layerViews)
923 {
924 if (imageView.valid())
925 {
926 garbage->emplace_back(GetGarbage(&imageView));
927 }
928 }
929 }
930 imageViewVector->clear();
931 }
932
DestroyLayerLevelImageViews(LayerLevelImageViewVector * imageViewVector,VkDevice device)933 void DestroyLayerLevelImageViews(LayerLevelImageViewVector *imageViewVector, VkDevice device)
934 {
935 for (ImageViewVector &layerViews : *imageViewVector)
936 {
937 for (ImageView &imageView : layerViews)
938 {
939 imageView.destroy(device);
940 }
941 }
942 imageViewVector->clear();
943 }
944
ReleaseSubresourceImageViews(SubresourceImageViewMap * imageViews,GarbageObjects * garbage)945 void ReleaseSubresourceImageViews(SubresourceImageViewMap *imageViews, GarbageObjects *garbage)
946 {
947 for (auto &iter : *imageViews)
948 {
949 std::unique_ptr<ImageView> &imageView = iter.second;
950 if (imageView->valid())
951 {
952 garbage->emplace_back(GetGarbage(imageView.get()));
953 }
954 }
955 imageViews->clear();
956 }
957
DestroySubresourceImageViews(SubresourceImageViewMap * imageViews,VkDevice device)958 void DestroySubresourceImageViews(SubresourceImageViewMap *imageViews, VkDevice device)
959 {
960 for (auto &iter : *imageViews)
961 {
962 std::unique_ptr<ImageView> &imageView = iter.second;
963 imageView->destroy(device);
964 }
965 imageViews->clear();
966 }
967
GetLevelImageView(ImageViewVector * imageViews,LevelIndex levelVk,uint32_t levelCount)968 ImageView *GetLevelImageView(ImageViewVector *imageViews, LevelIndex levelVk, uint32_t levelCount)
969 {
970 // Lazily allocate the storage for image views. We allocate the full level count because we
971 // don't want to trigger any std::vector reallocations. Reallocations could invalidate our
972 // view pointers.
973 if (imageViews->empty())
974 {
975 imageViews->resize(levelCount);
976 }
977 ASSERT(imageViews->size() > levelVk.get());
978
979 return &(*imageViews)[levelVk.get()];
980 }
981
GetLevelLayerImageView(LayerLevelImageViewVector * imageViews,LevelIndex levelVk,uint32_t layer,uint32_t levelCount,uint32_t layerCount)982 ImageView *GetLevelLayerImageView(LayerLevelImageViewVector *imageViews,
983 LevelIndex levelVk,
984 uint32_t layer,
985 uint32_t levelCount,
986 uint32_t layerCount)
987 {
988 // Lazily allocate the storage for image views. We allocate the full layer count because we
989 // don't want to trigger any std::vector reallocations. Reallocations could invalidate our
990 // view pointers.
991 if (imageViews->empty())
992 {
993 imageViews->resize(layerCount);
994 }
995 ASSERT(imageViews->size() > layer);
996
997 return GetLevelImageView(&(*imageViews)[layer], levelVk, levelCount);
998 }
999
1000 // Special rules apply to VkBufferImageCopy with depth/stencil. The components are tightly packed
1001 // into a depth or stencil section of the destination buffer. See the spec:
1002 // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VkBufferImageCopy.html
GetDepthStencilImageToBufferFormat(const angle::Format & imageFormat,VkImageAspectFlagBits copyAspect)1003 const angle::Format &GetDepthStencilImageToBufferFormat(const angle::Format &imageFormat,
1004 VkImageAspectFlagBits copyAspect)
1005 {
1006 if (copyAspect == VK_IMAGE_ASPECT_STENCIL_BIT)
1007 {
1008 ASSERT(imageFormat.id == angle::FormatID::D24_UNORM_S8_UINT ||
1009 imageFormat.id == angle::FormatID::D32_FLOAT_S8X24_UINT ||
1010 imageFormat.id == angle::FormatID::S8_UINT);
1011 return angle::Format::Get(angle::FormatID::S8_UINT);
1012 }
1013
1014 ASSERT(copyAspect == VK_IMAGE_ASPECT_DEPTH_BIT);
1015
1016 switch (imageFormat.id)
1017 {
1018 case angle::FormatID::D16_UNORM:
1019 return imageFormat;
1020 case angle::FormatID::D24_UNORM_X8_UINT:
1021 return imageFormat;
1022 case angle::FormatID::D24_UNORM_S8_UINT:
1023 return angle::Format::Get(angle::FormatID::D24_UNORM_X8_UINT);
1024 case angle::FormatID::D32_FLOAT:
1025 return imageFormat;
1026 case angle::FormatID::D32_FLOAT_S8X24_UINT:
1027 return angle::Format::Get(angle::FormatID::D32_FLOAT);
1028 default:
1029 UNREACHABLE();
1030 return imageFormat;
1031 }
1032 }
1033
GetRobustResourceClearValue(const angle::Format & intendedFormat,const angle::Format & actualFormat)1034 VkClearValue GetRobustResourceClearValue(const angle::Format &intendedFormat,
1035 const angle::Format &actualFormat)
1036 {
1037 VkClearValue clearValue = {};
1038 if (intendedFormat.hasDepthOrStencilBits())
1039 {
1040 clearValue.depthStencil = kRobustInitDepthStencilValue;
1041 }
1042 else
1043 {
1044 clearValue.color = HasEmulatedImageChannels(intendedFormat, actualFormat)
1045 ? kEmulatedInitColorValue
1046 : kRobustInitColorValue;
1047 }
1048 return clearValue;
1049 }
1050
IsShaderReadOnlyLayout(const ImageMemoryBarrierData & imageLayout)1051 bool IsShaderReadOnlyLayout(const ImageMemoryBarrierData &imageLayout)
1052 {
1053 // We also use VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL for texture sample from depth
1054 // texture. See GetImageReadLayout() for detail.
1055 return imageLayout.layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ||
1056 imageLayout.layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
1057 }
1058
IsAnySubresourceContentDefined(const gl::TexLevelArray<angle::BitSet8<8>> & contentDefined)1059 bool IsAnySubresourceContentDefined(const gl::TexLevelArray<angle::BitSet8<8>> &contentDefined)
1060 {
1061 for (const angle::BitSet8<8> &levelContentDefined : contentDefined)
1062 {
1063 if (levelContentDefined.any())
1064 {
1065 return true;
1066 }
1067 }
1068 return false;
1069 }
1070
ExtendRenderPassInvalidateArea(const gl::Rectangle & invalidateArea,gl::Rectangle * out)1071 void ExtendRenderPassInvalidateArea(const gl::Rectangle &invalidateArea, gl::Rectangle *out)
1072 {
1073 if (out->empty())
1074 {
1075 *out = invalidateArea;
1076 }
1077 else
1078 {
1079 gl::ExtendRectangle(*out, invalidateArea, out);
1080 }
1081 }
1082
CanCopyWithTransferForCopyImage(Renderer * renderer,ImageHelper * srcImage,ImageHelper * dstImage)1083 bool CanCopyWithTransferForCopyImage(Renderer *renderer,
1084 ImageHelper *srcImage,
1085 ImageHelper *dstImage)
1086 {
1087 // Neither source nor destination formats can be emulated for copy image through transfer,
1088 // unless they are emulated with the same format!
1089 bool isFormatCompatible =
1090 (!srcImage->hasEmulatedImageFormat() && !dstImage->hasEmulatedImageFormat()) ||
1091 srcImage->getActualFormatID() == dstImage->getActualFormatID();
1092
1093 // If neither formats are emulated, GL validation ensures that pixelBytes is the same for both.
1094 ASSERT(!isFormatCompatible ||
1095 srcImage->getActualFormat().pixelBytes == dstImage->getActualFormat().pixelBytes);
1096
1097 return isFormatCompatible &&
1098 CanCopyWithTransfer(renderer, srcImage->getUsage(), dstImage->getActualFormatID(),
1099 dstImage->getTilingMode());
1100 }
1101
ReleaseBufferListToRenderer(Context * context,BufferHelperQueue * buffers)1102 void ReleaseBufferListToRenderer(Context *context, BufferHelperQueue *buffers)
1103 {
1104 for (std::unique_ptr<BufferHelper> &toFree : *buffers)
1105 {
1106 toFree->release(context);
1107 }
1108 buffers->clear();
1109 }
1110
DestroyBufferList(Renderer * renderer,BufferHelperQueue * buffers)1111 void DestroyBufferList(Renderer *renderer, BufferHelperQueue *buffers)
1112 {
1113 for (std::unique_ptr<BufferHelper> &toDestroy : *buffers)
1114 {
1115 toDestroy->destroy(renderer);
1116 }
1117 buffers->clear();
1118 }
1119
1120 // Helper functions used below
GetLoadOpShorthand(RenderPassLoadOp loadOp)1121 char GetLoadOpShorthand(RenderPassLoadOp loadOp)
1122 {
1123 switch (loadOp)
1124 {
1125 case RenderPassLoadOp::Clear:
1126 return 'C';
1127 case RenderPassLoadOp::Load:
1128 return 'L';
1129 case RenderPassLoadOp::None:
1130 return 'N';
1131 default:
1132 return 'D';
1133 }
1134 }
1135
GetStoreOpShorthand(RenderPassStoreOp storeOp)1136 char GetStoreOpShorthand(RenderPassStoreOp storeOp)
1137 {
1138 switch (storeOp)
1139 {
1140 case RenderPassStoreOp::Store:
1141 return 'S';
1142 case RenderPassStoreOp::None:
1143 return 'N';
1144 default:
1145 return 'D';
1146 }
1147 }
1148
IsClear(UpdateSource updateSource)1149 bool IsClear(UpdateSource updateSource)
1150 {
1151 return updateSource == UpdateSource::Clear ||
1152 updateSource == UpdateSource::ClearEmulatedChannelsOnly ||
1153 updateSource == UpdateSource::ClearAfterInvalidate;
1154 }
1155
IsClearOfAllChannels(UpdateSource updateSource)1156 bool IsClearOfAllChannels(UpdateSource updateSource)
1157 {
1158 return updateSource == UpdateSource::Clear ||
1159 updateSource == UpdateSource::ClearAfterInvalidate;
1160 }
1161
InitDynamicDescriptorPool(ErrorContext * context,const DescriptorSetLayoutDesc & descriptorSetLayoutDesc,const DescriptorSetLayout & descriptorSetLayout,uint32_t descriptorCountMultiplier,DynamicDescriptorPool * poolToInit)1162 angle::Result InitDynamicDescriptorPool(ErrorContext *context,
1163 const DescriptorSetLayoutDesc &descriptorSetLayoutDesc,
1164 const DescriptorSetLayout &descriptorSetLayout,
1165 uint32_t descriptorCountMultiplier,
1166 DynamicDescriptorPool *poolToInit)
1167 {
1168 std::vector<VkDescriptorPoolSize> descriptorPoolSizes;
1169 DescriptorSetLayoutBindingVector bindingVector;
1170 descriptorSetLayoutDesc.unpackBindings(&bindingVector);
1171 descriptorPoolSizes.reserve(bindingVector.size());
1172
1173 for (const VkDescriptorSetLayoutBinding &binding : bindingVector)
1174 {
1175 if (binding.descriptorCount > 0)
1176 {
1177 VkDescriptorPoolSize poolSize = {};
1178 poolSize.type = binding.descriptorType;
1179 poolSize.descriptorCount = binding.descriptorCount * descriptorCountMultiplier;
1180 descriptorPoolSizes.emplace_back(poolSize);
1181 }
1182 }
1183
1184 if (!descriptorPoolSizes.empty())
1185 {
1186 ANGLE_TRY(poolToInit->init(context, descriptorPoolSizes.data(), descriptorPoolSizes.size(),
1187 descriptorSetLayout));
1188 }
1189
1190 return angle::Result::Continue;
1191 }
1192
CheckSubpassCommandBufferCount(uint32_t count)1193 bool CheckSubpassCommandBufferCount(uint32_t count)
1194 {
1195 // When using angle::SharedRingBufferAllocator we must ensure that allocator is attached and
1196 // detached from the same priv::SecondaryCommandBuffer instance.
1197 // Custom command buffer (priv::SecondaryCommandBuffer) may contain commands for multiple
1198 // subpasses, therefore we do not need multiple buffers.
1199 return (count == 1 || !RenderPassCommandBuffer::ExecutesInline());
1200 }
1201
IsAnyLayout(VkImageLayout needle,const VkImageLayout * haystack,uint32_t haystackCount)1202 bool IsAnyLayout(VkImageLayout needle, const VkImageLayout *haystack, uint32_t haystackCount)
1203 {
1204 const VkImageLayout *haystackEnd = haystack + haystackCount;
1205 return std::find(haystack, haystackEnd, needle) != haystackEnd;
1206 }
1207
AggregateSkipLevels(const gl::CubeFaceArray<gl::TexLevelMask> & skipLevels)1208 gl::TexLevelMask AggregateSkipLevels(const gl::CubeFaceArray<gl::TexLevelMask> &skipLevels)
1209 {
1210 gl::TexLevelMask skipLevelsAllFaces = skipLevels[0];
1211 for (size_t face = 1; face < gl::kCubeFaceCount; ++face)
1212 {
1213 skipLevelsAllFaces |= skipLevels[face];
1214 }
1215 return skipLevelsAllFaces;
1216 }
1217
1218 // Get layer mask for a particular image level.
GetImageLayerWriteMask(uint32_t layerStart,uint32_t layerCount)1219 ImageLayerWriteMask GetImageLayerWriteMask(uint32_t layerStart, uint32_t layerCount)
1220 {
1221 ImageLayerWriteMask layerMask = angle::BitMask<uint64_t>(layerCount);
1222 uint32_t rotateShift = layerStart % kMaxParallelLayerWrites;
1223 layerMask = (layerMask << rotateShift) | (layerMask >> (kMaxParallelLayerWrites - rotateShift));
1224 return layerMask;
1225 }
1226
MakeImageSubresourceReadRange(gl::LevelIndex level,uint32_t levelCount,uint32_t layer,LayerMode layerMode,ImageViewColorspace readColorspace,ImageViewColorspace writeColorspace)1227 ImageSubresourceRange MakeImageSubresourceReadRange(gl::LevelIndex level,
1228 uint32_t levelCount,
1229 uint32_t layer,
1230 LayerMode layerMode,
1231 ImageViewColorspace readColorspace,
1232 ImageViewColorspace writeColorspace)
1233 {
1234 ImageSubresourceRange range;
1235
1236 SetBitField(range.level, level.get());
1237 SetBitField(range.levelCount, levelCount);
1238 SetBitField(range.layer, layer);
1239 SetBitField(range.layerMode, layerMode);
1240 SetBitField(range.readColorspace, readColorspace == ImageViewColorspace::SRGB ? 1 : 0);
1241 SetBitField(range.writeColorspace, writeColorspace == ImageViewColorspace::SRGB ? 1 : 0);
1242
1243 return range;
1244 }
1245
MakeImageSubresourceDrawRange(gl::LevelIndex level,uint32_t layer,LayerMode layerMode,ImageViewColorspace readColorspace,ImageViewColorspace writeColorspace)1246 ImageSubresourceRange MakeImageSubresourceDrawRange(gl::LevelIndex level,
1247 uint32_t layer,
1248 LayerMode layerMode,
1249 ImageViewColorspace readColorspace,
1250 ImageViewColorspace writeColorspace)
1251 {
1252 ImageSubresourceRange range;
1253
1254 SetBitField(range.level, level.get());
1255 SetBitField(range.levelCount, 1);
1256 SetBitField(range.layer, layer);
1257 SetBitField(range.layerMode, layerMode);
1258 SetBitField(range.readColorspace, readColorspace == ImageViewColorspace::SRGB ? 1 : 0);
1259 SetBitField(range.writeColorspace, writeColorspace == ImageViewColorspace::SRGB ? 1 : 0);
1260
1261 return range;
1262 }
1263
1264 // Obtain VkClearColorValue from input byte data and actual format.
GetVkClearColorValueFromBytes(uint8_t * actualData,const angle::Format & actualFormat,VkClearValue * clearValueOut)1265 void GetVkClearColorValueFromBytes(uint8_t *actualData,
1266 const angle::Format &actualFormat,
1267 VkClearValue *clearValueOut)
1268 {
1269 ASSERT(actualData != nullptr && !actualFormat.hasDepthOrStencilBits());
1270
1271 *clearValueOut = {};
1272 VkClearColorValue colorValue = {{}};
1273 actualFormat.pixelReadFunction(actualData, reinterpret_cast<uint8_t *>(&colorValue));
1274 clearValueOut->color = colorValue;
1275 }
1276
1277 // Obtain VkClearDepthStencilValue from input byte data and intended format.
GetVkClearDepthStencilValueFromBytes(uint8_t * intendedData,const angle::Format & intendedFormat,VkClearValue * clearValueOut)1278 void GetVkClearDepthStencilValueFromBytes(uint8_t *intendedData,
1279 const angle::Format &intendedFormat,
1280 VkClearValue *clearValueOut)
1281 {
1282 ASSERT(intendedData != nullptr && intendedFormat.hasDepthOrStencilBits());
1283
1284 *clearValueOut = {};
1285 uint32_t dsData[4] = {0};
1286 double depthValue = 0;
1287
1288 intendedFormat.pixelReadFunction(intendedData, reinterpret_cast<uint8_t *>(dsData));
1289 memcpy(&depthValue, &dsData[0], sizeof(double));
1290 clearValueOut->depthStencil.depth = static_cast<float>(depthValue);
1291 clearValueOut->depthStencil.stencil = dsData[2];
1292 }
1293
ConvertShaderBitSetToVkPipelineStageFlags(const gl::ShaderBitSet & writeShaderStages)1294 VkPipelineStageFlags ConvertShaderBitSetToVkPipelineStageFlags(
1295 const gl::ShaderBitSet &writeShaderStages)
1296 {
1297 VkPipelineStageFlags pipelineStageFlags = 0;
1298 for (gl::ShaderType shaderType : writeShaderStages)
1299 {
1300 const PipelineStage stage = GetPipelineStage(shaderType);
1301 pipelineStageFlags |= kBufferMemoryBarrierData[stage].pipelineStageFlags;
1302 }
1303 return pipelineStageFlags;
1304 }
1305 } // anonymous namespace
1306
1307 // This is an arbitrary max. We can change this later if necessary.
1308 uint32_t DynamicDescriptorPool::mMaxSetsPerPool = 16;
1309 uint32_t DynamicDescriptorPool::mMaxSetsPerPoolMultiplier = 2;
1310
GetImageLayoutFromGLImageLayout(ErrorContext * context,GLenum layout)1311 ImageLayout GetImageLayoutFromGLImageLayout(ErrorContext *context, GLenum layout)
1312 {
1313 switch (layout)
1314 {
1315 case GL_NONE:
1316 return ImageLayout::Undefined;
1317 case GL_LAYOUT_GENERAL_EXT:
1318 return ImageLayout::ExternalShadersWrite;
1319 case GL_LAYOUT_COLOR_ATTACHMENT_EXT:
1320 return ImageLayout::ColorWrite;
1321 case GL_LAYOUT_DEPTH_STENCIL_ATTACHMENT_EXT:
1322 return ImageLayout::DepthWriteStencilWrite;
1323 case GL_LAYOUT_DEPTH_STENCIL_READ_ONLY_EXT:
1324 return ImageLayout::DepthReadStencilRead;
1325 case GL_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_EXT:
1326 return ImageLayout::DepthReadStencilWrite;
1327 case GL_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_EXT:
1328 return ImageLayout::DepthWriteStencilRead;
1329 case GL_LAYOUT_SHADER_READ_ONLY_EXT:
1330 return ImageLayout::ExternalShadersReadOnly;
1331 case GL_LAYOUT_TRANSFER_SRC_EXT:
1332 return ImageLayout::TransferSrc;
1333 case GL_LAYOUT_TRANSFER_DST_EXT:
1334 return ImageLayout::TransferDst;
1335 default:
1336 UNREACHABLE();
1337 return vk::ImageLayout::Undefined;
1338 }
1339 }
1340
ConvertImageLayoutToGLImageLayout(ImageLayout layout)1341 GLenum ConvertImageLayoutToGLImageLayout(ImageLayout layout)
1342 {
1343 switch (kImageMemoryBarrierData[layout].layout)
1344 {
1345 case VK_IMAGE_LAYOUT_UNDEFINED:
1346 return GL_NONE;
1347 case VK_IMAGE_LAYOUT_GENERAL:
1348 return GL_LAYOUT_GENERAL_EXT;
1349 case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
1350 return GL_LAYOUT_COLOR_ATTACHMENT_EXT;
1351 case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
1352 return GL_LAYOUT_DEPTH_STENCIL_ATTACHMENT_EXT;
1353 case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
1354 return GL_LAYOUT_DEPTH_STENCIL_READ_ONLY_EXT;
1355 case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
1356 return GL_LAYOUT_SHADER_READ_ONLY_EXT;
1357 case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
1358 return GL_LAYOUT_TRANSFER_SRC_EXT;
1359 case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
1360 return GL_LAYOUT_TRANSFER_DST_EXT;
1361 case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL:
1362 return GL_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_EXT;
1363 case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL:
1364 return GL_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_EXT;
1365 default:
1366 break;
1367 }
1368 UNREACHABLE();
1369 return GL_NONE;
1370 }
1371
ConvertImageLayoutToVkImageLayout(ImageLayout imageLayout)1372 VkImageLayout ConvertImageLayoutToVkImageLayout(ImageLayout imageLayout)
1373 {
1374 return kImageMemoryBarrierData[imageLayout].layout;
1375 }
1376
GetPipelineStageGroupFromStageFlags(VkPipelineStageFlags dstStageMask)1377 PipelineStageGroup GetPipelineStageGroupFromStageFlags(VkPipelineStageFlags dstStageMask)
1378 {
1379 if ((dstStageMask & ~kFragmentAndAttachmentPipelineStageFlags) == 0)
1380 {
1381 return PipelineStageGroup::FragmentOnly;
1382 }
1383 else if (dstStageMask == VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT)
1384 {
1385 return PipelineStageGroup::ComputeOnly;
1386 }
1387 else if ((dstStageMask & ~kPreFragmentStageFlags) == 0)
1388 {
1389 return PipelineStageGroup::PreFragmentOnly;
1390 }
1391 return PipelineStageGroup::Other;
1392 }
1393
InitializeImageLayoutAndMemoryBarrierDataMap(ImageLayoutToMemoryBarrierDataMap * map,VkPipelineStageFlags supportedVulkanPipelineStageMask)1394 void InitializeImageLayoutAndMemoryBarrierDataMap(
1395 ImageLayoutToMemoryBarrierDataMap *map,
1396 VkPipelineStageFlags supportedVulkanPipelineStageMask)
1397 {
1398 *map = kImageMemoryBarrierData;
1399 for (ImageMemoryBarrierData &barrierData : *map)
1400 {
1401 barrierData.srcStageMask &= supportedVulkanPipelineStageMask;
1402 barrierData.dstStageMask &= supportedVulkanPipelineStageMask;
1403 ASSERT(barrierData.pipelineStageGroup ==
1404 GetPipelineStageGroupFromStageFlags(barrierData.dstStageMask));
1405 }
1406 }
1407
FormatHasNecessaryFeature(Renderer * renderer,angle::FormatID formatID,VkImageTiling tilingMode,VkFormatFeatureFlags featureBits)1408 bool FormatHasNecessaryFeature(Renderer *renderer,
1409 angle::FormatID formatID,
1410 VkImageTiling tilingMode,
1411 VkFormatFeatureFlags featureBits)
1412 {
1413 return (tilingMode == VK_IMAGE_TILING_OPTIMAL)
1414 ? renderer->hasImageFormatFeatureBits(formatID, featureBits)
1415 : renderer->hasLinearImageFormatFeatureBits(formatID, featureBits);
1416 }
1417
CanCopyWithTransfer(Renderer * renderer,VkImageUsageFlags srcUsage,angle::FormatID dstFormatID,VkImageTiling dstTilingMode)1418 bool CanCopyWithTransfer(Renderer *renderer,
1419 VkImageUsageFlags srcUsage,
1420 angle::FormatID dstFormatID,
1421 VkImageTiling dstTilingMode)
1422 {
1423 // Checks that the formats in the copy transfer have the appropriate transfer bits
1424 bool srcFormatHasNecessaryFeature = (srcUsage & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) != 0;
1425 bool dstFormatHasNecessaryFeature = FormatHasNecessaryFeature(
1426 renderer, dstFormatID, dstTilingMode, VK_FORMAT_FEATURE_TRANSFER_DST_BIT);
1427
1428 return srcFormatHasNecessaryFeature && dstFormatHasNecessaryFeature;
1429 }
1430
InitializeEventStageToVkPipelineStageFlagsMap(EventStageToVkPipelineStageFlagsMap * map,VkPipelineStageFlags supportedVulkanPipelineStageMask)1431 void InitializeEventStageToVkPipelineStageFlagsMap(
1432 EventStageToVkPipelineStageFlagsMap *map,
1433 VkPipelineStageFlags supportedVulkanPipelineStageMask)
1434 {
1435 map->fill(0);
1436
1437 for (const BufferMemoryBarrierData &bufferBarrierData : kBufferMemoryBarrierData)
1438 {
1439 const EventStage eventStage = bufferBarrierData.eventStage;
1440 if (eventStage != EventStage::InvalidEnum)
1441 {
1442 (*map)[eventStage] |=
1443 bufferBarrierData.pipelineStageFlags & supportedVulkanPipelineStageMask;
1444 }
1445 }
1446
1447 for (const ImageMemoryBarrierData &imageBarrierData : kImageMemoryBarrierData)
1448 {
1449 const EventStage eventStage = imageBarrierData.eventStage;
1450 if (eventStage != EventStage::InvalidEnum)
1451 {
1452 (*map)[eventStage] |= imageBarrierData.dstStageMask & supportedVulkanPipelineStageMask;
1453 }
1454 }
1455 }
1456
1457 // Context implementation
Context(Renderer * renderer)1458 Context::Context(Renderer *renderer)
1459 : ErrorContext(renderer), mShareGroupRefCountedEventsGarbageRecycler(nullptr)
1460 {}
1461
~Context()1462 Context::~Context()
1463 {
1464 ASSERT(mForeignImagesInUse.empty());
1465 }
1466
onForeignImageUse(ImageHelper * image)1467 void Context::onForeignImageUse(ImageHelper *image)
1468 {
1469 // The image might be used multiple times in the same frame, |mForeignImagesInUse| is a "set"
1470 // so the image is tracked only once.
1471 mForeignImagesInUse.insert(image);
1472 }
1473
finalizeForeignImage(ImageHelper * image)1474 void Context::finalizeForeignImage(ImageHelper *image)
1475 {
1476 // The image must have been marked as in use, otherwise finalize is called while the initial use
1477 // was missed.
1478 ASSERT(mForeignImagesInUse.find(image) != mForeignImagesInUse.end());
1479 // The image must not already be finalized.
1480 ASSERT(
1481 std::find_if(mImagesToTransitionToForeign.begin(), mImagesToTransitionToForeign.end(),
1482 [image = image->getImage().getHandle()](const VkImageMemoryBarrier &barrier) {
1483 return barrier.image == image;
1484 }) == mImagesToTransitionToForeign.end());
1485
1486 mImagesToTransitionToForeign.push_back(image->releaseToForeign(mRenderer));
1487 mForeignImagesInUse.erase(image);
1488 }
1489
finalizeAllForeignImages()1490 void Context::finalizeAllForeignImages()
1491 {
1492 mImagesToTransitionToForeign.reserve(mImagesToTransitionToForeign.size() +
1493 mForeignImagesInUse.size());
1494 while (!mForeignImagesInUse.empty())
1495 {
1496 finalizeForeignImage(*mForeignImagesInUse.begin());
1497 }
1498 }
1499
1500 // PackedClearValuesArray implementation
PackedClearValuesArray()1501 PackedClearValuesArray::PackedClearValuesArray() : mValues{} {}
1502 PackedClearValuesArray::~PackedClearValuesArray() = default;
1503
1504 PackedClearValuesArray::PackedClearValuesArray(const PackedClearValuesArray &other) = default;
1505 PackedClearValuesArray &PackedClearValuesArray::operator=(const PackedClearValuesArray &rhs) =
1506 default;
1507
storeColor(PackedAttachmentIndex index,const VkClearValue & clearValue)1508 void PackedClearValuesArray::storeColor(PackedAttachmentIndex index, const VkClearValue &clearValue)
1509 {
1510 mValues[index.get()] = clearValue;
1511 }
1512
storeDepthStencil(PackedAttachmentIndex index,const VkClearValue & clearValue)1513 void PackedClearValuesArray::storeDepthStencil(PackedAttachmentIndex index,
1514 const VkClearValue &clearValue)
1515 {
1516 mValues[index.get()] = clearValue;
1517 }
1518
1519 // RenderPassAttachment implementation
RenderPassAttachment()1520 RenderPassAttachment::RenderPassAttachment()
1521 {
1522 reset();
1523 }
1524
init(ImageHelper * image,UniqueSerial imageSiblingSerial,gl::LevelIndex levelIndex,uint32_t layerIndex,uint32_t layerCount,VkImageAspectFlagBits aspect)1525 void RenderPassAttachment::init(ImageHelper *image,
1526 UniqueSerial imageSiblingSerial,
1527 gl::LevelIndex levelIndex,
1528 uint32_t layerIndex,
1529 uint32_t layerCount,
1530 VkImageAspectFlagBits aspect)
1531 {
1532 ASSERT(mImage == nullptr);
1533
1534 mImage = image;
1535 mImageSiblingSerial = imageSiblingSerial;
1536 mLevelIndex = levelIndex;
1537 mLayerIndex = layerIndex;
1538 mLayerCount = layerCount;
1539 mAspect = aspect;
1540
1541 mImage->setRenderPassUsageFlag(RenderPassUsage::RenderTargetAttachment);
1542 }
1543
reset()1544 void RenderPassAttachment::reset()
1545 {
1546 mImage = nullptr;
1547
1548 mAccess = ResourceAccess::Unused;
1549
1550 mInvalidatedCmdCount = kInfiniteCmdCount;
1551 mDisabledCmdCount = kInfiniteCmdCount;
1552 mInvalidateArea = gl::Rectangle();
1553 }
1554
onAccess(ResourceAccess access,uint32_t currentCmdCount)1555 void RenderPassAttachment::onAccess(ResourceAccess access, uint32_t currentCmdCount)
1556 {
1557 // Update the access for optimizing this render pass's loadOp
1558 UpdateAccess(&mAccess, access);
1559
1560 // Update the invalidate state for optimizing this render pass's storeOp
1561 if (onAccessImpl(access, currentCmdCount))
1562 {
1563 // The attachment is no longer invalid, so restore its content.
1564 restoreContent();
1565 }
1566 }
1567
invalidate(const gl::Rectangle & invalidateArea,bool isAttachmentEnabled,uint32_t currentCmdCount)1568 void RenderPassAttachment::invalidate(const gl::Rectangle &invalidateArea,
1569 bool isAttachmentEnabled,
1570 uint32_t currentCmdCount)
1571 {
1572 // Keep track of the command count in the render pass at the time of invalidation. If there are
1573 // more commands in the future, invalidate must be undone.
1574 mInvalidatedCmdCount = currentCmdCount;
1575
1576 // Also track the command count if the attachment is currently disabled.
1577 mDisabledCmdCount = isAttachmentEnabled ? kInfiniteCmdCount : currentCmdCount;
1578
1579 // Set/extend the invalidate area.
1580 ExtendRenderPassInvalidateArea(invalidateArea, &mInvalidateArea);
1581 }
1582
onRenderAreaGrowth(ContextVk * contextVk,const gl::Rectangle & newRenderArea)1583 void RenderPassAttachment::onRenderAreaGrowth(ContextVk *contextVk,
1584 const gl::Rectangle &newRenderArea)
1585 {
1586 // Remove invalidate if it's no longer applicable.
1587 if (mInvalidateArea.empty() || mInvalidateArea.encloses(newRenderArea))
1588 {
1589 return;
1590 }
1591
1592 ANGLE_VK_PERF_WARNING(contextVk, GL_DEBUG_SEVERITY_LOW,
1593 "InvalidateSubFramebuffer discarded due to increased scissor region");
1594
1595 mInvalidateArea = gl::Rectangle();
1596 mInvalidatedCmdCount = kInfiniteCmdCount;
1597 }
1598
finalizeLoadStore(ErrorContext * context,uint32_t currentCmdCount,bool hasUnresolveAttachment,bool hasResolveAttachment,RenderPassLoadOp * loadOp,RenderPassStoreOp * storeOp,bool * isInvalidatedOut)1599 void RenderPassAttachment::finalizeLoadStore(ErrorContext *context,
1600 uint32_t currentCmdCount,
1601 bool hasUnresolveAttachment,
1602 bool hasResolveAttachment,
1603 RenderPassLoadOp *loadOp,
1604 RenderPassStoreOp *storeOp,
1605 bool *isInvalidatedOut)
1606 {
1607 if (mAspect != VK_IMAGE_ASPECT_COLOR_BIT)
1608 {
1609 const RenderPassUsage readOnlyAttachmentUsage =
1610 mAspect == VK_IMAGE_ASPECT_STENCIL_BIT ? RenderPassUsage::StencilReadOnlyAttachment
1611 : RenderPassUsage::DepthReadOnlyAttachment;
1612 // Ensure we don't write to a read-only attachment. (ReadOnly -> !Write)
1613 ASSERT(!mImage->hasRenderPassUsageFlag(readOnlyAttachmentUsage) ||
1614 !HasResourceWriteAccess(mAccess));
1615 }
1616
1617 // If the attachment is invalidated, skip the store op. If we are not loading or clearing the
1618 // attachment and the attachment has not been used, auto-invalidate it.
1619 const bool notLoaded = *loadOp == RenderPassLoadOp::DontCare && !hasUnresolveAttachment;
1620 if (isInvalidated(currentCmdCount) || (notLoaded && !HasResourceWriteAccess(mAccess)))
1621 {
1622 *storeOp = RenderPassStoreOp::DontCare;
1623 *isInvalidatedOut = true;
1624 }
1625 else if (hasWriteAfterInvalidate(currentCmdCount))
1626 {
1627 // The attachment was invalidated, but is now valid. Let the image know the contents are
1628 // now defined so a future render pass would use loadOp=LOAD.
1629 restoreContent();
1630 }
1631
1632 // For read only depth stencil, we can use StoreOpNone if available. DontCare is still
1633 // preferred, so do this after handling DontCare.
1634 const bool supportsLoadStoreOpNone =
1635 context->getFeatures().supportsRenderPassLoadStoreOpNone.enabled;
1636 const bool supportsStoreOpNone =
1637 supportsLoadStoreOpNone || context->getFeatures().supportsRenderPassStoreOpNone.enabled;
1638 if (mAccess == ResourceAccess::ReadOnly && supportsStoreOpNone)
1639 {
1640 if (*storeOp == RenderPassStoreOp::Store && *loadOp != RenderPassLoadOp::Clear)
1641 {
1642 *storeOp = RenderPassStoreOp::None;
1643 }
1644 }
1645
1646 if (mAccess == ResourceAccess::Unused)
1647 {
1648 if (*storeOp != RenderPassStoreOp::DontCare)
1649 {
1650 switch (*loadOp)
1651 {
1652 case RenderPassLoadOp::Clear:
1653 // Cannot optimize away the ops if the attachment is cleared (even if not used
1654 // afterwards)
1655 break;
1656 case RenderPassLoadOp::Load:
1657 // Make sure the attachment is neither loaded nor stored (as it's neither used
1658 // nor invalidated), if possible.
1659 if (supportsLoadStoreOpNone)
1660 {
1661 *loadOp = RenderPassLoadOp::None;
1662 }
1663 if (supportsStoreOpNone)
1664 {
1665 *storeOp = RenderPassStoreOp::None;
1666 }
1667 break;
1668 case RenderPassLoadOp::DontCare:
1669 // loadOp=DontCare should be covered by storeOp=DontCare below.
1670 break;
1671 case RenderPassLoadOp::None:
1672 default:
1673 // loadOp=None is never decided upfront.
1674 UNREACHABLE();
1675 break;
1676 }
1677 }
1678 }
1679
1680 if (mAccess == ResourceAccess::Unused || (mAccess == ResourceAccess::ReadOnly && notLoaded))
1681 {
1682 // If we are loading or clearing the attachment, but the attachment has not been used,
1683 // and the data has also not been stored back into attachment, then just skip the
1684 // load/clear op. If loadOp/storeOp=None is supported, prefer that to reduce the amount
1685 // of synchronization; DontCare is a write operation, while None is not.
1686 //
1687 // Don't optimize away a Load or Clear if there is a resolve attachment. Although the
1688 // storeOp=DontCare the image content needs to be resolved into the resolve attachment.
1689 const bool attachmentNeedsToBeResolved =
1690 hasResolveAttachment &&
1691 (*loadOp == RenderPassLoadOp::Load || *loadOp == RenderPassLoadOp::Clear);
1692 if (*storeOp == RenderPassStoreOp::DontCare && !attachmentNeedsToBeResolved)
1693 {
1694 if (supportsLoadStoreOpNone && !isInvalidated(currentCmdCount))
1695 {
1696 *loadOp = RenderPassLoadOp::None;
1697 *storeOp = RenderPassStoreOp::None;
1698 }
1699 else
1700 {
1701 *loadOp = RenderPassLoadOp::DontCare;
1702 }
1703 }
1704 }
1705 }
1706
restoreContent()1707 void RenderPassAttachment::restoreContent()
1708 {
1709 // Note that the image may have been deleted since the render pass has started.
1710 if (mImage)
1711 {
1712 ASSERT(mImage->valid());
1713 if (mAspect == VK_IMAGE_ASPECT_STENCIL_BIT)
1714 {
1715 mImage->restoreSubresourceStencilContent(mLevelIndex, mLayerIndex, mLayerCount);
1716 }
1717 else
1718 {
1719 mImage->restoreSubresourceContent(mLevelIndex, mLayerIndex, mLayerCount);
1720 }
1721 mInvalidateArea = gl::Rectangle();
1722 }
1723 }
1724
hasWriteAfterInvalidate(uint32_t currentCmdCount) const1725 bool RenderPassAttachment::hasWriteAfterInvalidate(uint32_t currentCmdCount) const
1726 {
1727 return (mInvalidatedCmdCount != kInfiniteCmdCount &&
1728 std::min(mDisabledCmdCount, currentCmdCount) != mInvalidatedCmdCount);
1729 }
1730
isInvalidated(uint32_t currentCmdCount) const1731 bool RenderPassAttachment::isInvalidated(uint32_t currentCmdCount) const
1732 {
1733 return mInvalidatedCmdCount != kInfiniteCmdCount &&
1734 std::min(mDisabledCmdCount, currentCmdCount) == mInvalidatedCmdCount;
1735 }
1736
onAccessImpl(ResourceAccess access,uint32_t currentCmdCount)1737 bool RenderPassAttachment::onAccessImpl(ResourceAccess access, uint32_t currentCmdCount)
1738 {
1739 if (mInvalidatedCmdCount == kInfiniteCmdCount)
1740 {
1741 // If never invalidated or no longer invalidated, return early.
1742 return false;
1743 }
1744 if (HasResourceWriteAccess(access))
1745 {
1746 // Drawing to this attachment is being enabled. Assume that drawing will immediately occur
1747 // after this attachment is enabled, and that means that the attachment will no longer be
1748 // invalidated.
1749 mInvalidatedCmdCount = kInfiniteCmdCount;
1750 mDisabledCmdCount = kInfiniteCmdCount;
1751 // Return true to indicate that the store op should remain STORE and that mContentDefined
1752 // should be set to true;
1753 return true;
1754 }
1755 // Drawing to this attachment is being disabled.
1756 if (hasWriteAfterInvalidate(currentCmdCount))
1757 {
1758 // The attachment was previously drawn while enabled, and so is no longer invalidated.
1759 mInvalidatedCmdCount = kInfiniteCmdCount;
1760 mDisabledCmdCount = kInfiniteCmdCount;
1761 // Return true to indicate that the store op should remain STORE and that mContentDefined
1762 // should be set to true;
1763 return true;
1764 }
1765
1766 // Use the latest CmdCount at the start of being disabled. At the end of the render pass,
1767 // cmdCountDisabled is <= the actual command count, and so it's compared with
1768 // cmdCountInvalidated. If the same, the attachment is still invalidated.
1769 mDisabledCmdCount = currentCmdCount;
1770 return false;
1771 }
1772
1773 // CommandBufferHelperCommon implementation.
CommandBufferHelperCommon()1774 CommandBufferHelperCommon::CommandBufferHelperCommon()
1775 : mCommandPool(nullptr), mHasShaderStorageOutput(false), mHasGLMemoryBarrierIssued(false)
1776 {}
1777
~CommandBufferHelperCommon()1778 CommandBufferHelperCommon::~CommandBufferHelperCommon() {}
1779
initializeImpl()1780 void CommandBufferHelperCommon::initializeImpl()
1781 {
1782 mCommandAllocator.init();
1783 }
1784
resetImpl(ErrorContext * context)1785 void CommandBufferHelperCommon::resetImpl(ErrorContext *context)
1786 {
1787 ASSERT(!mAcquireNextImageSemaphore.valid());
1788 mCommandAllocator.resetAllocator();
1789 ASSERT(!mIsAnyHostVisibleBufferWritten);
1790
1791 ASSERT(mRefCountedEvents.empty());
1792 ASSERT(mRefCountedEventCollector.empty());
1793 }
1794
1795 template <class DerivedT>
attachCommandPoolImpl(ErrorContext * context,SecondaryCommandPool * commandPool)1796 angle::Result CommandBufferHelperCommon::attachCommandPoolImpl(ErrorContext *context,
1797 SecondaryCommandPool *commandPool)
1798 {
1799 if constexpr (!DerivedT::ExecutesInline())
1800 {
1801 DerivedT *derived = static_cast<DerivedT *>(this);
1802 ASSERT(commandPool != nullptr);
1803 ASSERT(mCommandPool == nullptr);
1804 ASSERT(!derived->getCommandBuffer().valid());
1805
1806 mCommandPool = commandPool;
1807
1808 ANGLE_TRY(derived->initializeCommandBuffer(context));
1809 }
1810 return angle::Result::Continue;
1811 }
1812
1813 template <class DerivedT, bool kIsRenderPassBuffer>
detachCommandPoolImpl(ErrorContext * context,SecondaryCommandPool ** commandPoolOut)1814 angle::Result CommandBufferHelperCommon::detachCommandPoolImpl(
1815 ErrorContext *context,
1816 SecondaryCommandPool **commandPoolOut)
1817 {
1818 if constexpr (!DerivedT::ExecutesInline())
1819 {
1820 DerivedT *derived = static_cast<DerivedT *>(this);
1821 ASSERT(mCommandPool != nullptr);
1822 ASSERT(derived->getCommandBuffer().valid());
1823
1824 if constexpr (!kIsRenderPassBuffer)
1825 {
1826 ASSERT(!derived->getCommandBuffer().empty());
1827 ANGLE_TRY(derived->endCommandBuffer(context));
1828 }
1829
1830 *commandPoolOut = mCommandPool;
1831 mCommandPool = nullptr;
1832 }
1833 ASSERT(mCommandPool == nullptr);
1834 return angle::Result::Continue;
1835 }
1836
1837 template <class DerivedT>
releaseCommandPoolImpl()1838 void CommandBufferHelperCommon::releaseCommandPoolImpl()
1839 {
1840 if constexpr (!DerivedT::ExecutesInline())
1841 {
1842 DerivedT *derived = static_cast<DerivedT *>(this);
1843 ASSERT(mCommandPool != nullptr);
1844
1845 if (derived->getCommandBuffer().valid())
1846 {
1847 ASSERT(derived->getCommandBuffer().empty());
1848 mCommandPool->collect(&derived->getCommandBuffer());
1849 }
1850
1851 mCommandPool = nullptr;
1852 }
1853 ASSERT(mCommandPool == nullptr);
1854 }
1855
1856 template <class DerivedT>
attachAllocatorImpl(SecondaryCommandMemoryAllocator * allocator)1857 void CommandBufferHelperCommon::attachAllocatorImpl(SecondaryCommandMemoryAllocator *allocator)
1858 {
1859 if constexpr (DerivedT::ExecutesInline())
1860 {
1861 auto &commandBuffer = static_cast<DerivedT *>(this)->getCommandBuffer();
1862 mCommandAllocator.attachAllocator(allocator);
1863 commandBuffer.attachAllocator(mCommandAllocator.getAllocator());
1864 }
1865 }
1866
1867 template <class DerivedT>
detachAllocatorImpl()1868 SecondaryCommandMemoryAllocator *CommandBufferHelperCommon::detachAllocatorImpl()
1869 {
1870 SecondaryCommandMemoryAllocator *result = nullptr;
1871 if constexpr (DerivedT::ExecutesInline())
1872 {
1873 auto &commandBuffer = static_cast<DerivedT *>(this)->getCommandBuffer();
1874 commandBuffer.detachAllocator(mCommandAllocator.getAllocator());
1875 result = mCommandAllocator.detachAllocator(commandBuffer.empty());
1876 }
1877 return result;
1878 }
1879
1880 template <class DerivedT>
assertCanBeRecycledImpl()1881 void CommandBufferHelperCommon::assertCanBeRecycledImpl()
1882 {
1883 DerivedT *derived = static_cast<DerivedT *>(this);
1884 ASSERT(mCommandPool == nullptr);
1885 ASSERT(!mCommandAllocator.hasAllocatorLinks());
1886 // Vulkan secondary command buffers must be invalid (collected).
1887 ASSERT(DerivedT::ExecutesInline() || !derived->getCommandBuffer().valid());
1888 // ANGLEs Custom secondary command buffers must be empty (reset).
1889 ASSERT(!DerivedT::ExecutesInline() || derived->getCommandBuffer().empty());
1890 }
1891
bufferWrite(Context * context,VkAccessFlags writeAccessType,PipelineStage writeStage,BufferHelper * buffer)1892 void CommandBufferHelperCommon::bufferWrite(Context *context,
1893 VkAccessFlags writeAccessType,
1894 PipelineStage writeStage,
1895 BufferHelper *buffer)
1896 {
1897 VkPipelineStageFlags writePipelineStageFlags =
1898 kBufferMemoryBarrierData[writeStage].pipelineStageFlags;
1899 bufferWriteImpl(context, writeAccessType, writePipelineStageFlags, writeStage, buffer);
1900 }
1901
bufferWrite(Context * context,VkAccessFlags writeAccessType,const gl::ShaderBitSet & writeShaderStages,BufferHelper * buffer)1902 void CommandBufferHelperCommon::bufferWrite(Context *context,
1903 VkAccessFlags writeAccessType,
1904 const gl::ShaderBitSet &writeShaderStages,
1905 BufferHelper *buffer)
1906 {
1907 VkPipelineStageFlags writePipelineStageFlags =
1908 ConvertShaderBitSetToVkPipelineStageFlags(writeShaderStages);
1909 PipelineStage firstWriteStage = GetPipelineStage(writeShaderStages.first());
1910 bufferWriteImpl(context, writeAccessType, writePipelineStageFlags, firstWriteStage, buffer);
1911 }
1912
bufferRead(Context * context,VkAccessFlags readAccessType,PipelineStage readStage,BufferHelper * buffer)1913 void CommandBufferHelperCommon::bufferRead(Context *context,
1914 VkAccessFlags readAccessType,
1915 PipelineStage readStage,
1916 BufferHelper *buffer)
1917 {
1918 VkPipelineStageFlags readPipelineStageFlags =
1919 kBufferMemoryBarrierData[readStage].pipelineStageFlags;
1920 bufferReadImpl(context, readAccessType, readPipelineStageFlags, readStage, buffer);
1921 }
1922
bufferRead(Context * context,VkAccessFlags readAccessType,const gl::ShaderBitSet & readShaderStages,BufferHelper * buffer)1923 void CommandBufferHelperCommon::bufferRead(Context *context,
1924 VkAccessFlags readAccessType,
1925 const gl::ShaderBitSet &readShaderStages,
1926 BufferHelper *buffer)
1927 {
1928 for (const gl::ShaderType shaderType : readShaderStages)
1929 {
1930 PipelineStage readStage = GetPipelineStage(shaderType);
1931 VkPipelineStageFlags readPipelineStageFlags =
1932 kBufferMemoryBarrierData[readStage].pipelineStageFlags;
1933 bufferReadImpl(context, readAccessType, readPipelineStageFlags, readStage, buffer);
1934 }
1935 }
1936
bufferWriteImpl(Context * context,VkAccessFlags writeAccessType,VkPipelineStageFlags writePipelineStageFlags,PipelineStage writeStage,BufferHelper * buffer)1937 void CommandBufferHelperCommon::bufferWriteImpl(Context *context,
1938 VkAccessFlags writeAccessType,
1939 VkPipelineStageFlags writePipelineStageFlags,
1940 PipelineStage writeStage,
1941 BufferHelper *buffer)
1942 {
1943 buffer->recordWriteBarrier(context, writeAccessType, writePipelineStageFlags, writeStage,
1944 mQueueSerial, &mPipelineBarriers, &mEventBarriers,
1945 &mRefCountedEventCollector);
1946
1947 // Make sure host-visible buffer writes result in a barrier inserted at the end of the frame to
1948 // make the results visible to the host. The buffer may be mapped by the application in the
1949 // future.
1950 if (buffer->isHostVisible())
1951 {
1952 mIsAnyHostVisibleBufferWritten = true;
1953 }
1954
1955 buffer->recordWriteEvent(context, writeAccessType, writePipelineStageFlags, mQueueSerial,
1956 writeStage, &mRefCountedEvents);
1957 }
1958
bufferReadImpl(Context * context,VkAccessFlags readAccessType,VkPipelineStageFlags readPipelineStageFlags,PipelineStage readStage,BufferHelper * buffer)1959 void CommandBufferHelperCommon::bufferReadImpl(Context *context,
1960 VkAccessFlags readAccessType,
1961 VkPipelineStageFlags readPipelineStageFlags,
1962 PipelineStage readStage,
1963 BufferHelper *buffer)
1964 {
1965 buffer->recordReadBarrier(context, readAccessType, readPipelineStageFlags, readStage,
1966 &mPipelineBarriers, &mEventBarriers, &mRefCountedEventCollector);
1967 ASSERT(!usesBufferForWrite(*buffer));
1968
1969 buffer->recordReadEvent(context, readAccessType, readPipelineStageFlags, readStage,
1970 mQueueSerial, kBufferMemoryBarrierData[readStage].eventStage,
1971 &mRefCountedEvents);
1972 }
1973
imageReadImpl(Context * context,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,BarrierType barrierType,ImageHelper * image)1974 void CommandBufferHelperCommon::imageReadImpl(Context *context,
1975 VkImageAspectFlags aspectFlags,
1976 ImageLayout imageLayout,
1977 BarrierType barrierType,
1978 ImageHelper *image)
1979 {
1980 if (image->isReadBarrierNecessary(context->getRenderer(), imageLayout))
1981 {
1982 updateImageLayoutAndBarrier(context, image, aspectFlags, imageLayout, barrierType);
1983 }
1984 }
1985
imageWriteImpl(Context * context,gl::LevelIndex level,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,BarrierType barrierType,ImageHelper * image)1986 void CommandBufferHelperCommon::imageWriteImpl(Context *context,
1987 gl::LevelIndex level,
1988 uint32_t layerStart,
1989 uint32_t layerCount,
1990 VkImageAspectFlags aspectFlags,
1991 ImageLayout imageLayout,
1992 BarrierType barrierType,
1993 ImageHelper *image)
1994 {
1995 image->onWrite(level, 1, layerStart, layerCount, aspectFlags);
1996 if (image->isWriteBarrierNecessary(imageLayout, level, 1, layerStart, layerCount))
1997 {
1998 updateImageLayoutAndBarrier(context, image, aspectFlags, imageLayout, barrierType);
1999 }
2000 }
2001
updateImageLayoutAndBarrier(Context * context,ImageHelper * image,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,BarrierType barrierType)2002 void CommandBufferHelperCommon::updateImageLayoutAndBarrier(Context *context,
2003 ImageHelper *image,
2004 VkImageAspectFlags aspectFlags,
2005 ImageLayout imageLayout,
2006 BarrierType barrierType)
2007 {
2008 VkSemaphore semaphore = VK_NULL_HANDLE;
2009 image->updateLayoutAndBarrier(context, aspectFlags, imageLayout, barrierType, mQueueSerial,
2010 &mPipelineBarriers, &mEventBarriers, &mRefCountedEventCollector,
2011 &semaphore);
2012 // If image has an ANI semaphore, move it to command buffer so that we can wait for it in
2013 // next submission.
2014 if (semaphore != VK_NULL_HANDLE)
2015 {
2016 ASSERT(!mAcquireNextImageSemaphore.valid());
2017 mAcquireNextImageSemaphore.setHandle(semaphore);
2018 }
2019 }
2020
retainImageWithEvent(Context * context,ImageHelper * image)2021 void CommandBufferHelperCommon::retainImageWithEvent(Context *context, ImageHelper *image)
2022 {
2023 image->setQueueSerial(mQueueSerial);
2024 image->updatePipelineStageAccessHistory();
2025
2026 if (context->getFeatures().useVkEventForImageBarrier.enabled)
2027 {
2028 image->setCurrentRefCountedEvent(context, &mRefCountedEvents);
2029 }
2030 }
2031
2032 template <typename CommandBufferT>
flushSetEventsImpl(Context * context,CommandBufferT * commandBuffer)2033 void CommandBufferHelperCommon::flushSetEventsImpl(Context *context, CommandBufferT *commandBuffer)
2034 {
2035 if (mRefCountedEvents.empty())
2036 {
2037 return;
2038 }
2039
2040 // Add VkCmdSetEvent here to track the completion of this renderPass.
2041 mRefCountedEvents.flushSetEvents(context->getRenderer(), commandBuffer);
2042 // We no longer need event, so garbage collect it.
2043 mRefCountedEvents.releaseToEventCollector(&mRefCountedEventCollector);
2044 }
2045
2046 template void CommandBufferHelperCommon::flushSetEventsImpl<priv::SecondaryCommandBuffer>(
2047 Context *context,
2048 priv::SecondaryCommandBuffer *commandBuffer);
2049 template void CommandBufferHelperCommon::flushSetEventsImpl<VulkanSecondaryCommandBuffer>(
2050 Context *context,
2051 VulkanSecondaryCommandBuffer *commandBuffer);
2052
executeBarriers(Renderer * renderer,CommandsState * commandsState)2053 void CommandBufferHelperCommon::executeBarriers(Renderer *renderer, CommandsState *commandsState)
2054 {
2055 // Add ANI semaphore to the command submission.
2056 if (mAcquireNextImageSemaphore.valid())
2057 {
2058 commandsState->waitSemaphores.emplace_back(mAcquireNextImageSemaphore.release());
2059 commandsState->waitSemaphoreStageMasks.emplace_back(kSwapchainAcquireImageWaitStageFlags);
2060 }
2061
2062 mPipelineBarriers.execute(renderer, &commandsState->primaryCommands);
2063 mEventBarriers.execute(renderer, &commandsState->primaryCommands);
2064 }
2065
addCommandDiagnosticsCommon(std::ostringstream * out)2066 void CommandBufferHelperCommon::addCommandDiagnosticsCommon(std::ostringstream *out)
2067 {
2068 mPipelineBarriers.addDiagnosticsString(*out);
2069 mEventBarriers.addDiagnosticsString(*out);
2070 }
2071
2072 // OutsideRenderPassCommandBufferHelper implementation.
OutsideRenderPassCommandBufferHelper()2073 OutsideRenderPassCommandBufferHelper::OutsideRenderPassCommandBufferHelper() {}
2074
~OutsideRenderPassCommandBufferHelper()2075 OutsideRenderPassCommandBufferHelper::~OutsideRenderPassCommandBufferHelper() {}
2076
initialize(ErrorContext * context)2077 angle::Result OutsideRenderPassCommandBufferHelper::initialize(ErrorContext *context)
2078 {
2079 initializeImpl();
2080 return initializeCommandBuffer(context);
2081 }
initializeCommandBuffer(ErrorContext * context)2082 angle::Result OutsideRenderPassCommandBufferHelper::initializeCommandBuffer(ErrorContext *context)
2083 {
2084 // Skip initialization in the Pool-detached state.
2085 if (!ExecutesInline() && mCommandPool == nullptr)
2086 {
2087 return angle::Result::Continue;
2088 }
2089 return mCommandBuffer.initialize(context, mCommandPool, false,
2090 mCommandAllocator.getAllocator());
2091 }
2092
reset(ErrorContext * context,SecondaryCommandBufferCollector * commandBufferCollector)2093 angle::Result OutsideRenderPassCommandBufferHelper::reset(
2094 ErrorContext *context,
2095 SecondaryCommandBufferCollector *commandBufferCollector)
2096 {
2097 resetImpl(context);
2098
2099 // Collect/Reset the command buffer
2100 commandBufferCollector->collectCommandBuffer(std::move(mCommandBuffer));
2101 mIsCommandBufferEnded = false;
2102
2103 // Invalidate the queue serial here. We will get a new queue serial after commands flush.
2104 mQueueSerial = QueueSerial();
2105
2106 return initializeCommandBuffer(context);
2107 }
2108
imageRead(Context * context,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,ImageHelper * image)2109 void OutsideRenderPassCommandBufferHelper::imageRead(Context *context,
2110 VkImageAspectFlags aspectFlags,
2111 ImageLayout imageLayout,
2112 ImageHelper *image)
2113 {
2114 if (image->getResourceUse() >= mQueueSerial)
2115 {
2116 // If image is already used by renderPass, it may already set the event to renderPass's
2117 // event. In this case we already lost the previous event to wait for, thus use pipeline
2118 // barrier instead of event
2119 imageReadImpl(context, aspectFlags, imageLayout, BarrierType::Pipeline, image);
2120 }
2121 else
2122 {
2123 imageReadImpl(context, aspectFlags, imageLayout, BarrierType::Event, image);
2124 // Usually an image can only used by a RenderPassCommands or OutsideRenderPassCommands
2125 // because the layout will be different, except with image sampled from compute shader. In
2126 // this case, the renderPassCommands' read will override the outsideRenderPassCommands'
2127 retainImageWithEvent(context, image);
2128 }
2129 }
2130
imageWrite(Context * context,gl::LevelIndex level,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,ImageHelper * image)2131 void OutsideRenderPassCommandBufferHelper::imageWrite(Context *context,
2132 gl::LevelIndex level,
2133 uint32_t layerStart,
2134 uint32_t layerCount,
2135 VkImageAspectFlags aspectFlags,
2136 ImageLayout imageLayout,
2137 ImageHelper *image)
2138 {
2139 imageWriteImpl(context, level, layerStart, layerCount, aspectFlags, imageLayout,
2140 BarrierType::Event, image);
2141 retainImageWithEvent(context, image);
2142 }
2143
retainImage(ImageHelper * image)2144 void OutsideRenderPassCommandBufferHelper::retainImage(ImageHelper *image)
2145 {
2146 // We want explicit control on when VkEvent is used for outsideRPCommands to minimize the
2147 // overhead, so do not setEvent here.
2148 image->setQueueSerial(mQueueSerial);
2149 image->updatePipelineStageAccessHistory();
2150 }
2151
trackImageWithEvent(Context * context,ImageHelper * image)2152 void OutsideRenderPassCommandBufferHelper::trackImageWithEvent(Context *context, ImageHelper *image)
2153 {
2154 image->setCurrentRefCountedEvent(context, &mRefCountedEvents);
2155 flushSetEventsImpl(context, &mCommandBuffer);
2156 }
2157
collectRefCountedEventsGarbage(RefCountedEventsGarbageRecycler * garbageRecycler)2158 void OutsideRenderPassCommandBufferHelper::collectRefCountedEventsGarbage(
2159 RefCountedEventsGarbageRecycler *garbageRecycler)
2160 {
2161 ASSERT(garbageRecycler != nullptr);
2162 if (!mRefCountedEventCollector.empty())
2163 {
2164 garbageRecycler->collectGarbage(mQueueSerial, std::move(mRefCountedEventCollector));
2165 }
2166 }
2167
flushToPrimary(Context * context,CommandsState * commandsState)2168 angle::Result OutsideRenderPassCommandBufferHelper::flushToPrimary(Context *context,
2169 CommandsState *commandsState)
2170 {
2171 ANGLE_TRACE_EVENT0("gpu.angle", "OutsideRenderPassCommandBufferHelper::flushToPrimary");
2172 ASSERT(!empty());
2173
2174 Renderer *renderer = context->getRenderer();
2175
2176 // Commands that are added to primary before beginRenderPass command
2177 executeBarriers(renderer, commandsState);
2178
2179 ANGLE_TRY(endCommandBuffer(context));
2180 ASSERT(mIsCommandBufferEnded);
2181 mCommandBuffer.executeCommands(&commandsState->primaryCommands);
2182
2183 // Call VkCmdSetEvent to track the completion of this renderPass.
2184 flushSetEventsImpl(context, &commandsState->primaryCommands);
2185
2186 // Proactively reset all released events before ending command buffer.
2187 context->getRenderer()->getRefCountedEventRecycler()->resetEvents(
2188 context, mQueueSerial, &commandsState->primaryCommands);
2189
2190 // Restart the command buffer.
2191 return reset(context, &commandsState->secondaryCommands);
2192 }
2193
endCommandBuffer(ErrorContext * context)2194 angle::Result OutsideRenderPassCommandBufferHelper::endCommandBuffer(ErrorContext *context)
2195 {
2196 ASSERT(ExecutesInline() || mCommandPool != nullptr);
2197 ASSERT(mCommandBuffer.valid());
2198 ASSERT(!mIsCommandBufferEnded);
2199
2200 ANGLE_TRY(mCommandBuffer.end(context));
2201 mIsCommandBufferEnded = true;
2202
2203 return angle::Result::Continue;
2204 }
2205
attachCommandPool(ErrorContext * context,SecondaryCommandPool * commandPool)2206 angle::Result OutsideRenderPassCommandBufferHelper::attachCommandPool(
2207 ErrorContext *context,
2208 SecondaryCommandPool *commandPool)
2209 {
2210 return attachCommandPoolImpl<OutsideRenderPassCommandBufferHelper>(context, commandPool);
2211 }
2212
detachCommandPool(ErrorContext * context,SecondaryCommandPool ** commandPoolOut)2213 angle::Result OutsideRenderPassCommandBufferHelper::detachCommandPool(
2214 ErrorContext *context,
2215 SecondaryCommandPool **commandPoolOut)
2216 {
2217 return detachCommandPoolImpl<OutsideRenderPassCommandBufferHelper, false>(context,
2218 commandPoolOut);
2219 }
2220
releaseCommandPool()2221 void OutsideRenderPassCommandBufferHelper::releaseCommandPool()
2222 {
2223 releaseCommandPoolImpl<OutsideRenderPassCommandBufferHelper>();
2224 }
2225
attachAllocator(SecondaryCommandMemoryAllocator * allocator)2226 void OutsideRenderPassCommandBufferHelper::attachAllocator(
2227 SecondaryCommandMemoryAllocator *allocator)
2228 {
2229 attachAllocatorImpl<OutsideRenderPassCommandBufferHelper>(allocator);
2230 }
2231
detachAllocator()2232 SecondaryCommandMemoryAllocator *OutsideRenderPassCommandBufferHelper::detachAllocator()
2233 {
2234 return detachAllocatorImpl<OutsideRenderPassCommandBufferHelper>();
2235 }
2236
assertCanBeRecycled()2237 void OutsideRenderPassCommandBufferHelper::assertCanBeRecycled()
2238 {
2239 assertCanBeRecycledImpl<OutsideRenderPassCommandBufferHelper>();
2240 }
2241
getCommandDiagnostics()2242 std::string OutsideRenderPassCommandBufferHelper::getCommandDiagnostics()
2243 {
2244 std::ostringstream out;
2245 addCommandDiagnosticsCommon(&out);
2246
2247 out << mCommandBuffer.dumpCommands("\\l");
2248
2249 return out.str();
2250 }
2251
2252 // RenderPassFramebuffer implementation.
reset()2253 void RenderPassFramebuffer::reset()
2254 {
2255 mInitialFramebuffer.release();
2256 mImageViews.clear();
2257 mIsImageless = false;
2258 mIsDefault = false;
2259 }
2260
addResolveAttachment(size_t viewIndex,VkImageView view)2261 void RenderPassFramebuffer::addResolveAttachment(size_t viewIndex, VkImageView view)
2262 {
2263 // The initial framebuffer is no longer usable.
2264 mInitialFramebuffer.release();
2265
2266 if (viewIndex >= mImageViews.size())
2267 {
2268 mImageViews.resize(viewIndex + 1, VK_NULL_HANDLE);
2269 }
2270
2271 ASSERT(mImageViews[viewIndex] == VK_NULL_HANDLE);
2272 mImageViews[viewIndex] = view;
2273 }
2274
packResolveViewsAndCreateFramebuffer(ErrorContext * context,const RenderPass & renderPass,Framebuffer * framebufferOut)2275 angle::Result RenderPassFramebuffer::packResolveViewsAndCreateFramebuffer(
2276 ErrorContext *context,
2277 const RenderPass &renderPass,
2278 Framebuffer *framebufferOut)
2279 {
2280 // This is only called if the initial framebuffer was not usable. Since this is called when
2281 // the render pass is finalized, the render pass that is passed in is the final one (not a
2282 // compatible one) and the framebuffer that is created is not imageless.
2283 ASSERT(!mInitialFramebuffer.valid());
2284
2285 PackViews(&mImageViews);
2286 mIsImageless = false;
2287
2288 VkFramebufferCreateInfo framebufferInfo = {};
2289 framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
2290 framebufferInfo.flags = 0;
2291 framebufferInfo.renderPass = renderPass.getHandle();
2292 framebufferInfo.attachmentCount = static_cast<uint32_t>(mImageViews.size());
2293 framebufferInfo.pAttachments = mImageViews.data();
2294 framebufferInfo.width = mWidth;
2295 framebufferInfo.height = mHeight;
2296 framebufferInfo.layers = mLayers;
2297
2298 ANGLE_VK_TRY(context, framebufferOut->init(context->getDevice(), framebufferInfo));
2299 return angle::Result::Continue;
2300 }
2301
packResolveViewsForRenderPassBegin(VkRenderPassAttachmentBeginInfo * beginInfoOut)2302 void RenderPassFramebuffer::packResolveViewsForRenderPassBegin(
2303 VkRenderPassAttachmentBeginInfo *beginInfoOut)
2304 {
2305 // Called when using the initial framebuffer which is imageless
2306 ASSERT(mInitialFramebuffer.valid());
2307 ASSERT(mIsImageless);
2308
2309 PackViews(&mImageViews);
2310
2311 *beginInfoOut = {};
2312 beginInfoOut->sType = VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO_KHR;
2313 beginInfoOut->attachmentCount = static_cast<uint32_t>(mImageViews.size());
2314 beginInfoOut->pAttachments = mImageViews.data();
2315 }
2316
2317 // static
PackViews(FramebufferAttachmentsVector<VkImageView> * views)2318 void RenderPassFramebuffer::PackViews(FramebufferAttachmentsVector<VkImageView> *views)
2319 {
2320 PackedAttachmentIndex packIndex = kAttachmentIndexZero;
2321 for (size_t viewIndex = 0; viewIndex < views->size(); ++viewIndex)
2322 {
2323 if ((*views)[viewIndex] != VK_NULL_HANDLE)
2324 {
2325 (*views)[packIndex.get()] = (*views)[viewIndex];
2326 ++packIndex;
2327 }
2328 }
2329
2330 views->resize(packIndex.get());
2331 }
2332
2333 // RenderPassCommandBufferHelper implementation.
RenderPassCommandBufferHelper()2334 RenderPassCommandBufferHelper::RenderPassCommandBufferHelper()
2335 : mCurrentSubpassCommandBufferIndex(0),
2336 mCounter(0),
2337 mClearValues{},
2338 mRenderPassStarted(false),
2339 mTransformFeedbackCounterBuffers{},
2340 mTransformFeedbackCounterBufferOffsets{},
2341 mValidTransformFeedbackBufferCount(0),
2342 mRebindTransformFeedbackBuffers(false),
2343 mIsTransformFeedbackActiveUnpaused(false),
2344 mPreviousSubpassesCmdCount(0),
2345 mDepthStencilAttachmentIndex(kAttachmentIndexInvalid),
2346 mColorAttachmentsCount(0),
2347 mImageOptimizeForPresent(nullptr),
2348 mImageOptimizeForPresentOriginalLayout(ImageLayout::Undefined)
2349 {}
2350
~RenderPassCommandBufferHelper()2351 RenderPassCommandBufferHelper::~RenderPassCommandBufferHelper() {}
2352
initialize(ErrorContext * context)2353 angle::Result RenderPassCommandBufferHelper::initialize(ErrorContext *context)
2354 {
2355 initializeImpl();
2356 return initializeCommandBuffer(context);
2357 }
initializeCommandBuffer(ErrorContext * context)2358 angle::Result RenderPassCommandBufferHelper::initializeCommandBuffer(ErrorContext *context)
2359 {
2360 // Skip initialization in the Pool-detached state.
2361 if (!ExecutesInline() && mCommandPool == nullptr)
2362 {
2363 return angle::Result::Continue;
2364 }
2365 return getCommandBuffer().initialize(context, mCommandPool, true,
2366 mCommandAllocator.getAllocator());
2367 }
2368
reset(ErrorContext * context,SecondaryCommandBufferCollector * commandBufferCollector)2369 angle::Result RenderPassCommandBufferHelper::reset(
2370 ErrorContext *context,
2371 SecondaryCommandBufferCollector *commandBufferCollector)
2372 {
2373 resetImpl(context);
2374
2375 for (PackedAttachmentIndex index = kAttachmentIndexZero; index < mColorAttachmentsCount;
2376 ++index)
2377 {
2378 mColorAttachments[index].reset();
2379 mColorResolveAttachments[index].reset();
2380 }
2381
2382 mDepthAttachment.reset();
2383 mDepthResolveAttachment.reset();
2384 mStencilAttachment.reset();
2385 mStencilResolveAttachment.reset();
2386
2387 mFragmentShadingRateAtachment.reset();
2388
2389 mRenderPassStarted = false;
2390 mValidTransformFeedbackBufferCount = 0;
2391 mRebindTransformFeedbackBuffers = false;
2392 mHasShaderStorageOutput = false;
2393 mHasGLMemoryBarrierIssued = false;
2394 mPreviousSubpassesCmdCount = 0;
2395 mColorAttachmentsCount = PackedAttachmentCount(0);
2396 mDepthStencilAttachmentIndex = kAttachmentIndexInvalid;
2397 mImageOptimizeForPresent = nullptr;
2398 mImageOptimizeForPresentOriginalLayout = ImageLayout::Undefined;
2399
2400 ASSERT(CheckSubpassCommandBufferCount(getSubpassCommandBufferCount()));
2401
2402 // Collect/Reset the command buffers
2403 for (uint32_t subpass = 0; subpass < getSubpassCommandBufferCount(); ++subpass)
2404 {
2405 commandBufferCollector->collectCommandBuffer(std::move(mCommandBuffers[subpass]));
2406 }
2407
2408 mCurrentSubpassCommandBufferIndex = 0;
2409
2410 // Reset the image views used for imageless framebuffer (if any)
2411 mFramebuffer.reset();
2412
2413 // Invalidate the queue serial here. We will get a new queue serial when we begin renderpass.
2414 mQueueSerial = QueueSerial();
2415
2416 return initializeCommandBuffer(context);
2417 }
2418
imageRead(ContextVk * contextVk,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,ImageHelper * image)2419 void RenderPassCommandBufferHelper::imageRead(ContextVk *contextVk,
2420 VkImageAspectFlags aspectFlags,
2421 ImageLayout imageLayout,
2422 ImageHelper *image)
2423 {
2424 imageReadImpl(contextVk, aspectFlags, imageLayout, BarrierType::Event, image);
2425 // As noted in the header we don't support multiple read layouts for Images.
2426 // We allow duplicate uses in the RP to accommodate for normal GL sampler usage.
2427 retainImageWithEvent(contextVk, image);
2428 }
2429
imageWrite(ContextVk * contextVk,gl::LevelIndex level,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,ImageHelper * image)2430 void RenderPassCommandBufferHelper::imageWrite(ContextVk *contextVk,
2431 gl::LevelIndex level,
2432 uint32_t layerStart,
2433 uint32_t layerCount,
2434 VkImageAspectFlags aspectFlags,
2435 ImageLayout imageLayout,
2436 ImageHelper *image)
2437 {
2438 imageWriteImpl(contextVk, level, layerStart, layerCount, aspectFlags, imageLayout,
2439 BarrierType::Event, image);
2440 retainImageWithEvent(contextVk, image);
2441 }
2442
colorImagesDraw(gl::LevelIndex level,uint32_t layerStart,uint32_t layerCount,ImageHelper * image,ImageHelper * resolveImage,UniqueSerial imageSiblingSerial,PackedAttachmentIndex packedAttachmentIndex)2443 void RenderPassCommandBufferHelper::colorImagesDraw(gl::LevelIndex level,
2444 uint32_t layerStart,
2445 uint32_t layerCount,
2446 ImageHelper *image,
2447 ImageHelper *resolveImage,
2448 UniqueSerial imageSiblingSerial,
2449 PackedAttachmentIndex packedAttachmentIndex)
2450 {
2451 ASSERT(packedAttachmentIndex < mColorAttachmentsCount);
2452
2453 image->onRenderPassAttach(mQueueSerial);
2454
2455 mColorAttachments[packedAttachmentIndex].init(image, imageSiblingSerial, level, layerStart,
2456 layerCount, VK_IMAGE_ASPECT_COLOR_BIT);
2457
2458 if (resolveImage)
2459 {
2460 resolveImage->onRenderPassAttach(mQueueSerial);
2461 mColorResolveAttachments[packedAttachmentIndex].init(resolveImage, imageSiblingSerial,
2462 level, layerStart, layerCount,
2463 VK_IMAGE_ASPECT_COLOR_BIT);
2464 }
2465 }
2466
depthStencilImagesDraw(gl::LevelIndex level,uint32_t layerStart,uint32_t layerCount,ImageHelper * image,ImageHelper * resolveImage,UniqueSerial imageSiblingSerial)2467 void RenderPassCommandBufferHelper::depthStencilImagesDraw(gl::LevelIndex level,
2468 uint32_t layerStart,
2469 uint32_t layerCount,
2470 ImageHelper *image,
2471 ImageHelper *resolveImage,
2472 UniqueSerial imageSiblingSerial)
2473 {
2474 ASSERT(!usesImage(*image));
2475 ASSERT(!resolveImage || !usesImage(*resolveImage));
2476
2477 // Because depthStencil buffer's read/write property can change while we build renderpass, we
2478 // defer the image layout changes until endRenderPass time or when images going away so that we
2479 // only insert layout change barrier once.
2480 image->onRenderPassAttach(mQueueSerial);
2481
2482 mDepthAttachment.init(image, imageSiblingSerial, level, layerStart, layerCount,
2483 VK_IMAGE_ASPECT_DEPTH_BIT);
2484 mStencilAttachment.init(image, imageSiblingSerial, level, layerStart, layerCount,
2485 VK_IMAGE_ASPECT_STENCIL_BIT);
2486
2487 if (resolveImage)
2488 {
2489 // Note that the resolve depth/stencil image has the same level/layer index as the
2490 // depth/stencil image as currently it can only ever come from
2491 // multisampled-render-to-texture renderbuffers.
2492 resolveImage->onRenderPassAttach(mQueueSerial);
2493
2494 mDepthResolveAttachment.init(resolveImage, imageSiblingSerial, level, layerStart,
2495 layerCount, VK_IMAGE_ASPECT_DEPTH_BIT);
2496 mStencilResolveAttachment.init(resolveImage, imageSiblingSerial, level, layerStart,
2497 layerCount, VK_IMAGE_ASPECT_STENCIL_BIT);
2498 }
2499 }
2500
fragmentShadingRateImageRead(ImageHelper * image)2501 void RenderPassCommandBufferHelper::fragmentShadingRateImageRead(ImageHelper *image)
2502 {
2503 ASSERT(image && image->valid());
2504 ASSERT(!usesImage(*image));
2505
2506 image->onRenderPassAttach(mQueueSerial);
2507
2508 // Initialize RenderPassAttachment for fragment shading rate attachment.
2509 mFragmentShadingRateAtachment.init(image, {}, gl::LevelIndex(0), 0, 1,
2510 VK_IMAGE_ASPECT_COLOR_BIT);
2511
2512 image->resetRenderPassUsageFlags();
2513 image->setRenderPassUsageFlag(RenderPassUsage::FragmentShadingRateReadOnlyAttachment);
2514 }
2515
onColorAccess(PackedAttachmentIndex packedAttachmentIndex,ResourceAccess access)2516 void RenderPassCommandBufferHelper::onColorAccess(PackedAttachmentIndex packedAttachmentIndex,
2517 ResourceAccess access)
2518 {
2519 ASSERT(packedAttachmentIndex < mColorAttachmentsCount);
2520 mColorAttachments[packedAttachmentIndex].onAccess(access, getRenderPassWriteCommandCount());
2521 }
2522
onDepthAccess(ResourceAccess access)2523 void RenderPassCommandBufferHelper::onDepthAccess(ResourceAccess access)
2524 {
2525 mDepthAttachment.onAccess(access, getRenderPassWriteCommandCount());
2526 }
2527
onStencilAccess(ResourceAccess access)2528 void RenderPassCommandBufferHelper::onStencilAccess(ResourceAccess access)
2529 {
2530 mStencilAttachment.onAccess(access, getRenderPassWriteCommandCount());
2531 }
2532
updateDepthReadOnlyMode(RenderPassUsageFlags dsUsageFlags)2533 void RenderPassCommandBufferHelper::updateDepthReadOnlyMode(RenderPassUsageFlags dsUsageFlags)
2534 {
2535 ASSERT(mRenderPassStarted);
2536 updateStartedRenderPassWithDepthStencilMode(&mDepthResolveAttachment, hasDepthWriteOrClear(),
2537 dsUsageFlags,
2538 RenderPassUsage::DepthReadOnlyAttachment);
2539 }
2540
updateStencilReadOnlyMode(RenderPassUsageFlags dsUsageFlags)2541 void RenderPassCommandBufferHelper::updateStencilReadOnlyMode(RenderPassUsageFlags dsUsageFlags)
2542 {
2543 ASSERT(mRenderPassStarted);
2544 updateStartedRenderPassWithDepthStencilMode(&mStencilResolveAttachment,
2545 hasStencilWriteOrClear(), dsUsageFlags,
2546 RenderPassUsage::StencilReadOnlyAttachment);
2547 }
2548
updateDepthStencilReadOnlyMode(RenderPassUsageFlags dsUsageFlags,VkImageAspectFlags dsAspectFlags)2549 void RenderPassCommandBufferHelper::updateDepthStencilReadOnlyMode(
2550 RenderPassUsageFlags dsUsageFlags,
2551 VkImageAspectFlags dsAspectFlags)
2552 {
2553 ASSERT(mRenderPassStarted);
2554 if ((dsAspectFlags & VK_IMAGE_ASPECT_DEPTH_BIT) != 0)
2555 {
2556 updateDepthReadOnlyMode(dsUsageFlags);
2557 }
2558 if ((dsAspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) != 0)
2559 {
2560 updateStencilReadOnlyMode(dsUsageFlags);
2561 }
2562 }
2563
updateStartedRenderPassWithDepthStencilMode(RenderPassAttachment * resolveAttachment,bool renderPassHasWriteOrClear,RenderPassUsageFlags dsUsageFlags,RenderPassUsage readOnlyAttachmentUsage)2564 void RenderPassCommandBufferHelper::updateStartedRenderPassWithDepthStencilMode(
2565 RenderPassAttachment *resolveAttachment,
2566 bool renderPassHasWriteOrClear,
2567 RenderPassUsageFlags dsUsageFlags,
2568 RenderPassUsage readOnlyAttachmentUsage)
2569 {
2570 ASSERT(mRenderPassStarted);
2571 ASSERT(mDepthAttachment.getImage() == mStencilAttachment.getImage());
2572 ASSERT(mDepthResolveAttachment.getImage() == mStencilResolveAttachment.getImage());
2573
2574 // Determine read-only mode for depth or stencil
2575 const bool readOnlyMode =
2576 mDepthStencilAttachmentIndex != kAttachmentIndexInvalid &&
2577 resolveAttachment->getImage() == nullptr &&
2578 (dsUsageFlags.test(readOnlyAttachmentUsage) || !renderPassHasWriteOrClear);
2579
2580 // If readOnlyMode is false, we are switching out of read only mode due to depth/stencil write.
2581 // We must not be in the read only feedback loop mode because the logic in
2582 // DIRTY_BIT_READ_ONLY_DEPTH_FEEDBACK_LOOP_MODE should ensure we end the previous renderpass and
2583 // a new renderpass will start with feedback loop disabled.
2584 ASSERT(readOnlyMode || !dsUsageFlags.test(readOnlyAttachmentUsage));
2585
2586 ImageHelper *depthStencilImage = mDepthAttachment.getImage();
2587 if (depthStencilImage)
2588 {
2589 if (readOnlyMode)
2590 {
2591 depthStencilImage->setRenderPassUsageFlag(readOnlyAttachmentUsage);
2592 }
2593 else
2594 {
2595 depthStencilImage->clearRenderPassUsageFlag(readOnlyAttachmentUsage);
2596 }
2597 }
2598 // The depth/stencil resolve image is never in read-only mode
2599 }
2600
finalizeColorImageLayout(Context * context,ImageHelper * image,PackedAttachmentIndex packedAttachmentIndex,bool isResolveImage)2601 void RenderPassCommandBufferHelper::finalizeColorImageLayout(
2602 Context *context,
2603 ImageHelper *image,
2604 PackedAttachmentIndex packedAttachmentIndex,
2605 bool isResolveImage)
2606 {
2607 ASSERT(packedAttachmentIndex < mColorAttachmentsCount);
2608 ASSERT(image != nullptr);
2609
2610 // Do layout change.
2611 ImageLayout imageLayout;
2612 if (image->usedByCurrentRenderPassAsAttachmentAndSampler(RenderPassUsage::ColorTextureSampler))
2613 {
2614 // texture code already picked layout and inserted barrier
2615 imageLayout = image->getCurrentImageLayout();
2616 ASSERT(imageLayout == ImageLayout::ColorWriteFragmentShaderFeedback ||
2617 imageLayout == ImageLayout::ColorWriteAllShadersFeedback);
2618 }
2619 else
2620 {
2621 // When color is unresolved, use a layout that includes fragment shader reads. This is done
2622 // for all color resolve attachments even if they are not all unresolved for simplicity. In
2623 // particular, the GL color index is not available (only the packed index) at this point,
2624 // but that is needed to query whether the attachment is unresolved or not.
2625 const bool hasUnresolve =
2626 isResolveImage && mRenderPassDesc.getColorUnresolveAttachmentMask().any();
2627 imageLayout = hasUnresolve ? ImageLayout::MSRTTEmulationColorUnresolveAndResolve
2628 : ImageLayout::ColorWrite;
2629 if (context->getFeatures().preferDynamicRendering.enabled &&
2630 mRenderPassDesc.hasColorFramebufferFetch())
2631 {
2632 // Note MSRTT emulation is not implemented with dynamic rendering.
2633 ASSERT(imageLayout == ImageLayout::ColorWrite);
2634 imageLayout = ImageLayout::ColorWriteAndInput;
2635 }
2636 else if (image->getCurrentImageLayout() == ImageLayout::SharedPresent)
2637 {
2638 // Once you transition to ImageLayout::SharedPresent, you never transition out of it.
2639 ASSERT(imageLayout == ImageLayout::ColorWrite);
2640 imageLayout = ImageLayout::SharedPresent;
2641 }
2642
2643 updateImageLayoutAndBarrier(context, image, VK_IMAGE_ASPECT_COLOR_BIT, imageLayout,
2644 BarrierType::Event);
2645 }
2646
2647 if (!isResolveImage)
2648 {
2649 mAttachmentOps.setLayouts(packedAttachmentIndex, imageLayout, imageLayout);
2650 }
2651 else
2652 {
2653 SetBitField(mAttachmentOps[packedAttachmentIndex].finalResolveLayout, imageLayout);
2654 }
2655
2656 // Dynamic rendering does not have implicit layout transitions at render pass boundaries. This
2657 // optimization is instead done by recording the necessary transition after the render pass
2658 // directly on the primary command buffer.
2659 if (mImageOptimizeForPresent == image)
2660 {
2661 ASSERT(isDefault());
2662 ASSERT(context->getFeatures().supportsPresentation.enabled);
2663 ASSERT(packedAttachmentIndex == kAttachmentIndexZero);
2664 // Shared present mode must not change layout
2665 ASSERT(imageLayout != ImageLayout::SharedPresent);
2666
2667 // Use finalLayout instead of extra barrier for layout change to present. For dynamic
2668 // rendering, this is not possible and is done when the render pass is flushed. However,
2669 // because this function is expected to finalize the image layout, we still have to pretend
2670 // the image is in the present layout already.
2671 mImageOptimizeForPresentOriginalLayout = mImageOptimizeForPresent->getCurrentImageLayout();
2672 mImageOptimizeForPresent->setCurrentImageLayout(context->getRenderer(),
2673 ImageLayout::Present);
2674
2675 if (!context->getFeatures().preferDynamicRendering.enabled)
2676 {
2677 if (isResolveImage)
2678 {
2679 SetBitField(mAttachmentOps[packedAttachmentIndex].finalResolveLayout,
2680 mImageOptimizeForPresent->getCurrentImageLayout());
2681 }
2682 else
2683 {
2684 SetBitField(mAttachmentOps[packedAttachmentIndex].finalLayout,
2685 mImageOptimizeForPresent->getCurrentImageLayout());
2686 }
2687 mImageOptimizeForPresent = nullptr;
2688 mImageOptimizeForPresentOriginalLayout = ImageLayout::Undefined;
2689 }
2690 }
2691
2692 if (isResolveImage)
2693 {
2694 // Note: the color image will have its flags reset after load/store ops are determined.
2695 image->resetRenderPassUsageFlags();
2696 }
2697 }
2698
finalizeColorImageLoadStore(Context * context,PackedAttachmentIndex packedAttachmentIndex)2699 void RenderPassCommandBufferHelper::finalizeColorImageLoadStore(
2700 Context *context,
2701 PackedAttachmentIndex packedAttachmentIndex)
2702 {
2703 PackedAttachmentOpsDesc &ops = mAttachmentOps[packedAttachmentIndex];
2704 RenderPassLoadOp loadOp = static_cast<RenderPassLoadOp>(ops.loadOp);
2705 RenderPassStoreOp storeOp = static_cast<RenderPassStoreOp>(ops.storeOp);
2706
2707 // This has to be called after layout been finalized
2708 ASSERT(ops.initialLayout != static_cast<uint16_t>(ImageLayout::Undefined));
2709
2710 uint32_t currentCmdCount = getRenderPassWriteCommandCount();
2711 bool isInvalidated = false;
2712
2713 RenderPassAttachment &colorAttachment = mColorAttachments[packedAttachmentIndex];
2714 colorAttachment.finalizeLoadStore(
2715 context, currentCmdCount, mRenderPassDesc.getColorUnresolveAttachmentMask().any(),
2716 mRenderPassDesc.getColorResolveAttachmentMask().any(), &loadOp, &storeOp, &isInvalidated);
2717
2718 if (isInvalidated)
2719 {
2720 ops.isInvalidated = true;
2721 }
2722
2723 if (!ops.isInvalidated)
2724 {
2725 mColorResolveAttachments[packedAttachmentIndex].restoreContent();
2726 }
2727
2728 // If the image is being written to, mark its contents defined.
2729 // This has to be done after storeOp has been finalized.
2730 if (storeOp == RenderPassStoreOp::Store)
2731 {
2732 colorAttachment.restoreContent();
2733 }
2734
2735 SetBitField(ops.loadOp, loadOp);
2736 SetBitField(ops.storeOp, storeOp);
2737 }
2738
finalizeDepthStencilImageLayout(Context * context)2739 void RenderPassCommandBufferHelper::finalizeDepthStencilImageLayout(Context *context)
2740 {
2741 ASSERT(mDepthAttachment.getImage() != nullptr);
2742 ASSERT(mDepthAttachment.getImage() == mStencilAttachment.getImage());
2743
2744 ImageHelper *depthStencilImage = mDepthAttachment.getImage();
2745
2746 // Do depth stencil layout change.
2747 ImageLayout imageLayout;
2748 bool barrierRequired;
2749
2750 const bool isDepthAttachmentAndSampler =
2751 depthStencilImage->usedByCurrentRenderPassAsAttachmentAndSampler(
2752 RenderPassUsage::DepthTextureSampler);
2753 const bool isStencilAttachmentAndSampler =
2754 depthStencilImage->usedByCurrentRenderPassAsAttachmentAndSampler(
2755 RenderPassUsage::StencilTextureSampler);
2756 const bool isReadOnlyDepth =
2757 depthStencilImage->hasRenderPassUsageFlag(RenderPassUsage::DepthReadOnlyAttachment);
2758 const bool isReadOnlyStencil =
2759 depthStencilImage->hasRenderPassUsageFlag(RenderPassUsage::StencilReadOnlyAttachment);
2760 BarrierType barrierType = BarrierType::Event;
2761
2762 if (isDepthAttachmentAndSampler || isStencilAttachmentAndSampler)
2763 {
2764 // texture code already picked layout and inserted barrier
2765 imageLayout = depthStencilImage->getCurrentImageLayout();
2766
2767 if ((isDepthAttachmentAndSampler && !isReadOnlyDepth) ||
2768 (isStencilAttachmentAndSampler && !isReadOnlyStencil))
2769 {
2770 ASSERT(imageLayout == ImageLayout::DepthStencilFragmentShaderFeedback ||
2771 imageLayout == ImageLayout::DepthStencilAllShadersFeedback);
2772 barrierRequired = true;
2773 }
2774 else
2775 {
2776 ASSERT(imageLayout == ImageLayout::DepthWriteStencilReadFragmentShaderStencilRead ||
2777 imageLayout == ImageLayout::DepthWriteStencilReadAllShadersStencilRead ||
2778 imageLayout == ImageLayout::DepthReadStencilWriteFragmentShaderDepthRead ||
2779 imageLayout == ImageLayout::DepthReadStencilWriteAllShadersDepthRead ||
2780 imageLayout == ImageLayout::DepthReadStencilReadFragmentShaderRead ||
2781 imageLayout == ImageLayout::DepthReadStencilReadAllShadersRead);
2782 barrierRequired =
2783 depthStencilImage->isReadBarrierNecessary(context->getRenderer(), imageLayout);
2784 }
2785 }
2786 else
2787 {
2788 if (mRenderPassDesc.hasDepthStencilFramebufferFetch())
2789 {
2790 imageLayout = ImageLayout::DepthStencilWriteAndInput;
2791 }
2792 else if (isReadOnlyDepth)
2793 {
2794 imageLayout = isReadOnlyStencil ? ImageLayout::DepthReadStencilRead
2795 : ImageLayout::DepthReadStencilWrite;
2796 }
2797 else
2798 {
2799 imageLayout = isReadOnlyStencil ? ImageLayout::DepthWriteStencilRead
2800 : ImageLayout::DepthWriteStencilWrite;
2801 }
2802
2803 barrierRequired =
2804 !isReadOnlyDepth || !isReadOnlyStencil ||
2805 depthStencilImage->isReadBarrierNecessary(context->getRenderer(), imageLayout);
2806 }
2807
2808 mAttachmentOps.setLayouts(mDepthStencilAttachmentIndex, imageLayout, imageLayout);
2809
2810 if (barrierRequired)
2811 {
2812 const angle::Format &format = depthStencilImage->getActualFormat();
2813 ASSERT(format.hasDepthOrStencilBits());
2814 VkImageAspectFlags aspectFlags = GetDepthStencilAspectFlags(format);
2815 updateImageLayoutAndBarrier(context, depthStencilImage, aspectFlags, imageLayout,
2816 barrierType);
2817 }
2818 }
2819
finalizeDepthStencilResolveImageLayout(Context * context)2820 void RenderPassCommandBufferHelper::finalizeDepthStencilResolveImageLayout(Context *context)
2821 {
2822 ASSERT(mDepthResolveAttachment.getImage() != nullptr);
2823 ASSERT(mDepthResolveAttachment.getImage() == mStencilResolveAttachment.getImage());
2824
2825 ImageHelper *depthStencilResolveImage = mDepthResolveAttachment.getImage();
2826
2827 // When depth/stencil is unresolved, use a layout that includes fragment shader reads.
2828 ImageLayout imageLayout = mRenderPassDesc.hasDepthStencilUnresolveAttachment()
2829 ? ImageLayout::MSRTTEmulationDepthStencilUnresolveAndResolve
2830 : ImageLayout::DepthStencilResolve;
2831 const angle::Format &format = depthStencilResolveImage->getActualFormat();
2832 ASSERT(format.hasDepthOrStencilBits());
2833 VkImageAspectFlags aspectFlags = GetDepthStencilAspectFlags(format);
2834
2835 updateImageLayoutAndBarrier(context, depthStencilResolveImage, aspectFlags, imageLayout,
2836 BarrierType::Event);
2837
2838 // The resolve image can never be read-only.
2839 ASSERT(!depthStencilResolveImage->hasRenderPassUsageFlag(
2840 RenderPassUsage::DepthReadOnlyAttachment));
2841 ASSERT(!depthStencilResolveImage->hasRenderPassUsageFlag(
2842 RenderPassUsage::StencilReadOnlyAttachment));
2843 ASSERT(mDepthStencilAttachmentIndex != kAttachmentIndexInvalid);
2844 const PackedAttachmentOpsDesc &dsOps = mAttachmentOps[mDepthStencilAttachmentIndex];
2845
2846 // If the image is being written to, mark its contents defined.
2847 if (!dsOps.isInvalidated && mRenderPassDesc.hasDepthResolveAttachment())
2848 {
2849 mDepthResolveAttachment.restoreContent();
2850 }
2851 if (!dsOps.isStencilInvalidated && mRenderPassDesc.hasStencilResolveAttachment())
2852 {
2853 mStencilResolveAttachment.restoreContent();
2854 }
2855
2856 depthStencilResolveImage->resetRenderPassUsageFlags();
2857 }
2858
finalizeFragmentShadingRateImageLayout(Context * context)2859 void RenderPassCommandBufferHelper::finalizeFragmentShadingRateImageLayout(Context *context)
2860 {
2861 ImageHelper *image = mFragmentShadingRateAtachment.getImage();
2862 ImageLayout imageLayout = ImageLayout::FragmentShadingRateAttachmentReadOnly;
2863 ASSERT(image && image->valid());
2864 if (image->isReadBarrierNecessary(context->getRenderer(), imageLayout))
2865 {
2866 updateImageLayoutAndBarrier(context, image, VK_IMAGE_ASPECT_COLOR_BIT, imageLayout,
2867 BarrierType::Event);
2868 }
2869 image->resetRenderPassUsageFlags();
2870 }
2871
finalizeImageLayout(Context * context,const ImageHelper * image,UniqueSerial imageSiblingSerial)2872 void RenderPassCommandBufferHelper::finalizeImageLayout(Context *context,
2873 const ImageHelper *image,
2874 UniqueSerial imageSiblingSerial)
2875 {
2876 if (image->hasRenderPassUsageFlag(RenderPassUsage::RenderTargetAttachment))
2877 {
2878 for (PackedAttachmentIndex index = kAttachmentIndexZero; index < mColorAttachmentsCount;
2879 ++index)
2880 {
2881 if (mColorAttachments[index].hasImage(image, imageSiblingSerial))
2882 {
2883 finalizeColorImageLayoutAndLoadStore(context, index);
2884 mColorAttachments[index].reset();
2885 }
2886 else if (mColorResolveAttachments[index].hasImage(image, imageSiblingSerial))
2887 {
2888 finalizeColorImageLayout(context, mColorResolveAttachments[index].getImage(), index,
2889 true);
2890 mColorResolveAttachments[index].reset();
2891 }
2892 }
2893 }
2894
2895 if (mDepthAttachment.hasImage(image, imageSiblingSerial))
2896 {
2897 finalizeDepthStencilImageLayoutAndLoadStore(context);
2898 mDepthAttachment.reset();
2899 mStencilAttachment.reset();
2900 }
2901
2902 if (mDepthResolveAttachment.hasImage(image, imageSiblingSerial))
2903 {
2904 finalizeDepthStencilResolveImageLayout(context);
2905 mDepthResolveAttachment.reset();
2906 mStencilResolveAttachment.reset();
2907 }
2908
2909 if (mFragmentShadingRateAtachment.hasImage(image, imageSiblingSerial))
2910 {
2911 finalizeFragmentShadingRateImageLayout(context);
2912 mFragmentShadingRateAtachment.reset();
2913 }
2914 }
2915
finalizeDepthStencilLoadStore(Context * context)2916 void RenderPassCommandBufferHelper::finalizeDepthStencilLoadStore(Context *context)
2917 {
2918 ASSERT(mDepthStencilAttachmentIndex != kAttachmentIndexInvalid);
2919
2920 PackedAttachmentOpsDesc &dsOps = mAttachmentOps[mDepthStencilAttachmentIndex];
2921 RenderPassLoadOp depthLoadOp = static_cast<RenderPassLoadOp>(dsOps.loadOp);
2922 RenderPassStoreOp depthStoreOp = static_cast<RenderPassStoreOp>(dsOps.storeOp);
2923 RenderPassLoadOp stencilLoadOp = static_cast<RenderPassLoadOp>(dsOps.stencilLoadOp);
2924 RenderPassStoreOp stencilStoreOp = static_cast<RenderPassStoreOp>(dsOps.stencilStoreOp);
2925
2926 // This has to be called after layout been finalized
2927 ASSERT(dsOps.initialLayout != static_cast<uint16_t>(ImageLayout::Undefined));
2928
2929 uint32_t currentCmdCount = getRenderPassWriteCommandCount();
2930 bool isDepthInvalidated = false;
2931 bool isStencilInvalidated = false;
2932 bool hasDepthResolveAttachment = mRenderPassDesc.hasDepthResolveAttachment();
2933 bool hasStencilResolveAttachment = mRenderPassDesc.hasStencilResolveAttachment();
2934
2935 mDepthAttachment.finalizeLoadStore(
2936 context, currentCmdCount, mRenderPassDesc.hasDepthUnresolveAttachment(),
2937 hasDepthResolveAttachment, &depthLoadOp, &depthStoreOp, &isDepthInvalidated);
2938 mStencilAttachment.finalizeLoadStore(
2939 context, currentCmdCount, mRenderPassDesc.hasStencilUnresolveAttachment(),
2940 hasStencilResolveAttachment, &stencilLoadOp, &stencilStoreOp, &isStencilInvalidated);
2941
2942 const bool disableMixedDepthStencilLoadOpNoneAndLoad =
2943 context->getFeatures().disallowMixedDepthStencilLoadOpNoneAndLoad.enabled;
2944
2945 if (disableMixedDepthStencilLoadOpNoneAndLoad)
2946 {
2947 if (depthLoadOp == RenderPassLoadOp::None && stencilLoadOp != RenderPassLoadOp::None)
2948 {
2949 depthLoadOp = RenderPassLoadOp::Load;
2950 }
2951 if (depthLoadOp != RenderPassLoadOp::None && stencilLoadOp == RenderPassLoadOp::None)
2952 {
2953 stencilLoadOp = RenderPassLoadOp::Load;
2954 }
2955 }
2956
2957 if (isDepthInvalidated)
2958 {
2959 dsOps.isInvalidated = true;
2960 }
2961 if (isStencilInvalidated)
2962 {
2963 dsOps.isStencilInvalidated = true;
2964 }
2965
2966 // If any aspect is missing, set the corresponding ops to don't care.
2967 const uint32_t depthStencilIndexGL =
2968 static_cast<uint32_t>(mRenderPassDesc.depthStencilAttachmentIndex());
2969 const angle::FormatID attachmentFormatID = mRenderPassDesc[depthStencilIndexGL];
2970 ASSERT(attachmentFormatID != angle::FormatID::NONE);
2971 const angle::Format &angleFormat = angle::Format::Get(attachmentFormatID);
2972
2973 if (angleFormat.depthBits == 0)
2974 {
2975 depthLoadOp = RenderPassLoadOp::DontCare;
2976 depthStoreOp = RenderPassStoreOp::DontCare;
2977 }
2978 if (angleFormat.stencilBits == 0)
2979 {
2980 stencilLoadOp = RenderPassLoadOp::DontCare;
2981 stencilStoreOp = RenderPassStoreOp::DontCare;
2982 }
2983
2984 // If the image is being written to, mark its contents defined.
2985 // This has to be done after storeOp has been finalized.
2986 ASSERT(mDepthAttachment.getImage() == mStencilAttachment.getImage());
2987 if (!mDepthAttachment.getImage()->hasRenderPassUsageFlag(
2988 RenderPassUsage::DepthReadOnlyAttachment))
2989 {
2990 if (depthStoreOp == RenderPassStoreOp::Store)
2991 {
2992 mDepthAttachment.restoreContent();
2993 }
2994 }
2995 if (!mStencilAttachment.getImage()->hasRenderPassUsageFlag(
2996 RenderPassUsage::StencilReadOnlyAttachment))
2997 {
2998 if (stencilStoreOp == RenderPassStoreOp::Store)
2999 {
3000 mStencilAttachment.restoreContent();
3001 }
3002 }
3003
3004 SetBitField(dsOps.loadOp, depthLoadOp);
3005 SetBitField(dsOps.storeOp, depthStoreOp);
3006 SetBitField(dsOps.stencilLoadOp, stencilLoadOp);
3007 SetBitField(dsOps.stencilStoreOp, stencilStoreOp);
3008 }
3009
finalizeColorImageLayoutAndLoadStore(Context * context,PackedAttachmentIndex packedAttachmentIndex)3010 void RenderPassCommandBufferHelper::finalizeColorImageLayoutAndLoadStore(
3011 Context *context,
3012 PackedAttachmentIndex packedAttachmentIndex)
3013 {
3014 finalizeColorImageLayout(context, mColorAttachments[packedAttachmentIndex].getImage(),
3015 packedAttachmentIndex, false);
3016 finalizeColorImageLoadStore(context, packedAttachmentIndex);
3017
3018 mColorAttachments[packedAttachmentIndex].getImage()->resetRenderPassUsageFlags();
3019 }
3020
finalizeDepthStencilImageLayoutAndLoadStore(Context * context)3021 void RenderPassCommandBufferHelper::finalizeDepthStencilImageLayoutAndLoadStore(Context *context)
3022 {
3023 finalizeDepthStencilImageLayout(context);
3024 finalizeDepthStencilLoadStore(context);
3025
3026 ASSERT(mDepthAttachment.getImage() == mStencilAttachment.getImage());
3027 mDepthAttachment.getImage()->resetRenderPassUsageFlags();
3028 }
3029
collectRefCountedEventsGarbage(Renderer * renderer,RefCountedEventsGarbageRecycler * garbageRecycler)3030 void RenderPassCommandBufferHelper::collectRefCountedEventsGarbage(
3031 Renderer *renderer,
3032 RefCountedEventsGarbageRecycler *garbageRecycler)
3033 {
3034 // For render pass the VkCmdSetEvent works differently from OutsideRenderPassCommands.
3035 // VkCmdEndRenderPass are called in the primary command buffer, and VkCmdSetEvents has to be
3036 // issued after VkCmdEndRenderPass. This means VkCmdSetEvent has to be delayed. Because of this,
3037 // here we simply make a copy of the VkEvent from RefCountedEvent and then add the
3038 // RefCountedEvent to the garbage collector. No VkCmdSetEvent call is issued here (they will be
3039 // issued at flushToPrimary time).
3040 mVkEventArray.init(renderer, mRefCountedEvents);
3041 mRefCountedEvents.releaseToEventCollector(&mRefCountedEventCollector);
3042
3043 if (!mRefCountedEventCollector.empty())
3044 {
3045 garbageRecycler->collectGarbage(mQueueSerial, std::move(mRefCountedEventCollector));
3046 }
3047 }
3048
updatePerfCountersForDynamicRenderingInstance(ErrorContext * context,angle::VulkanPerfCounters * countersOut)3049 void RenderPassCommandBufferHelper::updatePerfCountersForDynamicRenderingInstance(
3050 ErrorContext *context,
3051 angle::VulkanPerfCounters *countersOut)
3052 {
3053 mRenderPassDesc.updatePerfCounters(context, mFramebuffer.getUnpackedImageViews(),
3054 mAttachmentOps, countersOut);
3055 }
3056
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)3057 angle::Result RenderPassCommandBufferHelper::beginRenderPass(
3058 ContextVk *contextVk,
3059 RenderPassFramebuffer &&framebuffer,
3060 const gl::Rectangle &renderArea,
3061 const RenderPassDesc &renderPassDesc,
3062 const AttachmentOpsArray &renderPassAttachmentOps,
3063 const PackedAttachmentCount colorAttachmentCount,
3064 const PackedAttachmentIndex depthStencilAttachmentIndex,
3065 const PackedClearValuesArray &clearValues,
3066 const QueueSerial &queueSerial,
3067 RenderPassCommandBuffer **commandBufferOut)
3068 {
3069 ASSERT(!mRenderPassStarted);
3070
3071 mRenderPassDesc = renderPassDesc;
3072 mAttachmentOps = renderPassAttachmentOps;
3073 mDepthStencilAttachmentIndex = depthStencilAttachmentIndex;
3074 mColorAttachmentsCount = colorAttachmentCount;
3075 mFramebuffer = std::move(framebuffer);
3076 mRenderArea = renderArea;
3077 mClearValues = clearValues;
3078 mQueueSerial = queueSerial;
3079 *commandBufferOut = &getCommandBuffer();
3080
3081 mRenderPassStarted = true;
3082 mCounter++;
3083
3084 return beginRenderPassCommandBuffer(contextVk);
3085 }
3086
beginRenderPassCommandBuffer(ContextVk * contextVk)3087 angle::Result RenderPassCommandBufferHelper::beginRenderPassCommandBuffer(ContextVk *contextVk)
3088 {
3089 VkCommandBufferInheritanceInfo inheritanceInfo;
3090 VkCommandBufferInheritanceRenderingInfo renderingInfo;
3091 gl::DrawBuffersArray<VkFormat> colorFormatStorage;
3092
3093 ANGLE_TRY(RenderPassCommandBuffer::InitializeRenderPassInheritanceInfo(
3094 contextVk, mFramebuffer.getFramebuffer(), mRenderPassDesc, &inheritanceInfo, &renderingInfo,
3095 &colorFormatStorage));
3096 inheritanceInfo.subpass = mCurrentSubpassCommandBufferIndex;
3097
3098 return getCommandBuffer().begin(contextVk, inheritanceInfo);
3099 }
3100
endRenderPass(ContextVk * contextVk)3101 angle::Result RenderPassCommandBufferHelper::endRenderPass(ContextVk *contextVk)
3102 {
3103 ANGLE_TRY(endRenderPassCommandBuffer(contextVk));
3104
3105 for (PackedAttachmentIndex index = kAttachmentIndexZero; index < mColorAttachmentsCount;
3106 ++index)
3107 {
3108 if (mColorAttachments[index].getImage() != nullptr)
3109 {
3110 finalizeColorImageLayoutAndLoadStore(contextVk, index);
3111 }
3112 if (mColorResolveAttachments[index].getImage() != nullptr)
3113 {
3114 finalizeColorImageLayout(contextVk, mColorResolveAttachments[index].getImage(), index,
3115 true);
3116 }
3117 }
3118
3119 if (mFragmentShadingRateAtachment.getImage() != nullptr)
3120 {
3121 finalizeFragmentShadingRateImageLayout(contextVk);
3122 }
3123
3124 if (mDepthStencilAttachmentIndex != kAttachmentIndexInvalid)
3125 {
3126 // Do depth stencil layout change and load store optimization.
3127 ASSERT(mDepthAttachment.getImage() == mStencilAttachment.getImage());
3128 ASSERT(mDepthResolveAttachment.getImage() == mStencilResolveAttachment.getImage());
3129 if (mDepthAttachment.getImage() != nullptr)
3130 {
3131 finalizeDepthStencilImageLayoutAndLoadStore(contextVk);
3132 }
3133 if (mDepthResolveAttachment.getImage() != nullptr)
3134 {
3135 finalizeDepthStencilResolveImageLayout(contextVk);
3136 }
3137 }
3138
3139 return angle::Result::Continue;
3140 }
3141
endRenderPassCommandBuffer(ContextVk * contextVk)3142 angle::Result RenderPassCommandBufferHelper::endRenderPassCommandBuffer(ContextVk *contextVk)
3143 {
3144 return getCommandBuffer().end(contextVk);
3145 }
3146
nextSubpass(ContextVk * contextVk,RenderPassCommandBuffer ** commandBufferOut)3147 angle::Result RenderPassCommandBufferHelper::nextSubpass(ContextVk *contextVk,
3148 RenderPassCommandBuffer **commandBufferOut)
3149 {
3150 ASSERT(!contextVk->getFeatures().preferDynamicRendering.enabled);
3151
3152 if (ExecutesInline())
3153 {
3154 // When using ANGLE secondary command buffers, the commands are inline and are executed on
3155 // the primary command buffer. This means that vkCmdNextSubpass can be intermixed with the
3156 // rest of the commands, and there is no need to split command buffers.
3157 //
3158 // Note also that the command buffer handle doesn't change in this case.
3159 getCommandBuffer().nextSubpass(VK_SUBPASS_CONTENTS_INLINE);
3160 return angle::Result::Continue;
3161 }
3162
3163 // When using Vulkan secondary command buffers, each subpass's contents must be recorded in a
3164 // separate command buffer that is vkCmdExecuteCommands'ed in the primary command buffer.
3165 // vkCmdNextSubpass calls must also be issued in the primary command buffer.
3166 //
3167 // To support this, a list of command buffers are kept, one for each subpass. When moving to
3168 // the next subpass, the previous command buffer is ended and a new one is initialized and
3169 // begun.
3170
3171 // Accumulate command count for tracking purposes.
3172 mPreviousSubpassesCmdCount = getRenderPassWriteCommandCount();
3173
3174 ANGLE_TRY(endRenderPassCommandBuffer(contextVk));
3175 markClosed();
3176
3177 ++mCurrentSubpassCommandBufferIndex;
3178 ASSERT(getSubpassCommandBufferCount() <= kMaxSubpassCount);
3179
3180 ANGLE_TRY(initializeCommandBuffer(contextVk));
3181 ANGLE_TRY(beginRenderPassCommandBuffer(contextVk));
3182 markOpen();
3183
3184 // Return the new command buffer handle
3185 *commandBufferOut = &getCommandBuffer();
3186 return angle::Result::Continue;
3187 }
3188
beginTransformFeedback(size_t validBufferCount,const VkBuffer * counterBuffers,const VkDeviceSize * counterBufferOffsets,bool rebindBuffers)3189 void RenderPassCommandBufferHelper::beginTransformFeedback(size_t validBufferCount,
3190 const VkBuffer *counterBuffers,
3191 const VkDeviceSize *counterBufferOffsets,
3192 bool rebindBuffers)
3193 {
3194 mValidTransformFeedbackBufferCount = static_cast<uint32_t>(validBufferCount);
3195 mRebindTransformFeedbackBuffers = rebindBuffers;
3196
3197 for (size_t index = 0; index < validBufferCount; index++)
3198 {
3199 mTransformFeedbackCounterBuffers[index] = counterBuffers[index];
3200 mTransformFeedbackCounterBufferOffsets[index] = counterBufferOffsets[index];
3201 }
3202 }
3203
endTransformFeedback()3204 void RenderPassCommandBufferHelper::endTransformFeedback()
3205 {
3206 pauseTransformFeedback();
3207 mValidTransformFeedbackBufferCount = 0;
3208 }
3209
invalidateRenderPassColorAttachment(const gl::State & state,size_t colorIndexGL,PackedAttachmentIndex attachmentIndex,const gl::Rectangle & invalidateArea)3210 void RenderPassCommandBufferHelper::invalidateRenderPassColorAttachment(
3211 const gl::State &state,
3212 size_t colorIndexGL,
3213 PackedAttachmentIndex attachmentIndex,
3214 const gl::Rectangle &invalidateArea)
3215 {
3216 // Color write is enabled if:
3217 //
3218 // - Draw buffer is enabled (this is implicit, as invalidate only affects enabled draw buffers)
3219 // - Color output is not entirely masked
3220 // - Rasterizer-discard is not enabled
3221 const gl::BlendStateExt &blendStateExt = state.getBlendStateExt();
3222 const bool isColorWriteEnabled =
3223 blendStateExt.getColorMaskIndexed(colorIndexGL) != 0 && !state.isRasterizerDiscardEnabled();
3224 mColorAttachments[attachmentIndex].invalidate(invalidateArea, isColorWriteEnabled,
3225 getRenderPassWriteCommandCount());
3226 }
3227
invalidateRenderPassDepthAttachment(const gl::DepthStencilState & dsState,const gl::Rectangle & invalidateArea)3228 void RenderPassCommandBufferHelper::invalidateRenderPassDepthAttachment(
3229 const gl::DepthStencilState &dsState,
3230 const gl::Rectangle &invalidateArea)
3231 {
3232 const bool isDepthWriteEnabled = dsState.depthTest && dsState.depthMask;
3233 mDepthAttachment.invalidate(invalidateArea, isDepthWriteEnabled,
3234 getRenderPassWriteCommandCount());
3235 }
3236
invalidateRenderPassStencilAttachment(const gl::DepthStencilState & dsState,GLuint framebufferStencilSize,const gl::Rectangle & invalidateArea)3237 void RenderPassCommandBufferHelper::invalidateRenderPassStencilAttachment(
3238 const gl::DepthStencilState &dsState,
3239 GLuint framebufferStencilSize,
3240 const gl::Rectangle &invalidateArea)
3241 {
3242 const bool isStencilWriteEnabled =
3243 dsState.stencilTest && (!dsState.isStencilNoOp(framebufferStencilSize) ||
3244 !dsState.isStencilBackNoOp(framebufferStencilSize));
3245 mStencilAttachment.invalidate(invalidateArea, isStencilWriteEnabled,
3246 getRenderPassWriteCommandCount());
3247 }
3248
flushToPrimary(Context * context,CommandsState * commandsState,const RenderPass & renderPass,VkFramebuffer framebufferOverride)3249 angle::Result RenderPassCommandBufferHelper::flushToPrimary(Context *context,
3250 CommandsState *commandsState,
3251 const RenderPass &renderPass,
3252 VkFramebuffer framebufferOverride)
3253 {
3254 Renderer *renderer = context->getRenderer();
3255 // |framebufferOverride| must only be provided if the initial framebuffer the render pass was
3256 // started with is not usable (due to the addition of resolve attachments after the fact).
3257 ASSERT(framebufferOverride == VK_NULL_HANDLE ||
3258 mFramebuffer.needsNewFramebufferWithResolveAttachments());
3259 // When a new framebuffer had to be created because of addition of resolve attachments, it's
3260 // never imageless.
3261 ASSERT(!(framebufferOverride != VK_NULL_HANDLE && mFramebuffer.isImageless()));
3262
3263 ANGLE_TRACE_EVENT0("gpu.angle", "RenderPassCommandBufferHelper::flushToPrimary");
3264 ASSERT(mRenderPassStarted);
3265 PrimaryCommandBuffer &primary = commandsState->primaryCommands;
3266
3267 // Commands that are added to primary before beginRenderPass command
3268 executeBarriers(renderer, commandsState);
3269
3270 constexpr VkSubpassContents kSubpassContents =
3271 ExecutesInline() ? VK_SUBPASS_CONTENTS_INLINE
3272 : VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS;
3273
3274 if (!renderPass.valid())
3275 {
3276 mRenderPassDesc.beginRendering(context, &primary, mRenderArea, kSubpassContents,
3277 mFramebuffer.getUnpackedImageViews(), mAttachmentOps,
3278 mClearValues, mFramebuffer.getLayers());
3279 }
3280 else
3281 {
3282 // With imageless framebuffers, the attachments should be also added to beginInfo.
3283 VkRenderPassAttachmentBeginInfo attachmentBeginInfo = {};
3284 if (mFramebuffer.isImageless())
3285 {
3286 mFramebuffer.packResolveViewsForRenderPassBegin(&attachmentBeginInfo);
3287
3288 // If nullColorAttachmentWithExternalFormatResolve is true, there will be no color
3289 // attachment even though mRenderPassDesc indicates so.
3290 ASSERT((mRenderPassDesc.hasYUVResolveAttachment() &&
3291 renderer->nullColorAttachmentWithExternalFormatResolve()) ||
3292 attachmentBeginInfo.attachmentCount == mRenderPassDesc.attachmentCount());
3293 }
3294
3295 mRenderPassDesc.beginRenderPass(
3296 context, &primary, renderPass,
3297 framebufferOverride ? framebufferOverride : mFramebuffer.getFramebuffer().getHandle(),
3298 mRenderArea, kSubpassContents, mClearValues,
3299 mFramebuffer.isImageless() ? &attachmentBeginInfo : nullptr);
3300 }
3301
3302 // Run commands inside the RenderPass.
3303 for (uint32_t subpass = 0; subpass < getSubpassCommandBufferCount(); ++subpass)
3304 {
3305 if (subpass > 0)
3306 {
3307 ASSERT(!context->getFeatures().preferDynamicRendering.enabled);
3308 primary.nextSubpass(kSubpassContents);
3309 }
3310 mCommandBuffers[subpass].executeCommands(&primary);
3311 }
3312
3313 if (!renderPass.valid())
3314 {
3315 primary.endRendering();
3316
3317 if (mImageOptimizeForPresent != nullptr)
3318 {
3319 // finalizeColorImageLayout forces layout to Present. If this is not the case, that
3320 // code was not run (so mImageOptimizeForPresentOriginalLayout is invalid).
3321 ASSERT(mImageOptimizeForPresent->getCurrentImageLayout() == ImageLayout::Present);
3322
3323 // Restore the original layout of the image and do the real transition after the render
3324 // pass ends.
3325 mImageOptimizeForPresent->setCurrentImageLayout(renderer,
3326 mImageOptimizeForPresentOriginalLayout);
3327 mImageOptimizeForPresent->recordWriteBarrierOneOff(renderer, ImageLayout::Present,
3328 &primary, nullptr);
3329 mImageOptimizeForPresent = nullptr;
3330 mImageOptimizeForPresentOriginalLayout = ImageLayout::Undefined;
3331 }
3332 }
3333 else
3334 {
3335 primary.endRenderPass();
3336 }
3337
3338 // Now issue VkCmdSetEvents to primary command buffer
3339 ASSERT(mRefCountedEvents.empty());
3340 mVkEventArray.flushSetEvents(&primary);
3341
3342 // Restart the command buffer.
3343 return reset(context, &commandsState->secondaryCommands);
3344 }
3345
addColorResolveAttachment(size_t colorIndexGL,ImageHelper * image,VkImageView view,gl::LevelIndex level,uint32_t layerStart,uint32_t layerCount,UniqueSerial imageSiblingSerial)3346 void RenderPassCommandBufferHelper::addColorResolveAttachment(size_t colorIndexGL,
3347 ImageHelper *image,
3348 VkImageView view,
3349 gl::LevelIndex level,
3350 uint32_t layerStart,
3351 uint32_t layerCount,
3352 UniqueSerial imageSiblingSerial)
3353 {
3354 mFramebuffer.addColorResolveAttachment(colorIndexGL, view);
3355 mRenderPassDesc.packColorResolveAttachment(colorIndexGL);
3356
3357 PackedAttachmentIndex packedAttachmentIndex =
3358 mRenderPassDesc.getPackedColorAttachmentIndex(colorIndexGL);
3359 ASSERT(mColorResolveAttachments[packedAttachmentIndex].getImage() == nullptr);
3360
3361 image->onRenderPassAttach(mQueueSerial);
3362 mColorResolveAttachments[packedAttachmentIndex].init(
3363 image, imageSiblingSerial, level, layerStart, layerCount, VK_IMAGE_ASPECT_COLOR_BIT);
3364 }
3365
addDepthStencilResolveAttachment(ImageHelper * image,VkImageView view,VkImageAspectFlags aspects,gl::LevelIndex level,uint32_t layerStart,uint32_t layerCount,UniqueSerial imageSiblingSerial)3366 void RenderPassCommandBufferHelper::addDepthStencilResolveAttachment(
3367 ImageHelper *image,
3368 VkImageView view,
3369 VkImageAspectFlags aspects,
3370 gl::LevelIndex level,
3371 uint32_t layerStart,
3372 uint32_t layerCount,
3373 UniqueSerial imageSiblingSerial)
3374 {
3375 mFramebuffer.addDepthStencilResolveAttachment(view);
3376 if ((aspects & VK_IMAGE_ASPECT_DEPTH_BIT) != 0)
3377 {
3378 mRenderPassDesc.packDepthResolveAttachment();
3379 }
3380 if ((aspects & VK_IMAGE_ASPECT_STENCIL_BIT) != 0)
3381 {
3382 mRenderPassDesc.packStencilResolveAttachment();
3383 }
3384
3385 image->onRenderPassAttach(mQueueSerial);
3386 mDepthResolveAttachment.init(image, imageSiblingSerial, level, layerStart, layerCount,
3387 VK_IMAGE_ASPECT_DEPTH_BIT);
3388 mStencilResolveAttachment.init(image, imageSiblingSerial, level, layerStart, layerCount,
3389 VK_IMAGE_ASPECT_STENCIL_BIT);
3390 }
3391
resumeTransformFeedback()3392 void RenderPassCommandBufferHelper::resumeTransformFeedback()
3393 {
3394 ASSERT(isTransformFeedbackStarted());
3395
3396 uint32_t numCounterBuffers =
3397 mRebindTransformFeedbackBuffers ? 0 : mValidTransformFeedbackBufferCount;
3398
3399 mRebindTransformFeedbackBuffers = false;
3400 mIsTransformFeedbackActiveUnpaused = true;
3401
3402 getCommandBuffer().beginTransformFeedback(0, numCounterBuffers,
3403 mTransformFeedbackCounterBuffers.data(),
3404 mTransformFeedbackCounterBufferOffsets.data());
3405 }
3406
pauseTransformFeedback()3407 void RenderPassCommandBufferHelper::pauseTransformFeedback()
3408 {
3409 ASSERT(isTransformFeedbackStarted() && isTransformFeedbackActiveUnpaused());
3410 mIsTransformFeedbackActiveUnpaused = false;
3411 getCommandBuffer().endTransformFeedback(0, mValidTransformFeedbackBufferCount,
3412 mTransformFeedbackCounterBuffers.data(),
3413 mTransformFeedbackCounterBufferOffsets.data());
3414 }
3415
updateRenderPassColorClear(PackedAttachmentIndex colorIndexVk,const VkClearValue & clearValue)3416 void RenderPassCommandBufferHelper::updateRenderPassColorClear(PackedAttachmentIndex colorIndexVk,
3417 const VkClearValue &clearValue)
3418 {
3419 mAttachmentOps.setClearOp(colorIndexVk);
3420 mClearValues.storeColor(colorIndexVk, clearValue);
3421 }
3422
updateRenderPassDepthStencilClear(VkImageAspectFlags aspectFlags,const VkClearValue & clearValue)3423 void RenderPassCommandBufferHelper::updateRenderPassDepthStencilClear(
3424 VkImageAspectFlags aspectFlags,
3425 const VkClearValue &clearValue)
3426 {
3427 // Don't overwrite prior clear values for individual aspects.
3428 VkClearValue combinedClearValue = mClearValues[mDepthStencilAttachmentIndex];
3429
3430 if ((aspectFlags & VK_IMAGE_ASPECT_DEPTH_BIT) != 0)
3431 {
3432 mAttachmentOps.setClearOp(mDepthStencilAttachmentIndex);
3433 combinedClearValue.depthStencil.depth = clearValue.depthStencil.depth;
3434 }
3435
3436 if ((aspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) != 0)
3437 {
3438 mAttachmentOps.setClearStencilOp(mDepthStencilAttachmentIndex);
3439 combinedClearValue.depthStencil.stencil = clearValue.depthStencil.stencil;
3440 }
3441
3442 // Bypass special D/S handling. This clear values array stores values packed.
3443 mClearValues.storeDepthStencil(mDepthStencilAttachmentIndex, combinedClearValue);
3444 }
3445
growRenderArea(ContextVk * contextVk,const gl::Rectangle & newRenderArea)3446 void RenderPassCommandBufferHelper::growRenderArea(ContextVk *contextVk,
3447 const gl::Rectangle &newRenderArea)
3448 {
3449 // The render area is grown such that it covers both the previous and the new render areas.
3450 gl::GetEnclosingRectangle(mRenderArea, newRenderArea, &mRenderArea);
3451
3452 // Remove invalidates that are no longer applicable.
3453 mDepthAttachment.onRenderAreaGrowth(contextVk, mRenderArea);
3454 mStencilAttachment.onRenderAreaGrowth(contextVk, mRenderArea);
3455 }
3456
attachCommandPool(ErrorContext * context,SecondaryCommandPool * commandPool)3457 angle::Result RenderPassCommandBufferHelper::attachCommandPool(ErrorContext *context,
3458 SecondaryCommandPool *commandPool)
3459 {
3460 ASSERT(!mRenderPassStarted);
3461 ASSERT(getSubpassCommandBufferCount() == 1);
3462 return attachCommandPoolImpl<RenderPassCommandBufferHelper>(context, commandPool);
3463 }
3464
detachCommandPool(SecondaryCommandPool ** commandPoolOut)3465 void RenderPassCommandBufferHelper::detachCommandPool(SecondaryCommandPool **commandPoolOut)
3466 {
3467 ASSERT(mRenderPassStarted);
3468 angle::Result result =
3469 detachCommandPoolImpl<RenderPassCommandBufferHelper, true>(nullptr, commandPoolOut);
3470 ASSERT(result == angle::Result::Continue);
3471 }
3472
releaseCommandPool()3473 void RenderPassCommandBufferHelper::releaseCommandPool()
3474 {
3475 ASSERT(!mRenderPassStarted);
3476 ASSERT(getSubpassCommandBufferCount() == 1);
3477 releaseCommandPoolImpl<RenderPassCommandBufferHelper>();
3478 }
3479
attachAllocator(SecondaryCommandMemoryAllocator * allocator)3480 void RenderPassCommandBufferHelper::attachAllocator(SecondaryCommandMemoryAllocator *allocator)
3481 {
3482 ASSERT(CheckSubpassCommandBufferCount(getSubpassCommandBufferCount()));
3483 attachAllocatorImpl<RenderPassCommandBufferHelper>(allocator);
3484 }
3485
detachAllocator()3486 SecondaryCommandMemoryAllocator *RenderPassCommandBufferHelper::detachAllocator()
3487 {
3488 ASSERT(CheckSubpassCommandBufferCount(getSubpassCommandBufferCount()));
3489 return detachAllocatorImpl<RenderPassCommandBufferHelper>();
3490 }
3491
assertCanBeRecycled()3492 void RenderPassCommandBufferHelper::assertCanBeRecycled()
3493 {
3494 ASSERT(!mRenderPassStarted);
3495 ASSERT(getSubpassCommandBufferCount() == 1);
3496 assertCanBeRecycledImpl<RenderPassCommandBufferHelper>();
3497 }
3498
getCommandDiagnostics()3499 std::string RenderPassCommandBufferHelper::getCommandDiagnostics()
3500 {
3501 std::ostringstream out;
3502 addCommandDiagnosticsCommon(&out);
3503
3504 size_t attachmentCount = mRenderPassDesc.clearableAttachmentCount();
3505 size_t depthStencilAttachmentCount = mRenderPassDesc.hasDepthStencilAttachment() ? 1 : 0;
3506 size_t colorAttachmentCount = attachmentCount - depthStencilAttachmentCount;
3507
3508 PackedAttachmentIndex attachmentIndexVk(0);
3509 std::string loadOps, storeOps;
3510
3511 if (colorAttachmentCount > 0)
3512 {
3513 loadOps += " Color: ";
3514 storeOps += " Color: ";
3515
3516 for (size_t i = 0; i < colorAttachmentCount; ++i)
3517 {
3518 loadOps += GetLoadOpShorthand(
3519 static_cast<RenderPassLoadOp>(mAttachmentOps[attachmentIndexVk].loadOp));
3520 storeOps += GetStoreOpShorthand(
3521 static_cast<RenderPassStoreOp>(mAttachmentOps[attachmentIndexVk].storeOp));
3522 ++attachmentIndexVk;
3523 }
3524 }
3525
3526 if (depthStencilAttachmentCount > 0)
3527 {
3528 ASSERT(depthStencilAttachmentCount == 1);
3529
3530 loadOps += " Depth/Stencil: ";
3531 storeOps += " Depth/Stencil: ";
3532
3533 loadOps += GetLoadOpShorthand(
3534 static_cast<RenderPassLoadOp>(mAttachmentOps[attachmentIndexVk].loadOp));
3535 loadOps += GetLoadOpShorthand(
3536 static_cast<RenderPassLoadOp>(mAttachmentOps[attachmentIndexVk].stencilLoadOp));
3537
3538 storeOps += GetStoreOpShorthand(
3539 static_cast<RenderPassStoreOp>(mAttachmentOps[attachmentIndexVk].storeOp));
3540 storeOps += GetStoreOpShorthand(
3541 static_cast<RenderPassStoreOp>(mAttachmentOps[attachmentIndexVk].stencilStoreOp));
3542 }
3543
3544 if (attachmentCount > 0)
3545 {
3546 out << "LoadOp: " << loadOps << "\\l";
3547 out << "StoreOp: " << storeOps << "\\l";
3548 }
3549
3550 for (uint32_t subpass = 0; subpass < getSubpassCommandBufferCount(); ++subpass)
3551 {
3552 if (subpass > 0)
3553 {
3554 out << "Next Subpass" << "\\l";
3555 }
3556 out << mCommandBuffers[subpass].dumpCommands("\\l");
3557 }
3558
3559 return out.str();
3560 }
3561
3562 // CommandBufferRecycler implementation.
3563 template <typename CommandBufferHelperT>
onDestroy()3564 void CommandBufferRecycler<CommandBufferHelperT>::onDestroy()
3565 {
3566 std::unique_lock<angle::SimpleMutex> lock(mMutex);
3567 for (CommandBufferHelperT *commandBufferHelper : mCommandBufferHelperFreeList)
3568 {
3569 SafeDelete(commandBufferHelper);
3570 }
3571 mCommandBufferHelperFreeList.clear();
3572 }
3573
3574 template void CommandBufferRecycler<OutsideRenderPassCommandBufferHelper>::onDestroy();
3575 template void CommandBufferRecycler<RenderPassCommandBufferHelper>::onDestroy();
3576
3577 template <typename CommandBufferHelperT>
getCommandBufferHelper(ErrorContext * context,SecondaryCommandPool * commandPool,SecondaryCommandMemoryAllocator * commandsAllocator,CommandBufferHelperT ** commandBufferHelperOut)3578 angle::Result CommandBufferRecycler<CommandBufferHelperT>::getCommandBufferHelper(
3579 ErrorContext *context,
3580 SecondaryCommandPool *commandPool,
3581 SecondaryCommandMemoryAllocator *commandsAllocator,
3582 CommandBufferHelperT **commandBufferHelperOut)
3583 {
3584 std::unique_lock<angle::SimpleMutex> lock(mMutex);
3585 if (mCommandBufferHelperFreeList.empty())
3586 {
3587 CommandBufferHelperT *commandBuffer = new CommandBufferHelperT();
3588 *commandBufferHelperOut = commandBuffer;
3589 ANGLE_TRY(commandBuffer->initialize(context));
3590 }
3591 else
3592 {
3593 CommandBufferHelperT *commandBuffer = mCommandBufferHelperFreeList.back();
3594 mCommandBufferHelperFreeList.pop_back();
3595 *commandBufferHelperOut = commandBuffer;
3596 }
3597
3598 ANGLE_TRY((*commandBufferHelperOut)->attachCommandPool(context, commandPool));
3599
3600 // Attach functions are only used for ring buffer allocators.
3601 (*commandBufferHelperOut)->attachAllocator(commandsAllocator);
3602
3603 return angle::Result::Continue;
3604 }
3605
3606 template angle::Result
3607 CommandBufferRecycler<OutsideRenderPassCommandBufferHelper>::getCommandBufferHelper(
3608 ErrorContext *,
3609 SecondaryCommandPool *,
3610 SecondaryCommandMemoryAllocator *,
3611 OutsideRenderPassCommandBufferHelper **);
3612 template angle::Result CommandBufferRecycler<RenderPassCommandBufferHelper>::getCommandBufferHelper(
3613 ErrorContext *,
3614 SecondaryCommandPool *,
3615 SecondaryCommandMemoryAllocator *,
3616 RenderPassCommandBufferHelper **);
3617
3618 template <typename CommandBufferHelperT>
recycleCommandBufferHelper(CommandBufferHelperT ** commandBuffer)3619 void CommandBufferRecycler<CommandBufferHelperT>::recycleCommandBufferHelper(
3620 CommandBufferHelperT **commandBuffer)
3621 {
3622 (*commandBuffer)->assertCanBeRecycled();
3623 (*commandBuffer)->markOpen();
3624
3625 {
3626 std::unique_lock<angle::SimpleMutex> lock(mMutex);
3627 mCommandBufferHelperFreeList.push_back(*commandBuffer);
3628 }
3629
3630 *commandBuffer = nullptr;
3631 }
3632
3633 template void
3634 CommandBufferRecycler<OutsideRenderPassCommandBufferHelper>::recycleCommandBufferHelper(
3635 OutsideRenderPassCommandBufferHelper **);
3636 template void CommandBufferRecycler<RenderPassCommandBufferHelper>::recycleCommandBufferHelper(
3637 RenderPassCommandBufferHelper **);
3638
3639 // SecondaryCommandBufferCollector implementation.
collectCommandBuffer(priv::SecondaryCommandBuffer && commandBuffer)3640 void SecondaryCommandBufferCollector::collectCommandBuffer(
3641 priv::SecondaryCommandBuffer &&commandBuffer)
3642 {
3643 commandBuffer.reset();
3644 }
3645
collectCommandBuffer(VulkanSecondaryCommandBuffer && commandBuffer)3646 void SecondaryCommandBufferCollector::collectCommandBuffer(
3647 VulkanSecondaryCommandBuffer &&commandBuffer)
3648 {
3649 ASSERT(commandBuffer.valid());
3650 mCollectedCommandBuffers.emplace_back(std::move(commandBuffer));
3651 }
3652
releaseCommandBuffers()3653 void SecondaryCommandBufferCollector::releaseCommandBuffers()
3654 {
3655 // Note: we currently free the command buffers individually, but we could potentially reset the
3656 // entire command pool. https://issuetracker.google.com/issues/166793850
3657 for (VulkanSecondaryCommandBuffer &commandBuffer : mCollectedCommandBuffers)
3658 {
3659 commandBuffer.destroy();
3660 }
3661 mCollectedCommandBuffers.clear();
3662 }
3663
3664 // DynamicBuffer implementation.
DynamicBuffer()3665 DynamicBuffer::DynamicBuffer()
3666 : mUsage(0),
3667 mHostVisible(false),
3668 mInitialSize(0),
3669 mNextAllocationOffset(0),
3670 mSize(0),
3671 mSizeInRecentHistory(0),
3672 mAlignment(0),
3673 mMemoryPropertyFlags(0)
3674 {}
3675
DynamicBuffer(DynamicBuffer && other)3676 DynamicBuffer::DynamicBuffer(DynamicBuffer &&other)
3677 : mUsage(other.mUsage),
3678 mHostVisible(other.mHostVisible),
3679 mInitialSize(other.mInitialSize),
3680 mBuffer(std::move(other.mBuffer)),
3681 mNextAllocationOffset(other.mNextAllocationOffset),
3682 mSize(other.mSize),
3683 mSizeInRecentHistory(other.mSizeInRecentHistory),
3684 mAlignment(other.mAlignment),
3685 mMemoryPropertyFlags(other.mMemoryPropertyFlags),
3686 mInFlightBuffers(std::move(other.mInFlightBuffers)),
3687 mBufferFreeList(std::move(other.mBufferFreeList))
3688 {}
3689
init(Renderer * renderer,VkBufferUsageFlags usage,size_t alignment,size_t initialSize,bool hostVisible)3690 void DynamicBuffer::init(Renderer *renderer,
3691 VkBufferUsageFlags usage,
3692 size_t alignment,
3693 size_t initialSize,
3694 bool hostVisible)
3695 {
3696 mUsage = usage;
3697 mHostVisible = hostVisible;
3698 mMemoryPropertyFlags =
3699 (hostVisible) ? VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT : VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
3700
3701 if (hostVisible && renderer->getFeatures().preferHostCachedForNonStaticBufferUsage.enabled)
3702 {
3703 mMemoryPropertyFlags |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
3704 }
3705
3706 // Check that we haven't overridden the initial size of the buffer in setMinimumSizeForTesting.
3707 if (mInitialSize == 0)
3708 {
3709 mInitialSize = initialSize;
3710 mSize = 0;
3711 mSizeInRecentHistory = initialSize;
3712 }
3713
3714 // Workaround for the mock ICD not supporting allocations greater than 0x1000.
3715 // Could be removed if https://github.com/KhronosGroup/Vulkan-Tools/issues/84 is fixed.
3716 if (renderer->isMockICDEnabled())
3717 {
3718 mSize = std::min<size_t>(mSize, 0x1000);
3719 }
3720
3721 requireAlignment(renderer, alignment);
3722 }
3723
~DynamicBuffer()3724 DynamicBuffer::~DynamicBuffer()
3725 {
3726 ASSERT(mBuffer == nullptr);
3727 ASSERT(mInFlightBuffers.empty());
3728 ASSERT(mBufferFreeList.empty());
3729 }
3730
allocateNewBuffer(ErrorContext * context)3731 angle::Result DynamicBuffer::allocateNewBuffer(ErrorContext *context)
3732 {
3733 context->getPerfCounters().dynamicBufferAllocations++;
3734
3735 // Allocate the buffer
3736 ASSERT(!mBuffer);
3737 mBuffer = std::make_unique<BufferHelper>();
3738
3739 VkBufferCreateInfo createInfo = {};
3740 createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
3741 createInfo.flags = 0;
3742 createInfo.size = mSize;
3743 createInfo.usage = mUsage;
3744 createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
3745 createInfo.queueFamilyIndexCount = 0;
3746 createInfo.pQueueFamilyIndices = nullptr;
3747
3748 return mBuffer->init(context, createInfo, mMemoryPropertyFlags);
3749 }
3750
allocateFromCurrentBuffer(size_t sizeInBytes,BufferHelper ** bufferHelperOut)3751 bool DynamicBuffer::allocateFromCurrentBuffer(size_t sizeInBytes, BufferHelper **bufferHelperOut)
3752 {
3753 mNextAllocationOffset =
3754 roundUp<uint32_t>(mNextAllocationOffset, static_cast<uint32_t>(mAlignment));
3755
3756 ASSERT(bufferHelperOut);
3757 size_t sizeToAllocate = roundUp(sizeInBytes, mAlignment);
3758 angle::base::CheckedNumeric<size_t> checkedNextWriteOffset = mNextAllocationOffset;
3759 checkedNextWriteOffset += sizeToAllocate;
3760
3761 if (!checkedNextWriteOffset.IsValid() || checkedNextWriteOffset.ValueOrDie() > mSize)
3762 {
3763 return false;
3764 }
3765
3766 ASSERT(mBuffer != nullptr);
3767 ASSERT(mHostVisible);
3768 ASSERT(mBuffer->getMappedMemory());
3769 mBuffer->setSuballocationOffsetAndSize(mNextAllocationOffset, sizeToAllocate);
3770 *bufferHelperOut = mBuffer.get();
3771
3772 mNextAllocationOffset += static_cast<uint32_t>(sizeToAllocate);
3773 return true;
3774 }
3775
allocate(Context * context,size_t sizeInBytes,BufferHelper ** bufferHelperOut,bool * newBufferAllocatedOut)3776 angle::Result DynamicBuffer::allocate(Context *context,
3777 size_t sizeInBytes,
3778 BufferHelper **bufferHelperOut,
3779 bool *newBufferAllocatedOut)
3780 {
3781 bool newBuffer = !allocateFromCurrentBuffer(sizeInBytes, bufferHelperOut);
3782 if (newBufferAllocatedOut)
3783 {
3784 *newBufferAllocatedOut = newBuffer;
3785 }
3786
3787 if (!newBuffer)
3788 {
3789 return angle::Result::Continue;
3790 }
3791
3792 size_t sizeToAllocate = roundUp(sizeInBytes, mAlignment);
3793
3794 if (mBuffer)
3795 {
3796 // Make sure the buffer is not released externally.
3797 ASSERT(mBuffer->valid());
3798 mInFlightBuffers.push_back(std::move(mBuffer));
3799 ASSERT(!mBuffer);
3800 }
3801
3802 Renderer *renderer = context->getRenderer();
3803
3804 const size_t minRequiredBlockSize = std::max(mInitialSize, sizeToAllocate);
3805
3806 // The average required buffer size in recent history is used to determine whether the currently
3807 // used buffer size needs to be reduced (when it goes below 1/8 of the current buffer size).
3808 constexpr uint32_t kDecayCoeffPercent = 20;
3809 static_assert(kDecayCoeffPercent >= 0 && kDecayCoeffPercent <= 100);
3810 mSizeInRecentHistory = (mSizeInRecentHistory * kDecayCoeffPercent +
3811 minRequiredBlockSize * (100 - kDecayCoeffPercent) + 50) /
3812 100;
3813
3814 if (sizeToAllocate > mSize || mSizeInRecentHistory < mSize / 8)
3815 {
3816 mSize = minRequiredBlockSize;
3817 // Clear the free list since the free buffers are now either too small or too big.
3818 ReleaseBufferListToRenderer(context, &mBufferFreeList);
3819 }
3820
3821 // The front of the free list should be the oldest. Thus if it is in use the rest of the
3822 // free list should be in use as well.
3823 if (mBufferFreeList.empty() ||
3824 !renderer->hasResourceUseFinished(mBufferFreeList.front()->getResourceUse()))
3825 {
3826 ANGLE_TRY(allocateNewBuffer(context));
3827 }
3828 else
3829 {
3830 mBuffer = std::move(mBufferFreeList.front());
3831 mBufferFreeList.pop_front();
3832 }
3833
3834 ASSERT(mBuffer->getBlockMemorySize() == mSize);
3835
3836 mNextAllocationOffset = 0;
3837
3838 ASSERT(mBuffer != nullptr);
3839 mBuffer->setSuballocationOffsetAndSize(mNextAllocationOffset, sizeToAllocate);
3840 *bufferHelperOut = mBuffer.get();
3841
3842 mNextAllocationOffset += static_cast<uint32_t>(sizeToAllocate);
3843 return angle::Result::Continue;
3844 }
3845
release(Context * context)3846 void DynamicBuffer::release(Context *context)
3847 {
3848 reset();
3849
3850 ReleaseBufferListToRenderer(context, &mInFlightBuffers);
3851 ReleaseBufferListToRenderer(context, &mBufferFreeList);
3852
3853 if (mBuffer)
3854 {
3855 mBuffer->release(context);
3856 mBuffer.reset(nullptr);
3857 }
3858 }
3859
updateQueueSerialAndReleaseInFlightBuffers(ContextVk * contextVk,const QueueSerial & queueSerial)3860 void DynamicBuffer::updateQueueSerialAndReleaseInFlightBuffers(ContextVk *contextVk,
3861 const QueueSerial &queueSerial)
3862 {
3863 for (std::unique_ptr<BufferHelper> &bufferHelper : mInFlightBuffers)
3864 {
3865 // This function is used only for internal buffers, and they are all read-only.
3866 // It's possible this may change in the future, but there isn't a good way to detect that,
3867 // unfortunately.
3868 bufferHelper->setQueueSerial(queueSerial);
3869
3870 // We only keep free buffers that have the same size. Note that bufferHelper's size is
3871 // suballocation's size. We need to use the whole block memory size here.
3872 if (bufferHelper->getBlockMemorySize() != mSize)
3873 {
3874 bufferHelper->release(contextVk);
3875 }
3876 else
3877 {
3878 mBufferFreeList.push_back(std::move(bufferHelper));
3879 }
3880 }
3881 mInFlightBuffers.clear();
3882 }
3883
destroy(Renderer * renderer)3884 void DynamicBuffer::destroy(Renderer *renderer)
3885 {
3886 reset();
3887
3888 DestroyBufferList(renderer, &mInFlightBuffers);
3889 DestroyBufferList(renderer, &mBufferFreeList);
3890
3891 if (mBuffer)
3892 {
3893 mBuffer->unmap(renderer);
3894 mBuffer->destroy(renderer);
3895 mBuffer.reset(nullptr);
3896 }
3897 }
3898
requireAlignment(Renderer * renderer,size_t alignment)3899 void DynamicBuffer::requireAlignment(Renderer *renderer, size_t alignment)
3900 {
3901 ASSERT(alignment > 0);
3902
3903 size_t prevAlignment = mAlignment;
3904
3905 // If alignment was never set, initialize it with the atom size limit.
3906 if (prevAlignment == 0)
3907 {
3908 prevAlignment =
3909 static_cast<size_t>(renderer->getPhysicalDeviceProperties().limits.nonCoherentAtomSize);
3910 ASSERT(gl::isPow2(prevAlignment));
3911 }
3912
3913 // We need lcm(prevAlignment, alignment). Usually, one divides the other so std::max() could be
3914 // used instead. Only known case where this assumption breaks is for 3-component types with
3915 // 16- or 32-bit channels, so that's special-cased to avoid a full-fledged lcm implementation.
3916
3917 if (gl::isPow2(prevAlignment * alignment))
3918 {
3919 ASSERT(alignment % prevAlignment == 0 || prevAlignment % alignment == 0);
3920
3921 alignment = std::max(prevAlignment, alignment);
3922 }
3923 else
3924 {
3925 ASSERT(prevAlignment % 3 != 0 || gl::isPow2(prevAlignment / 3));
3926 ASSERT(alignment % 3 != 0 || gl::isPow2(alignment / 3));
3927
3928 prevAlignment = prevAlignment % 3 == 0 ? prevAlignment / 3 : prevAlignment;
3929 alignment = alignment % 3 == 0 ? alignment / 3 : alignment;
3930
3931 alignment = std::max(prevAlignment, alignment) * 3;
3932 }
3933
3934 // If alignment has changed, make sure the next allocation is done at an aligned offset.
3935 if (alignment != mAlignment)
3936 {
3937 mNextAllocationOffset = roundUp(mNextAllocationOffset, static_cast<uint32_t>(alignment));
3938 }
3939
3940 mAlignment = alignment;
3941 }
3942
setMinimumSizeForTesting(size_t minSize)3943 void DynamicBuffer::setMinimumSizeForTesting(size_t minSize)
3944 {
3945 // This will really only have an effect next time we call allocate.
3946 mInitialSize = minSize;
3947
3948 // Forces a new allocation on the next allocate.
3949 mSize = 0;
3950 mSizeInRecentHistory = 0;
3951 }
3952
reset()3953 void DynamicBuffer::reset()
3954 {
3955 mSize = 0;
3956 mSizeInRecentHistory = 0;
3957 mNextAllocationOffset = 0;
3958 }
3959
3960 // BufferPool implementation.
BufferPool()3961 BufferPool::BufferPool()
3962 : mVirtualBlockCreateFlags(vma::VirtualBlockCreateFlagBits::GENERAL),
3963 mUsage(0),
3964 mHostVisible(false),
3965 mSize(0),
3966 mMemoryTypeIndex(0),
3967 mTotalMemorySize(0),
3968 mNumberOfNewBuffersNeededSinceLastPrune(0)
3969 {}
3970
BufferPool(BufferPool && other)3971 BufferPool::BufferPool(BufferPool &&other)
3972 : mVirtualBlockCreateFlags(other.mVirtualBlockCreateFlags),
3973 mUsage(other.mUsage),
3974 mHostVisible(other.mHostVisible),
3975 mSize(other.mSize),
3976 mMemoryTypeIndex(other.mMemoryTypeIndex)
3977 {}
3978
initWithFlags(Renderer * renderer,vma::VirtualBlockCreateFlags flags,VkBufferUsageFlags usage,VkDeviceSize initialSize,uint32_t memoryTypeIndex,VkMemoryPropertyFlags memoryPropertyFlags)3979 void BufferPool::initWithFlags(Renderer *renderer,
3980 vma::VirtualBlockCreateFlags flags,
3981 VkBufferUsageFlags usage,
3982 VkDeviceSize initialSize,
3983 uint32_t memoryTypeIndex,
3984 VkMemoryPropertyFlags memoryPropertyFlags)
3985 {
3986 mVirtualBlockCreateFlags = flags;
3987 mUsage = usage;
3988 mMemoryTypeIndex = memoryTypeIndex;
3989 if (initialSize)
3990 {
3991 // Should be power of two
3992 ASSERT(gl::isPow2(initialSize));
3993 mSize = initialSize;
3994 }
3995 else
3996 {
3997 mSize = renderer->getPreferedBufferBlockSize(memoryTypeIndex);
3998 }
3999 mHostVisible = ((memoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0);
4000 mBufferBlocks.reserve(32);
4001 }
4002
~BufferPool()4003 BufferPool::~BufferPool()
4004 {
4005 ASSERT(mBufferBlocks.empty());
4006 ASSERT(mEmptyBufferBlocks.empty());
4007 }
4008
pruneEmptyBuffers(Renderer * renderer)4009 void BufferPool::pruneEmptyBuffers(Renderer *renderer)
4010 {
4011 // Walk through mBuffers and move empty buffers to mEmptyBuffer and remove null
4012 // pointers for allocation performance.
4013 bool needsCompact = false;
4014 size_t nonEmptyBufferCount = 0;
4015 for (std::unique_ptr<BufferBlock> &block : mBufferBlocks)
4016 {
4017 if (block->isEmpty())
4018 {
4019 // We will always free empty buffers that has smaller size. Or if the empty buffer has
4020 // been found empty for long enough time, or we accumulated too many empty buffers, we
4021 // also free it.
4022 if (block->getMemorySize() < mSize)
4023 {
4024 mTotalMemorySize -= block->getMemorySize();
4025 block->destroy(renderer);
4026 block.reset();
4027 }
4028 else
4029 {
4030 mEmptyBufferBlocks.push_back(std::move(block));
4031 }
4032 needsCompact = true;
4033 }
4034 else
4035 {
4036 if (needsCompact)
4037 {
4038 mBufferBlocks[nonEmptyBufferCount] = std::move(block);
4039 }
4040 nonEmptyBufferCount++;
4041 }
4042 }
4043
4044 if (needsCompact)
4045 {
4046 mBufferBlocks.resize(nonEmptyBufferCount);
4047 }
4048
4049 // Decide how many empty buffers to keep around and trim down the excessive empty buffers. We
4050 // keep track of how many buffers are needed since last prune. Assume we are in stable state,
4051 // which means we may still need that many empty buffers in next prune cycle. To reduce chance
4052 // to call into vulkan driver to allocate new buffers, we try to keep that many empty buffers
4053 // around, subject to the maximum cap. If we overestimate, next cycle they used fewer buffers,
4054 // we will trim excessive empty buffers at next prune call. Or if we underestimate, we will end
4055 // up have to call into vulkan driver allocate new buffers, but next cycle we should correct
4056 // ourselves to keep enough number of empty buffers around.
4057 size_t buffersToKeep = std::min(mNumberOfNewBuffersNeededSinceLastPrune,
4058 static_cast<size_t>(kMaxTotalEmptyBufferBytes / mSize));
4059 while (mEmptyBufferBlocks.size() > buffersToKeep)
4060 {
4061 std::unique_ptr<BufferBlock> &block = mEmptyBufferBlocks.back();
4062 mTotalMemorySize -= block->getMemorySize();
4063 block->destroy(renderer);
4064 mEmptyBufferBlocks.pop_back();
4065 }
4066 mNumberOfNewBuffersNeededSinceLastPrune = 0;
4067 }
4068
allocateNewBuffer(ErrorContext * context,VkDeviceSize sizeInBytes)4069 VkResult BufferPool::allocateNewBuffer(ErrorContext *context, VkDeviceSize sizeInBytes)
4070 {
4071 Renderer *renderer = context->getRenderer();
4072 const Allocator &allocator = renderer->getAllocator();
4073
4074 VkDeviceSize heapSize =
4075 renderer->getMemoryProperties().getHeapSizeForMemoryType(mMemoryTypeIndex);
4076
4077 // First ensure we are not exceeding the heapSize to avoid the validation error.
4078 VK_RESULT_CHECK(sizeInBytes <= heapSize, VK_ERROR_OUT_OF_DEVICE_MEMORY);
4079
4080 // Double the size until meet the requirement. This also helps reducing the fragmentation. Since
4081 // this is global pool, we have less worry about memory waste.
4082 VkDeviceSize newSize = mSize;
4083 while (newSize < sizeInBytes)
4084 {
4085 newSize <<= 1;
4086 }
4087 mSize = std::min(newSize, heapSize);
4088
4089 // Allocate buffer
4090 VkBufferCreateInfo createInfo = {};
4091 createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4092 createInfo.flags = 0;
4093 createInfo.size = mSize;
4094 createInfo.usage = mUsage;
4095 createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
4096 createInfo.queueFamilyIndexCount = 0;
4097 createInfo.pQueueFamilyIndices = nullptr;
4098
4099 VkMemoryPropertyFlags memoryPropertyFlags;
4100 allocator.getMemoryTypeProperties(mMemoryTypeIndex, &memoryPropertyFlags);
4101
4102 DeviceScoped<Buffer> buffer(renderer->getDevice());
4103 VK_RESULT_TRY(buffer.get().init(context->getDevice(), createInfo));
4104
4105 DeviceScoped<DeviceMemory> deviceMemory(renderer->getDevice());
4106 VkMemoryPropertyFlags memoryPropertyFlagsOut;
4107 VkDeviceSize sizeOut;
4108 uint32_t memoryTypeIndex;
4109 VK_RESULT_TRY(AllocateBufferMemory(context, MemoryAllocationType::Buffer, memoryPropertyFlags,
4110 &memoryPropertyFlagsOut, nullptr, &buffer.get(),
4111 &memoryTypeIndex, &deviceMemory.get(), &sizeOut));
4112 ASSERT(sizeOut >= mSize);
4113
4114 // Allocate bufferBlock
4115 std::unique_ptr<BufferBlock> block = std::make_unique<BufferBlock>();
4116 VK_RESULT_TRY(block->init(context, buffer.get(), memoryTypeIndex, mVirtualBlockCreateFlags,
4117 deviceMemory.get(), memoryPropertyFlagsOut, mSize));
4118
4119 if (mHostVisible)
4120 {
4121 VK_RESULT_TRY(block->map(context->getDevice()));
4122 }
4123
4124 mTotalMemorySize += block->getMemorySize();
4125 // Append the bufferBlock into the pool
4126 mBufferBlocks.push_back(std::move(block));
4127 context->getPerfCounters().allocateNewBufferBlockCalls++;
4128
4129 return VK_SUCCESS;
4130 }
4131
allocateBuffer(ErrorContext * context,VkDeviceSize sizeInBytes,VkDeviceSize alignment,BufferSuballocation * suballocation)4132 VkResult BufferPool::allocateBuffer(ErrorContext *context,
4133 VkDeviceSize sizeInBytes,
4134 VkDeviceSize alignment,
4135 BufferSuballocation *suballocation)
4136 {
4137 ASSERT(alignment);
4138 VmaVirtualAllocation allocation;
4139 VkDeviceSize offset;
4140 VkDeviceSize alignedSize = roundUp(sizeInBytes, alignment);
4141
4142 if (alignedSize >= kMaxBufferSizeForSuballocation)
4143 {
4144 VkDeviceSize heapSize =
4145 context->getRenderer()->getMemoryProperties().getHeapSizeForMemoryType(
4146 mMemoryTypeIndex);
4147 // First ensure we are not exceeding the heapSize to avoid the validation error.
4148 VK_RESULT_CHECK(sizeInBytes <= heapSize, VK_ERROR_OUT_OF_DEVICE_MEMORY);
4149
4150 // Allocate buffer
4151 VkBufferCreateInfo createInfo = {};
4152 createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4153 createInfo.flags = 0;
4154 createInfo.size = alignedSize;
4155 createInfo.usage = mUsage;
4156 createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
4157 createInfo.queueFamilyIndexCount = 0;
4158 createInfo.pQueueFamilyIndices = nullptr;
4159
4160 VkMemoryPropertyFlags memoryPropertyFlags;
4161 const Allocator &allocator = context->getRenderer()->getAllocator();
4162 allocator.getMemoryTypeProperties(mMemoryTypeIndex, &memoryPropertyFlags);
4163
4164 DeviceScoped<Buffer> buffer(context->getDevice());
4165 VK_RESULT_TRY(buffer.get().init(context->getDevice(), createInfo));
4166
4167 DeviceScoped<DeviceMemory> deviceMemory(context->getDevice());
4168 VkMemoryPropertyFlags memoryPropertyFlagsOut;
4169 VkDeviceSize sizeOut;
4170 uint32_t memoryTypeIndex;
4171 VK_RESULT_TRY(AllocateBufferMemory(
4172 context, MemoryAllocationType::Buffer, memoryPropertyFlags, &memoryPropertyFlagsOut,
4173 nullptr, &buffer.get(), &memoryTypeIndex, &deviceMemory.get(), &sizeOut));
4174 ASSERT(sizeOut >= alignedSize);
4175
4176 suballocation->initWithEntireBuffer(context, buffer.get(), MemoryAllocationType::Buffer,
4177 memoryTypeIndex, deviceMemory.get(),
4178 memoryPropertyFlagsOut, alignedSize, sizeOut);
4179 if (mHostVisible)
4180 {
4181 VK_RESULT_TRY(suballocation->map(context));
4182 }
4183 return VK_SUCCESS;
4184 }
4185
4186 // We always allocate from reverse order so that older buffers have a chance to be empty. The
4187 // assumption is that to allocate from new buffers first may have a better chance to leave the
4188 // older buffers completely empty and we may able to free it.
4189 for (auto iter = mBufferBlocks.rbegin(); iter != mBufferBlocks.rend();)
4190 {
4191 std::unique_ptr<BufferBlock> &block = *iter;
4192 if (block->isEmpty() && block->getMemorySize() < mSize)
4193 {
4194 // Don't try to allocate from an empty buffer that has smaller size. It will get
4195 // released when pruneEmptyBuffers get called later on.
4196 ++iter;
4197 continue;
4198 }
4199
4200 if (block->allocate(alignedSize, alignment, &allocation, &offset) == VK_SUCCESS)
4201 {
4202 suballocation->init(block.get(), allocation, offset, alignedSize);
4203 return VK_SUCCESS;
4204 }
4205 ++iter;
4206 }
4207
4208 // Try to allocate from empty buffers
4209 while (!mEmptyBufferBlocks.empty())
4210 {
4211 std::unique_ptr<BufferBlock> &block = mEmptyBufferBlocks.back();
4212 if (block->getMemorySize() < mSize)
4213 {
4214 mTotalMemorySize -= block->getMemorySize();
4215 block->destroy(context->getRenderer());
4216 mEmptyBufferBlocks.pop_back();
4217 }
4218 else
4219 {
4220 VK_RESULT_TRY(block->allocate(alignedSize, alignment, &allocation, &offset));
4221 suballocation->init(block.get(), allocation, offset, alignedSize);
4222 mBufferBlocks.push_back(std::move(block));
4223 mEmptyBufferBlocks.pop_back();
4224 mNumberOfNewBuffersNeededSinceLastPrune++;
4225 return VK_SUCCESS;
4226 }
4227 }
4228
4229 // Failed to allocate from empty buffer. Now try to allocate a new buffer.
4230 VK_RESULT_TRY(allocateNewBuffer(context, alignedSize));
4231
4232 // Sub-allocate from the bufferBlock.
4233 std::unique_ptr<BufferBlock> &block = mBufferBlocks.back();
4234 VK_RESULT_CHECK(block->allocate(alignedSize, alignment, &allocation, &offset) == VK_SUCCESS,
4235 VK_ERROR_OUT_OF_DEVICE_MEMORY);
4236 suballocation->init(block.get(), allocation, offset, alignedSize);
4237 mNumberOfNewBuffersNeededSinceLastPrune++;
4238
4239 return VK_SUCCESS;
4240 }
4241
destroy(Renderer * renderer,bool orphanNonEmptyBufferBlock)4242 void BufferPool::destroy(Renderer *renderer, bool orphanNonEmptyBufferBlock)
4243 {
4244 for (std::unique_ptr<BufferBlock> &block : mBufferBlocks)
4245 {
4246 if (block->isEmpty())
4247 {
4248 block->destroy(renderer);
4249 }
4250 else
4251 {
4252 // When orphan is not allowed, all BufferBlocks must be empty.
4253 ASSERT(orphanNonEmptyBufferBlock);
4254 renderer->addBufferBlockToOrphanList(block.release());
4255 }
4256 }
4257 mBufferBlocks.clear();
4258
4259 for (std::unique_ptr<BufferBlock> &block : mEmptyBufferBlocks)
4260 {
4261 block->destroy(renderer);
4262 }
4263 mEmptyBufferBlocks.clear();
4264 }
4265
getTotalEmptyMemorySize() const4266 VkDeviceSize BufferPool::getTotalEmptyMemorySize() const
4267 {
4268 VkDeviceSize totalMemorySize = 0;
4269 for (const std::unique_ptr<BufferBlock> &block : mEmptyBufferBlocks)
4270 {
4271 totalMemorySize += block->getMemorySize();
4272 }
4273 return totalMemorySize;
4274 }
4275
addStats(std::ostringstream * out) const4276 void BufferPool::addStats(std::ostringstream *out) const
4277 {
4278 VkDeviceSize totalUnusedBytes = 0;
4279 VkDeviceSize totalMemorySize = 0;
4280 for (size_t i = 0; i < mBufferBlocks.size(); i++)
4281 {
4282 const std::unique_ptr<BufferBlock> &block = mBufferBlocks[i];
4283 vma::StatInfo statInfo;
4284 block->calculateStats(&statInfo);
4285 ASSERT(statInfo.basicInfo.blockCount == 1);
4286 INFO() << "[" << i << "]={" << " allocationCount:" << statInfo.basicInfo.allocationCount
4287 << " blockBytes:" << statInfo.basicInfo.blockBytes
4288 << " allocationBytes:" << statInfo.basicInfo.allocationBytes
4289 << " unusedRangeCount:" << statInfo.unusedRangeCount
4290 << " allocationSizeMin:" << statInfo.allocationSizeMin
4291 << " allocationSizeMax:" << statInfo.allocationSizeMax
4292 << " unusedRangeSizeMin:" << statInfo.unusedRangeSizeMin
4293 << " unusedRangeSizeMax:" << statInfo.unusedRangeSizeMax << " }";
4294 VkDeviceSize unusedBytes =
4295 statInfo.basicInfo.blockBytes - statInfo.basicInfo.allocationBytes;
4296 totalUnusedBytes += unusedBytes;
4297 totalMemorySize += block->getMemorySize();
4298 }
4299 *out << "mBufferBlocks.size():" << mBufferBlocks.size()
4300 << " totalUnusedBytes:" << totalUnusedBytes / 1024
4301 << "KB / totalMemorySize:" << totalMemorySize / 1024 << "KB";
4302 *out << " emptyBuffers [memorySize:" << getTotalEmptyMemorySize() / 1024 << "KB "
4303 << " count:" << mEmptyBufferBlocks.size()
4304 << " needed: " << mNumberOfNewBuffersNeededSinceLastPrune << "]";
4305 }
4306
4307 // DescriptorSetHelper implementation.
destroy(VkDevice device)4308 void DescriptorSetHelper::destroy(VkDevice device)
4309 {
4310 if (valid())
4311 {
4312 // Since the pool is created without VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, we
4313 // don't call vkFreeDescriptorSets. We always add to garbage list so that it can be
4314 // recycled. Since we dont actually know if it is GPU completed, we always just add to the
4315 // pending garbage list assuming the worst case.
4316 DescriptorPoolPointer pool(device, mPool);
4317 DescriptorSetPointer garbage(device, std::move(*this));
4318 pool->addPendingGarbage(std::move(garbage));
4319 ASSERT(!valid());
4320 }
4321 }
4322
4323 // DescriptorPoolHelper implementation.
DescriptorPoolHelper()4324 DescriptorPoolHelper::DescriptorPoolHelper()
4325 : mMaxDescriptorSets(0), mValidDescriptorSets(0), mFreeDescriptorSets(0)
4326 {}
4327
~DescriptorPoolHelper()4328 DescriptorPoolHelper::~DescriptorPoolHelper()
4329 {
4330 ASSERT(mPendingGarbageList.empty());
4331 ASSERT(mFinishedGarbageList.empty());
4332 }
4333
init(ErrorContext * context,const std::vector<VkDescriptorPoolSize> & poolSizesIn,uint32_t maxSets)4334 angle::Result DescriptorPoolHelper::init(ErrorContext *context,
4335 const std::vector<VkDescriptorPoolSize> &poolSizesIn,
4336 uint32_t maxSets)
4337 {
4338 Renderer *renderer = context->getRenderer();
4339
4340 ASSERT(mPendingGarbageList.empty());
4341 ASSERT(mFinishedGarbageList.empty());
4342
4343 if (mDescriptorPool.valid())
4344 {
4345 mDescriptorPool.destroy(renderer->getDevice());
4346 }
4347
4348 // Make a copy of the pool sizes, so we can grow them to satisfy the specified maxSets.
4349 std::vector<VkDescriptorPoolSize> poolSizes = poolSizesIn;
4350
4351 for (VkDescriptorPoolSize &poolSize : poolSizes)
4352 {
4353 poolSize.descriptorCount *= maxSets;
4354 }
4355
4356 VkDescriptorPoolCreateInfo descriptorPoolInfo = {};
4357 descriptorPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
4358 descriptorPoolInfo.flags = 0;
4359 descriptorPoolInfo.maxSets = maxSets;
4360 descriptorPoolInfo.poolSizeCount = static_cast<uint32_t>(poolSizes.size());
4361 descriptorPoolInfo.pPoolSizes = poolSizes.data();
4362
4363 mMaxDescriptorSets = maxSets;
4364 mFreeDescriptorSets = maxSets;
4365 mValidDescriptorSets = 0;
4366
4367 ANGLE_VK_TRY(context, mDescriptorPool.init(renderer->getDevice(), descriptorPoolInfo));
4368
4369 mRenderer = renderer;
4370
4371 return angle::Result::Continue;
4372 }
4373
destroy(VkDevice device)4374 void DescriptorPoolHelper::destroy(VkDevice device)
4375 {
4376 ASSERT(mValidDescriptorSets == 0);
4377 ASSERT(mPendingGarbageList.empty());
4378 ASSERT(mFinishedGarbageList.empty());
4379 mDescriptorPool.destroy(device);
4380 }
4381
allocateVkDescriptorSet(ErrorContext * context,const DescriptorSetLayout & descriptorSetLayout,VkDescriptorSet * descriptorSetOut)4382 bool DescriptorPoolHelper::allocateVkDescriptorSet(ErrorContext *context,
4383 const DescriptorSetLayout &descriptorSetLayout,
4384 VkDescriptorSet *descriptorSetOut)
4385 {
4386 if (mFreeDescriptorSets > 0)
4387 {
4388 VkDescriptorSetAllocateInfo allocInfo = {};
4389 allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
4390 allocInfo.descriptorPool = mDescriptorPool.getHandle();
4391 allocInfo.descriptorSetCount = 1;
4392 allocInfo.pSetLayouts = descriptorSetLayout.ptr();
4393
4394 VkResult result = mDescriptorPool.allocateDescriptorSets(context->getDevice(), allocInfo,
4395 descriptorSetOut);
4396 ++context->getPerfCounters().descriptorSetAllocations;
4397 // If fail, it means our own accounting has a bug.
4398 ASSERT(result == VK_SUCCESS);
4399 mFreeDescriptorSets--;
4400 mValidDescriptorSets++;
4401 return true;
4402 }
4403
4404 return false;
4405 }
4406
cleanupPendingGarbage()4407 void DescriptorPoolHelper::cleanupPendingGarbage()
4408 {
4409 while (!mPendingGarbageList.empty())
4410 {
4411 DescriptorSetPointer &garbage = mPendingGarbageList.front();
4412 if (!mRenderer->hasResourceUseFinished(garbage->getResourceUse()))
4413 {
4414 break;
4415 }
4416 mFinishedGarbageList.push_back(std::move(garbage));
4417 mPendingGarbageList.pop_front();
4418 }
4419 }
4420
recycleFromGarbage(Renderer * renderer,DescriptorSetPointer * descriptorSetOut)4421 bool DescriptorPoolHelper::recycleFromGarbage(Renderer *renderer,
4422 DescriptorSetPointer *descriptorSetOut)
4423 {
4424 if (mFinishedGarbageList.empty())
4425 {
4426 cleanupPendingGarbage();
4427 }
4428
4429 if (!mFinishedGarbageList.empty())
4430 {
4431 DescriptorSetPointer &garbage = mFinishedGarbageList.front();
4432 *descriptorSetOut = std::move(garbage);
4433 mFinishedGarbageList.pop_front();
4434 mValidDescriptorSets++;
4435 return true;
4436 }
4437
4438 return false;
4439 }
4440
allocateDescriptorSet(ErrorContext * context,const DescriptorSetLayout & descriptorSetLayout,const DescriptorPoolPointer & pool,DescriptorSetPointer * descriptorSetOut)4441 bool DescriptorPoolHelper::allocateDescriptorSet(ErrorContext *context,
4442 const DescriptorSetLayout &descriptorSetLayout,
4443 const DescriptorPoolPointer &pool,
4444 DescriptorSetPointer *descriptorSetOut)
4445 {
4446 ASSERT(pool.get() == this);
4447 VkDescriptorSet descriptorSet;
4448 if (allocateVkDescriptorSet(context, descriptorSetLayout, &descriptorSet))
4449 {
4450 DescriptorSetHelper helper = DescriptorSetHelper(descriptorSet, pool);
4451 *descriptorSetOut = DescriptorSetPointer(context->getDevice(), std::move(helper));
4452 return true;
4453 }
4454 return false;
4455 }
4456
destroyGarbage()4457 void DescriptorPoolHelper::destroyGarbage()
4458 {
4459 ASSERT(mPendingGarbageList.empty());
4460
4461 while (!mFinishedGarbageList.empty())
4462 {
4463 DescriptorSetPointer &garbage = mFinishedGarbageList.front();
4464 ASSERT(garbage.unique());
4465 ASSERT(garbage->valid());
4466 // Because we do not use VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT when pool is
4467 // created, We can't free each individual descriptor set before destroying the pool, we
4468 // simply clear the descriptorSet and the mPool weak pointer so that
4469 // DescriptorSetHelper::destroy will not find it the garbage being valid and try to add to
4470 // garbage list again.
4471 garbage->mDescriptorSet = VK_NULL_HANDLE;
4472 garbage->mPool.reset();
4473 ASSERT(!garbage->valid());
4474 mFinishedGarbageList.pop_front();
4475 }
4476 }
4477
4478 // DynamicDescriptorPool implementation.
DynamicDescriptorPool()4479 DynamicDescriptorPool::DynamicDescriptorPool() : mCachedDescriptorSetLayout(VK_NULL_HANDLE)
4480 {
4481 mDescriptorPools.reserve(32);
4482 }
4483
~DynamicDescriptorPool()4484 DynamicDescriptorPool::~DynamicDescriptorPool()
4485 {
4486 ASSERT(mLRUList.empty());
4487 ASSERT(mDescriptorSetCache.empty());
4488 ASSERT(mDescriptorPools.empty());
4489 }
4490
DynamicDescriptorPool(DynamicDescriptorPool && other)4491 DynamicDescriptorPool::DynamicDescriptorPool(DynamicDescriptorPool &&other)
4492 : DynamicDescriptorPool()
4493 {
4494 *this = std::move(other);
4495 }
4496
operator =(DynamicDescriptorPool && other)4497 DynamicDescriptorPool &DynamicDescriptorPool::operator=(DynamicDescriptorPool &&other)
4498 {
4499 std::swap(mDescriptorPools, other.mDescriptorPools);
4500 std::swap(mPoolSizes, other.mPoolSizes);
4501 std::swap(mCachedDescriptorSetLayout, other.mCachedDescriptorSetLayout);
4502 std::swap(mLRUList, other.mLRUList);
4503 std::swap(mDescriptorSetCache, other.mDescriptorSetCache);
4504 return *this;
4505 }
4506
init(ErrorContext * context,const VkDescriptorPoolSize * setSizes,size_t setSizeCount,const DescriptorSetLayout & descriptorSetLayout)4507 angle::Result DynamicDescriptorPool::init(ErrorContext *context,
4508 const VkDescriptorPoolSize *setSizes,
4509 size_t setSizeCount,
4510 const DescriptorSetLayout &descriptorSetLayout)
4511 {
4512 ASSERT(setSizes);
4513 ASSERT(setSizeCount);
4514 ASSERT(mDescriptorPools.empty());
4515 ASSERT(mCachedDescriptorSetLayout == VK_NULL_HANDLE);
4516 mPoolSizes.reserve(setSizeCount);
4517 mPoolSizes.assign(setSizes, setSizes + setSizeCount);
4518 mCachedDescriptorSetLayout = descriptorSetLayout.getHandle();
4519
4520 DescriptorPoolPointer newPool = DescriptorPoolPointer::MakeShared(context->getDevice());
4521 ANGLE_TRY(newPool->init(context, mPoolSizes, mMaxSetsPerPool));
4522
4523 mDescriptorPools.emplace_back(std::move(newPool));
4524
4525 return angle::Result::Continue;
4526 }
4527
destroy(VkDevice device)4528 void DynamicDescriptorPool::destroy(VkDevice device)
4529 {
4530 // Destroy cache
4531 mDescriptorSetCache.clear();
4532
4533 // Destroy LRU list and SharedDescriptorSetCacheKey.
4534 for (auto it = mLRUList.begin(); it != mLRUList.end();)
4535 {
4536 (it->sharedCacheKey)->destroy(device);
4537 it = mLRUList.erase(it);
4538 }
4539 ASSERT(mLRUList.empty());
4540
4541 for (DescriptorPoolPointer &pool : mDescriptorPools)
4542 {
4543 pool->cleanupPendingGarbage();
4544 pool->destroyGarbage();
4545 ASSERT(pool.unique());
4546 }
4547 mDescriptorPools.clear();
4548
4549 mCachedDescriptorSetLayout = VK_NULL_HANDLE;
4550 }
4551
allocateFromExistingPool(ErrorContext * context,const DescriptorSetLayout & descriptorSetLayout,DescriptorSetPointer * descriptorSetOut)4552 bool DynamicDescriptorPool::allocateFromExistingPool(ErrorContext *context,
4553 const DescriptorSetLayout &descriptorSetLayout,
4554 DescriptorSetPointer *descriptorSetOut)
4555 {
4556 for (size_t poolIndex = 0; poolIndex < mDescriptorPools.size(); ++poolIndex)
4557 {
4558 DescriptorPoolPointer &pool = mDescriptorPools[poolIndex];
4559 if (!pool || !pool->valid())
4560 {
4561 continue;
4562 }
4563 if (pool->allocateDescriptorSet(context, descriptorSetLayout, pool, descriptorSetOut))
4564 {
4565 return true;
4566 }
4567 }
4568 return false;
4569 }
4570
recycleFromGarbage(Renderer * renderer,DescriptorSetPointer * descriptorSetOut)4571 bool DynamicDescriptorPool::recycleFromGarbage(Renderer *renderer,
4572 DescriptorSetPointer *descriptorSetOut)
4573 {
4574 for (DescriptorPoolPointer &pool : mDescriptorPools)
4575 {
4576 if (pool->recycleFromGarbage(renderer, descriptorSetOut))
4577 {
4578 return true;
4579 }
4580 }
4581 return false;
4582 }
4583
evictStaleDescriptorSets(Renderer * renderer,uint32_t oldestFrameToKeep,uint32_t currentFrame)4584 bool DynamicDescriptorPool::evictStaleDescriptorSets(Renderer *renderer,
4585 uint32_t oldestFrameToKeep,
4586 uint32_t currentFrame)
4587 {
4588 ASSERT(oldestFrameToKeep < currentFrame);
4589 size_t descriptorSetEvicted = 0;
4590 // Walk LRU list backwards from oldest to most recent, evict anything that earlier than
4591 // oldestFrameIDToKeep.
4592 auto it = mLRUList.rbegin();
4593 while (it != mLRUList.rend())
4594 {
4595 DescriptorSetPointer &descriptorSet = it->descriptorSet;
4596 if (descriptorSet.unique())
4597 {
4598 // Stop if it is recently being used.
4599 if (descriptorSet->getLastUsedFrame() > oldestFrameToKeep)
4600 {
4601 break;
4602 }
4603 // Stop if GPU is still busy
4604 if (!renderer->hasResourceUseFinished(descriptorSet->getResourceUse()))
4605 {
4606 break;
4607 }
4608 // Evict it from the cache and remove it from LRU list.
4609 bool removed = mDescriptorSetCache.eraseDescriptorSet(it->sharedCacheKey->getDesc());
4610 ASSERT(removed);
4611 // Invalidate the sharedCacheKey so that they could be reused.
4612 it->sharedCacheKey->destroy(renderer->getDevice());
4613 ASSERT(!it->sharedCacheKey->valid());
4614
4615 // Note that erase it from LRU list will "destroy" descriptorSet. Since we
4616 // never actually destroy descriptorSet, it will just add to the garbage list. Here we
4617 // want more explicit control to add it to the front of list (because we know it is
4618 // already GPU completed) instead to the end of the list, so we do it explicitly.
4619 DescriptorPoolWeakPointer pool = descriptorSet->getPool();
4620 pool->addFinishedGarbage(std::move(descriptorSet));
4621 descriptorSetEvicted++;
4622
4623 // This should destroy descriptorSet, which is already invalid;
4624 it = decltype(it)(mLRUList.erase(std::next(it).base()));
4625 mCacheStats.decrementSize();
4626 }
4627 else
4628 {
4629 // It means it is still bound to one of the programs. Move it to the front of the LRU
4630 // list to avoid repeatedly hitting it for every eviction.
4631 mLRUList.splice(mLRUList.begin(), mLRUList, std::next(it).base());
4632 ++it;
4633 // Update to currentFrame to maintain LRU order
4634 descriptorSet->updateLastUsedFrame(currentFrame);
4635 }
4636 }
4637
4638 if (descriptorSetEvicted > 0)
4639 {
4640 // If there is any pool that is completely empty, destroy it first so that we can allocate
4641 // from partial pool.
4642 checkAndDestroyUnusedPool(renderer);
4643 return true;
4644 }
4645
4646 return false;
4647 }
4648
allocateDescriptorSet(ErrorContext * context,const DescriptorSetLayout & descriptorSetLayout,DescriptorSetPointer * descriptorSetOut)4649 angle::Result DynamicDescriptorPool::allocateDescriptorSet(
4650 ErrorContext *context,
4651 const DescriptorSetLayout &descriptorSetLayout,
4652 DescriptorSetPointer *descriptorSetOut)
4653 {
4654 ASSERT(!mDescriptorPools.empty());
4655 ASSERT(descriptorSetLayout.getHandle() == mCachedDescriptorSetLayout);
4656
4657 if (allocateFromExistingPool(context, descriptorSetLayout, descriptorSetOut))
4658 {
4659 return angle::Result::Continue;
4660 }
4661
4662 if (recycleFromGarbage(context->getRenderer(), descriptorSetOut))
4663 {
4664 return angle::Result::Continue;
4665 }
4666
4667 // Last, try to allocate a new pool (and/or evict an existing pool)
4668 ANGLE_TRY(allocateNewPool(context));
4669 bool success = allocateFromExistingPool(context, descriptorSetLayout, descriptorSetOut);
4670 // Allocate from a new pool must succeed.
4671 ASSERT(success);
4672
4673 return angle::Result::Continue;
4674 }
4675
getOrAllocateDescriptorSet(Context * context,uint32_t currentFrame,const DescriptorSetDesc & desc,const DescriptorSetLayout & descriptorSetLayout,DescriptorSetPointer * descriptorSetOut,SharedDescriptorSetCacheKey * newSharedCacheKeyOut)4676 angle::Result DynamicDescriptorPool::getOrAllocateDescriptorSet(
4677 Context *context,
4678 uint32_t currentFrame,
4679 const DescriptorSetDesc &desc,
4680 const DescriptorSetLayout &descriptorSetLayout,
4681 DescriptorSetPointer *descriptorSetOut,
4682 SharedDescriptorSetCacheKey *newSharedCacheKeyOut)
4683 {
4684 Renderer *renderer = context->getRenderer();
4685 ASSERT(context->getFeatures().descriptorSetCache.enabled);
4686 bool success;
4687
4688 // First scan the descriptorSet cache.
4689 DescriptorSetLRUListIterator listIterator;
4690 if (mDescriptorSetCache.getDescriptorSet(desc, &listIterator))
4691 {
4692 *descriptorSetOut = listIterator->descriptorSet;
4693 (*newSharedCacheKeyOut).reset();
4694 // Move it to the front of the LRU list.
4695 mLRUList.splice(mLRUList.begin(), mLRUList, listIterator);
4696 mCacheStats.hit();
4697 return angle::Result::Continue;
4698 }
4699
4700 // Try to allocate from the existing pool (or recycle from garbage list)
4701 success = allocateFromExistingPool(context, descriptorSetLayout, descriptorSetOut);
4702
4703 // Try to recycle from the garbage list.
4704 if (!success)
4705 {
4706 success = recycleFromGarbage(context->getRenderer(), descriptorSetOut);
4707 }
4708
4709 // Try to evict oldest descriptorSets that has not being used in last
4710 // kDescriptorSetCacheRetireAge.
4711 if (!success && currentFrame > kDescriptorSetCacheRetireAge)
4712 {
4713 uint32_t oldestFrameToKeep = currentFrame - kDescriptorSetCacheRetireAge;
4714 if (evictStaleDescriptorSets(renderer, oldestFrameToKeep, currentFrame))
4715 {
4716 success = recycleFromGarbage(renderer, descriptorSetOut);
4717 }
4718 }
4719
4720 // Last, try to allocate a new pool
4721 if (!success)
4722 {
4723 ANGLE_TRY(allocateNewPool(context));
4724 success = allocateFromExistingPool(context, descriptorSetLayout, descriptorSetOut);
4725 // Allocate from a new pool must succeed.
4726 ASSERT(success);
4727 }
4728
4729 ASSERT(descriptorSetOut->unique());
4730 ASSERT((*descriptorSetOut)->valid());
4731
4732 // Let pool know there is a shared cache key created and destroys the shared cache key
4733 // when it destroys the pool.
4734 SharedDescriptorSetCacheKey sharedCacheKey = CreateSharedDescriptorSetCacheKey(desc, this);
4735
4736 // Add to the front of the LRU list and add list iterator to the cache
4737 mLRUList.push_front({sharedCacheKey, *descriptorSetOut});
4738 mDescriptorSetCache.insertDescriptorSet(desc, mLRUList.begin());
4739 mCacheStats.missAndIncrementSize();
4740
4741 *newSharedCacheKeyOut = sharedCacheKey;
4742 return angle::Result::Continue;
4743 }
4744
allocateNewPool(ErrorContext * context)4745 angle::Result DynamicDescriptorPool::allocateNewPool(ErrorContext *context)
4746 {
4747 static constexpr size_t kMaxPools = 99999;
4748 ANGLE_VK_CHECK(context, mDescriptorPools.size() < kMaxPools, VK_ERROR_TOO_MANY_OBJECTS);
4749 // This pool is getting hot, so grow its max size to try and prevent allocating another pool in
4750 // the future.
4751 if (mMaxSetsPerPool < kMaxSetsPerPoolMax)
4752 {
4753 mMaxSetsPerPool *= mMaxSetsPerPoolMultiplier;
4754 }
4755 DescriptorPoolPointer newPool = DescriptorPoolPointer::MakeShared(context->getDevice());
4756 ANGLE_TRY(newPool->init(context, mPoolSizes, mMaxSetsPerPool));
4757 mDescriptorPools.emplace_back(std::move(newPool));
4758
4759 return angle::Result::Continue;
4760 }
4761
releaseCachedDescriptorSet(Renderer * renderer,const DescriptorSetDesc & desc)4762 void DynamicDescriptorPool::releaseCachedDescriptorSet(Renderer *renderer,
4763 const DescriptorSetDesc &desc)
4764 {
4765 ASSERT(renderer->getFeatures().descriptorSetCache.enabled);
4766 DescriptorSetLRUListIterator listIter;
4767 // Remove from the cache hash map. Note that we can't delete it until refcount goes to 0
4768 if (mDescriptorSetCache.eraseDescriptorSet(desc, &listIter))
4769 {
4770 DescriptorSetPointer descriptorSet = std::move(listIter->descriptorSet);
4771 mCacheStats.decrementSize();
4772 mLRUList.erase(listIter);
4773
4774 if (descriptorSet.unique())
4775 {
4776 DescriptorPoolWeakPointer pool = descriptorSet->getPool();
4777 pool->addPendingGarbage(std::move(descriptorSet));
4778 }
4779 }
4780 }
4781
destroyCachedDescriptorSet(Renderer * renderer,const DescriptorSetDesc & desc)4782 void DynamicDescriptorPool::destroyCachedDescriptorSet(Renderer *renderer,
4783 const DescriptorSetDesc &desc)
4784 {
4785 ASSERT(renderer->getFeatures().descriptorSetCache.enabled);
4786 DescriptorSetLRUListIterator listIter;
4787 // Remove from the cache hash map. Note that we can't delete it until refcount goes to 0
4788 if (mDescriptorSetCache.eraseDescriptorSet(desc, &listIter))
4789 {
4790 DescriptorSetPointer descriptorSet = std::move(listIter->descriptorSet);
4791 mCacheStats.decrementSize();
4792 mLRUList.erase(listIter);
4793
4794 if (descriptorSet.unique())
4795 {
4796 DescriptorPoolWeakPointer pool = descriptorSet->getPool();
4797 pool->addFinishedGarbage(std::move(descriptorSet));
4798 if (pool->canDestroy())
4799 {
4800 destroyUnusedPool(renderer, pool);
4801 }
4802 }
4803 }
4804 }
4805
destroyUnusedPool(Renderer * renderer,const DescriptorPoolWeakPointer & pool)4806 void DynamicDescriptorPool::destroyUnusedPool(Renderer *renderer,
4807 const DescriptorPoolWeakPointer &pool)
4808 {
4809 ASSERT(renderer->getFeatures().descriptorSetCache.enabled);
4810 ASSERT(pool->canDestroy());
4811
4812 // We always keep at least one pool around.
4813 if (mDescriptorPools.size() < 2)
4814 {
4815 return;
4816 }
4817
4818 // Erase it from the array
4819 for (auto it = mDescriptorPools.begin(); it != mDescriptorPools.end(); ++it)
4820 {
4821 if (pool.owner_equal(*it))
4822 {
4823 ASSERT(pool->valid());
4824 pool->destroyGarbage();
4825 ASSERT((*it).unique());
4826 it = mDescriptorPools.erase(it);
4827 return;
4828 }
4829 }
4830 }
4831
checkAndDestroyUnusedPool(Renderer * renderer)4832 void DynamicDescriptorPool::checkAndDestroyUnusedPool(Renderer *renderer)
4833 {
4834 ASSERT(renderer->getFeatures().descriptorSetCache.enabled);
4835 for (auto pool : mDescriptorPools)
4836 {
4837 pool->cleanupPendingGarbage();
4838 }
4839
4840 // We always keep at least one pool around.
4841 if (mDescriptorPools.size() < 2)
4842 {
4843 return;
4844 }
4845
4846 // Erase it from the array
4847 for (auto it = mDescriptorPools.begin(); it != mDescriptorPools.end();)
4848 {
4849 if ((*it)->canDestroy())
4850 {
4851 (*it)->destroyGarbage();
4852 ASSERT((*it).unique());
4853 it = mDescriptorPools.erase(it);
4854 }
4855 else
4856 {
4857 ++it;
4858 }
4859 }
4860 }
4861
4862 // For ASSERT only
hasCachedDescriptorSet(const DescriptorSetDesc & desc) const4863 bool DynamicDescriptorPool::hasCachedDescriptorSet(const DescriptorSetDesc &desc) const
4864 {
4865 DescriptorSetLRUListIterator listIterator;
4866 return mDescriptorSetCache.getDescriptorSet(desc, &listIterator);
4867 }
4868
4869 // For testing only!
GetMaxSetsPerPoolForTesting()4870 uint32_t DynamicDescriptorPool::GetMaxSetsPerPoolForTesting()
4871 {
4872 return mMaxSetsPerPool;
4873 }
4874
4875 // For testing only!
SetMaxSetsPerPoolForTesting(uint32_t maxSetsPerPool)4876 void DynamicDescriptorPool::SetMaxSetsPerPoolForTesting(uint32_t maxSetsPerPool)
4877 {
4878 mMaxSetsPerPool = maxSetsPerPool;
4879 }
4880
4881 // For testing only!
GetMaxSetsPerPoolMultiplierForTesting()4882 uint32_t DynamicDescriptorPool::GetMaxSetsPerPoolMultiplierForTesting()
4883 {
4884 return mMaxSetsPerPoolMultiplier;
4885 }
4886
4887 // For testing only!
SetMaxSetsPerPoolMultiplierForTesting(uint32_t maxSetsPerPoolMultiplier)4888 void DynamicDescriptorPool::SetMaxSetsPerPoolMultiplierForTesting(uint32_t maxSetsPerPoolMultiplier)
4889 {
4890 mMaxSetsPerPoolMultiplier = maxSetsPerPoolMultiplier;
4891 }
4892
4893 // DynamicallyGrowingPool implementation
4894 template <typename Pool>
DynamicallyGrowingPool()4895 DynamicallyGrowingPool<Pool>::DynamicallyGrowingPool()
4896 : mPoolSize(0), mCurrentPool(0), mCurrentFreeEntry(0)
4897 {
4898 mPools.reserve(64);
4899 }
4900
4901 template <typename Pool>
4902 DynamicallyGrowingPool<Pool>::~DynamicallyGrowingPool() = default;
4903
4904 template <typename Pool>
initEntryPool(ErrorContext * contextVk,uint32_t poolSize)4905 angle::Result DynamicallyGrowingPool<Pool>::initEntryPool(ErrorContext *contextVk,
4906 uint32_t poolSize)
4907 {
4908 ASSERT(mPools.empty());
4909 mPoolSize = poolSize;
4910 mCurrentFreeEntry = poolSize;
4911 return angle::Result::Continue;
4912 }
4913
4914 template <typename Pool>
destroyEntryPool(VkDevice device)4915 void DynamicallyGrowingPool<Pool>::destroyEntryPool(VkDevice device)
4916 {
4917 for (PoolResource &resource : mPools)
4918 {
4919 destroyPoolImpl(device, resource.pool);
4920 }
4921 mPools.clear();
4922 }
4923
4924 template <typename Pool>
findFreeEntryPool(ContextVk * contextVk)4925 bool DynamicallyGrowingPool<Pool>::findFreeEntryPool(ContextVk *contextVk)
4926 {
4927 Renderer *renderer = contextVk->getRenderer();
4928 for (size_t poolIndex = 0; poolIndex < mPools.size(); ++poolIndex)
4929 {
4930 PoolResource &pool = mPools[poolIndex];
4931 if (pool.freedCount == mPoolSize && renderer->hasResourceUseFinished(pool.getResourceUse()))
4932 {
4933 mCurrentPool = poolIndex;
4934 mCurrentFreeEntry = 0;
4935
4936 pool.freedCount = 0;
4937
4938 return true;
4939 }
4940 }
4941
4942 return false;
4943 }
4944
4945 template <typename Pool>
allocateNewEntryPool(ContextVk * contextVk,Pool && pool)4946 angle::Result DynamicallyGrowingPool<Pool>::allocateNewEntryPool(ContextVk *contextVk, Pool &&pool)
4947 {
4948 mPools.emplace_back(std::move(pool), 0);
4949
4950 mCurrentPool = mPools.size() - 1;
4951 mCurrentFreeEntry = 0;
4952
4953 return angle::Result::Continue;
4954 }
4955
4956 template <typename Pool>
onEntryFreed(ContextVk * contextVk,size_t poolIndex,const ResourceUse & use)4957 void DynamicallyGrowingPool<Pool>::onEntryFreed(ContextVk *contextVk,
4958 size_t poolIndex,
4959 const ResourceUse &use)
4960 {
4961 ASSERT(poolIndex < mPools.size() && mPools[poolIndex].freedCount < mPoolSize);
4962 if (!contextVk->getRenderer()->hasResourceUseFinished(use))
4963 {
4964 mPools[poolIndex].mergeResourceUse(use);
4965 }
4966 ++mPools[poolIndex].freedCount;
4967 }
4968
4969 template <typename Pool>
allocatePoolEntries(ContextVk * contextVk,uint32_t entryCount,uint32_t * poolIndex,uint32_t * currentEntryOut)4970 angle::Result DynamicallyGrowingPool<Pool>::allocatePoolEntries(ContextVk *contextVk,
4971 uint32_t entryCount,
4972 uint32_t *poolIndex,
4973 uint32_t *currentEntryOut)
4974 {
4975 if (mCurrentFreeEntry + entryCount > mPoolSize)
4976 {
4977 if (!findFreeEntryPool(contextVk))
4978 {
4979 Pool newPool;
4980 ANGLE_TRY(allocatePoolImpl(contextVk, newPool, mPoolSize));
4981 ANGLE_TRY(allocateNewEntryPool(contextVk, std::move(newPool)));
4982 }
4983 }
4984
4985 *poolIndex = static_cast<uint32_t>(mCurrentPool);
4986 *currentEntryOut = mCurrentFreeEntry;
4987
4988 mCurrentFreeEntry += entryCount;
4989
4990 return angle::Result::Continue;
4991 }
4992
4993 template <typename Pool>
PoolResource(Pool && poolIn,uint32_t freedCountIn)4994 DynamicallyGrowingPool<Pool>::PoolResource::PoolResource(Pool &&poolIn, uint32_t freedCountIn)
4995 : pool(std::move(poolIn)), freedCount(freedCountIn)
4996 {}
4997
4998 template <typename Pool>
PoolResource(PoolResource && other)4999 DynamicallyGrowingPool<Pool>::PoolResource::PoolResource(PoolResource &&other)
5000 : Resource(std::move(other)), pool(std::move(other.pool)), freedCount(other.freedCount)
5001 {}
5002
5003 // DynamicQueryPool implementation
5004 DynamicQueryPool::DynamicQueryPool() = default;
5005
5006 DynamicQueryPool::~DynamicQueryPool() = default;
5007
init(ContextVk * contextVk,VkQueryType type,uint32_t poolSize)5008 angle::Result DynamicQueryPool::init(ContextVk *contextVk, VkQueryType type, uint32_t poolSize)
5009 {
5010 // SecondaryCommandBuffer's ResetQueryPoolParams would like the query index to fit in 24 bits.
5011 ASSERT(poolSize < (1 << 24));
5012
5013 ANGLE_TRY(initEntryPool(contextVk, poolSize));
5014 mQueryType = type;
5015 return angle::Result::Continue;
5016 }
5017
destroy(VkDevice device)5018 void DynamicQueryPool::destroy(VkDevice device)
5019 {
5020 destroyEntryPool(device);
5021 }
5022
destroyPoolImpl(VkDevice device,QueryPool & poolToDestroy)5023 void DynamicQueryPool::destroyPoolImpl(VkDevice device, QueryPool &poolToDestroy)
5024 {
5025 poolToDestroy.destroy(device);
5026 }
5027
allocateQuery(ContextVk * contextVk,QueryHelper * queryOut,uint32_t queryCount)5028 angle::Result DynamicQueryPool::allocateQuery(ContextVk *contextVk,
5029 QueryHelper *queryOut,
5030 uint32_t queryCount)
5031 {
5032 ASSERT(!queryOut->valid());
5033
5034 uint32_t currentPool = 0;
5035 uint32_t queryIndex = 0;
5036 ANGLE_TRY(allocatePoolEntries(contextVk, queryCount, ¤tPool, &queryIndex));
5037
5038 queryOut->init(this, currentPool, queryIndex, queryCount);
5039
5040 return angle::Result::Continue;
5041 }
5042
allocatePoolImpl(ContextVk * contextVk,QueryPool & poolToAllocate,uint32_t entriesToAllocate)5043 angle::Result DynamicQueryPool::allocatePoolImpl(ContextVk *contextVk,
5044 QueryPool &poolToAllocate,
5045 uint32_t entriesToAllocate)
5046 {
5047 VkQueryPoolCreateInfo queryPoolInfo = {};
5048 queryPoolInfo.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
5049 queryPoolInfo.flags = 0;
5050 queryPoolInfo.queryType = this->mQueryType;
5051 queryPoolInfo.queryCount = entriesToAllocate;
5052 queryPoolInfo.pipelineStatistics = 0;
5053
5054 if (this->mQueryType == VK_QUERY_TYPE_PIPELINE_STATISTICS)
5055 {
5056 queryPoolInfo.pipelineStatistics = VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT;
5057 }
5058
5059 ANGLE_VK_TRY(contextVk, poolToAllocate.init(contextVk->getDevice(), queryPoolInfo));
5060 return angle::Result::Continue;
5061 }
5062
freeQuery(ContextVk * contextVk,QueryHelper * query)5063 void DynamicQueryPool::freeQuery(ContextVk *contextVk, QueryHelper *query)
5064 {
5065 if (query->valid())
5066 {
5067 size_t poolIndex = query->mQueryPoolIndex;
5068 ASSERT(getQueryPool(poolIndex).valid());
5069
5070 onEntryFreed(contextVk, poolIndex, query->getResourceUse());
5071
5072 query->deinit();
5073 }
5074 }
5075
5076 // QueryResult implementation
setResults(uint64_t * results,uint32_t queryCount)5077 void QueryResult::setResults(uint64_t *results, uint32_t queryCount)
5078 {
5079 ASSERT(mResults[0] == 0 && mResults[1] == 0);
5080
5081 // Accumulate the query results. For multiview, where multiple query indices are used to return
5082 // the results, it's undefined how the results are distributed between indices, but the sum is
5083 // guaranteed to be the desired result.
5084 for (uint32_t query = 0; query < queryCount; ++query)
5085 {
5086 for (uint32_t perQueryIndex = 0; perQueryIndex < mIntsPerResult; ++perQueryIndex)
5087 {
5088 mResults[perQueryIndex] += results[query * mIntsPerResult + perQueryIndex];
5089 }
5090 }
5091 }
5092
5093 // QueryHelper implementation
QueryHelper()5094 QueryHelper::QueryHelper()
5095 : mDynamicQueryPool(nullptr),
5096 mQueryPoolIndex(0),
5097 mQuery(0),
5098 mQueryCount(0),
5099 mStatus(QueryStatus::Inactive)
5100 {}
5101
~QueryHelper()5102 QueryHelper::~QueryHelper() {}
5103
5104 // Move constructor
QueryHelper(QueryHelper && rhs)5105 QueryHelper::QueryHelper(QueryHelper &&rhs)
5106 : Resource(std::move(rhs)),
5107 mDynamicQueryPool(rhs.mDynamicQueryPool),
5108 mQueryPoolIndex(rhs.mQueryPoolIndex),
5109 mQuery(rhs.mQuery),
5110 mQueryCount(rhs.mQueryCount),
5111 mStatus(rhs.mStatus)
5112 {
5113 rhs.mDynamicQueryPool = nullptr;
5114 rhs.mQueryPoolIndex = 0;
5115 rhs.mQuery = 0;
5116 rhs.mQueryCount = 0;
5117 rhs.mStatus = QueryStatus::Inactive;
5118 }
5119
operator =(QueryHelper && rhs)5120 QueryHelper &QueryHelper::operator=(QueryHelper &&rhs)
5121 {
5122 Resource::operator=(std::move(rhs));
5123 std::swap(mDynamicQueryPool, rhs.mDynamicQueryPool);
5124 std::swap(mQueryPoolIndex, rhs.mQueryPoolIndex);
5125 std::swap(mQuery, rhs.mQuery);
5126 std::swap(mQueryCount, rhs.mQueryCount);
5127 std::swap(mStatus, rhs.mStatus);
5128 return *this;
5129 }
5130
init(const DynamicQueryPool * dynamicQueryPool,const size_t queryPoolIndex,uint32_t query,uint32_t queryCount)5131 void QueryHelper::init(const DynamicQueryPool *dynamicQueryPool,
5132 const size_t queryPoolIndex,
5133 uint32_t query,
5134 uint32_t queryCount)
5135 {
5136 mDynamicQueryPool = dynamicQueryPool;
5137 mQueryPoolIndex = queryPoolIndex;
5138 mQuery = query;
5139 mQueryCount = queryCount;
5140
5141 ASSERT(mQueryCount <= gl::IMPLEMENTATION_ANGLE_MULTIVIEW_MAX_VIEWS);
5142 }
5143
deinit()5144 void QueryHelper::deinit()
5145 {
5146 mDynamicQueryPool = nullptr;
5147 mQueryPoolIndex = 0;
5148 mQuery = 0;
5149 mQueryCount = 0;
5150 mUse.reset();
5151 mStatus = QueryStatus::Inactive;
5152 }
5153
5154 template <typename CommandBufferT>
beginQueryImpl(ContextVk * contextVk,OutsideRenderPassCommandBuffer * resetCommandBuffer,CommandBufferT * commandBuffer)5155 void QueryHelper::beginQueryImpl(ContextVk *contextVk,
5156 OutsideRenderPassCommandBuffer *resetCommandBuffer,
5157 CommandBufferT *commandBuffer)
5158 {
5159 ASSERT(mStatus != QueryStatus::Active);
5160 const QueryPool &queryPool = getQueryPool();
5161 resetQueryPoolImpl(contextVk, queryPool, resetCommandBuffer);
5162 commandBuffer->beginQuery(queryPool, mQuery, 0);
5163 mStatus = QueryStatus::Active;
5164 }
5165
5166 template <typename CommandBufferT>
endQueryImpl(ContextVk * contextVk,CommandBufferT * commandBuffer)5167 void QueryHelper::endQueryImpl(ContextVk *contextVk, CommandBufferT *commandBuffer)
5168 {
5169 ASSERT(mStatus != QueryStatus::Ended);
5170 commandBuffer->endQuery(getQueryPool(), mQuery);
5171 mStatus = QueryStatus::Ended;
5172 }
5173
beginQuery(ContextVk * contextVk)5174 angle::Result QueryHelper::beginQuery(ContextVk *contextVk)
5175 {
5176 if (contextVk->hasActiveRenderPass())
5177 {
5178 ANGLE_TRY(contextVk->flushCommandsAndEndRenderPass(
5179 RenderPassClosureReason::BeginNonRenderPassQuery));
5180 }
5181
5182 OutsideRenderPassCommandBuffer *commandBuffer;
5183 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer({}, &commandBuffer));
5184
5185 ANGLE_TRY(contextVk->handleGraphicsEventLog(rx::GraphicsEventCmdBuf::InOutsideCmdBufQueryCmd));
5186
5187 beginQueryImpl(contextVk, commandBuffer, commandBuffer);
5188
5189 return angle::Result::Continue;
5190 }
5191
endQuery(ContextVk * contextVk)5192 angle::Result QueryHelper::endQuery(ContextVk *contextVk)
5193 {
5194 if (contextVk->hasActiveRenderPass())
5195 {
5196 ANGLE_TRY(contextVk->flushCommandsAndEndRenderPass(
5197 RenderPassClosureReason::EndNonRenderPassQuery));
5198 }
5199
5200 CommandBufferAccess access;
5201 OutsideRenderPassCommandBuffer *commandBuffer;
5202 access.onQueryAccess(this);
5203 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
5204
5205 ANGLE_TRY(contextVk->handleGraphicsEventLog(rx::GraphicsEventCmdBuf::InOutsideCmdBufQueryCmd));
5206
5207 endQueryImpl(contextVk, commandBuffer);
5208
5209 return angle::Result::Continue;
5210 }
5211
5212 template <typename CommandBufferT>
resetQueryPoolImpl(ContextVk * contextVk,const QueryPool & queryPool,CommandBufferT * commandBuffer)5213 void QueryHelper::resetQueryPoolImpl(ContextVk *contextVk,
5214 const QueryPool &queryPool,
5215 CommandBufferT *commandBuffer)
5216 {
5217 Renderer *renderer = contextVk->getRenderer();
5218 if (renderer->getFeatures().supportsHostQueryReset.enabled)
5219 {
5220 vkResetQueryPoolEXT(contextVk->getDevice(), queryPool.getHandle(), mQuery, mQueryCount);
5221 }
5222 else
5223 {
5224 commandBuffer->resetQueryPool(queryPool, mQuery, mQueryCount);
5225 }
5226 }
5227
beginRenderPassQuery(ContextVk * contextVk)5228 angle::Result QueryHelper::beginRenderPassQuery(ContextVk *contextVk)
5229 {
5230 OutsideRenderPassCommandBuffer *outsideRenderPassCommandBuffer;
5231 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer({}, &outsideRenderPassCommandBuffer));
5232
5233 RenderPassCommandBuffer *renderPassCommandBuffer =
5234 &contextVk->getStartedRenderPassCommands().getCommandBuffer();
5235
5236 beginQueryImpl(contextVk, outsideRenderPassCommandBuffer, renderPassCommandBuffer);
5237
5238 return angle::Result::Continue;
5239 }
5240
endRenderPassQuery(ContextVk * contextVk)5241 void QueryHelper::endRenderPassQuery(ContextVk *contextVk)
5242 {
5243 if (mStatus == QueryStatus::Active)
5244 {
5245 endQueryImpl(contextVk, &contextVk->getStartedRenderPassCommands().getCommandBuffer());
5246 contextVk->getStartedRenderPassCommands().retainResource(this);
5247 }
5248 }
5249
flushAndWriteTimestamp(ContextVk * contextVk)5250 angle::Result QueryHelper::flushAndWriteTimestamp(ContextVk *contextVk)
5251 {
5252 if (contextVk->hasActiveRenderPass())
5253 {
5254 ANGLE_TRY(
5255 contextVk->flushCommandsAndEndRenderPass(RenderPassClosureReason::TimestampQuery));
5256 }
5257
5258 CommandBufferAccess access;
5259 OutsideRenderPassCommandBuffer *commandBuffer;
5260 access.onQueryAccess(this);
5261 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
5262 writeTimestamp(contextVk, commandBuffer);
5263 return angle::Result::Continue;
5264 }
5265
writeTimestampToPrimary(ContextVk * contextVk,PrimaryCommandBuffer * primary)5266 void QueryHelper::writeTimestampToPrimary(ContextVk *contextVk, PrimaryCommandBuffer *primary)
5267 {
5268 // Note that commands may not be flushed at this point.
5269
5270 const QueryPool &queryPool = getQueryPool();
5271 resetQueryPoolImpl(contextVk, queryPool, primary);
5272 primary->writeTimestamp(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, queryPool, mQuery);
5273 }
5274
writeTimestamp(ContextVk * contextVk,OutsideRenderPassCommandBuffer * commandBuffer)5275 void QueryHelper::writeTimestamp(ContextVk *contextVk,
5276 OutsideRenderPassCommandBuffer *commandBuffer)
5277 {
5278 const QueryPool &queryPool = getQueryPool();
5279 resetQueryPoolImpl(contextVk, queryPool, commandBuffer);
5280 commandBuffer->writeTimestamp(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, queryPool, mQuery);
5281 }
5282
hasSubmittedCommands() const5283 bool QueryHelper::hasSubmittedCommands() const
5284 {
5285 return mUse.valid();
5286 }
5287
getUint64ResultNonBlocking(ContextVk * contextVk,QueryResult * resultOut,bool * availableOut)5288 angle::Result QueryHelper::getUint64ResultNonBlocking(ContextVk *contextVk,
5289 QueryResult *resultOut,
5290 bool *availableOut)
5291 {
5292 ASSERT(valid());
5293 VkResult result;
5294
5295 // Ensure that we only wait if we have inserted a query in command buffer. Otherwise you will
5296 // wait forever and trigger GPU timeout.
5297 if (hasSubmittedCommands())
5298 {
5299 constexpr VkQueryResultFlags kFlags = VK_QUERY_RESULT_64_BIT;
5300 result = getResultImpl(contextVk, kFlags, resultOut);
5301 }
5302 else
5303 {
5304 result = VK_SUCCESS;
5305 *resultOut = 0;
5306 }
5307
5308 if (result == VK_NOT_READY)
5309 {
5310 *availableOut = false;
5311 return angle::Result::Continue;
5312 }
5313 else
5314 {
5315 ANGLE_VK_TRY(contextVk, result);
5316 *availableOut = true;
5317 }
5318 return angle::Result::Continue;
5319 }
5320
getUint64Result(ContextVk * contextVk,QueryResult * resultOut)5321 angle::Result QueryHelper::getUint64Result(ContextVk *contextVk, QueryResult *resultOut)
5322 {
5323 ASSERT(valid());
5324 if (hasSubmittedCommands())
5325 {
5326 constexpr VkQueryResultFlags kFlags = VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT;
5327 ANGLE_VK_TRY(contextVk, getResultImpl(contextVk, kFlags, resultOut));
5328 }
5329 else
5330 {
5331 *resultOut = 0;
5332 }
5333 return angle::Result::Continue;
5334 }
5335
getResultImpl(ContextVk * contextVk,const VkQueryResultFlags flags,QueryResult * resultOut)5336 VkResult QueryHelper::getResultImpl(ContextVk *contextVk,
5337 const VkQueryResultFlags flags,
5338 QueryResult *resultOut)
5339 {
5340 std::array<uint64_t, 2 * gl::IMPLEMENTATION_ANGLE_MULTIVIEW_MAX_VIEWS> results;
5341
5342 VkDevice device = contextVk->getDevice();
5343 VkResult result = getQueryPool().getResults(device, mQuery, mQueryCount, sizeof(results),
5344 results.data(), sizeof(uint64_t), flags);
5345
5346 if (result == VK_SUCCESS)
5347 {
5348 resultOut->setResults(results.data(), mQueryCount);
5349 }
5350
5351 return result;
5352 }
5353
5354 // SemaphoreHelper implementation
SemaphoreHelper()5355 SemaphoreHelper::SemaphoreHelper() : mSemaphorePoolIndex(0), mSemaphore(0) {}
5356
~SemaphoreHelper()5357 SemaphoreHelper::~SemaphoreHelper() {}
5358
SemaphoreHelper(SemaphoreHelper && other)5359 SemaphoreHelper::SemaphoreHelper(SemaphoreHelper &&other)
5360 : mSemaphorePoolIndex(other.mSemaphorePoolIndex), mSemaphore(other.mSemaphore)
5361 {
5362 other.mSemaphore = nullptr;
5363 }
5364
operator =(SemaphoreHelper && other)5365 SemaphoreHelper &SemaphoreHelper::operator=(SemaphoreHelper &&other)
5366 {
5367 std::swap(mSemaphorePoolIndex, other.mSemaphorePoolIndex);
5368 std::swap(mSemaphore, other.mSemaphore);
5369 return *this;
5370 }
5371
init(const size_t semaphorePoolIndex,const Semaphore * semaphore)5372 void SemaphoreHelper::init(const size_t semaphorePoolIndex, const Semaphore *semaphore)
5373 {
5374 mSemaphorePoolIndex = semaphorePoolIndex;
5375 mSemaphore = semaphore;
5376 }
5377
deinit()5378 void SemaphoreHelper::deinit()
5379 {
5380 mSemaphorePoolIndex = 0;
5381 mSemaphore = nullptr;
5382 }
5383
GetPipelineStage(gl::ShaderType stage)5384 PipelineStage GetPipelineStage(gl::ShaderType stage)
5385 {
5386 const PipelineStage pipelineStage = kPipelineStageShaderMap[stage];
5387 ASSERT(pipelineStage == PipelineStage::VertexShader ||
5388 pipelineStage == PipelineStage::TessellationControl ||
5389 pipelineStage == PipelineStage::TessellationEvaluation ||
5390 pipelineStage == PipelineStage::GeometryShader ||
5391 pipelineStage == PipelineStage::FragmentShader ||
5392 pipelineStage == PipelineStage::ComputeShader);
5393 return pipelineStage;
5394 }
5395
5396 // PipelineBarrier implementation.
addDiagnosticsString(std::ostringstream & out) const5397 void PipelineBarrier::addDiagnosticsString(std::ostringstream &out) const
5398 {
5399 if (mMemoryBarrierSrcAccess != 0 || mMemoryBarrierDstAccess != 0)
5400 {
5401 out << "Src: 0x" << std::hex << mMemoryBarrierSrcAccess << " → Dst: 0x" << std::hex
5402 << mMemoryBarrierDstAccess << std::endl;
5403 }
5404 }
5405
5406 // PipelineBarrierArray implementation.
execute(Renderer * renderer,PrimaryCommandBuffer * primary)5407 void PipelineBarrierArray::execute(Renderer *renderer, PrimaryCommandBuffer *primary)
5408 {
5409 // make a local copy for faster access
5410 PipelineStagesMask mask = mBarrierMask;
5411 if (mask.none())
5412 {
5413 return;
5414 }
5415
5416 if (renderer->getFeatures().preferAggregateBarrierCalls.enabled)
5417 {
5418 PipelineStagesMask::Iterator iter = mask.begin();
5419 PipelineBarrier &barrier = mBarriers[*iter];
5420 for (++iter; iter != mask.end(); ++iter)
5421 {
5422 barrier.merge(&mBarriers[*iter]);
5423 }
5424 barrier.execute(primary);
5425 }
5426 else
5427 {
5428 for (PipelineStage pipelineStage : mask)
5429 {
5430 PipelineBarrier &barrier = mBarriers[pipelineStage];
5431 barrier.execute(primary);
5432 }
5433 }
5434 mBarrierMask.reset();
5435 }
5436
addDiagnosticsString(std::ostringstream & out) const5437 void PipelineBarrierArray::addDiagnosticsString(std::ostringstream &out) const
5438 {
5439 out << "Memory Barrier: ";
5440 for (PipelineStage pipelineStage : mBarrierMask)
5441 {
5442 const PipelineBarrier &barrier = mBarriers[pipelineStage];
5443 if (!barrier.isEmpty())
5444 {
5445 barrier.addDiagnosticsString(out);
5446 }
5447 }
5448 out << "\\l";
5449 }
5450
5451 // BufferHelper implementation.
BufferHelper()5452 BufferHelper::BufferHelper()
5453 : mCurrentWriteAccess(0),
5454 mCurrentReadAccess(0),
5455 mCurrentWriteStages(0),
5456 mCurrentReadStages(0),
5457 mSerial(),
5458 mClientBuffer(nullptr),
5459 mIsReleasedToExternal(false)
5460 {}
5461
~BufferHelper()5462 BufferHelper::~BufferHelper()
5463 {
5464 // We must have released external buffer properly
5465 ASSERT(mClientBuffer == nullptr);
5466 }
5467
BufferHelper(BufferHelper && other)5468 BufferHelper::BufferHelper(BufferHelper &&other)
5469 {
5470 *this = std::move(other);
5471 }
5472
operator =(BufferHelper && other)5473 BufferHelper &BufferHelper::operator=(BufferHelper &&other)
5474 {
5475 ReadWriteResource::operator=(std::move(other));
5476
5477 mSuballocation = std::move(other.mSuballocation);
5478 mBufferWithUserSize = std::move(other.mBufferWithUserSize);
5479
5480 mCurrentDeviceQueueIndex = other.mCurrentDeviceQueueIndex;
5481 mIsReleasedToExternal = other.mIsReleasedToExternal;
5482 mCurrentWriteAccess = other.mCurrentWriteAccess;
5483 mCurrentReadAccess = other.mCurrentReadAccess;
5484 mCurrentWriteStages = other.mCurrentWriteStages;
5485 mCurrentReadStages = other.mCurrentReadStages;
5486 if (other.mCurrentWriteEvent.valid())
5487 {
5488 mCurrentWriteEvent = std::move(other.mCurrentWriteEvent);
5489 }
5490 if (!other.mCurrentReadEvents.empty())
5491 {
5492 mCurrentReadEvents = std::move(other.mCurrentReadEvents);
5493 }
5494 mTransformFeedbackWriteHeuristicBits = std::move(other.mTransformFeedbackWriteHeuristicBits);
5495 mSerial = other.mSerial;
5496 mClientBuffer = std::move(other.mClientBuffer);
5497
5498 return *this;
5499 }
5500
init(ErrorContext * context,const VkBufferCreateInfo & requestedCreateInfo,VkMemoryPropertyFlags memoryPropertyFlags)5501 angle::Result BufferHelper::init(ErrorContext *context,
5502 const VkBufferCreateInfo &requestedCreateInfo,
5503 VkMemoryPropertyFlags memoryPropertyFlags)
5504 {
5505 Renderer *renderer = context->getRenderer();
5506 const Allocator &allocator = renderer->getAllocator();
5507
5508 initializeBarrierTracker(context);
5509
5510 VkBufferCreateInfo modifiedCreateInfo;
5511 const VkBufferCreateInfo *createInfo = &requestedCreateInfo;
5512
5513 if (renderer->getFeatures().padBuffersToMaxVertexAttribStride.enabled)
5514 {
5515 const VkDeviceSize maxVertexAttribStride = renderer->getMaxVertexAttribStride();
5516 ASSERT(maxVertexAttribStride);
5517 modifiedCreateInfo = requestedCreateInfo;
5518 modifiedCreateInfo.size += maxVertexAttribStride;
5519 createInfo = &modifiedCreateInfo;
5520 }
5521
5522 VkMemoryPropertyFlags requiredFlags =
5523 (memoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
5524 VkMemoryPropertyFlags preferredFlags =
5525 (memoryPropertyFlags & (~VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT));
5526
5527 bool persistentlyMapped = renderer->getFeatures().persistentlyMappedBuffers.enabled;
5528
5529 // Check that the allocation is not too large.
5530 uint32_t memoryTypeIndex = kInvalidMemoryTypeIndex;
5531 ANGLE_VK_TRY(context, allocator.findMemoryTypeIndexForBufferInfo(
5532 *createInfo, requiredFlags, preferredFlags, persistentlyMapped,
5533 &memoryTypeIndex));
5534
5535 VkDeviceSize heapSize =
5536 renderer->getMemoryProperties().getHeapSizeForMemoryType(memoryTypeIndex);
5537
5538 ANGLE_VK_CHECK(context, createInfo->size <= heapSize, VK_ERROR_OUT_OF_DEVICE_MEMORY);
5539
5540 VkMemoryPropertyFlags memoryPropertyFlagsOut;
5541 allocator.getMemoryTypeProperties(memoryTypeIndex, &memoryPropertyFlagsOut);
5542 // Allocate buffer object
5543 DeviceScoped<Buffer> buffer(renderer->getDevice());
5544 ANGLE_VK_TRY(context, buffer.get().init(context->getDevice(), *createInfo));
5545
5546 DeviceScoped<DeviceMemory> deviceMemory(renderer->getDevice());
5547 VkDeviceSize sizeOut;
5548 uint32_t bufferMemoryTypeIndex;
5549 ANGLE_VK_TRY(context,
5550 AllocateBufferMemory(context, MemoryAllocationType::Buffer, memoryPropertyFlagsOut,
5551 &memoryPropertyFlagsOut, nullptr, &buffer.get(),
5552 &bufferMemoryTypeIndex, &deviceMemory.get(), &sizeOut));
5553 ASSERT(sizeOut >= createInfo->size);
5554
5555 mSuballocation.initWithEntireBuffer(context, buffer.get(), MemoryAllocationType::Buffer,
5556 bufferMemoryTypeIndex, deviceMemory.get(),
5557 memoryPropertyFlagsOut, requestedCreateInfo.size, sizeOut);
5558 if (isHostVisible())
5559 {
5560 uint8_t *ptrOut;
5561 ANGLE_TRY(map(context, &ptrOut));
5562 }
5563
5564 if (renderer->getFeatures().allocateNonZeroMemory.enabled)
5565 {
5566 ANGLE_TRY(initializeNonZeroMemory(context, createInfo->usage, createInfo->size));
5567 }
5568
5569 return angle::Result::Continue;
5570 }
5571
initExternal(ErrorContext * context,VkMemoryPropertyFlags memoryProperties,const VkBufferCreateInfo & requestedCreateInfo,GLeglClientBufferEXT clientBuffer)5572 angle::Result BufferHelper::initExternal(ErrorContext *context,
5573 VkMemoryPropertyFlags memoryProperties,
5574 const VkBufferCreateInfo &requestedCreateInfo,
5575 GLeglClientBufferEXT clientBuffer)
5576 {
5577 ASSERT(IsAndroid());
5578
5579 Renderer *renderer = context->getRenderer();
5580
5581 initializeBarrierTracker(context);
5582
5583 VkBufferCreateInfo modifiedCreateInfo = requestedCreateInfo;
5584 VkExternalMemoryBufferCreateInfo externCreateInfo = {};
5585 externCreateInfo.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO;
5586 externCreateInfo.handleTypes =
5587 VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
5588 externCreateInfo.pNext = nullptr;
5589 modifiedCreateInfo.pNext = &externCreateInfo;
5590
5591 DeviceScoped<Buffer> buffer(renderer->getDevice());
5592 ANGLE_VK_TRY(context, buffer.get().init(renderer->getDevice(), modifiedCreateInfo));
5593
5594 DeviceScoped<DeviceMemory> deviceMemory(renderer->getDevice());
5595 VkMemoryPropertyFlags memoryPropertyFlagsOut;
5596 VkDeviceSize allocatedSize = 0;
5597 uint32_t memoryTypeIndex;
5598 ANGLE_TRY(InitAndroidExternalMemory(context, clientBuffer, memoryProperties, &buffer.get(),
5599 &memoryPropertyFlagsOut, &memoryTypeIndex,
5600 &deviceMemory.get(), &allocatedSize));
5601 mClientBuffer = clientBuffer;
5602
5603 mSuballocation.initWithEntireBuffer(context, buffer.get(), MemoryAllocationType::BufferExternal,
5604 memoryTypeIndex, deviceMemory.get(), memoryPropertyFlagsOut,
5605 requestedCreateInfo.size, allocatedSize);
5606 if (isHostVisible())
5607 {
5608 uint8_t *ptrOut;
5609 ANGLE_TRY(map(context, &ptrOut));
5610 }
5611 return angle::Result::Continue;
5612 }
5613
initSuballocation(Context * context,uint32_t memoryTypeIndex,size_t size,size_t alignment,BufferUsageType usageType,BufferPool * pool)5614 VkResult BufferHelper::initSuballocation(Context *context,
5615 uint32_t memoryTypeIndex,
5616 size_t size,
5617 size_t alignment,
5618 BufferUsageType usageType,
5619 BufferPool *pool)
5620 {
5621 ASSERT(pool != nullptr);
5622 Renderer *renderer = context->getRenderer();
5623
5624 // We should reset these in case the BufferHelper object has been released and called
5625 // initSuballocation again.
5626 initializeBarrierTracker(context);
5627
5628 if (renderer->getFeatures().padBuffersToMaxVertexAttribStride.enabled)
5629 {
5630 const VkDeviceSize maxVertexAttribStride = renderer->getMaxVertexAttribStride();
5631 ASSERT(maxVertexAttribStride);
5632 size += maxVertexAttribStride;
5633 }
5634
5635 VK_RESULT_TRY(pool->allocateBuffer(context, size, alignment, &mSuballocation));
5636
5637 context->getPerfCounters().bufferSuballocationCalls++;
5638
5639 return VK_SUCCESS;
5640 }
5641
initializeBarrierTracker(ErrorContext * context)5642 void BufferHelper::initializeBarrierTracker(ErrorContext *context)
5643 {
5644 Renderer *renderer = context->getRenderer();
5645 mCurrentDeviceQueueIndex = context->getDeviceQueueIndex();
5646 mIsReleasedToExternal = false;
5647 mCurrentWriteEvent.release(renderer);
5648 mCurrentReadEvents.release(renderer);
5649 mSerial = renderer->getResourceSerialFactory().generateBufferSerial();
5650 mCurrentWriteAccess = 0;
5651 mCurrentReadAccess = 0;
5652 mCurrentWriteStages = 0;
5653 mCurrentReadStages = 0;
5654 }
5655
initializeNonZeroMemory(ErrorContext * context,VkBufferUsageFlags usage,VkDeviceSize size)5656 angle::Result BufferHelper::initializeNonZeroMemory(ErrorContext *context,
5657 VkBufferUsageFlags usage,
5658 VkDeviceSize size)
5659 {
5660 Renderer *renderer = context->getRenderer();
5661
5662 // This memory can't be mapped, so the buffer must be marked as a transfer destination so we
5663 // can use a staging resource to initialize it to a non-zero value. If the memory is
5664 // mappable we do the initialization in AllocateBufferMemory.
5665 if (!isHostVisible() && (usage & VK_BUFFER_USAGE_TRANSFER_DST_BIT) != 0)
5666 {
5667 ASSERT((usage & VK_BUFFER_USAGE_TRANSFER_DST_BIT) != 0);
5668 // Staging buffer memory is non-zero-initialized in 'init'.
5669 StagingBuffer stagingBuffer;
5670 ANGLE_TRY(stagingBuffer.init(context, size, StagingUsage::Both));
5671
5672 // Queue a DMA copy.
5673 VkBufferCopy copyRegion = {};
5674 copyRegion.srcOffset = 0;
5675 copyRegion.dstOffset = getOffset();
5676 copyRegion.size = size;
5677
5678 ScopedPrimaryCommandBuffer scopedCommandBuffer(renderer->getDevice());
5679 ANGLE_TRY(renderer->getCommandBufferOneOff(context, ProtectionType::Unprotected,
5680 &scopedCommandBuffer));
5681 PrimaryCommandBuffer &commandBuffer = scopedCommandBuffer.get();
5682
5683 commandBuffer.copyBuffer(stagingBuffer.getBuffer(), getBuffer(), 1, ©Region);
5684
5685 ANGLE_VK_TRY(context, commandBuffer.end());
5686
5687 QueueSerial queueSerial;
5688 ANGLE_TRY(renderer->queueSubmitOneOff(
5689 context, std::move(scopedCommandBuffer), ProtectionType::Unprotected,
5690 egl::ContextPriority::Medium, VK_NULL_HANDLE, 0, &queueSerial));
5691
5692 stagingBuffer.collectGarbage(renderer, queueSerial);
5693 // Update both ResourceUse objects, since mReadOnlyUse tracks when the buffer can be
5694 // destroyed, and mReadWriteUse tracks when the write has completed.
5695 setWriteQueueSerial(queueSerial);
5696 }
5697 else if (isHostVisible())
5698 {
5699 // Can map the memory.
5700 // Pick an arbitrary value to initialize non-zero memory for sanitization.
5701 constexpr int kNonZeroInitValue = 55;
5702 uint8_t *mapPointer = mSuballocation.getMappedMemory();
5703 memset(mapPointer, kNonZeroInitValue, static_cast<size_t>(getSize()));
5704 if (!isCoherent())
5705 {
5706 mSuballocation.flush(renderer);
5707 }
5708 }
5709
5710 return angle::Result::Continue;
5711 }
5712
getBufferForVertexArray(ContextVk * contextVk,VkDeviceSize actualDataSize,VkDeviceSize * offsetOut)5713 const Buffer &BufferHelper::getBufferForVertexArray(ContextVk *contextVk,
5714 VkDeviceSize actualDataSize,
5715 VkDeviceSize *offsetOut)
5716 {
5717 ASSERT(mSuballocation.valid());
5718 ASSERT(actualDataSize <= mSuballocation.getSize());
5719
5720 if (!contextVk->hasRobustAccess() || !mSuballocation.isSuballocated() ||
5721 actualDataSize == mSuballocation.getSize())
5722 {
5723 *offsetOut = mSuballocation.getOffset();
5724 return mSuballocation.getBuffer();
5725 }
5726
5727 if (!mBufferWithUserSize.valid())
5728 {
5729 // Allocate buffer that is backed by sub-range of the memory for vertex array usage. This is
5730 // only needed when robust resource init is enabled so that vulkan driver will know the
5731 // exact size of the vertex buffer it is supposedly to use and prevent out of bound access.
5732 VkBufferCreateInfo createInfo = {};
5733 createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
5734 createInfo.flags = 0;
5735 createInfo.size = actualDataSize;
5736 createInfo.usage = kVertexBufferUsageFlags | kIndexBufferUsageFlags;
5737 createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
5738 createInfo.queueFamilyIndexCount = 0;
5739 createInfo.pQueueFamilyIndices = nullptr;
5740 mBufferWithUserSize.init(contextVk->getDevice(), createInfo);
5741
5742 VkMemoryRequirements memoryRequirements;
5743 mBufferWithUserSize.getMemoryRequirements(contextVk->getDevice(), &memoryRequirements);
5744 ASSERT(contextVk->getRenderer()->isMockICDEnabled() ||
5745 mSuballocation.getSize() >= memoryRequirements.size);
5746 ASSERT(!contextVk->getRenderer()->isMockICDEnabled() ||
5747 mSuballocation.getOffset() % memoryRequirements.alignment == 0);
5748
5749 mBufferWithUserSize.bindMemory(contextVk->getDevice(), mSuballocation.getDeviceMemory(),
5750 mSuballocation.getOffset());
5751 }
5752 *offsetOut = 0;
5753 return mBufferWithUserSize;
5754 }
5755
onBufferUserSizeChange(Renderer * renderer)5756 bool BufferHelper::onBufferUserSizeChange(Renderer *renderer)
5757 {
5758 // Buffer's user size and allocation size may be different due to alignment requirement. In
5759 // normal usage we just use the actual allocation size and it is good enough. But when
5760 // robustResourceInit is enabled, mBufferWithUserSize is created to mjatch the exact user
5761 // size. Thus when user size changes, we must clear and recreate this mBufferWithUserSize.
5762 if (mBufferWithUserSize.valid())
5763 {
5764 BufferSuballocation unusedSuballocation;
5765 renderer->collectSuballocationGarbage(mUse, std::move(unusedSuballocation),
5766 std::move(mBufferWithUserSize));
5767 mSerial = renderer->getResourceSerialFactory().generateBufferSerial();
5768 return true;
5769 }
5770 return false;
5771 }
5772
destroy(Renderer * renderer)5773 void BufferHelper::destroy(Renderer *renderer)
5774 {
5775 mCurrentWriteEvent.release(renderer);
5776 mCurrentReadEvents.release(renderer);
5777 ASSERT(mDescriptorSetCacheManager.allValidEntriesAreCached(nullptr));
5778 mDescriptorSetCacheManager.destroyKeys(renderer);
5779 unmap(renderer);
5780 mBufferWithUserSize.destroy(renderer->getDevice());
5781 mSuballocation.destroy(renderer);
5782 if (mClientBuffer != nullptr)
5783 {
5784 ReleaseAndroidExternalMemory(renderer, mClientBuffer);
5785 mClientBuffer = nullptr;
5786 }
5787 }
5788
release(Renderer * renderer)5789 void BufferHelper::release(Renderer *renderer)
5790 {
5791 mCurrentWriteEvent.release(renderer);
5792 mCurrentReadEvents.release(renderer);
5793 releaseImpl(renderer);
5794 }
5795
release(Context * context)5796 void BufferHelper::release(Context *context)
5797 {
5798 mCurrentWriteEvent.release(context);
5799 mCurrentReadEvents.release(context);
5800 releaseImpl(context->getRenderer());
5801 }
5802
releaseImpl(Renderer * renderer)5803 void BufferHelper::releaseImpl(Renderer *renderer)
5804 {
5805 ASSERT(mDescriptorSetCacheManager.empty());
5806 unmap(renderer);
5807
5808 if (mSuballocation.valid())
5809 {
5810 renderer->collectSuballocationGarbage(mUse, std::move(mSuballocation),
5811 std::move(mBufferWithUserSize));
5812 }
5813 mUse.reset();
5814 mWriteUse.reset();
5815 ASSERT(!mBufferWithUserSize.valid());
5816
5817 if (mClientBuffer != nullptr)
5818 {
5819 ReleaseAndroidExternalMemory(renderer, mClientBuffer);
5820 mClientBuffer = nullptr;
5821 }
5822 }
5823
releaseBufferAndDescriptorSetCache(ContextVk * contextVk)5824 void BufferHelper::releaseBufferAndDescriptorSetCache(ContextVk *contextVk)
5825 {
5826 Renderer *renderer = contextVk->getRenderer();
5827
5828 ASSERT(mDescriptorSetCacheManager.allValidEntriesAreCached(contextVk));
5829 if (renderer->hasResourceUseFinished(getResourceUse()))
5830 {
5831 mDescriptorSetCacheManager.destroyKeys(renderer);
5832 }
5833 else
5834 {
5835 mDescriptorSetCacheManager.releaseKeys(renderer);
5836 }
5837
5838 release(contextVk);
5839 }
5840
map(ErrorContext * context,uint8_t ** ptrOut)5841 angle::Result BufferHelper::map(ErrorContext *context, uint8_t **ptrOut)
5842 {
5843 if (!mSuballocation.isMapped())
5844 {
5845 ANGLE_VK_TRY(context, mSuballocation.map(context));
5846 }
5847 *ptrOut = mSuballocation.getMappedMemory();
5848 return angle::Result::Continue;
5849 }
5850
mapWithOffset(ErrorContext * context,uint8_t ** ptrOut,size_t offset)5851 angle::Result BufferHelper::mapWithOffset(ErrorContext *context, uint8_t **ptrOut, size_t offset)
5852 {
5853 uint8_t *mapBufPointer;
5854 ANGLE_TRY(map(context, &mapBufPointer));
5855 *ptrOut = mapBufPointer + offset;
5856 return angle::Result::Continue;
5857 }
5858
flush(Renderer * renderer,VkDeviceSize offset,VkDeviceSize size)5859 angle::Result BufferHelper::flush(Renderer *renderer, VkDeviceSize offset, VkDeviceSize size)
5860 {
5861 mSuballocation.flush(renderer);
5862 return angle::Result::Continue;
5863 }
flush(Renderer * renderer)5864 angle::Result BufferHelper::flush(Renderer *renderer)
5865 {
5866 return flush(renderer, 0, getSize());
5867 }
5868
invalidate(Renderer * renderer,VkDeviceSize offset,VkDeviceSize size)5869 angle::Result BufferHelper::invalidate(Renderer *renderer, VkDeviceSize offset, VkDeviceSize size)
5870 {
5871 mSuballocation.invalidate(renderer);
5872 return angle::Result::Continue;
5873 }
invalidate(Renderer * renderer)5874 angle::Result BufferHelper::invalidate(Renderer *renderer)
5875 {
5876 return invalidate(renderer, 0, getSize());
5877 }
5878
changeQueueFamily(uint32_t srcQueueFamilyIndex,uint32_t dstQueueFamilyIndex,OutsideRenderPassCommandBuffer * commandBuffer)5879 void BufferHelper::changeQueueFamily(uint32_t srcQueueFamilyIndex,
5880 uint32_t dstQueueFamilyIndex,
5881 OutsideRenderPassCommandBuffer *commandBuffer)
5882 {
5883 VkBufferMemoryBarrier bufferMemoryBarrier = {};
5884 bufferMemoryBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
5885 bufferMemoryBarrier.srcAccessMask = 0;
5886 bufferMemoryBarrier.dstAccessMask = 0;
5887 bufferMemoryBarrier.srcQueueFamilyIndex = srcQueueFamilyIndex;
5888 bufferMemoryBarrier.dstQueueFamilyIndex = dstQueueFamilyIndex;
5889 bufferMemoryBarrier.buffer = getBuffer().getHandle();
5890 bufferMemoryBarrier.offset = getOffset();
5891 bufferMemoryBarrier.size = getSize();
5892
5893 commandBuffer->bufferBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
5894 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, &bufferMemoryBarrier);
5895 }
5896
acquireFromExternal(DeviceQueueIndex externalQueueFamilyIndex,DeviceQueueIndex newDeviceQueueIndex,OutsideRenderPassCommandBuffer * commandBuffer)5897 void BufferHelper::acquireFromExternal(DeviceQueueIndex externalQueueFamilyIndex,
5898 DeviceQueueIndex newDeviceQueueIndex,
5899 OutsideRenderPassCommandBuffer *commandBuffer)
5900 {
5901 changeQueueFamily(externalQueueFamilyIndex.familyIndex(), newDeviceQueueIndex.familyIndex(),
5902 commandBuffer);
5903 mCurrentDeviceQueueIndex = newDeviceQueueIndex;
5904 mIsReleasedToExternal = false;
5905 }
5906
releaseToExternal(DeviceQueueIndex externalQueueIndex,OutsideRenderPassCommandBuffer * commandBuffer)5907 void BufferHelper::releaseToExternal(DeviceQueueIndex externalQueueIndex,
5908 OutsideRenderPassCommandBuffer *commandBuffer)
5909 {
5910 if (mCurrentDeviceQueueIndex.familyIndex() != externalQueueIndex.familyIndex())
5911 {
5912 changeQueueFamily(mCurrentDeviceQueueIndex.familyIndex(), externalQueueIndex.familyIndex(),
5913 commandBuffer);
5914 mCurrentDeviceQueueIndex = kInvalidDeviceQueueIndex;
5915 }
5916 mIsReleasedToExternal = true;
5917 }
5918
recordReadBarrier(Context * context,VkAccessFlags readAccessType,VkPipelineStageFlags readPipelineStageFlags,PipelineStage stageIndex,PipelineBarrierArray * pipelineBarriers,EventBarrierArray * eventBarriers,RefCountedEventCollector * eventCollector)5919 void BufferHelper::recordReadBarrier(Context *context,
5920 VkAccessFlags readAccessType,
5921 VkPipelineStageFlags readPipelineStageFlags,
5922 PipelineStage stageIndex,
5923 PipelineBarrierArray *pipelineBarriers,
5924 EventBarrierArray *eventBarriers,
5925 RefCountedEventCollector *eventCollector)
5926 {
5927 // If the type of read already tracked by mCurrentReadEvents, it means we must already inserted
5928 // the barrier when mCurrentReadEvents is set. No new barrier is needed.
5929 EventStage eventStage = kBufferMemoryBarrierData[stageIndex].eventStage;
5930 if (mCurrentReadEvents.hasEventAndAccess(eventStage, readAccessType))
5931 {
5932 ASSERT((context->getRenderer()->getPipelineStageMask(eventStage) &
5933 readPipelineStageFlags) == readPipelineStageFlags);
5934 ASSERT((mCurrentReadEvents.getAccessFlags(eventStage) & readAccessType) == readAccessType);
5935 return;
5936 }
5937
5938 // If the type of read already tracked by mCurrentReadAccess, it means we must already inserted
5939 // the barrier when mCurrentReadAccess is set. No new barrier is needed.
5940 if ((mCurrentReadAccess & readAccessType) == readAccessType &&
5941 (mCurrentReadStages & readPipelineStageFlags) == readPipelineStageFlags)
5942 {
5943 return;
5944 }
5945
5946 // Barrier against prior write VkEvent.
5947 if (mCurrentWriteEvent.valid())
5948 {
5949 eventBarriers->addEventMemoryBarrier(context->getRenderer(), mCurrentWriteEvent.getEvent(),
5950 mCurrentWriteEvent.getAccessFlags(),
5951 readPipelineStageFlags, readAccessType);
5952 }
5953
5954 // Barrier against prior access that not tracked by VkEvent using pipelineBarrier.
5955 if (mCurrentWriteAccess != 0)
5956 {
5957 pipelineBarriers->mergeMemoryBarrier(stageIndex, mCurrentWriteStages,
5958 readPipelineStageFlags, mCurrentWriteAccess,
5959 readAccessType);
5960 }
5961 }
5962
recordReadEvent(Context * context,VkAccessFlags readAccessType,VkPipelineStageFlags readPipelineStageFlags,PipelineStage readStage,const QueueSerial & queueSerial,EventStage eventStage,RefCountedEventArray * refCountedEventArray)5963 void BufferHelper::recordReadEvent(Context *context,
5964 VkAccessFlags readAccessType,
5965 VkPipelineStageFlags readPipelineStageFlags,
5966 PipelineStage readStage,
5967 const QueueSerial &queueSerial,
5968 EventStage eventStage,
5969 RefCountedEventArray *refCountedEventArray)
5970 {
5971 bool useVkEvent = false;
5972 if (context->getFeatures().useVkEventForBufferBarrier.enabled &&
5973 eventStage != EventStage::InvalidEnum)
5974 {
5975 // VkCmdSetEvent can remove the unnecessary GPU pipeline bubble that comes from false
5976 // dependency between fragment and vertex/transfer/compute stages. But it also comes with
5977 // higher overhead. In order to strike the balance, right now we only track it with VkEvent
5978 // if it ever written by transform feedback.
5979 useVkEvent = mTransformFeedbackWriteHeuristicBits.any();
5980 }
5981
5982 if (useVkEvent && refCountedEventArray->initEventAtStage(context, eventStage))
5983 {
5984 // Replace the mCurrentReadEvents so that it tracks the current read so that we can
5985 // waitEvent later.
5986 mCurrentReadEvents.replaceEventAtStage(
5987 context, eventStage, refCountedEventArray->getEvent(eventStage), readAccessType);
5988 }
5989 else
5990 {
5991 // Accumulate new read usage to be used in pipelineBarrier.
5992 mCurrentReadAccess |= readAccessType;
5993 mCurrentReadStages |= readPipelineStageFlags;
5994 }
5995
5996 if (getResourceUse() >= queueSerial)
5997 {
5998 // We should not run into situation that RP is writing to it while we are reading it here
5999 ASSERT(!(getWriteResourceUse() >= queueSerial));
6000 // A buffer could have read accessed by both renderPassCommands and
6001 // outsideRenderPassCommands and there is no need to endRP or flush. In this case, the
6002 // renderPassCommands' read will override the outsideRenderPassCommands' read, since its
6003 // queueSerial must be greater than outsideRP.
6004 }
6005 else
6006 {
6007 setQueueSerial(queueSerial);
6008 }
6009 }
6010
recordWriteBarrier(Context * context,VkAccessFlags writeAccessType,VkPipelineStageFlags writeStage,PipelineStage stageIndex,const QueueSerial & queueSerial,PipelineBarrierArray * pipelineBarriers,EventBarrierArray * eventBarriers,RefCountedEventCollector * eventCollector)6011 void BufferHelper::recordWriteBarrier(Context *context,
6012 VkAccessFlags writeAccessType,
6013 VkPipelineStageFlags writeStage,
6014 PipelineStage stageIndex,
6015 const QueueSerial &queueSerial,
6016 PipelineBarrierArray *pipelineBarriers,
6017 EventBarrierArray *eventBarriers,
6018 RefCountedEventCollector *eventCollector)
6019 {
6020 Renderer *renderer = context->getRenderer();
6021
6022 // Barrier against prior read VkEvents.
6023 if (!mCurrentReadEvents.empty())
6024 {
6025 // If we already have a event in the same command buffer, fall back to pipeline. Otherwise
6026 // you may run into wait an event that has not been set. This may be can be removed once we
6027 // fix https://issuetracker.google.com/392968868
6028 if (usedByCommandBuffer(queueSerial))
6029 {
6030 for (EventStage eventStage : mCurrentReadEvents.getBitMask())
6031 {
6032 mCurrentReadStages |= renderer->getPipelineStageMask(eventStage);
6033 mCurrentReadAccess |= mCurrentReadEvents.getAccessFlags(eventStage);
6034 }
6035 }
6036 else
6037 {
6038 for (EventStage eventStage : mCurrentReadEvents.getBitMask())
6039 {
6040 const RefCountedEvent &waitEvent = mCurrentReadEvents.getEvent(eventStage);
6041 const VkAccessFlags srcAccess = mCurrentReadEvents.getAccessFlags(eventStage);
6042 eventBarriers->addEventMemoryBarrier(renderer, waitEvent, srcAccess, writeStage,
6043 writeAccessType);
6044 }
6045 }
6046 // Garbage collect the event, which tracks GPU completion automatically.
6047 mCurrentReadEvents.releaseToEventCollector(eventCollector);
6048 }
6049
6050 // Barrier against prior write VkEvent.
6051 if (mCurrentWriteEvent.valid())
6052 {
6053 const VkPipelineStageFlags srcStageFlags =
6054 renderer->getPipelineStageMask(mCurrentWriteEvent.getEventStage());
6055
6056 // If we already have a write event in the same command buffer, fall back to pipeline
6057 // barrier. Using VkEvent to track multiple writes either requires tracking multiple write
6058 // events or has to replace existing event with another event that tracks more pipeline
6059 // stage bits. Both are a bit complex. Without evidence showing we are hitting performance
6060 // issue in real world situation, this will just use pipeline barriers to track extra stages
6061 // that not captured by mCurrentWriteEvent.
6062 if (writtenByCommandBuffer(queueSerial))
6063 {
6064 mCurrentWriteStages |= srcStageFlags;
6065 mCurrentWriteAccess |= mCurrentWriteEvent.getAccessFlags();
6066 }
6067 else
6068 {
6069 eventBarriers->addEventMemoryBarrier(
6070 context->getRenderer(), mCurrentWriteEvent.getEvent(),
6071 mCurrentWriteEvent.getAccessFlags(), writeStage, writeAccessType);
6072 }
6073 // Garbage collect the event, which tracks GPU completion automatically.
6074 mCurrentWriteEvent.releaseToEventCollector(eventCollector);
6075 }
6076
6077 // We don't need to check mCurrentReadStages here since if it is not zero,
6078 // mCurrentReadAccess must not be zero as well. stage is finer grain than accessType.
6079 ASSERT((!mCurrentReadStages && !mCurrentReadAccess) ||
6080 (mCurrentReadStages && mCurrentReadAccess));
6081
6082 // Barrier against prior access that not tracked by VkEvent using pipelineBarrier.
6083 if (mCurrentReadAccess != 0 || mCurrentWriteAccess != 0)
6084 {
6085 // If there are more pipeline stage bits not captured by eventBarrier, use pipelineBarrier.
6086 VkPipelineStageFlags srcStageMask = mCurrentWriteStages | mCurrentReadStages;
6087 if (srcStageMask)
6088 {
6089 pipelineBarriers->mergeMemoryBarrier(stageIndex, srcStageMask, writeStage,
6090 mCurrentWriteAccess, writeAccessType);
6091 }
6092
6093 mCurrentReadStages = 0;
6094 mCurrentReadAccess = 0;
6095 mCurrentWriteStages = 0;
6096 mCurrentWriteAccess = 0;
6097 }
6098 }
6099
recordWriteEvent(Context * context,VkAccessFlags writeAccessType,VkPipelineStageFlags writePipelineStageFlags,const QueueSerial & writeQueueSerial,PipelineStage writeStage,RefCountedEventArray * refCountedEventArray)6100 void BufferHelper::recordWriteEvent(Context *context,
6101 VkAccessFlags writeAccessType,
6102 VkPipelineStageFlags writePipelineStageFlags,
6103 const QueueSerial &writeQueueSerial,
6104 PipelineStage writeStage,
6105 RefCountedEventArray *refCountedEventArray)
6106 {
6107 EventStage eventStage = kBufferMemoryBarrierData[writeStage].eventStage;
6108 bool useVkEvent = false;
6109
6110 if (context->getFeatures().useVkEventForBufferBarrier.enabled &&
6111 eventStage != EventStage::InvalidEnum)
6112 {
6113 ASSERT(mCurrentReadEvents.empty());
6114 updatePipelineStageWriteHistory(writeStage);
6115
6116 // VkCmdSetEvent can remove the unnecessary GPU pipeline bubble that comes from false
6117 // dependency between fragment and vertex/transfer/compute stages. But it also comes with
6118 // higher overhead. In order to strike the balance, right now we only track it with VkEvent
6119 // if it ever written by transform feedback.
6120 useVkEvent = mTransformFeedbackWriteHeuristicBits.any();
6121
6122 // We only track one write event. In case of multiple writes like write from different
6123 // shader stages in the same render pass, only the first write is tracked by event,
6124 // additional writes will still be tracked by pipelineBarriers.
6125 if (mCurrentWriteEvent.valid())
6126 {
6127 useVkEvent = false;
6128 }
6129 }
6130
6131 if (useVkEvent && refCountedEventArray->initEventAtStage(context, eventStage))
6132 {
6133 // Copy the event to mCurrentEvent so that we can wait for it in future. This will add extra
6134 // refcount to the underlying VkEvent.
6135 mCurrentWriteEvent.setEventAndAccessFlags(refCountedEventArray->getEvent(eventStage),
6136 writeAccessType);
6137 }
6138 else
6139 {
6140 // Reset usages on the new write to be used by pipelineBarrier later.
6141 mCurrentWriteAccess = writeAccessType;
6142 mCurrentWriteStages = writePipelineStageFlags;
6143 }
6144
6145 setWriteQueueSerial(writeQueueSerial);
6146 }
6147
fillWithColor(const angle::Color<uint8_t> & color,const gl::InternalFormat & internalFormat)6148 void BufferHelper::fillWithColor(const angle::Color<uint8_t> &color,
6149 const gl::InternalFormat &internalFormat)
6150 {
6151 uint32_t count =
6152 static_cast<uint32_t>(getSize()) / static_cast<uint32_t>(internalFormat.pixelBytes);
6153 void *buffer = static_cast<void *>(getMappedMemory());
6154
6155 switch (internalFormat.internalFormat)
6156 {
6157 case GL_RGB565:
6158 {
6159 uint16_t pixelColor =
6160 ((color.blue & 0xF8) << 11) | ((color.green & 0xFC) << 5) | (color.red & 0xF8);
6161 uint16_t *pixelPtr = static_cast<uint16_t *>(buffer);
6162 std::fill_n<uint16_t *, uint32_t, uint16_t>(pixelPtr, count, pixelColor);
6163 }
6164 break;
6165 case GL_RGBA8:
6166 {
6167 uint32_t pixelColor =
6168 (color.alpha << 24) | (color.blue << 16) | (color.green << 8) | (color.red);
6169 uint32_t *pixelPtr = static_cast<uint32_t *>(buffer);
6170 std::fill_n<uint32_t *, uint32_t, uint32_t>(pixelPtr, count, pixelColor);
6171 }
6172 break;
6173 case GL_BGR565_ANGLEX:
6174 {
6175 uint16_t pixelColor =
6176 ((color.red & 0xF8) << 11) | ((color.green & 0xFC) << 5) | (color.blue & 0xF8);
6177 uint16_t *pixelPtr = static_cast<uint16_t *>(buffer);
6178 std::fill_n<uint16_t *, uint32_t, uint16_t>(pixelPtr, count, pixelColor);
6179 }
6180 break;
6181 case GL_BGRA8_EXT:
6182 {
6183 uint32_t pixelColor =
6184 (color.alpha << 24) | (color.red << 16) | (color.green << 8) | (color.blue);
6185 uint32_t *pixelPtr = static_cast<uint32_t *>(buffer);
6186 std::fill_n<uint32_t *, uint32_t, uint32_t>(pixelPtr, count, pixelColor);
6187 }
6188 break;
6189 default:
6190 UNREACHABLE(); // Unsupported format
6191 }
6192 }
6193
fillWithPattern(const void * pattern,size_t patternSize,size_t offset,size_t size)6194 void BufferHelper::fillWithPattern(const void *pattern,
6195 size_t patternSize,
6196 size_t offset,
6197 size_t size)
6198 {
6199 ASSERT(offset + size <= getSize());
6200 ASSERT((size % patternSize) == 0);
6201 ASSERT((offset % patternSize) == 0);
6202
6203 uint8_t *buffer = getMappedMemory() + offset;
6204 std::memcpy(buffer, pattern, patternSize);
6205 size_t remaining = size - patternSize;
6206 while (remaining > patternSize)
6207 {
6208 std::memcpy(buffer + patternSize, buffer, patternSize);
6209 remaining -= patternSize;
6210 patternSize *= 2;
6211 }
6212 std::memcpy(buffer + patternSize, buffer, remaining);
6213 return;
6214 }
6215
6216 // Used for ImageHelper non-zero memory allocation when useVmaForImageSuballocation is disabled.
InitMappableDeviceMemory(ErrorContext * context,DeviceMemory * deviceMemory,VkDeviceSize size,int value,VkMemoryPropertyFlags memoryPropertyFlags)6217 angle::Result InitMappableDeviceMemory(ErrorContext *context,
6218 DeviceMemory *deviceMemory,
6219 VkDeviceSize size,
6220 int value,
6221 VkMemoryPropertyFlags memoryPropertyFlags)
6222 {
6223 ASSERT(!context->getFeatures().useVmaForImageSuballocation.enabled);
6224 VkDevice device = context->getDevice();
6225
6226 uint8_t *mapPointer;
6227 ANGLE_VK_TRY(context, deviceMemory->map(device, 0, VK_WHOLE_SIZE, 0, &mapPointer));
6228 memset(mapPointer, value, static_cast<size_t>(size));
6229
6230 // if the memory type is not host coherent, we perform an explicit flush.
6231 if ((memoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) == 0)
6232 {
6233 VkMappedMemoryRange mappedRange = {};
6234 mappedRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
6235 mappedRange.memory = deviceMemory->getHandle();
6236 mappedRange.size = VK_WHOLE_SIZE;
6237 ANGLE_VK_TRY(context, vkFlushMappedMemoryRanges(device, 1, &mappedRange));
6238 }
6239
6240 deviceMemory->unmap(device);
6241
6242 return angle::Result::Continue;
6243 }
6244
6245 // ImageHelper implementation.
ImageHelper()6246 ImageHelper::ImageHelper()
6247 {
6248 resetCachedProperties();
6249 // Reserve reasonable amount of space to avoid storage reallocation.
6250 mSubresourceUpdates.reserve(12);
6251 }
6252
~ImageHelper()6253 ImageHelper::~ImageHelper()
6254 {
6255 ASSERT(!valid());
6256 ASSERT(!mAcquireNextImageSemaphore.valid());
6257 }
6258
resetCachedProperties()6259 void ImageHelper::resetCachedProperties()
6260 {
6261 mImageType = VK_IMAGE_TYPE_2D;
6262 mTilingMode = VK_IMAGE_TILING_OPTIMAL;
6263 mCreateFlags = kVkImageCreateFlagsNone;
6264 mUsage = 0;
6265 mExtents = {};
6266 mRotatedAspectRatio = false;
6267 mIntendedFormatID = angle::FormatID::NONE;
6268 mActualFormatID = angle::FormatID::NONE;
6269 mSamples = 1;
6270 mImageSerial = kInvalidImageSerial;
6271 mCurrentLayout = ImageLayout::Undefined;
6272 mCurrentDeviceQueueIndex = kInvalidDeviceQueueIndex;
6273 mIsReleasedToExternal = false;
6274 mIsForeignImage = false;
6275 mLastNonShaderReadOnlyLayout = ImageLayout::Undefined;
6276 mCurrentShaderReadStageMask = 0;
6277 mFirstAllocatedLevel = gl::LevelIndex(0);
6278 mLayerCount = 0;
6279 mLevelCount = 0;
6280 mTotalStagedBufferUpdateSize = 0;
6281 mAllocationSize = 0;
6282 mMemoryAllocationType = MemoryAllocationType::InvalidEnum;
6283 mMemoryTypeIndex = kInvalidMemoryTypeIndex;
6284 std::fill(mViewFormats.begin(), mViewFormats.begin() + mViewFormats.max_size(),
6285 VK_FORMAT_UNDEFINED);
6286 mYcbcrConversionDesc.reset();
6287 mCurrentSingleClearValue.reset();
6288 mRenderPassUsageFlags.reset();
6289
6290 setEntireContentUndefined();
6291 }
6292
setEntireContentDefined()6293 void ImageHelper::setEntireContentDefined()
6294 {
6295 for (LevelContentDefinedMask &levelContentDefined : mContentDefined)
6296 {
6297 levelContentDefined.set();
6298 }
6299 for (LevelContentDefinedMask &levelContentDefined : mStencilContentDefined)
6300 {
6301 levelContentDefined.set();
6302 }
6303 }
6304
setEntireContentUndefined()6305 void ImageHelper::setEntireContentUndefined()
6306 {
6307 for (LevelContentDefinedMask &levelContentDefined : mContentDefined)
6308 {
6309 levelContentDefined.reset();
6310 }
6311 for (LevelContentDefinedMask &levelContentDefined : mStencilContentDefined)
6312 {
6313 levelContentDefined.reset();
6314 }
6315
6316 // Note: this function is typically called during init/release, but also when importing an image
6317 // from Vulkan, so unlike invalidateSubresourceContentImpl, it doesn't attempt to make sure
6318 // emulated formats have a clear staged.
6319 }
6320
setContentDefined(LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags)6321 void ImageHelper::setContentDefined(LevelIndex levelStart,
6322 uint32_t levelCount,
6323 uint32_t layerStart,
6324 uint32_t layerCount,
6325 VkImageAspectFlags aspectFlags)
6326 {
6327 // Mark the range as defined. Layers above 8 are discarded, and are always assumed to have
6328 // defined contents.
6329 if (layerStart >= kMaxContentDefinedLayerCount)
6330 {
6331 return;
6332 }
6333
6334 uint8_t layerRangeBits =
6335 GetContentDefinedLayerRangeBits(layerStart, layerCount, kMaxContentDefinedLayerCount);
6336
6337 for (uint32_t levelOffset = 0; levelOffset < levelCount; ++levelOffset)
6338 {
6339 LevelIndex level = levelStart + levelOffset;
6340
6341 if ((aspectFlags & ~VK_IMAGE_ASPECT_STENCIL_BIT) != 0)
6342 {
6343 getLevelContentDefined(level) |= layerRangeBits;
6344 }
6345 if ((aspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) != 0)
6346 {
6347 getLevelStencilContentDefined(level) |= layerRangeBits;
6348 }
6349 }
6350 }
6351
getLevelContentDefined(LevelIndex level)6352 ImageHelper::LevelContentDefinedMask &ImageHelper::getLevelContentDefined(LevelIndex level)
6353 {
6354 return mContentDefined[level.get()];
6355 }
6356
getLevelStencilContentDefined(LevelIndex level)6357 ImageHelper::LevelContentDefinedMask &ImageHelper::getLevelStencilContentDefined(LevelIndex level)
6358 {
6359 return mStencilContentDefined[level.get()];
6360 }
6361
getLevelContentDefined(LevelIndex level) const6362 const ImageHelper::LevelContentDefinedMask &ImageHelper::getLevelContentDefined(
6363 LevelIndex level) const
6364 {
6365 return mContentDefined[level.get()];
6366 }
6367
getLevelStencilContentDefined(LevelIndex level) const6368 const ImageHelper::LevelContentDefinedMask &ImageHelper::getLevelStencilContentDefined(
6369 LevelIndex level) const
6370 {
6371 return mStencilContentDefined[level.get()];
6372 }
6373
deriveConversionDesc(ErrorContext * context,angle::FormatID actualFormatID,angle::FormatID intendedFormatID)6374 YcbcrConversionDesc ImageHelper::deriveConversionDesc(ErrorContext *context,
6375 angle::FormatID actualFormatID,
6376 angle::FormatID intendedFormatID)
6377 {
6378 YcbcrConversionDesc conversionDesc{};
6379 const angle::Format &actualFormat = angle::Format::Get(actualFormatID);
6380
6381 if (actualFormat.isYUV)
6382 {
6383 // Build a suitable conversionDesc; the image is not external but may be YUV
6384 // if app is using ANGLE's YUV internalformat extensions.
6385 Renderer *renderer = context->getRenderer();
6386
6387 // The Vulkan spec states: The potential format features of the sampler YCBCR conversion
6388 // must support VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT or
6389 // VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT
6390 constexpr VkFormatFeatureFlags kChromaSubSampleFeatureBits =
6391 VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT |
6392 VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT |
6393 VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT;
6394
6395 VkFormatFeatureFlags supportedFeatureBits =
6396 renderer->getImageFormatFeatureBits(actualFormatID, kChromaSubSampleFeatureBits);
6397
6398 VkChromaLocation supportedLocation =
6399 (supportedFeatureBits & VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT) != 0
6400 ? VK_CHROMA_LOCATION_COSITED_EVEN
6401 : VK_CHROMA_LOCATION_MIDPOINT;
6402 vk::YcbcrLinearFilterSupport linearFilterSupported =
6403 (supportedFeatureBits &
6404 VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT) != 0
6405 ? vk::YcbcrLinearFilterSupport::Supported
6406 : vk::YcbcrLinearFilterSupport::Unsupported;
6407
6408 VkSamplerYcbcrModelConversion conversionModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601;
6409 VkSamplerYcbcrRange colorRange = VK_SAMPLER_YCBCR_RANGE_ITU_NARROW;
6410 VkFilter chromaFilter = kDefaultYCbCrChromaFilter;
6411 VkComponentMapping components = {
6412 VK_COMPONENT_SWIZZLE_IDENTITY,
6413 VK_COMPONENT_SWIZZLE_IDENTITY,
6414 VK_COMPONENT_SWIZZLE_IDENTITY,
6415 VK_COMPONENT_SWIZZLE_IDENTITY,
6416 };
6417
6418 conversionDesc.update(renderer, 0, conversionModel, colorRange, supportedLocation,
6419 supportedLocation, chromaFilter, components, intendedFormatID,
6420 linearFilterSupported);
6421 }
6422
6423 return conversionDesc;
6424 }
6425
init(ErrorContext * 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)6426 angle::Result ImageHelper::init(ErrorContext *context,
6427 gl::TextureType textureType,
6428 const VkExtent3D &extents,
6429 const Format &format,
6430 GLint samples,
6431 VkImageUsageFlags usage,
6432 gl::LevelIndex firstLevel,
6433 uint32_t mipLevels,
6434 uint32_t layerCount,
6435 bool isRobustResourceInitEnabled,
6436 bool hasProtectedContent)
6437 {
6438 return initExternal(context, textureType, extents, format.getIntendedFormatID(),
6439 format.getActualRenderableImageFormatID(), samples, usage,
6440 kVkImageCreateFlagsNone, ImageLayout::Undefined, nullptr, firstLevel,
6441 mipLevels, layerCount, isRobustResourceInitEnabled, hasProtectedContent,
6442 deriveConversionDesc(context, format.getActualRenderableImageFormatID(),
6443 format.getIntendedFormatID()),
6444 nullptr);
6445 }
6446
initFromCreateInfo(ErrorContext * context,const VkImageCreateInfo & requestedCreateInfo,VkMemoryPropertyFlags memoryPropertyFlags)6447 angle::Result ImageHelper::initFromCreateInfo(ErrorContext *context,
6448 const VkImageCreateInfo &requestedCreateInfo,
6449 VkMemoryPropertyFlags memoryPropertyFlags)
6450 {
6451 ASSERT(!valid());
6452 ASSERT(!IsAnySubresourceContentDefined(mContentDefined));
6453 ASSERT(!IsAnySubresourceContentDefined(mStencilContentDefined));
6454
6455 mImageType = requestedCreateInfo.imageType;
6456 mExtents = requestedCreateInfo.extent;
6457 mRotatedAspectRatio = false;
6458 mSamples = std::max((int)requestedCreateInfo.samples, 1);
6459 mImageSerial = context->getRenderer()->getResourceSerialFactory().generateImageSerial();
6460 mLayerCount = requestedCreateInfo.arrayLayers;
6461 mLevelCount = requestedCreateInfo.mipLevels;
6462 mUsage = requestedCreateInfo.usage;
6463
6464 // Validate that mLayerCount is compatible with the image type
6465 ASSERT(requestedCreateInfo.imageType != VK_IMAGE_TYPE_3D || mLayerCount == 1);
6466 ASSERT(requestedCreateInfo.imageType != VK_IMAGE_TYPE_2D || mExtents.depth == 1);
6467
6468 mCurrentLayout = ImageLayout::Undefined;
6469
6470 ANGLE_VK_TRY(context, mImage.init(context->getDevice(), requestedCreateInfo));
6471
6472 mVkImageCreateInfo = requestedCreateInfo;
6473 mVkImageCreateInfo.pNext = nullptr;
6474 mVkImageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
6475
6476 MemoryProperties memoryProperties = {};
6477
6478 ANGLE_TRY(initMemoryAndNonZeroFillIfNeeded(context, false, memoryProperties,
6479 memoryPropertyFlags,
6480 vk::MemoryAllocationType::StagingImage));
6481 return angle::Result::Continue;
6482 }
6483
copyToBufferOneOff(ErrorContext * context,BufferHelper * stagingBuffer,VkBufferImageCopy copyRegion)6484 angle::Result ImageHelper::copyToBufferOneOff(ErrorContext *context,
6485 BufferHelper *stagingBuffer,
6486 VkBufferImageCopy copyRegion)
6487 {
6488 Renderer *renderer = context->getRenderer();
6489 ScopedPrimaryCommandBuffer scopedCommandBuffer(renderer->getDevice());
6490 ANGLE_TRY(renderer->getCommandBufferOneOff(context, ProtectionType::Unprotected,
6491 &scopedCommandBuffer));
6492 PrimaryCommandBuffer &commandBuffer = scopedCommandBuffer.get();
6493
6494 VkSemaphore acquireNextImageSemaphore;
6495 recordBarrierOneOffImpl(renderer, getAspectFlags(), ImageLayout::TransferDst,
6496 renderer->getQueueFamilyIndex(), &commandBuffer,
6497 &acquireNextImageSemaphore);
6498 commandBuffer.copyBufferToImage(stagingBuffer->getBuffer().getHandle(), getImage(),
6499 getCurrentLayout(), 1, ©Region);
6500 ANGLE_VK_TRY(context, commandBuffer.end());
6501
6502 QueueSerial submitQueueSerial;
6503 ANGLE_TRY(renderer->queueSubmitOneOff(
6504 context, std::move(scopedCommandBuffer), ProtectionType::Unprotected,
6505 egl::ContextPriority::Medium, acquireNextImageSemaphore,
6506 kSwapchainAcquireImageWaitStageFlags, &submitQueueSerial));
6507
6508 return renderer->finishQueueSerial(context, submitQueueSerial);
6509 }
6510
initMSAASwapchain(ErrorContext * context,gl::TextureType textureType,const VkExtent3D & extents,bool rotatedAspectRatio,angle::FormatID intendedFormatID,angle::FormatID actualFormatID,GLint samples,VkImageUsageFlags usage,gl::LevelIndex firstLevel,uint32_t mipLevels,uint32_t layerCount,bool isRobustResourceInitEnabled,bool hasProtectedContent)6511 angle::Result ImageHelper::initMSAASwapchain(ErrorContext *context,
6512 gl::TextureType textureType,
6513 const VkExtent3D &extents,
6514 bool rotatedAspectRatio,
6515 angle::FormatID intendedFormatID,
6516 angle::FormatID actualFormatID,
6517 GLint samples,
6518 VkImageUsageFlags usage,
6519 gl::LevelIndex firstLevel,
6520 uint32_t mipLevels,
6521 uint32_t layerCount,
6522 bool isRobustResourceInitEnabled,
6523 bool hasProtectedContent)
6524 {
6525 ANGLE_TRY(initExternal(context, textureType, extents, intendedFormatID, actualFormatID, samples,
6526 usage, kVkImageCreateFlagsNone, ImageLayout::Undefined, nullptr,
6527 firstLevel, mipLevels, layerCount, isRobustResourceInitEnabled,
6528 hasProtectedContent, YcbcrConversionDesc{}, nullptr));
6529 if (rotatedAspectRatio)
6530 {
6531 std::swap(mExtents.width, mExtents.height);
6532 }
6533 mRotatedAspectRatio = rotatedAspectRatio;
6534 return angle::Result::Continue;
6535 }
6536
initExternal(ErrorContext * context,gl::TextureType textureType,const VkExtent3D & extents,angle::FormatID intendedFormatID,angle::FormatID actualFormatID,GLint samples,VkImageUsageFlags usage,VkImageCreateFlags additionalCreateFlags,ImageLayout initialLayout,const void * externalImageCreateInfo,gl::LevelIndex firstLevel,uint32_t mipLevels,uint32_t layerCount,bool isRobustResourceInitEnabled,bool hasProtectedContent,YcbcrConversionDesc conversionDesc,const void * compressionControl)6537 angle::Result ImageHelper::initExternal(ErrorContext *context,
6538 gl::TextureType textureType,
6539 const VkExtent3D &extents,
6540 angle::FormatID intendedFormatID,
6541 angle::FormatID actualFormatID,
6542 GLint samples,
6543 VkImageUsageFlags usage,
6544 VkImageCreateFlags additionalCreateFlags,
6545 ImageLayout initialLayout,
6546 const void *externalImageCreateInfo,
6547 gl::LevelIndex firstLevel,
6548 uint32_t mipLevels,
6549 uint32_t layerCount,
6550 bool isRobustResourceInitEnabled,
6551 bool hasProtectedContent,
6552 YcbcrConversionDesc conversionDesc,
6553 const void *compressionControl)
6554 {
6555 ASSERT(!valid());
6556 ASSERT(!IsAnySubresourceContentDefined(mContentDefined));
6557 ASSERT(!IsAnySubresourceContentDefined(mStencilContentDefined));
6558
6559 Renderer *renderer = context->getRenderer();
6560
6561 mImageType = gl_vk::GetImageType(textureType);
6562 mExtents = extents;
6563 mRotatedAspectRatio = false;
6564 mIntendedFormatID = intendedFormatID;
6565 mActualFormatID = actualFormatID;
6566 mSamples = std::max(samples, 1);
6567 mImageSerial = renderer->getResourceSerialFactory().generateImageSerial();
6568 mFirstAllocatedLevel = firstLevel;
6569 mLevelCount = mipLevels;
6570 mLayerCount = layerCount;
6571 mCreateFlags =
6572 vk::GetMinimalImageCreateFlags(renderer, textureType, usage) | additionalCreateFlags;
6573 mUsage = usage;
6574
6575 // Validate that mLayerCount is compatible with the texture type
6576 ASSERT(textureType != gl::TextureType::_3D || mLayerCount == 1);
6577 ASSERT(textureType != gl::TextureType::_2DArray || mExtents.depth == 1);
6578 ASSERT(textureType != gl::TextureType::External || mLayerCount == 1);
6579 ASSERT(textureType != gl::TextureType::Rectangle || mLayerCount == 1);
6580 ASSERT(textureType != gl::TextureType::CubeMap || mLayerCount == gl::kCubeFaceCount);
6581 ASSERT(textureType != gl::TextureType::CubeMapArray || mLayerCount % gl::kCubeFaceCount == 0);
6582
6583 // If externalImageCreateInfo is provided, use that directly. Otherwise derive the necessary
6584 // pNext chain.
6585 const void *imageCreateInfoPNext = externalImageCreateInfo;
6586 VkImageFormatListCreateInfoKHR imageFormatListInfoStorage;
6587 ImageListFormats imageListFormatsStorage;
6588
6589 if (externalImageCreateInfo == nullptr)
6590 {
6591 imageCreateInfoPNext = DeriveCreateInfoPNext(
6592 context, mUsage, actualFormatID, compressionControl, &imageFormatListInfoStorage,
6593 &imageListFormatsStorage, &mCreateFlags);
6594 }
6595 else
6596 {
6597 // Derive the tiling for external images.
6598 deriveExternalImageTiling(externalImageCreateInfo);
6599 }
6600
6601 mYcbcrConversionDesc = conversionDesc;
6602
6603 const angle::Format &actualFormat = angle::Format::Get(actualFormatID);
6604 const angle::Format &intendedFormat = angle::Format::Get(intendedFormatID);
6605 VkFormat actualVkFormat = GetVkFormatFromFormatID(renderer, actualFormatID);
6606
6607 ANGLE_TRACE_EVENT_INSTANT("gpu.angle.texture_metrics", "ImageHelper::initExternal",
6608 "intended_format", intendedFormat.glInternalFormat, "actual_format",
6609 actualFormat.glInternalFormat, "width", extents.width, "height",
6610 extents.height);
6611
6612 if (actualFormat.isYUV)
6613 {
6614 ASSERT(mYcbcrConversionDesc.valid());
6615
6616 // The Vulkan spec states: If the pNext chain includes a VkExternalFormatANDROID structure
6617 // whose externalFormat member is not 0, flags must not include
6618 // VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT
6619 if (!IsYUVExternalFormat(actualFormatID))
6620 {
6621 // The Vulkan spec states: If sampler is used and the VkFormat of the image is a
6622 // multi-planar format, the image must have been created with
6623 // VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT
6624 mCreateFlags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
6625 }
6626 }
6627
6628 if (hasProtectedContent)
6629 {
6630 mCreateFlags |= VK_IMAGE_CREATE_PROTECTED_BIT;
6631 }
6632
6633 VkImageCreateInfo imageInfo = {};
6634 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
6635 imageInfo.pNext = imageCreateInfoPNext;
6636 imageInfo.flags = mCreateFlags;
6637 imageInfo.imageType = mImageType;
6638 imageInfo.format = actualVkFormat;
6639 imageInfo.extent = mExtents;
6640 imageInfo.mipLevels = mLevelCount;
6641 imageInfo.arrayLayers = mLayerCount;
6642 imageInfo.samples =
6643 gl_vk::GetSamples(mSamples, context->getFeatures().limitSampleCountTo2.enabled);
6644 imageInfo.tiling = mTilingMode;
6645 imageInfo.usage = mUsage;
6646 imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
6647 imageInfo.queueFamilyIndexCount = 0;
6648 imageInfo.pQueueFamilyIndices = nullptr;
6649 imageInfo.initialLayout = ConvertImageLayoutToVkImageLayout(initialLayout);
6650
6651 mCurrentLayout = initialLayout;
6652 mCurrentDeviceQueueIndex = kInvalidDeviceQueueIndex;
6653 mIsReleasedToExternal = false;
6654 mIsForeignImage = false;
6655 mLastNonShaderReadOnlyLayout = ImageLayout::Undefined;
6656 mCurrentShaderReadStageMask = 0;
6657
6658 ANGLE_VK_TRY(context, mImage.init(context->getDevice(), imageInfo));
6659
6660 // Find the image formats in pNext chain in imageInfo.
6661 deriveImageViewFormatFromCreateInfoPNext(imageInfo, mViewFormats);
6662
6663 mVkImageCreateInfo = imageInfo;
6664 mVkImageCreateInfo.pNext = nullptr;
6665 mVkImageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
6666
6667 stageClearIfEmulatedFormat(isRobustResourceInitEnabled, externalImageCreateInfo != nullptr);
6668
6669 // Consider the contents defined for any image that has the PREINITIALIZED layout, or is
6670 // imported from external.
6671 if (initialLayout != ImageLayout::Undefined || externalImageCreateInfo != nullptr)
6672 {
6673 setEntireContentDefined();
6674 }
6675
6676 return angle::Result::Continue;
6677 }
6678
6679 // static
DeriveCreateInfoPNext(ErrorContext * context,VkImageUsageFlags usage,angle::FormatID actualFormatID,const void * pNext,VkImageFormatListCreateInfoKHR * imageFormatListInfoStorage,std::array<VkFormat,kImageListFormatCount> * imageListFormatsStorage,VkImageCreateFlags * createFlagsOut)6680 const void *ImageHelper::DeriveCreateInfoPNext(
6681 ErrorContext *context,
6682 VkImageUsageFlags usage,
6683 angle::FormatID actualFormatID,
6684 const void *pNext,
6685 VkImageFormatListCreateInfoKHR *imageFormatListInfoStorage,
6686 std::array<VkFormat, kImageListFormatCount> *imageListFormatsStorage,
6687 VkImageCreateFlags *createFlagsOut)
6688 {
6689 // With the introduction of sRGB related GLES extensions any sample/render target could be
6690 // respecified causing it to be interpreted in a different colorspace. Create the VkImage
6691 // accordingly.
6692 Renderer *renderer = context->getRenderer();
6693 const angle::Format &actualFormat = angle::Format::Get(actualFormatID);
6694 angle::FormatID additionalFormat =
6695 actualFormat.isSRGB ? ConvertToLinear(actualFormatID) : ConvertToSRGB(actualFormatID);
6696 (*imageListFormatsStorage)[0] = vk::GetVkFormatFromFormatID(renderer, actualFormatID);
6697 (*imageListFormatsStorage)[1] = vk::GetVkFormatFromFormatID(renderer, additionalFormat);
6698
6699 // Don't add the format list if the storage bit is enabled for the image; framebuffer
6700 // compression is already disabled in that case, and GL allows many formats to alias
6701 // the original format for storage images (more than ANGLE provides in the format list).
6702 if (renderer->getFeatures().supportsImageFormatList.enabled &&
6703 renderer->haveSameFormatFeatureBits(actualFormatID, additionalFormat) &&
6704 (usage & VK_IMAGE_USAGE_STORAGE_BIT) == 0)
6705 {
6706 // Add VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT to VkImage create flag
6707 *createFlagsOut |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
6708
6709 // There is just 1 additional format we might use to create a VkImageView for this
6710 // VkImage
6711 imageFormatListInfoStorage->sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR;
6712 imageFormatListInfoStorage->pNext = pNext;
6713 imageFormatListInfoStorage->viewFormatCount = kImageListFormatCount;
6714 imageFormatListInfoStorage->pViewFormats = imageListFormatsStorage->data();
6715
6716 pNext = imageFormatListInfoStorage;
6717 }
6718
6719 return pNext;
6720 }
6721
6722 // static
FormatSupportsUsage(Renderer * renderer,VkFormat format,VkImageType imageType,VkImageTiling tilingMode,VkImageUsageFlags usageFlags,VkImageCreateFlags createFlags,void * formatInfoPNext,void * propertiesPNext,const FormatSupportCheck formatSupportCheck)6723 bool ImageHelper::FormatSupportsUsage(Renderer *renderer,
6724 VkFormat format,
6725 VkImageType imageType,
6726 VkImageTiling tilingMode,
6727 VkImageUsageFlags usageFlags,
6728 VkImageCreateFlags createFlags,
6729 void *formatInfoPNext,
6730 void *propertiesPNext,
6731 const FormatSupportCheck formatSupportCheck)
6732 {
6733 VkPhysicalDeviceImageFormatInfo2 imageFormatInfo = {};
6734 imageFormatInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
6735 imageFormatInfo.pNext = formatInfoPNext;
6736 imageFormatInfo.format = format;
6737 imageFormatInfo.type = imageType;
6738 imageFormatInfo.tiling = tilingMode;
6739 imageFormatInfo.usage = usageFlags;
6740 imageFormatInfo.flags = createFlags;
6741
6742 VkImageFormatProperties2 imageFormatProperties2 = {};
6743 imageFormatProperties2.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
6744 imageFormatProperties2.pNext = propertiesPNext;
6745
6746 VkResult result = vkGetPhysicalDeviceImageFormatProperties2(
6747 renderer->getPhysicalDevice(), &imageFormatInfo, &imageFormatProperties2);
6748
6749 if (formatSupportCheck == FormatSupportCheck::RequireMultisampling)
6750 {
6751 // Some drivers return success but sampleCounts == 1 which means no MSRTT
6752 return result == VK_SUCCESS &&
6753 imageFormatProperties2.imageFormatProperties.sampleCounts > 1;
6754 }
6755 return result == VK_SUCCESS;
6756 }
6757
setImageFormatsFromActualFormat(VkFormat actualFormat,ImageFormats & imageFormatsOut)6758 void ImageHelper::setImageFormatsFromActualFormat(VkFormat actualFormat,
6759 ImageFormats &imageFormatsOut)
6760 {
6761 imageFormatsOut.push_back(actualFormat);
6762 }
6763
deriveImageViewFormatFromCreateInfoPNext(VkImageCreateInfo & imageInfo,ImageFormats & formatOut)6764 void ImageHelper::deriveImageViewFormatFromCreateInfoPNext(VkImageCreateInfo &imageInfo,
6765 ImageFormats &formatOut)
6766 {
6767 const VkBaseInStructure *pNextChain =
6768 reinterpret_cast<const VkBaseInStructure *>(imageInfo.pNext);
6769 while (pNextChain != nullptr &&
6770 pNextChain->sType != VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR)
6771 {
6772 pNextChain = pNextChain->pNext;
6773 }
6774
6775 // Clear formatOut in case it has leftovers from previous VkImage in the case of releaseImage
6776 // followed by initExternal.
6777 std::fill(formatOut.begin(), formatOut.begin() + formatOut.max_size(), VK_FORMAT_UNDEFINED);
6778 if (pNextChain != nullptr)
6779 {
6780 const VkImageFormatListCreateInfoKHR *imageFormatCreateInfo =
6781 reinterpret_cast<const VkImageFormatListCreateInfoKHR *>(pNextChain);
6782
6783 for (uint32_t i = 0; i < imageFormatCreateInfo->viewFormatCount; i++)
6784 {
6785 formatOut.push_back(*(imageFormatCreateInfo->pViewFormats + i));
6786 }
6787 }
6788 else
6789 {
6790 setImageFormatsFromActualFormat(imageInfo.format, formatOut);
6791 }
6792 }
6793
deriveExternalImageTiling(const void * createInfoChain)6794 void ImageHelper::deriveExternalImageTiling(const void *createInfoChain)
6795 {
6796 const VkBaseInStructure *chain = reinterpret_cast<const VkBaseInStructure *>(createInfoChain);
6797 while (chain != nullptr)
6798 {
6799 if (chain->sType == VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT ||
6800 chain->sType == VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT)
6801 {
6802 mTilingMode = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
6803 return;
6804 }
6805
6806 chain = reinterpret_cast<const VkBaseInStructure *>(chain->pNext);
6807 }
6808 }
6809
releaseImage(Renderer * renderer)6810 void ImageHelper::releaseImage(Renderer *renderer)
6811 {
6812 if (mImage.valid())
6813 {
6814 GarbageObjects garbageObjects;
6815 garbageObjects.reserve(2);
6816 garbageObjects.emplace_back(GarbageObject::Get(&mImage));
6817
6818 // mDeviceMemory and mVmaAllocation should not be valid at the same time.
6819 ASSERT(!mDeviceMemory.valid() || !mVmaAllocation.valid());
6820 if (mDeviceMemory.valid())
6821 {
6822 renderer->onMemoryDealloc(mMemoryAllocationType, mAllocationSize, mMemoryTypeIndex,
6823 mDeviceMemory.getHandle());
6824 garbageObjects.emplace_back(GarbageObject::Get(&mDeviceMemory));
6825 }
6826 if (mVmaAllocation.valid())
6827 {
6828 renderer->onMemoryDealloc(mMemoryAllocationType, mAllocationSize, mMemoryTypeIndex,
6829 mVmaAllocation.getHandle());
6830 garbageObjects.emplace_back(GarbageObject::Get(&mVmaAllocation));
6831 }
6832 renderer->collectGarbage(mUse, std::move(garbageObjects));
6833 }
6834 else
6835 {
6836 ASSERT(!mDeviceMemory.valid());
6837 ASSERT(!mVmaAllocation.valid());
6838 }
6839
6840 mCurrentEvent.release(renderer);
6841 mLastNonShaderReadOnlyEvent.release(renderer);
6842 mViewFormats.clear();
6843 mUse.reset();
6844 mImageSerial = kInvalidImageSerial;
6845 mMemoryAllocationType = MemoryAllocationType::InvalidEnum;
6846 setEntireContentUndefined();
6847 }
6848
releaseImageFromShareContexts(Renderer * renderer,ContextVk * contextVk,UniqueSerial imageSiblingSerial)6849 void ImageHelper::releaseImageFromShareContexts(Renderer *renderer,
6850 ContextVk *contextVk,
6851 UniqueSerial imageSiblingSerial)
6852 {
6853 finalizeImageLayoutInShareContexts(renderer, contextVk, imageSiblingSerial);
6854 contextVk->addToPendingImageGarbage(mUse, mAllocationSize);
6855 releaseImage(renderer);
6856 }
6857
finalizeImageLayoutInShareContexts(Renderer * renderer,ContextVk * contextVk,UniqueSerial imageSiblingSerial)6858 void ImageHelper::finalizeImageLayoutInShareContexts(Renderer *renderer,
6859 ContextVk *contextVk,
6860 UniqueSerial imageSiblingSerial)
6861 {
6862 if (contextVk && mImageSerial.valid())
6863 {
6864 for (auto context : contextVk->getShareGroup()->getContexts())
6865 {
6866 vk::GetImpl(context.second)->finalizeImageLayout(this, imageSiblingSerial);
6867 }
6868 }
6869 }
6870
releaseStagedUpdates(Renderer * renderer)6871 void ImageHelper::releaseStagedUpdates(Renderer *renderer)
6872 {
6873 ASSERT(validateSubresourceUpdateRefCountsConsistent());
6874
6875 // Remove updates that never made it to the texture.
6876 for (SubresourceUpdates &levelUpdates : mSubresourceUpdates)
6877 {
6878 while (!levelUpdates.empty())
6879 {
6880 levelUpdates.front().release(renderer);
6881 levelUpdates.pop_front();
6882 }
6883 }
6884
6885 ASSERT(validateSubresourceUpdateRefCountsConsistent());
6886
6887 mSubresourceUpdates.clear();
6888 mTotalStagedBufferUpdateSize = 0;
6889 mCurrentSingleClearValue.reset();
6890 }
6891
resetImageWeakReference()6892 void ImageHelper::resetImageWeakReference()
6893 {
6894 mImage.reset();
6895 mImageSerial = kInvalidImageSerial;
6896 mRotatedAspectRatio = false;
6897 // Caller must ensure ANI semaphores are properly waited or released.
6898 ASSERT(!mAcquireNextImageSemaphore.valid());
6899 }
6900
initializeNonZeroMemory(ErrorContext * context,bool hasProtectedContent,VkMemoryPropertyFlags flags,VkDeviceSize size)6901 angle::Result ImageHelper::initializeNonZeroMemory(ErrorContext *context,
6902 bool hasProtectedContent,
6903 VkMemoryPropertyFlags flags,
6904 VkDeviceSize size)
6905 {
6906 // If available, memory mapping should be used.
6907 Renderer *renderer = context->getRenderer();
6908
6909 if ((flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0)
6910 {
6911 // Wipe memory to an invalid value when the 'allocateNonZeroMemory' feature is enabled. The
6912 // invalid values ensures our testing doesn't assume zero-initialized memory.
6913 constexpr int kNonZeroInitValue = 0x3F;
6914 if (renderer->getFeatures().useVmaForImageSuballocation.enabled)
6915 {
6916 ANGLE_VK_TRY(context,
6917 renderer->getImageMemorySuballocator().mapMemoryAndInitWithNonZeroValue(
6918 renderer, &mVmaAllocation, size, kNonZeroInitValue, flags));
6919 }
6920 else
6921 {
6922 ANGLE_TRY(vk::InitMappableDeviceMemory(context, &mDeviceMemory, size, kNonZeroInitValue,
6923 flags));
6924 }
6925
6926 return angle::Result::Continue;
6927 }
6928
6929 // If mapping the memory is unavailable, a staging resource is used.
6930 const angle::Format &angleFormat = getActualFormat();
6931 bool isCompressedFormat = angleFormat.isBlock;
6932
6933 if (angleFormat.isYUV)
6934 {
6935 // VUID-vkCmdClearColorImage-image-01545
6936 // vkCmdClearColorImage(): format must not be one of the formats requiring sampler YCBCR
6937 // conversion for VK_IMAGE_ASPECT_COLOR_BIT image views
6938 return angle::Result::Continue;
6939 }
6940
6941 // Since we are going to do a one off out of order submission, there shouldn't any pending
6942 // setEvent.
6943 ASSERT(!mCurrentEvent.valid());
6944
6945 ScopedPrimaryCommandBuffer scopedCommandBuffer(renderer->getDevice());
6946 auto protectionType = ConvertProtectionBoolToType(hasProtectedContent);
6947 ANGLE_TRY(renderer->getCommandBufferOneOff(context, protectionType, &scopedCommandBuffer));
6948 PrimaryCommandBuffer &commandBuffer = scopedCommandBuffer.get();
6949
6950 // Queue a DMA copy.
6951 VkSemaphore acquireNextImageSemaphore;
6952 recordBarrierOneOffImpl(renderer, getAspectFlags(), ImageLayout::TransferDst,
6953 context->getDeviceQueueIndex(), &commandBuffer,
6954 &acquireNextImageSemaphore);
6955 // SwapChain image should not come here
6956 ASSERT(acquireNextImageSemaphore == VK_NULL_HANDLE);
6957
6958 StagingBuffer stagingBuffer;
6959
6960 if (isCompressedFormat)
6961 {
6962 // If format is compressed, set its contents through buffer copies.
6963
6964 // The staging buffer memory is non-zero-initialized in 'init'.
6965 ANGLE_TRY(stagingBuffer.init(context, size, StagingUsage::Write));
6966
6967 for (LevelIndex level(0); level < LevelIndex(mLevelCount); ++level)
6968 {
6969 VkBufferImageCopy copyRegion = {};
6970
6971 gl_vk::GetExtent(getLevelExtents(level), ©Region.imageExtent);
6972 copyRegion.imageSubresource.aspectMask = getAspectFlags();
6973 copyRegion.imageSubresource.layerCount = mLayerCount;
6974
6975 // If image has depth and stencil, copy to each individually per Vulkan spec.
6976 bool hasBothDepthAndStencil = isCombinedDepthStencilFormat();
6977 if (hasBothDepthAndStencil)
6978 {
6979 copyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
6980 }
6981
6982 commandBuffer.copyBufferToImage(stagingBuffer.getBuffer().getHandle(), mImage,
6983 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Region);
6984
6985 if (hasBothDepthAndStencil)
6986 {
6987 copyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
6988
6989 commandBuffer.copyBufferToImage(stagingBuffer.getBuffer().getHandle(), mImage,
6990 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1,
6991 ©Region);
6992 }
6993 }
6994 }
6995 else
6996 {
6997 // Otherwise issue clear commands.
6998 VkImageSubresourceRange subresource = {};
6999 subresource.aspectMask = getAspectFlags();
7000 subresource.baseMipLevel = 0;
7001 subresource.levelCount = mLevelCount;
7002 subresource.baseArrayLayer = 0;
7003 subresource.layerCount = mLayerCount;
7004
7005 // Arbitrary value to initialize the memory with. Note: the given uint value, reinterpreted
7006 // as float is about 0.7.
7007 constexpr uint32_t kInitValue = 0x3F345678;
7008 constexpr float kInitValueFloat = 0.12345f;
7009
7010 if ((subresource.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) != 0)
7011 {
7012 VkClearColorValue clearValue;
7013 clearValue.uint32[0] = kInitValue;
7014 clearValue.uint32[1] = kInitValue;
7015 clearValue.uint32[2] = kInitValue;
7016 clearValue.uint32[3] = kInitValue;
7017
7018 commandBuffer.clearColorImage(mImage, getCurrentLayout(), clearValue, 1, &subresource);
7019 }
7020 else
7021 {
7022 VkClearDepthStencilValue clearValue;
7023 clearValue.depth = kInitValueFloat;
7024 clearValue.stencil = kInitValue;
7025
7026 commandBuffer.clearDepthStencilImage(mImage, getCurrentLayout(), clearValue, 1,
7027 &subresource);
7028 }
7029 }
7030
7031 ANGLE_VK_TRY(context, commandBuffer.end());
7032
7033 QueueSerial queueSerial;
7034 ANGLE_TRY(renderer->queueSubmitOneOff(context, std::move(scopedCommandBuffer), protectionType,
7035 egl::ContextPriority::Medium, VK_NULL_HANDLE, 0,
7036 &queueSerial));
7037
7038 if (isCompressedFormat)
7039 {
7040 stagingBuffer.collectGarbage(renderer, queueSerial);
7041 }
7042 setQueueSerial(queueSerial);
7043 ASSERT(!mIsForeignImage);
7044
7045 return angle::Result::Continue;
7046 }
7047
initMemory(ErrorContext * context,const MemoryProperties & memoryProperties,VkMemoryPropertyFlags flags,VkMemoryPropertyFlags excludedFlags,const VkMemoryRequirements * memoryRequirements,const bool allocateDedicatedMemory,MemoryAllocationType allocationType,VkMemoryPropertyFlags * flagsOut,VkDeviceSize * sizeOut)7048 VkResult ImageHelper::initMemory(ErrorContext *context,
7049 const MemoryProperties &memoryProperties,
7050 VkMemoryPropertyFlags flags,
7051 VkMemoryPropertyFlags excludedFlags,
7052 const VkMemoryRequirements *memoryRequirements,
7053 const bool allocateDedicatedMemory,
7054 MemoryAllocationType allocationType,
7055 VkMemoryPropertyFlags *flagsOut,
7056 VkDeviceSize *sizeOut)
7057 {
7058 mMemoryAllocationType = allocationType;
7059
7060 // To allocate memory here, if possible, we use the image memory suballocator which uses VMA.
7061 ASSERT(excludedFlags < VK_MEMORY_PROPERTY_FLAG_BITS_MAX_ENUM);
7062 Renderer *renderer = context->getRenderer();
7063 if (renderer->getFeatures().useVmaForImageSuballocation.enabled)
7064 {
7065 // While it may be preferable to allocate the image on the device, it should also be
7066 // possible to allocate on other memory types if the device is out of memory.
7067 VkMemoryPropertyFlags requiredFlags = flags & (~excludedFlags);
7068 VkMemoryPropertyFlags preferredFlags = flags;
7069 VK_RESULT_TRY(renderer->getImageMemorySuballocator().allocateAndBindMemory(
7070 context, &mImage, &mVkImageCreateInfo, requiredFlags, preferredFlags,
7071 memoryRequirements, allocateDedicatedMemory, mMemoryAllocationType, &mVmaAllocation,
7072 flagsOut, &mMemoryTypeIndex, &mAllocationSize));
7073 }
7074 else
7075 {
7076 VK_RESULT_TRY(AllocateImageMemory(context, mMemoryAllocationType, flags, flagsOut, nullptr,
7077 &mImage, &mMemoryTypeIndex, &mDeviceMemory,
7078 &mAllocationSize));
7079 }
7080
7081 mCurrentDeviceQueueIndex = context->getDeviceQueueIndex();
7082 mIsReleasedToExternal = false;
7083 mIsForeignImage = false;
7084 *sizeOut = mAllocationSize;
7085
7086 return VK_SUCCESS;
7087 }
7088
initMemoryAndNonZeroFillIfNeeded(ErrorContext * context,bool hasProtectedContent,const MemoryProperties & memoryProperties,VkMemoryPropertyFlags flags,MemoryAllocationType allocationType)7089 angle::Result ImageHelper::initMemoryAndNonZeroFillIfNeeded(
7090 ErrorContext *context,
7091 bool hasProtectedContent,
7092 const MemoryProperties &memoryProperties,
7093 VkMemoryPropertyFlags flags,
7094 MemoryAllocationType allocationType)
7095 {
7096 Renderer *renderer = context->getRenderer();
7097 VkMemoryPropertyFlags outputFlags;
7098 VkDeviceSize outputSize;
7099
7100 if (hasProtectedContent)
7101 {
7102 flags |= VK_MEMORY_PROPERTY_PROTECTED_BIT;
7103 }
7104
7105 // Get memory requirements for the allocation.
7106 VkMemoryRequirements memoryRequirements;
7107 mImage.getMemoryRequirements(renderer->getDevice(), &memoryRequirements);
7108 bool allocateDedicatedMemory =
7109 renderer->getImageMemorySuballocator().needsDedicatedMemory(memoryRequirements.size);
7110
7111 ANGLE_VK_TRY(context,
7112 initMemory(context, memoryProperties, flags, 0, &memoryRequirements,
7113 allocateDedicatedMemory, allocationType, &outputFlags, &outputSize));
7114
7115 // Memory can only be non-zero initialized if the TRANSFER_DST usage is set. This is normally
7116 // the case, but not with |initImplicitMultisampledRenderToTexture| which creates a
7117 // lazy-allocated transient image.
7118 if (renderer->getFeatures().allocateNonZeroMemory.enabled &&
7119 (mUsage & VK_IMAGE_USAGE_TRANSFER_DST_BIT) != 0)
7120 {
7121 ANGLE_TRY(initializeNonZeroMemory(context, hasProtectedContent, outputFlags, outputSize));
7122 }
7123 return angle::Result::Continue;
7124 }
7125
initExternalMemory(ErrorContext * context,const MemoryProperties & memoryProperties,const VkMemoryRequirements & memoryRequirements,uint32_t extraAllocationInfoCount,const void ** extraAllocationInfo,DeviceQueueIndex currentDeviceQueueIndex,VkMemoryPropertyFlags flags)7126 angle::Result ImageHelper::initExternalMemory(ErrorContext *context,
7127 const MemoryProperties &memoryProperties,
7128 const VkMemoryRequirements &memoryRequirements,
7129 uint32_t extraAllocationInfoCount,
7130 const void **extraAllocationInfo,
7131 DeviceQueueIndex currentDeviceQueueIndex,
7132 VkMemoryPropertyFlags flags)
7133 {
7134 // Vulkan allows up to 4 memory planes.
7135 constexpr size_t kMaxMemoryPlanes = 4;
7136 constexpr VkImageAspectFlagBits kMemoryPlaneAspects[kMaxMemoryPlanes] = {
7137 VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT,
7138 VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT,
7139 VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT,
7140 VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT,
7141 };
7142 ASSERT(extraAllocationInfoCount <= kMaxMemoryPlanes);
7143
7144 VkBindImagePlaneMemoryInfoKHR bindImagePlaneMemoryInfo = {};
7145 bindImagePlaneMemoryInfo.sType = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO;
7146
7147 const VkBindImagePlaneMemoryInfoKHR *bindImagePlaneMemoryInfoPtr =
7148 extraAllocationInfoCount == 1 ? nullptr : &bindImagePlaneMemoryInfo;
7149
7150 mAllocationSize = memoryRequirements.size;
7151 mMemoryAllocationType = MemoryAllocationType::ImageExternal;
7152
7153 for (uint32_t memoryPlane = 0; memoryPlane < extraAllocationInfoCount; ++memoryPlane)
7154 {
7155 bindImagePlaneMemoryInfo.planeAspect = kMemoryPlaneAspects[memoryPlane];
7156
7157 ANGLE_VK_TRY(context, AllocateImageMemoryWithRequirements(
7158 context, mMemoryAllocationType, flags, memoryRequirements,
7159 extraAllocationInfo[memoryPlane], bindImagePlaneMemoryInfoPtr,
7160 &mImage, &mMemoryTypeIndex, &mDeviceMemory));
7161 }
7162 mCurrentDeviceQueueIndex = currentDeviceQueueIndex;
7163 mIsReleasedToExternal = false;
7164 mIsForeignImage = currentDeviceQueueIndex == kForeignDeviceQueueIndex;
7165
7166 return angle::Result::Continue;
7167 }
7168
initLayerImageView(ErrorContext * context,gl::TextureType textureType,VkImageAspectFlags aspectMask,const gl::SwizzleState & swizzleMap,ImageView * imageViewOut,LevelIndex baseMipLevelVk,uint32_t levelCount,uint32_t baseArrayLayer,uint32_t layerCount) const7169 angle::Result ImageHelper::initLayerImageView(ErrorContext *context,
7170 gl::TextureType textureType,
7171 VkImageAspectFlags aspectMask,
7172 const gl::SwizzleState &swizzleMap,
7173 ImageView *imageViewOut,
7174 LevelIndex baseMipLevelVk,
7175 uint32_t levelCount,
7176 uint32_t baseArrayLayer,
7177 uint32_t layerCount) const
7178 {
7179 return initLayerImageViewImpl(context, textureType, aspectMask, swizzleMap, imageViewOut,
7180 baseMipLevelVk, levelCount, baseArrayLayer, layerCount,
7181 GetVkFormatFromFormatID(context->getRenderer(), mActualFormatID),
7182 kDefaultImageViewUsageFlags, gl::YuvSamplingMode::Default);
7183 }
7184
initLayerImageViewWithUsage(ErrorContext * 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) const7185 angle::Result ImageHelper::initLayerImageViewWithUsage(ErrorContext *context,
7186 gl::TextureType textureType,
7187 VkImageAspectFlags aspectMask,
7188 const gl::SwizzleState &swizzleMap,
7189 ImageView *imageViewOut,
7190 LevelIndex baseMipLevelVk,
7191 uint32_t levelCount,
7192 uint32_t baseArrayLayer,
7193 uint32_t layerCount,
7194 VkImageUsageFlags imageUsageFlags) const
7195 {
7196 return initLayerImageViewImpl(context, textureType, aspectMask, swizzleMap, imageViewOut,
7197 baseMipLevelVk, levelCount, baseArrayLayer, layerCount,
7198 GetVkFormatFromFormatID(context->getRenderer(), mActualFormatID),
7199 imageUsageFlags, gl::YuvSamplingMode::Default);
7200 }
7201
initLayerImageViewWithYuvModeOverride(ErrorContext * context,gl::TextureType textureType,VkImageAspectFlags aspectMask,const gl::SwizzleState & swizzleMap,ImageView * imageViewOut,LevelIndex baseMipLevelVk,uint32_t levelCount,uint32_t baseArrayLayer,uint32_t layerCount,gl::YuvSamplingMode yuvSamplingMode,VkImageUsageFlags imageUsageFlags) const7202 angle::Result ImageHelper::initLayerImageViewWithYuvModeOverride(
7203 ErrorContext *context,
7204 gl::TextureType textureType,
7205 VkImageAspectFlags aspectMask,
7206 const gl::SwizzleState &swizzleMap,
7207 ImageView *imageViewOut,
7208 LevelIndex baseMipLevelVk,
7209 uint32_t levelCount,
7210 uint32_t baseArrayLayer,
7211 uint32_t layerCount,
7212 gl::YuvSamplingMode yuvSamplingMode,
7213 VkImageUsageFlags imageUsageFlags) const
7214 {
7215 return initLayerImageViewImpl(context, textureType, aspectMask, swizzleMap, imageViewOut,
7216 baseMipLevelVk, levelCount, baseArrayLayer, layerCount,
7217 GetVkFormatFromFormatID(context->getRenderer(), mActualFormatID),
7218 imageUsageFlags, yuvSamplingMode);
7219 }
7220
initLayerImageViewImpl(ErrorContext * 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) const7221 angle::Result ImageHelper::initLayerImageViewImpl(ErrorContext *context,
7222 gl::TextureType textureType,
7223 VkImageAspectFlags aspectMask,
7224 const gl::SwizzleState &swizzleMap,
7225 ImageView *imageViewOut,
7226 LevelIndex baseMipLevelVk,
7227 uint32_t levelCount,
7228 uint32_t baseArrayLayer,
7229 uint32_t layerCount,
7230 VkFormat imageFormat,
7231 VkImageUsageFlags usageFlags,
7232 gl::YuvSamplingMode yuvSamplingMode) const
7233 {
7234 VkImageViewCreateInfo viewInfo = {};
7235 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
7236 viewInfo.flags = 0;
7237 viewInfo.image = mImage.getHandle();
7238 viewInfo.viewType = gl_vk::GetImageViewType(textureType);
7239 viewInfo.format = imageFormat;
7240
7241 if (swizzleMap.swizzleRequired() && !mYcbcrConversionDesc.valid())
7242 {
7243 viewInfo.components.r = gl_vk::GetSwizzle(swizzleMap.swizzleRed);
7244 viewInfo.components.g = gl_vk::GetSwizzle(swizzleMap.swizzleGreen);
7245 viewInfo.components.b = gl_vk::GetSwizzle(swizzleMap.swizzleBlue);
7246 viewInfo.components.a = gl_vk::GetSwizzle(swizzleMap.swizzleAlpha);
7247 }
7248 else
7249 {
7250 viewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
7251 viewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
7252 viewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
7253 viewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
7254 }
7255 viewInfo.subresourceRange.aspectMask = aspectMask;
7256 viewInfo.subresourceRange.baseMipLevel = baseMipLevelVk.get();
7257 viewInfo.subresourceRange.levelCount = levelCount;
7258 viewInfo.subresourceRange.baseArrayLayer = baseArrayLayer;
7259 viewInfo.subresourceRange.layerCount = layerCount;
7260
7261 VkImageViewUsageCreateInfo imageViewUsageCreateInfo = {};
7262 if (usageFlags)
7263 {
7264 imageViewUsageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO;
7265 imageViewUsageCreateInfo.usage = usageFlags;
7266
7267 viewInfo.pNext = &imageViewUsageCreateInfo;
7268 }
7269
7270 VkSamplerYcbcrConversionInfo yuvConversionInfo = {};
7271
7272 auto conversionDesc =
7273 yuvSamplingMode == gl::YuvSamplingMode::Y2Y ? getY2YConversionDesc() : mYcbcrConversionDesc;
7274
7275 if (conversionDesc.valid())
7276 {
7277 ASSERT((context->getFeatures().supportsYUVSamplerConversion.enabled));
7278 yuvConversionInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO;
7279 yuvConversionInfo.pNext = nullptr;
7280 ANGLE_TRY(context->getRenderer()->getYuvConversionCache().getSamplerYcbcrConversion(
7281 context, conversionDesc, &yuvConversionInfo.conversion));
7282 AddToPNextChain(&viewInfo, &yuvConversionInfo);
7283
7284 // VUID-VkImageViewCreateInfo-image-02399
7285 // If image has an external format, format must be VK_FORMAT_UNDEFINED
7286 if (conversionDesc.getExternalFormat() != 0)
7287 {
7288 viewInfo.format = VK_FORMAT_UNDEFINED;
7289 }
7290 }
7291 ANGLE_VK_TRY(context, imageViewOut->init(context->getDevice(), viewInfo));
7292 return angle::Result::Continue;
7293 }
7294
initReinterpretedLayerImageView(ErrorContext * 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) const7295 angle::Result ImageHelper::initReinterpretedLayerImageView(ErrorContext *context,
7296 gl::TextureType textureType,
7297 VkImageAspectFlags aspectMask,
7298 const gl::SwizzleState &swizzleMap,
7299 ImageView *imageViewOut,
7300 LevelIndex baseMipLevelVk,
7301 uint32_t levelCount,
7302 uint32_t baseArrayLayer,
7303 uint32_t layerCount,
7304 VkImageUsageFlags imageUsageFlags,
7305 angle::FormatID imageViewFormat) const
7306 {
7307 VkImageUsageFlags usageFlags =
7308 imageUsageFlags & GetMaximalImageUsageFlags(context->getRenderer(), imageViewFormat);
7309
7310 return initLayerImageViewImpl(
7311 context, textureType, aspectMask, swizzleMap, imageViewOut, baseMipLevelVk, levelCount,
7312 baseArrayLayer, layerCount,
7313 vk::GetVkFormatFromFormatID(context->getRenderer(), imageViewFormat), usageFlags,
7314 gl::YuvSamplingMode::Default);
7315 }
7316
destroy(Renderer * renderer)7317 void ImageHelper::destroy(Renderer *renderer)
7318 {
7319 VkDevice device = renderer->getDevice();
7320
7321 // mDeviceMemory and mVmaAllocation should not be valid at the same time.
7322 ASSERT(!mDeviceMemory.valid() || !mVmaAllocation.valid());
7323 if (mDeviceMemory.valid())
7324 {
7325 renderer->onMemoryDealloc(mMemoryAllocationType, mAllocationSize, mMemoryTypeIndex,
7326 mDeviceMemory.getHandle());
7327 }
7328 if (mVmaAllocation.valid())
7329 {
7330 renderer->onMemoryDealloc(mMemoryAllocationType, mAllocationSize, mMemoryTypeIndex,
7331 mVmaAllocation.getHandle());
7332 }
7333
7334 mCurrentEvent.release(renderer);
7335 mLastNonShaderReadOnlyEvent.release(renderer);
7336 mImage.destroy(device);
7337 mDeviceMemory.destroy(device);
7338 mVmaAllocation.destroy(renderer->getAllocator());
7339 mCurrentLayout = ImageLayout::Undefined;
7340 mImageType = VK_IMAGE_TYPE_2D;
7341 mLayerCount = 0;
7342 mLevelCount = 0;
7343 mMemoryAllocationType = MemoryAllocationType::InvalidEnum;
7344
7345 setEntireContentUndefined();
7346 }
7347
init2DWeakReference(ErrorContext * context,VkImage handle,const gl::Extents & glExtents,bool rotatedAspectRatio,angle::FormatID intendedFormatID,angle::FormatID actualFormatID,VkImageCreateFlags createFlags,VkImageUsageFlags usage,GLint samples,bool isRobustResourceInitEnabled)7348 void ImageHelper::init2DWeakReference(ErrorContext *context,
7349 VkImage handle,
7350 const gl::Extents &glExtents,
7351 bool rotatedAspectRatio,
7352 angle::FormatID intendedFormatID,
7353 angle::FormatID actualFormatID,
7354 VkImageCreateFlags createFlags,
7355 VkImageUsageFlags usage,
7356 GLint samples,
7357 bool isRobustResourceInitEnabled)
7358 {
7359 ASSERT(!valid());
7360 ASSERT(!IsAnySubresourceContentDefined(mContentDefined));
7361 ASSERT(!IsAnySubresourceContentDefined(mStencilContentDefined));
7362 vk::Renderer *renderer = context->getRenderer();
7363
7364 gl_vk::GetExtent(glExtents, &mExtents);
7365 mRotatedAspectRatio = rotatedAspectRatio;
7366 mIntendedFormatID = intendedFormatID;
7367 mActualFormatID = actualFormatID;
7368 mCreateFlags = createFlags;
7369 mUsage = usage;
7370 mSamples = std::max(samples, 1);
7371 mImageSerial = renderer->getResourceSerialFactory().generateImageSerial();
7372 mCurrentDeviceQueueIndex = context->getDeviceQueueIndex();
7373 mIsReleasedToExternal = false;
7374 mIsForeignImage = false;
7375 mCurrentLayout = ImageLayout::Undefined;
7376 mLayerCount = 1;
7377 mLevelCount = 1;
7378
7379 // The view formats and usage flags are used for imageless framebuffers. Here, the former is set
7380 // similar to deriveImageViewFormatFromCreateInfoPNext() when there is no pNext from a
7381 // VkImageCreateInfo object.
7382 setImageFormatsFromActualFormat(GetVkFormatFromFormatID(renderer, actualFormatID),
7383 mViewFormats);
7384
7385 mImage.setHandle(handle);
7386
7387 stageClearIfEmulatedFormat(isRobustResourceInitEnabled, false);
7388 }
7389
init2DStaging(ErrorContext * context,bool hasProtectedContent,const MemoryProperties & memoryProperties,const gl::Extents & glExtents,angle::FormatID intendedFormatID,angle::FormatID actualFormatID,VkImageUsageFlags usage,uint32_t layerCount)7390 angle::Result ImageHelper::init2DStaging(ErrorContext *context,
7391 bool hasProtectedContent,
7392 const MemoryProperties &memoryProperties,
7393 const gl::Extents &glExtents,
7394 angle::FormatID intendedFormatID,
7395 angle::FormatID actualFormatID,
7396 VkImageUsageFlags usage,
7397 uint32_t layerCount)
7398 {
7399 gl_vk::GetExtent(glExtents, &mExtents);
7400
7401 return initStaging(context, hasProtectedContent, memoryProperties, VK_IMAGE_TYPE_2D, mExtents,
7402 intendedFormatID, actualFormatID, 1, usage, 1, layerCount);
7403 }
7404
initStaging(ErrorContext * 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)7405 angle::Result ImageHelper::initStaging(ErrorContext *context,
7406 bool hasProtectedContent,
7407 const MemoryProperties &memoryProperties,
7408 VkImageType imageType,
7409 const VkExtent3D &extents,
7410 angle::FormatID intendedFormatID,
7411 angle::FormatID actualFormatID,
7412 GLint samples,
7413 VkImageUsageFlags usage,
7414 uint32_t mipLevels,
7415 uint32_t layerCount)
7416 {
7417 ASSERT(!valid());
7418 ASSERT(!IsAnySubresourceContentDefined(mContentDefined));
7419 ASSERT(!IsAnySubresourceContentDefined(mStencilContentDefined));
7420 vk::Renderer *renderer = context->getRenderer();
7421
7422 mImageType = imageType;
7423 mExtents = extents;
7424 mRotatedAspectRatio = false;
7425 mIntendedFormatID = intendedFormatID;
7426 mActualFormatID = actualFormatID;
7427 mSamples = std::max(samples, 1);
7428 mImageSerial = renderer->getResourceSerialFactory().generateImageSerial();
7429 mLayerCount = layerCount;
7430 mLevelCount = mipLevels;
7431 mUsage = usage;
7432
7433 // Validate that mLayerCount is compatible with the image type
7434 ASSERT(imageType != VK_IMAGE_TYPE_3D || mLayerCount == 1);
7435 ASSERT(imageType != VK_IMAGE_TYPE_2D || mExtents.depth == 1);
7436
7437 mCurrentLayout = ImageLayout::Undefined;
7438
7439 VkImageCreateInfo imageInfo = {};
7440 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
7441 imageInfo.flags = hasProtectedContent ? VK_IMAGE_CREATE_PROTECTED_BIT : 0;
7442 imageInfo.imageType = mImageType;
7443 imageInfo.format = GetVkFormatFromFormatID(renderer, actualFormatID);
7444 imageInfo.extent = mExtents;
7445 imageInfo.mipLevels = mLevelCount;
7446 imageInfo.arrayLayers = mLayerCount;
7447 imageInfo.samples =
7448 gl_vk::GetSamples(mSamples, context->getFeatures().limitSampleCountTo2.enabled);
7449 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
7450 imageInfo.usage = usage;
7451 imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
7452 imageInfo.queueFamilyIndexCount = 0;
7453 imageInfo.pQueueFamilyIndices = nullptr;
7454 imageInfo.initialLayout = getCurrentLayout();
7455
7456 ANGLE_VK_TRY(context, mImage.init(context->getDevice(), imageInfo));
7457
7458 mVkImageCreateInfo = imageInfo;
7459 mVkImageCreateInfo.pNext = nullptr;
7460 mVkImageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
7461
7462 // Allocate and bind device-local memory.
7463 VkMemoryPropertyFlags memoryPropertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
7464 if (hasProtectedContent)
7465 {
7466 memoryPropertyFlags |= VK_MEMORY_PROPERTY_PROTECTED_BIT;
7467 }
7468
7469 ANGLE_TRY(initMemoryAndNonZeroFillIfNeeded(context, hasProtectedContent, memoryProperties,
7470 memoryPropertyFlags,
7471 vk::MemoryAllocationType::StagingImage));
7472 return angle::Result::Continue;
7473 }
7474
initImplicitMultisampledRenderToTexture(ErrorContext * context,bool hasProtectedContent,const MemoryProperties & memoryProperties,gl::TextureType textureType,GLint samples,const ImageHelper & resolveImage,const VkExtent3D & multisampleImageExtents,bool isRobustResourceInitEnabled)7475 angle::Result ImageHelper::initImplicitMultisampledRenderToTexture(
7476 ErrorContext *context,
7477 bool hasProtectedContent,
7478 const MemoryProperties &memoryProperties,
7479 gl::TextureType textureType,
7480 GLint samples,
7481 const ImageHelper &resolveImage,
7482 const VkExtent3D &multisampleImageExtents,
7483 bool isRobustResourceInitEnabled)
7484 {
7485 ASSERT(!valid());
7486 ASSERT(samples > 1);
7487 ASSERT(!IsAnySubresourceContentDefined(mContentDefined));
7488 ASSERT(!IsAnySubresourceContentDefined(mStencilContentDefined));
7489
7490 // The image is used as either color or depth/stencil attachment. Additionally, its memory is
7491 // lazily allocated as the contents are discarded at the end of the renderpass and with tiling
7492 // GPUs no actual backing memory is required.
7493 //
7494 // Note that the Vulkan image is created with or without VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT
7495 // based on whether the memory that will be used to create the image would have
7496 // VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT. TRANSIENT is provided if there is any memory that
7497 // supports LAZILY_ALLOCATED. However, based on actual image requirements, such a memory may
7498 // not be suitable for the image. We don't support such a case, which will result in the
7499 // |initMemory| call below failing.
7500 const bool hasLazilyAllocatedMemory = memoryProperties.hasLazilyAllocatedMemory();
7501
7502 const VkImageUsageFlags kLazyFlags =
7503 hasLazilyAllocatedMemory ? VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT : 0;
7504 constexpr VkImageUsageFlags kColorFlags =
7505 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
7506
7507 // Request input attachment flag iff supportsShaderFramebufferFetchDepthStencil is enabled.
7508 const VkImageUsageFlags depthStencilFlags =
7509 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT |
7510 ((context->getFeatures().supportsShaderFramebufferFetchDepthStencil.enabled)
7511 ? VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT
7512 : 0);
7513
7514 const VkImageUsageFlags kMultisampledUsageFlags =
7515 kLazyFlags |
7516 (resolveImage.getAspectFlags() == VK_IMAGE_ASPECT_COLOR_BIT ? kColorFlags
7517 : depthStencilFlags);
7518 const VkImageCreateFlags kMultisampledCreateFlags =
7519 hasProtectedContent ? VK_IMAGE_CREATE_PROTECTED_BIT : 0;
7520
7521 // Multisampled images have only 1 level
7522 constexpr uint32_t kLevelCount = 1;
7523
7524 ANGLE_TRY(initExternal(context, textureType, multisampleImageExtents,
7525 resolveImage.getIntendedFormatID(), resolveImage.getActualFormatID(),
7526 samples, kMultisampledUsageFlags, kMultisampledCreateFlags,
7527 ImageLayout::Undefined, nullptr, resolveImage.getFirstAllocatedLevel(),
7528 kLevelCount, resolveImage.getLayerCount(), isRobustResourceInitEnabled,
7529 hasProtectedContent, YcbcrConversionDesc{}, nullptr));
7530
7531 // Remove the emulated format clear from the multisampled image if any. There is one already
7532 // staged on the resolve image if needed.
7533 removeStagedUpdates(context, getFirstAllocatedLevel(), getLastAllocatedLevel());
7534
7535 const VkMemoryPropertyFlags kMultisampledMemoryFlags =
7536 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
7537 (hasLazilyAllocatedMemory ? VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT : 0) |
7538 (hasProtectedContent ? VK_MEMORY_PROPERTY_PROTECTED_BIT : 0);
7539
7540 // If this ever fails, it can be retried without the LAZILY_ALLOCATED flag (which will probably
7541 // still fail), but ideally that means GL_EXT_multisampled_render_to_texture should not be
7542 // advertised on this platform in the first place.
7543 ANGLE_TRY(initMemoryAndNonZeroFillIfNeeded(
7544 context, hasProtectedContent, memoryProperties, kMultisampledMemoryFlags,
7545 vk::MemoryAllocationType::ImplicitMultisampledRenderToTextureImage));
7546 return angle::Result::Continue;
7547 }
7548
getAspectFlags() const7549 VkImageAspectFlags ImageHelper::getAspectFlags() const
7550 {
7551 return GetFormatAspectFlags(angle::Format::Get(mActualFormatID));
7552 }
7553
isCombinedDepthStencilFormat() const7554 bool ImageHelper::isCombinedDepthStencilFormat() const
7555 {
7556 return (getAspectFlags() & kDepthStencilAspects) == kDepthStencilAspects;
7557 }
7558
setCurrentImageLayout(Renderer * renderer,ImageLayout newLayout)7559 void ImageHelper::setCurrentImageLayout(Renderer *renderer, ImageLayout newLayout)
7560 {
7561 // Once you transition to ImageLayout::SharedPresent, you never transition out of it.
7562 if (mCurrentLayout == ImageLayout::SharedPresent)
7563 {
7564 return;
7565 }
7566
7567 const ImageMemoryBarrierData &transitionFrom =
7568 renderer->getImageMemoryBarrierData(mCurrentLayout);
7569 const ImageMemoryBarrierData &transitionTo = renderer->getImageMemoryBarrierData(newLayout);
7570 mLastNonShaderReadOnlyLayout =
7571 !IsShaderReadOnlyLayout(transitionFrom) ? mCurrentLayout : mLastNonShaderReadOnlyLayout;
7572 // Force the use of BarrierType::Pipeline in the next barrierImpl call
7573 mLastNonShaderReadOnlyEvent.release(renderer);
7574 mCurrentShaderReadStageMask =
7575 IsShaderReadOnlyLayout(transitionTo) ? transitionTo.dstStageMask : 0;
7576 mCurrentLayout = newLayout;
7577 }
7578
getCurrentLayout() const7579 VkImageLayout ImageHelper::getCurrentLayout() const
7580 {
7581 return ConvertImageLayoutToVkImageLayout(mCurrentLayout);
7582 }
7583
getLevelExtents(LevelIndex levelVk) const7584 gl::Extents ImageHelper::getLevelExtents(LevelIndex levelVk) const
7585 {
7586 // Level 0 should be the size of the extents, after that every time you increase a level
7587 // you shrink the extents by half.
7588 uint32_t width = std::max(mExtents.width >> levelVk.get(), 1u);
7589 uint32_t height = std::max(mExtents.height >> levelVk.get(), 1u);
7590 uint32_t depth = std::max(mExtents.depth >> levelVk.get(), 1u);
7591
7592 return gl::Extents(width, height, depth);
7593 }
7594
getLevelExtents2D(LevelIndex levelVk) const7595 gl::Extents ImageHelper::getLevelExtents2D(LevelIndex levelVk) const
7596 {
7597 gl::Extents extents = getLevelExtents(levelVk);
7598 extents.depth = 1;
7599 return extents;
7600 }
7601
getRotatedExtents() const7602 const VkExtent3D ImageHelper::getRotatedExtents() const
7603 {
7604 VkExtent3D extents = mExtents;
7605 if (mRotatedAspectRatio)
7606 {
7607 std::swap(extents.width, extents.height);
7608 }
7609 return extents;
7610 }
7611
getRotatedLevelExtents2D(LevelIndex levelVk) const7612 gl::Extents ImageHelper::getRotatedLevelExtents2D(LevelIndex levelVk) const
7613 {
7614 gl::Extents extents = getLevelExtents2D(levelVk);
7615 if (mRotatedAspectRatio)
7616 {
7617 std::swap(extents.width, extents.height);
7618 }
7619 return extents;
7620 }
7621
isDepthOrStencil() const7622 bool ImageHelper::isDepthOrStencil() const
7623 {
7624 return getActualFormat().hasDepthOrStencilBits();
7625 }
7626
setRenderPassUsageFlag(RenderPassUsage flag)7627 void ImageHelper::setRenderPassUsageFlag(RenderPassUsage flag)
7628 {
7629 mRenderPassUsageFlags.set(flag);
7630 }
7631
clearRenderPassUsageFlag(RenderPassUsage flag)7632 void ImageHelper::clearRenderPassUsageFlag(RenderPassUsage flag)
7633 {
7634 mRenderPassUsageFlags.reset(flag);
7635 }
7636
resetRenderPassUsageFlags()7637 void ImageHelper::resetRenderPassUsageFlags()
7638 {
7639 mRenderPassUsageFlags.reset();
7640 }
7641
hasRenderPassUsageFlag(RenderPassUsage flag) const7642 bool ImageHelper::hasRenderPassUsageFlag(RenderPassUsage flag) const
7643 {
7644 return mRenderPassUsageFlags.test(flag);
7645 }
7646
hasAnyRenderPassUsageFlags() const7647 bool ImageHelper::hasAnyRenderPassUsageFlags() const
7648 {
7649 return mRenderPassUsageFlags.any();
7650 }
7651
usedByCurrentRenderPassAsAttachmentAndSampler(RenderPassUsage textureSamplerUsage) const7652 bool ImageHelper::usedByCurrentRenderPassAsAttachmentAndSampler(
7653 RenderPassUsage textureSamplerUsage) const
7654 {
7655 return mRenderPassUsageFlags[RenderPassUsage::RenderTargetAttachment] &&
7656 mRenderPassUsageFlags[textureSamplerUsage];
7657 }
7658
isReadBarrierNecessary(Renderer * renderer,ImageLayout newLayout) const7659 bool ImageHelper::isReadBarrierNecessary(Renderer *renderer, ImageLayout newLayout) const
7660 {
7661 // If transitioning to a different layout, we need always need a barrier.
7662 if (mCurrentLayout != newLayout)
7663 {
7664 return true;
7665 }
7666
7667 // RAR (read-after-read) is not a hazard and doesn't require a barrier.
7668 //
7669 // RAW (read-after-write) hazards always require a memory barrier. This can only happen if the
7670 // layout (same as new layout) is writable which in turn is only possible if the image is
7671 // simultaneously bound for shader write (i.e. the layout is GENERAL or SHARED_PRESENT).
7672 const ImageMemoryBarrierData &layoutData = renderer->getImageMemoryBarrierData(mCurrentLayout);
7673 return HasResourceWriteAccess(layoutData.type);
7674 }
7675
isReadSubresourceBarrierNecessary(ImageLayout newLayout,gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount) const7676 bool ImageHelper::isReadSubresourceBarrierNecessary(ImageLayout newLayout,
7677 gl::LevelIndex levelStart,
7678 uint32_t levelCount,
7679 uint32_t layerStart,
7680 uint32_t layerCount) const
7681 {
7682 // In case an image has both read and write permissions, the written subresources since the last
7683 // barrier should be checked to avoid RAW and WAR hazards. However, if a layout change is
7684 // necessary regardless, there is no need to check the written subresources.
7685 if (mCurrentLayout != newLayout)
7686 {
7687 return true;
7688 }
7689
7690 ImageLayerWriteMask layerMask = GetImageLayerWriteMask(layerStart, layerCount);
7691 for (uint32_t levelOffset = 0; levelOffset < levelCount; levelOffset++)
7692 {
7693 uint32_t level = levelStart.get() + levelOffset;
7694 if (areLevelSubresourcesWrittenWithinMaskRange(level, layerMask))
7695 {
7696 return true;
7697 }
7698 }
7699
7700 return false;
7701 }
7702
isWriteBarrierNecessary(ImageLayout newLayout,gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount) const7703 bool ImageHelper::isWriteBarrierNecessary(ImageLayout newLayout,
7704 gl::LevelIndex levelStart,
7705 uint32_t levelCount,
7706 uint32_t layerStart,
7707 uint32_t layerCount) const
7708 {
7709 // If transitioning to a different layout, we need always need a barrier.
7710 if (mCurrentLayout != newLayout)
7711 {
7712 return true;
7713 }
7714
7715 if (layerCount >= kMaxParallelLayerWrites)
7716 {
7717 return true;
7718 }
7719
7720 // If we are writing to the same parts of the image (level/layer), we need a barrier. Otherwise,
7721 // it can be done in parallel.
7722 ImageLayerWriteMask layerMask = GetImageLayerWriteMask(layerStart, layerCount);
7723 for (uint32_t levelOffset = 0; levelOffset < levelCount; levelOffset++)
7724 {
7725 uint32_t level = levelStart.get() + levelOffset;
7726 if (areLevelSubresourcesWrittenWithinMaskRange(level, layerMask))
7727 {
7728 return true;
7729 }
7730 }
7731
7732 return false;
7733 }
7734
changeLayoutAndQueue(Context * context,VkImageAspectFlags aspectMask,ImageLayout newLayout,DeviceQueueIndex newDeviceQueueIndex,OutsideRenderPassCommandBuffer * commandBuffer)7735 void ImageHelper::changeLayoutAndQueue(Context *context,
7736 VkImageAspectFlags aspectMask,
7737 ImageLayout newLayout,
7738 DeviceQueueIndex newDeviceQueueIndex,
7739 OutsideRenderPassCommandBuffer *commandBuffer)
7740 {
7741 ASSERT(!mIsForeignImage);
7742
7743 ASSERT(isQueueFamilyChangeNeccesary(newDeviceQueueIndex));
7744 VkSemaphore acquireNextImageSemaphore;
7745 // recordBarrierImpl should detect there is queue switch and fall back to pipelineBarrier
7746 // properly.
7747 recordBarrierImpl(context, aspectMask, newLayout, newDeviceQueueIndex, nullptr, commandBuffer,
7748 &acquireNextImageSemaphore);
7749 // SwapChain image should not get here.
7750 ASSERT(acquireNextImageSemaphore == VK_NULL_HANDLE);
7751 }
7752
acquireFromExternal(Context * context,DeviceQueueIndex externalQueueIndex,DeviceQueueIndex newDeviceQueueIndex,ImageLayout currentLayout,OutsideRenderPassCommandBuffer * commandBuffer)7753 void ImageHelper::acquireFromExternal(Context *context,
7754 DeviceQueueIndex externalQueueIndex,
7755 DeviceQueueIndex newDeviceQueueIndex,
7756 ImageLayout currentLayout,
7757 OutsideRenderPassCommandBuffer *commandBuffer)
7758 {
7759 // The image must be newly allocated or have been released to the external
7760 // queue. If this is not the case, it's an application bug, so ASSERT might
7761 // eventually need to change to a warning.
7762 ASSERT(mCurrentLayout == ImageLayout::ExternalPreInitialized ||
7763 mCurrentDeviceQueueIndex.familyIndex() == externalQueueIndex.familyIndex());
7764
7765 mCurrentLayout = currentLayout;
7766 mCurrentDeviceQueueIndex = externalQueueIndex;
7767 mIsReleasedToExternal = false;
7768
7769 // Only change the layout and queue if the layout is anything by Undefined. If it is undefined,
7770 // leave it to transition out as the image is used later.
7771 if (currentLayout != ImageLayout::Undefined)
7772 {
7773 changeLayoutAndQueue(context, getAspectFlags(), mCurrentLayout, newDeviceQueueIndex,
7774 commandBuffer);
7775 }
7776
7777 // It is unknown how the external has modified the image, so assume every subresource has
7778 // defined content. That is unless the layout is Undefined.
7779 if (currentLayout == ImageLayout::Undefined)
7780 {
7781 setEntireContentUndefined();
7782 }
7783 else
7784 {
7785 setEntireContentDefined();
7786 }
7787 }
7788
releaseToExternal(Context * context,DeviceQueueIndex externalQueueIndex,ImageLayout desiredLayout,OutsideRenderPassCommandBuffer * commandBuffer)7789 void ImageHelper::releaseToExternal(Context *context,
7790 DeviceQueueIndex externalQueueIndex,
7791 ImageLayout desiredLayout,
7792 OutsideRenderPassCommandBuffer *commandBuffer)
7793 {
7794 ASSERT(!mIsReleasedToExternal);
7795
7796 // A layout change is unnecessary if the image that was previously acquired was never used by
7797 // GL!
7798 if (mCurrentDeviceQueueIndex.familyIndex() != externalQueueIndex.familyIndex() ||
7799 mCurrentLayout != desiredLayout)
7800 {
7801 changeLayoutAndQueue(context, getAspectFlags(), desiredLayout, externalQueueIndex,
7802 commandBuffer);
7803 }
7804
7805 mIsReleasedToExternal = true;
7806 }
7807
releaseToForeign(Renderer * renderer)7808 VkImageMemoryBarrier ImageHelper::releaseToForeign(Renderer *renderer)
7809 {
7810 ASSERT(mIsForeignImage);
7811
7812 const ImageMemoryBarrierData barrierData = renderer->getImageMemoryBarrierData(mCurrentLayout);
7813
7814 VkImageMemoryBarrier barrier = {};
7815 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
7816 barrier.srcAccessMask = barrierData.srcAccessMask;
7817 barrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT;
7818 barrier.oldLayout = barrierData.layout;
7819 barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
7820 barrier.srcQueueFamilyIndex = renderer->getQueueFamilyIndex();
7821 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_FOREIGN_EXT;
7822 barrier.image = mImage.getHandle();
7823 barrier.subresourceRange.aspectMask = getAspectFlags();
7824 barrier.subresourceRange.levelCount = mLevelCount;
7825 barrier.subresourceRange.layerCount = mLayerCount;
7826
7827 mCurrentLayout = ImageLayout::ForeignAccess;
7828 mCurrentDeviceQueueIndex = kForeignDeviceQueueIndex;
7829 mLastNonShaderReadOnlyLayout = ImageLayout::Undefined;
7830 mCurrentShaderReadStageMask = 0;
7831
7832 return barrier;
7833 }
7834
toVkLevel(gl::LevelIndex levelIndexGL) const7835 LevelIndex ImageHelper::toVkLevel(gl::LevelIndex levelIndexGL) const
7836 {
7837 return gl_vk::GetLevelIndex(levelIndexGL, mFirstAllocatedLevel);
7838 }
7839
toGLLevel(LevelIndex levelIndexVk) const7840 gl::LevelIndex ImageHelper::toGLLevel(LevelIndex levelIndexVk) const
7841 {
7842 return vk_gl::GetLevelIndex(levelIndexVk, mFirstAllocatedLevel);
7843 }
7844
initImageMemoryBarrierStruct(Renderer * renderer,VkImageAspectFlags aspectMask,ImageLayout newLayout,uint32_t newQueueFamilyIndex,VkImageMemoryBarrier * imageMemoryBarrier) const7845 ANGLE_INLINE void ImageHelper::initImageMemoryBarrierStruct(
7846 Renderer *renderer,
7847 VkImageAspectFlags aspectMask,
7848 ImageLayout newLayout,
7849 uint32_t newQueueFamilyIndex,
7850 VkImageMemoryBarrier *imageMemoryBarrier) const
7851 {
7852 ASSERT(mCurrentDeviceQueueIndex.familyIndex() != QueueFamily::kInvalidIndex);
7853 ASSERT(newQueueFamilyIndex != QueueFamily::kInvalidIndex);
7854
7855 const ImageMemoryBarrierData &transitionFrom =
7856 renderer->getImageMemoryBarrierData(mCurrentLayout);
7857 const ImageMemoryBarrierData &transitionTo = renderer->getImageMemoryBarrierData(newLayout);
7858
7859 imageMemoryBarrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
7860 imageMemoryBarrier->srcAccessMask = transitionFrom.srcAccessMask;
7861 imageMemoryBarrier->dstAccessMask = transitionTo.dstAccessMask;
7862 imageMemoryBarrier->oldLayout = ConvertImageLayoutToVkImageLayout(mCurrentLayout);
7863 imageMemoryBarrier->newLayout = ConvertImageLayoutToVkImageLayout(newLayout);
7864 imageMemoryBarrier->srcQueueFamilyIndex = mCurrentDeviceQueueIndex.familyIndex();
7865 imageMemoryBarrier->dstQueueFamilyIndex = newQueueFamilyIndex;
7866 imageMemoryBarrier->image = mImage.getHandle();
7867
7868 // Transition the whole resource.
7869 imageMemoryBarrier->subresourceRange.aspectMask = aspectMask;
7870 imageMemoryBarrier->subresourceRange.baseMipLevel = 0;
7871 imageMemoryBarrier->subresourceRange.levelCount = mLevelCount;
7872 imageMemoryBarrier->subresourceRange.baseArrayLayer = 0;
7873 imageMemoryBarrier->subresourceRange.layerCount = mLayerCount;
7874 }
7875
7876 // Generalized to accept both "primary" and "secondary" command buffers.
7877 template <typename CommandBufferT>
barrierImpl(Renderer * renderer,VkImageAspectFlags aspectMask,ImageLayout newLayout,DeviceQueueIndex newDeviceQueueIndex,RefCountedEventCollector * eventCollector,CommandBufferT * commandBuffer,VkSemaphore * acquireNextImageSemaphoreOut)7878 void ImageHelper::barrierImpl(Renderer *renderer,
7879 VkImageAspectFlags aspectMask,
7880 ImageLayout newLayout,
7881 DeviceQueueIndex newDeviceQueueIndex,
7882 RefCountedEventCollector *eventCollector,
7883 CommandBufferT *commandBuffer,
7884 VkSemaphore *acquireNextImageSemaphoreOut)
7885 {
7886 // Release the ANI semaphore to caller to add to the command submission.
7887 ASSERT(acquireNextImageSemaphoreOut != nullptr || !mAcquireNextImageSemaphore.valid());
7888 if (acquireNextImageSemaphoreOut != nullptr)
7889 {
7890 *acquireNextImageSemaphoreOut = mAcquireNextImageSemaphore.release();
7891 }
7892
7893 if (mCurrentLayout == ImageLayout::SharedPresent)
7894 {
7895 const ImageMemoryBarrierData &transition =
7896 renderer->getImageMemoryBarrierData(mCurrentLayout);
7897 VkMemoryBarrier memoryBarrier = {};
7898 memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
7899 memoryBarrier.srcAccessMask = transition.srcAccessMask;
7900 memoryBarrier.dstAccessMask = transition.dstAccessMask;
7901
7902 commandBuffer->memoryBarrier(transition.srcStageMask, transition.dstStageMask,
7903 memoryBarrier);
7904 return;
7905 }
7906
7907 // Make sure we never transition out of SharedPresent
7908 ASSERT(mCurrentLayout != ImageLayout::SharedPresent || newLayout == ImageLayout::SharedPresent);
7909
7910 const ImageMemoryBarrierData &transitionFrom =
7911 renderer->getImageMemoryBarrierData(mCurrentLayout);
7912 const ImageMemoryBarrierData &transitionTo = renderer->getImageMemoryBarrierData(newLayout);
7913
7914 VkImageMemoryBarrier imageMemoryBarrier = {};
7915 initImageMemoryBarrierStruct(renderer, aspectMask, newLayout, newDeviceQueueIndex.familyIndex(),
7916 &imageMemoryBarrier);
7917
7918 VkPipelineStageFlags dstStageMask = transitionTo.dstStageMask;
7919
7920 // Fallback to pipelineBarrier if there is no event tracking image.
7921 // VkCmdWaitEvent requires the srcQueueFamilyIndex and dstQueueFamilyIndex members of any
7922 // element of pBufferMemoryBarriers or pImageMemoryBarriers must be equal
7923 // (VUID-vkCmdWaitEvents-srcQueueFamilyIndex-02803).
7924 BarrierType barrierType =
7925 mCurrentEvent.valid() && mCurrentDeviceQueueIndex == newDeviceQueueIndex
7926 ? BarrierType::Event
7927 : BarrierType::Pipeline;
7928
7929 if (barrierType == BarrierType::Event)
7930 {
7931 // If there is an event, we use the waitEvent to do layout change. Once we have waited, the
7932 // event gets garbage collected (which is GPU completion tracked) to avoid waited again in
7933 // future. We always use DstStageMask since that is what setEvent used and
7934 // VUID-vkCmdWaitEvents-srcStageMask-01158 requires they must match.
7935 VkPipelineStageFlags srcStageMask =
7936 renderer->getPipelineStageMask(mCurrentEvent.getEventStage());
7937 commandBuffer->imageWaitEvent(mCurrentEvent.getEvent().getHandle(), srcStageMask,
7938 dstStageMask, imageMemoryBarrier);
7939 eventCollector->emplace_back(std::move(mCurrentEvent));
7940 }
7941 else
7942 {
7943 // There might be other shaderRead operations there other than the current layout.
7944 VkPipelineStageFlags srcStageMask = transitionFrom.srcStageMask;
7945 if (mCurrentShaderReadStageMask)
7946 {
7947 srcStageMask |= mCurrentShaderReadStageMask;
7948 mCurrentShaderReadStageMask = 0;
7949 mLastNonShaderReadOnlyLayout = ImageLayout::Undefined;
7950 }
7951 commandBuffer->imageBarrier(srcStageMask, dstStageMask, imageMemoryBarrier);
7952 }
7953
7954 mCurrentLayout = newLayout;
7955 mCurrentDeviceQueueIndex = newDeviceQueueIndex;
7956 resetSubresourcesWrittenSinceBarrier();
7957 }
7958
7959 template <typename CommandBufferT>
recordBarrierImpl(Context * context,VkImageAspectFlags aspectMask,ImageLayout newLayout,DeviceQueueIndex newDeviceQueueIndex,RefCountedEventCollector * eventCollector,CommandBufferT * commandBuffer,VkSemaphore * acquireNextImageSemaphoreOut)7960 void ImageHelper::recordBarrierImpl(Context *context,
7961 VkImageAspectFlags aspectMask,
7962 ImageLayout newLayout,
7963 DeviceQueueIndex newDeviceQueueIndex,
7964 RefCountedEventCollector *eventCollector,
7965 CommandBufferT *commandBuffer,
7966 VkSemaphore *acquireNextImageSemaphoreOut)
7967 {
7968 Renderer *renderer = context->getRenderer();
7969 // mCurrentEvent must be invalid if useVkEventForImageBarrieris disabled.
7970 ASSERT(renderer->getFeatures().useVkEventForImageBarrier.enabled || !mCurrentEvent.valid());
7971
7972 if (mCurrentLayout == ImageLayout::SharedPresent)
7973 {
7974 // For now we always use pipelineBarrier for singlebuffer mode. We could use event here in
7975 // future.
7976 mCurrentEvent.release(context);
7977 }
7978
7979 // The image has transitioned out of the FOREIGN queue. Remember it so it can be transitioned
7980 // back on submission.
7981 if (mCurrentDeviceQueueIndex == kForeignDeviceQueueIndex)
7982 {
7983 context->onForeignImageUse(this);
7984 }
7985
7986 barrierImpl(renderer, aspectMask, newLayout, newDeviceQueueIndex, eventCollector, commandBuffer,
7987 acquireNextImageSemaphoreOut);
7988
7989 // We must release the event so that new event will be created and added. If we did not add new
7990 // event, because mCurrentEvent have been released, next barrier will automatically fallback to
7991 // pipelineBarrier. Otherwise if we keep mCurrentEvent here we may accidentally end up waiting
7992 // for an old event which creates sync hazard.
7993 mCurrentEvent.release(context);
7994 }
7995
recordBarrierOneOffImpl(Renderer * renderer,VkImageAspectFlags aspectMask,ImageLayout newLayout,DeviceQueueIndex newDeviceQueueIndex,PrimaryCommandBuffer * commandBuffer,VkSemaphore * acquireNextImageSemaphoreOut)7996 void ImageHelper::recordBarrierOneOffImpl(Renderer *renderer,
7997 VkImageAspectFlags aspectMask,
7998 ImageLayout newLayout,
7999 DeviceQueueIndex newDeviceQueueIndex,
8000 PrimaryCommandBuffer *commandBuffer,
8001 VkSemaphore *acquireNextImageSemaphoreOut)
8002 {
8003 // Release the event here to force pipelineBarrier.
8004 mCurrentEvent.release(renderer);
8005 ASSERT(mCurrentDeviceQueueIndex != kForeignDeviceQueueIndex);
8006
8007 barrierImpl(renderer, aspectMask, newLayout, newDeviceQueueIndex, nullptr, commandBuffer,
8008 acquireNextImageSemaphoreOut);
8009 }
8010
setSubresourcesWrittenSinceBarrier(gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount)8011 void ImageHelper::setSubresourcesWrittenSinceBarrier(gl::LevelIndex levelStart,
8012 uint32_t levelCount,
8013 uint32_t layerStart,
8014 uint32_t layerCount)
8015 {
8016 for (uint32_t levelOffset = 0; levelOffset < levelCount; levelOffset++)
8017 {
8018 uint32_t level = levelStart.get() + levelOffset;
8019 if (layerCount >= kMaxParallelLayerWrites)
8020 {
8021 mSubresourcesWrittenSinceBarrier[level].set();
8022 }
8023 else
8024 {
8025 ImageLayerWriteMask layerMask = GetImageLayerWriteMask(layerStart, layerCount);
8026 mSubresourcesWrittenSinceBarrier[level] |= layerMask;
8027 }
8028 }
8029 }
8030
resetSubresourcesWrittenSinceBarrier()8031 void ImageHelper::resetSubresourcesWrittenSinceBarrier()
8032 {
8033 for (auto &layerWriteMask : mSubresourcesWrittenSinceBarrier)
8034 {
8035 layerWriteMask.reset();
8036 }
8037 }
8038
recordWriteBarrier(Context * context,VkImageAspectFlags aspectMask,ImageLayout newLayout,gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount,OutsideRenderPassCommandBufferHelper * commands)8039 void ImageHelper::recordWriteBarrier(Context *context,
8040 VkImageAspectFlags aspectMask,
8041 ImageLayout newLayout,
8042 gl::LevelIndex levelStart,
8043 uint32_t levelCount,
8044 uint32_t layerStart,
8045 uint32_t layerCount,
8046 OutsideRenderPassCommandBufferHelper *commands)
8047 {
8048 if (isWriteBarrierNecessary(newLayout, levelStart, levelCount, layerStart, layerCount))
8049 {
8050 ASSERT(!mCurrentEvent.valid() || !commands->hasSetEventPendingFlush(mCurrentEvent));
8051 VkSemaphore acquireNextImageSemaphore;
8052 recordBarrierImpl(context, aspectMask, newLayout, context->getDeviceQueueIndex(),
8053 commands->getRefCountedEventCollector(), &commands->getCommandBuffer(),
8054 &acquireNextImageSemaphore);
8055
8056 if (acquireNextImageSemaphore != VK_NULL_HANDLE)
8057 {
8058 commands->setAcquireNextImageSemaphore(acquireNextImageSemaphore);
8059 }
8060 }
8061
8062 setSubresourcesWrittenSinceBarrier(levelStart, levelCount, layerStart, layerCount);
8063 }
8064
recordReadSubresourceBarrier(Context * context,VkImageAspectFlags aspectMask,ImageLayout newLayout,gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount,OutsideRenderPassCommandBufferHelper * commands)8065 void ImageHelper::recordReadSubresourceBarrier(Context *context,
8066 VkImageAspectFlags aspectMask,
8067 ImageLayout newLayout,
8068 gl::LevelIndex levelStart,
8069 uint32_t levelCount,
8070 uint32_t layerStart,
8071 uint32_t layerCount,
8072 OutsideRenderPassCommandBufferHelper *commands)
8073 {
8074 // This barrier is used for an image with both read/write permissions, including during mipmap
8075 // generation and self-copy.
8076 if (isReadSubresourceBarrierNecessary(newLayout, levelStart, levelCount, layerStart,
8077 layerCount))
8078 {
8079 ASSERT(!mCurrentEvent.valid() || !commands->hasSetEventPendingFlush(mCurrentEvent));
8080 VkSemaphore acquireNextImageSemaphore;
8081 recordBarrierImpl(context, aspectMask, newLayout, context->getDeviceQueueIndex(),
8082 commands->getRefCountedEventCollector(), &commands->getCommandBuffer(),
8083 &acquireNextImageSemaphore);
8084
8085 if (acquireNextImageSemaphore != VK_NULL_HANDLE)
8086 {
8087 commands->setAcquireNextImageSemaphore(acquireNextImageSemaphore);
8088 }
8089 }
8090
8091 // Levels/layers being read from are also registered to avoid RAW and WAR hazards.
8092 setSubresourcesWrittenSinceBarrier(levelStart, levelCount, layerStart, layerCount);
8093 }
8094
recordReadBarrier(Context * context,VkImageAspectFlags aspectMask,ImageLayout newLayout,OutsideRenderPassCommandBufferHelper * commands)8095 void ImageHelper::recordReadBarrier(Context *context,
8096 VkImageAspectFlags aspectMask,
8097 ImageLayout newLayout,
8098 OutsideRenderPassCommandBufferHelper *commands)
8099 {
8100 if (!isReadBarrierNecessary(context->getRenderer(), newLayout))
8101 {
8102 return;
8103 }
8104
8105 ASSERT(!mCurrentEvent.valid() || !commands->hasSetEventPendingFlush(mCurrentEvent));
8106 VkSemaphore acquireNextImageSemaphore;
8107 recordBarrierImpl(context, aspectMask, newLayout, context->getDeviceQueueIndex(),
8108 commands->getRefCountedEventCollector(), &commands->getCommandBuffer(),
8109 &acquireNextImageSemaphore);
8110
8111 if (acquireNextImageSemaphore != VK_NULL_HANDLE)
8112 {
8113 commands->setAcquireNextImageSemaphore(acquireNextImageSemaphore);
8114 }
8115 }
8116
updateLayoutAndBarrier(Context * context,VkImageAspectFlags aspectMask,ImageLayout newLayout,BarrierType barrierType,const QueueSerial & queueSerial,PipelineBarrierArray * pipelineBarriers,EventBarrierArray * eventBarriers,RefCountedEventCollector * eventCollector,VkSemaphore * semaphoreOut)8117 void ImageHelper::updateLayoutAndBarrier(Context *context,
8118 VkImageAspectFlags aspectMask,
8119 ImageLayout newLayout,
8120 BarrierType barrierType,
8121 const QueueSerial &queueSerial,
8122 PipelineBarrierArray *pipelineBarriers,
8123 EventBarrierArray *eventBarriers,
8124 RefCountedEventCollector *eventCollector,
8125 VkSemaphore *semaphoreOut)
8126 {
8127 Renderer *renderer = context->getRenderer();
8128 ASSERT(queueSerial.valid());
8129 ASSERT(!mBarrierQueueSerial.valid() ||
8130 mBarrierQueueSerial.getIndex() != queueSerial.getIndex() ||
8131 mBarrierQueueSerial.getSerial() <= queueSerial.getSerial());
8132 ASSERT(renderer->getImageMemoryBarrierData(newLayout).barrierIndex !=
8133 PipelineStage::InvalidEnum);
8134 // mCurrentEvent must be invalid if useVkEventForImageBarrieris disabled.
8135 ASSERT(renderer->getFeatures().useVkEventForImageBarrier.enabled || !mCurrentEvent.valid());
8136
8137 const bool hasQueueChange = mCurrentDeviceQueueIndex != context->getDeviceQueueIndex();
8138 if (hasQueueChange)
8139 {
8140 // Fallback to pipelineBarrier if the VkQueue has changed.
8141 barrierType = BarrierType::Pipeline;
8142 if (mCurrentDeviceQueueIndex == kForeignDeviceQueueIndex)
8143 {
8144 context->onForeignImageUse(this);
8145 }
8146 }
8147 else if (!mCurrentEvent.valid())
8148 {
8149 // Fallback to pipelineBarrier if there is no event tracking image.
8150 barrierType = BarrierType::Pipeline;
8151 }
8152
8153 // Once you transition to ImageLayout::SharedPresent, you never transition out of it.
8154 if (mCurrentLayout == ImageLayout::SharedPresent)
8155 {
8156 newLayout = ImageLayout::SharedPresent;
8157 }
8158
8159 if (newLayout == mCurrentLayout && !hasQueueChange)
8160 {
8161 if (mBarrierQueueSerial == queueSerial)
8162 {
8163 ASSERT(!mAcquireNextImageSemaphore.valid());
8164 // If there is no layout change and the previous layout change happened in the same
8165 // render pass, then early out do nothing. This can happen when the same image is
8166 // attached to the multiple attachments of the framebuffer.
8167 return;
8168 }
8169
8170 const ImageMemoryBarrierData &layoutData =
8171 renderer->getImageMemoryBarrierData(mCurrentLayout);
8172 // RAR is not a hazard and doesn't require a barrier, especially as the image layout hasn't
8173 // changed. The following asserts that such a barrier is not attempted.
8174 ASSERT(HasResourceWriteAccess(layoutData.type));
8175
8176 // No layout change, only memory barrier is required
8177 if (barrierType == BarrierType::Event)
8178 {
8179 eventBarriers->addEventMemoryBarrier(renderer, mCurrentEvent, layoutData.dstAccessMask,
8180 layoutData.dstStageMask, layoutData.dstAccessMask);
8181 // Garbage collect the event, which tracks GPU completion automatically.
8182 eventCollector->emplace_back(std::move(mCurrentEvent));
8183 }
8184 else
8185 {
8186 pipelineBarriers->mergeMemoryBarrier(layoutData.barrierIndex, layoutData.dstStageMask,
8187 layoutData.dstStageMask, layoutData.srcAccessMask,
8188 layoutData.dstAccessMask);
8189
8190 // Release it. No need to garbage collect since we did not use the event here. ALl
8191 // previous use of event should garbage tracked already.
8192 mCurrentEvent.release(context);
8193 }
8194 mBarrierQueueSerial = queueSerial;
8195 }
8196 else
8197 {
8198 const ImageMemoryBarrierData &transitionFrom =
8199 renderer->getImageMemoryBarrierData(mCurrentLayout);
8200 const ImageMemoryBarrierData &transitionTo = renderer->getImageMemoryBarrierData(newLayout);
8201 VkPipelineStageFlags srcStageMask = transitionFrom.srcStageMask;
8202 VkPipelineStageFlags dstStageMask = transitionTo.dstStageMask;
8203
8204 if (transitionFrom.layout == transitionTo.layout && IsShaderReadOnlyLayout(transitionTo) &&
8205 mBarrierQueueSerial == queueSerial && !hasQueueChange)
8206 {
8207 // If we are switching between different shader stage reads of the same render pass,
8208 // then there is no actual layout change or access type change. We only need a barrier
8209 // if we are making a read that is from a new stage. Also note that we do barrier
8210 // against previous non-shaderRead layout. We do not barrier between one shaderRead and
8211 // another shaderRead.
8212 bool isNewReadStage = (mCurrentShaderReadStageMask & dstStageMask) != dstStageMask;
8213 if (!isNewReadStage)
8214 {
8215 ASSERT(!mAcquireNextImageSemaphore.valid());
8216 return;
8217 }
8218
8219 ASSERT(!mLastNonShaderReadOnlyEvent.valid() ||
8220 mLastNonShaderReadOnlyEvent.getEventStage() ==
8221 GetImageLayoutEventStage(mLastNonShaderReadOnlyLayout));
8222 if (!mLastNonShaderReadOnlyEvent.valid())
8223 {
8224 barrierType = BarrierType::Pipeline;
8225 }
8226
8227 if (barrierType == BarrierType::Event)
8228 {
8229 // If we already inserted a barrier in the same renderPass, we has to add
8230 // the new stage mask to the existing VkCmdWaitEvent call, otherwise VVL will
8231 // complain.
8232 eventBarriers->addAdditionalStageAccess(mLastNonShaderReadOnlyEvent, dstStageMask,
8233 transitionTo.dstAccessMask);
8234 eventCollector->emplace_back(mLastNonShaderReadOnlyEvent);
8235 }
8236 else
8237 {
8238 const ImageMemoryBarrierData &layoutData =
8239 renderer->getImageMemoryBarrierData(mLastNonShaderReadOnlyLayout);
8240 pipelineBarriers->mergeMemoryBarrier(
8241 transitionTo.barrierIndex, layoutData.srcStageMask, dstStageMask,
8242 layoutData.srcAccessMask, transitionTo.dstAccessMask);
8243 }
8244
8245 mBarrierQueueSerial = queueSerial;
8246 // Accumulate new read stage.
8247 mCurrentShaderReadStageMask |= dstStageMask;
8248
8249 // Since we used pipelineBarrier, release the event now to avoid wait for the
8250 // event again.
8251 if (mCurrentEvent.valid())
8252 {
8253 eventCollector->emplace_back(std::move(mCurrentEvent));
8254 }
8255 }
8256 else
8257 {
8258 VkImageMemoryBarrier imageMemoryBarrier = {};
8259 initImageMemoryBarrierStruct(renderer, aspectMask, newLayout,
8260 context->getDeviceQueueIndex().familyIndex(),
8261 &imageMemoryBarrier);
8262
8263 if (transitionFrom.layout == transitionTo.layout &&
8264 IsShaderReadOnlyLayout(transitionTo))
8265 {
8266 // If we are transiting within shaderReadOnly layout, i.e. reading from different
8267 // shader stages, VkEvent can't handle this right now. In order for VkEvent to
8268 // handle this properly we have to wait for the previous shaderReadOnly layout
8269 // transition event and add a new memoryBarrier. But we may have lost that event
8270 // already if it has been used in a new render pass (because we have to update the
8271 // event even if there is no barrier needed). To workaround this issue we fall back
8272 // to pipelineBarrier for now.
8273 barrierType = BarrierType::Pipeline;
8274 }
8275 else if (mBarrierQueueSerial == queueSerial)
8276 {
8277 // If we already inserted a barrier in this render pass, force to use
8278 // pipelineBarrier. Otherwise we will end up inserting a VkCmdWaitEvent that has not
8279 // been set (See https://issuetracker.google.com/333419317 for example).
8280 barrierType = BarrierType::Pipeline;
8281 }
8282
8283 // if we transition from shaderReadOnly, we must add in stashed shader stage masks since
8284 // there might be outstanding shader reads from stages other than current layout. We do
8285 // not insert barrier between one shaderRead to another shaderRead
8286 if (mCurrentShaderReadStageMask)
8287 {
8288 if ((mCurrentShaderReadStageMask & srcStageMask) != mCurrentShaderReadStageMask)
8289 {
8290 // mCurrentShaderReadStageMask has more bits than srcStageMask. This means it
8291 // has been used by more than one shader stage in the same render pass. These
8292 // two usages are tracked by two different ImageLayout, even though underline
8293 // VkImageLayout is the same. This means two different RefCountedEvents since
8294 // each RefCountedEvent is associated with one ImageLayout. When we transit out
8295 // of this layout, we must wait for all reads to finish. But Right now
8296 // ImageHelper only keep track of the last read. To workaround this problem we
8297 // use pipelineBarrier in this case.
8298 barrierType = BarrierType::Pipeline;
8299 srcStageMask |= mCurrentShaderReadStageMask;
8300 }
8301 mCurrentShaderReadStageMask = 0;
8302 mLastNonShaderReadOnlyLayout = ImageLayout::Undefined;
8303 if (mLastNonShaderReadOnlyEvent.valid())
8304 {
8305 mLastNonShaderReadOnlyEvent.release(context);
8306 }
8307 }
8308
8309 // If we are transition into shaderRead layout, remember the last
8310 // non-shaderRead layout here.
8311 const bool isShaderReadOnly = IsShaderReadOnlyLayout(transitionTo);
8312 if (isShaderReadOnly)
8313 {
8314 mLastNonShaderReadOnlyEvent.release(context);
8315 mLastNonShaderReadOnlyLayout = mCurrentLayout;
8316 mCurrentShaderReadStageMask = dstStageMask;
8317 }
8318
8319 if (barrierType == BarrierType::Event)
8320 {
8321 eventBarriers->addEventImageBarrier(renderer, mCurrentEvent, dstStageMask,
8322 imageMemoryBarrier);
8323 if (isShaderReadOnly)
8324 {
8325 mLastNonShaderReadOnlyEvent = mCurrentEvent;
8326 }
8327 eventCollector->emplace_back(std::move(mCurrentEvent));
8328 }
8329 else
8330 {
8331 pipelineBarriers->mergeImageBarrier(transitionTo.barrierIndex, srcStageMask,
8332 dstStageMask, imageMemoryBarrier);
8333 mCurrentEvent.release(context);
8334 }
8335
8336 mBarrierQueueSerial = queueSerial;
8337 }
8338 mCurrentLayout = newLayout;
8339 }
8340
8341 mCurrentDeviceQueueIndex = context->getDeviceQueueIndex();
8342
8343 *semaphoreOut = mAcquireNextImageSemaphore.release();
8344 // We must release the event so that new event will be created and added. If we did not add new
8345 // event, because mCurrentEvent have been released, next barrier will automatically fallback to
8346 // pipelineBarrier. Otherwise if we keep mCurrentEvent here we may accidentally end up waiting
8347 // for an old event which creates sync hazard.
8348 ASSERT(!mCurrentEvent.valid());
8349 }
8350
setCurrentRefCountedEvent(Context * context,RefCountedEventArray * refCountedEventArray)8351 void ImageHelper::setCurrentRefCountedEvent(Context *context,
8352 RefCountedEventArray *refCountedEventArray)
8353 {
8354 ASSERT(context->getFeatures().useVkEventForImageBarrier.enabled);
8355
8356 // If there is already an event, release it first.
8357 mCurrentEvent.release(context);
8358
8359 // VkCmdSetEvent can remove the unnecessary GPU pipeline bubble that comes from false dependency
8360 // between fragment and vertex/transfer/compute stages. But it also comes with higher overhead.
8361 // In order to strike the balance, we exclude the images that are only used by one group of
8362 // pipeline stages in the past N references, where N is the heuristic window that we keep track
8363 // of. Use of VkEvent will not be beneficial if it is only accessed by one group of stages since
8364 // execution within the group is expected to be non-overlap.
8365 if (mPipelineStageAccessHeuristic == kPipelineStageAccessFragmentOnly ||
8366 mPipelineStageAccessHeuristic == kPipelineStageAccessPreFragmentOnly ||
8367 mPipelineStageAccessHeuristic == kPipelineStageAccessComputeOnly)
8368 {
8369 return;
8370 }
8371
8372 // Create the event if we have not yet so. Otherwise just use the already created event. This
8373 // means all images used in the same render pass that has the same layout will be tracked by the
8374 // same event.
8375 EventStage eventStage = GetImageLayoutEventStage(mCurrentLayout);
8376 if (!refCountedEventArray->getEvent(eventStage).valid() &&
8377 !refCountedEventArray->initEventAtStage(context, eventStage))
8378 {
8379 // If VkEvent creation fail, we fallback to pipelineBarrier
8380 return;
8381 }
8382
8383 // Copy the event to mCurrentEvent so that we can wait for it in future. This will add extra
8384 // refcount to the underlying VkEvent.
8385 mCurrentEvent = refCountedEventArray->getEvent(eventStage);
8386 }
8387
updatePipelineStageAccessHistory()8388 void ImageHelper::updatePipelineStageAccessHistory()
8389 {
8390 const ImageMemoryBarrierData &barrierData = kImageMemoryBarrierData[mCurrentLayout];
8391 mPipelineStageAccessHeuristic.onAccess(barrierData.pipelineStageGroup);
8392 }
8393
clearColor(Renderer * renderer,const VkClearColorValue & color,LevelIndex baseMipLevelVk,uint32_t levelCount,uint32_t baseArrayLayer,uint32_t layerCount,OutsideRenderPassCommandBuffer * commandBuffer)8394 void ImageHelper::clearColor(Renderer *renderer,
8395 const VkClearColorValue &color,
8396 LevelIndex baseMipLevelVk,
8397 uint32_t levelCount,
8398 uint32_t baseArrayLayer,
8399 uint32_t layerCount,
8400 OutsideRenderPassCommandBuffer *commandBuffer)
8401 {
8402 ASSERT(valid());
8403
8404 ASSERT(mCurrentLayout == ImageLayout::TransferDst ||
8405 mCurrentLayout == ImageLayout::SharedPresent);
8406
8407 VkImageSubresourceRange range = {};
8408 range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8409 range.baseMipLevel = baseMipLevelVk.get();
8410 range.levelCount = levelCount;
8411 range.baseArrayLayer = baseArrayLayer;
8412 range.layerCount = layerCount;
8413
8414 if (mImageType == VK_IMAGE_TYPE_3D)
8415 {
8416 ASSERT(baseArrayLayer == 0);
8417 ASSERT(layerCount == 1 ||
8418 layerCount == static_cast<uint32_t>(getLevelExtents(baseMipLevelVk).depth));
8419 range.layerCount = 1;
8420 }
8421
8422 commandBuffer->clearColorImage(mImage, getCurrentLayout(), color, 1, &range);
8423 }
8424
clearDepthStencil(Renderer * renderer,VkImageAspectFlags clearAspectFlags,const VkClearDepthStencilValue & depthStencil,LevelIndex baseMipLevelVk,uint32_t levelCount,uint32_t baseArrayLayer,uint32_t layerCount,OutsideRenderPassCommandBuffer * commandBuffer)8425 void ImageHelper::clearDepthStencil(Renderer *renderer,
8426 VkImageAspectFlags clearAspectFlags,
8427 const VkClearDepthStencilValue &depthStencil,
8428 LevelIndex baseMipLevelVk,
8429 uint32_t levelCount,
8430 uint32_t baseArrayLayer,
8431 uint32_t layerCount,
8432 OutsideRenderPassCommandBuffer *commandBuffer)
8433 {
8434 ASSERT(valid());
8435
8436 ASSERT(mCurrentLayout == ImageLayout::TransferDst);
8437
8438 VkImageSubresourceRange range = {};
8439 range.aspectMask = clearAspectFlags;
8440 range.baseMipLevel = baseMipLevelVk.get();
8441 range.levelCount = levelCount;
8442 range.baseArrayLayer = baseArrayLayer;
8443 range.layerCount = layerCount;
8444
8445 if (mImageType == VK_IMAGE_TYPE_3D)
8446 {
8447 ASSERT(baseArrayLayer == 0);
8448 ASSERT(layerCount == 1 ||
8449 layerCount == static_cast<uint32_t>(getLevelExtents(baseMipLevelVk).depth));
8450 range.layerCount = 1;
8451 }
8452
8453 commandBuffer->clearDepthStencilImage(mImage, getCurrentLayout(), depthStencil, 1, &range);
8454 }
8455
clear(Renderer * renderer,VkImageAspectFlags aspectFlags,const VkClearValue & value,LevelIndex mipLevel,uint32_t baseArrayLayer,uint32_t layerCount,OutsideRenderPassCommandBuffer * commandBuffer)8456 void ImageHelper::clear(Renderer *renderer,
8457 VkImageAspectFlags aspectFlags,
8458 const VkClearValue &value,
8459 LevelIndex mipLevel,
8460 uint32_t baseArrayLayer,
8461 uint32_t layerCount,
8462 OutsideRenderPassCommandBuffer *commandBuffer)
8463 {
8464 const angle::Format &angleFormat = getActualFormat();
8465 bool isDepthStencil = angleFormat.hasDepthOrStencilBits();
8466
8467 if (isDepthStencil)
8468 {
8469 clearDepthStencil(renderer, aspectFlags, value.depthStencil, mipLevel, 1, baseArrayLayer,
8470 layerCount, commandBuffer);
8471 }
8472 else
8473 {
8474 ASSERT(!angleFormat.isBlock);
8475
8476 clearColor(renderer, value.color, mipLevel, 1, baseArrayLayer, layerCount, commandBuffer);
8477 }
8478 }
8479
clearEmulatedChannels(ContextVk * contextVk,VkColorComponentFlags colorMaskFlags,const VkClearValue & value,LevelIndex mipLevel,uint32_t baseArrayLayer,uint32_t layerCount)8480 angle::Result ImageHelper::clearEmulatedChannels(ContextVk *contextVk,
8481 VkColorComponentFlags colorMaskFlags,
8482 const VkClearValue &value,
8483 LevelIndex mipLevel,
8484 uint32_t baseArrayLayer,
8485 uint32_t layerCount)
8486 {
8487 const gl::Extents levelExtents = getLevelExtents(mipLevel);
8488
8489 if (levelExtents.depth > 1)
8490 {
8491 // Currently not implemented for 3D textures
8492 UNIMPLEMENTED();
8493 return angle::Result::Continue;
8494 }
8495
8496 UtilsVk::ClearImageParameters params = {};
8497 params.clearArea = {0, 0, levelExtents.width, levelExtents.height};
8498 params.dstMip = mipLevel;
8499 params.colorMaskFlags = colorMaskFlags;
8500 params.colorClearValue = value.color;
8501
8502 for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex)
8503 {
8504 params.dstLayer = baseArrayLayer + layerIndex;
8505
8506 ANGLE_TRY(contextVk->getUtils().clearImage(contextVk, this, params));
8507 }
8508
8509 return angle::Result::Continue;
8510 }
8511
8512 // 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)8513 void ImageHelper::Copy(Renderer *renderer,
8514 ImageHelper *srcImage,
8515 ImageHelper *dstImage,
8516 const gl::Offset &srcOffset,
8517 const gl::Offset &dstOffset,
8518 const gl::Extents ©Size,
8519 const VkImageSubresourceLayers &srcSubresource,
8520 const VkImageSubresourceLayers &dstSubresource,
8521 OutsideRenderPassCommandBuffer *commandBuffer)
8522 {
8523 ASSERT(commandBuffer->valid() && srcImage->valid() && dstImage->valid());
8524
8525 ASSERT(srcImage->getCurrentLayout() == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
8526 ASSERT(dstImage->getCurrentLayout() == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
8527
8528 VkImageCopy region = {};
8529 region.srcSubresource = srcSubresource;
8530 region.srcOffset.x = srcOffset.x;
8531 region.srcOffset.y = srcOffset.y;
8532 region.srcOffset.z = srcOffset.z;
8533 region.dstSubresource = dstSubresource;
8534 region.dstOffset.x = dstOffset.x;
8535 region.dstOffset.y = dstOffset.y;
8536 region.dstOffset.z = dstOffset.z;
8537 region.extent.width = copySize.width;
8538 region.extent.height = copySize.height;
8539 region.extent.depth = copySize.depth;
8540
8541 commandBuffer->copyImage(srcImage->getImage(), srcImage->getCurrentLayout(),
8542 dstImage->getImage(), dstImage->getCurrentLayout(), 1, ®ion);
8543 }
8544
8545 // 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)8546 angle::Result ImageHelper::CopyImageSubData(const gl::Context *context,
8547 ImageHelper *srcImage,
8548 GLint srcLevel,
8549 GLint srcX,
8550 GLint srcY,
8551 GLint srcZ,
8552 ImageHelper *dstImage,
8553 GLint dstLevel,
8554 GLint dstX,
8555 GLint dstY,
8556 GLint dstZ,
8557 GLsizei srcWidth,
8558 GLsizei srcHeight,
8559 GLsizei srcDepth)
8560 {
8561 ContextVk *contextVk = GetImpl(context);
8562 Renderer *renderer = contextVk->getRenderer();
8563
8564 const gl::LevelIndex srcLevelGL = gl::LevelIndex(srcLevel);
8565 const gl::LevelIndex dstLevelGL = gl::LevelIndex(dstLevel);
8566
8567 if (CanCopyWithTransferForCopyImage(renderer, srcImage, dstImage))
8568 {
8569 bool isSrc3D = srcImage->getType() == VK_IMAGE_TYPE_3D;
8570 bool isDst3D = dstImage->getType() == VK_IMAGE_TYPE_3D;
8571 const VkImageAspectFlags aspectFlags = srcImage->getAspectFlags();
8572
8573 ASSERT(srcImage->getAspectFlags() == dstImage->getAspectFlags());
8574
8575 VkImageCopy region = {};
8576
8577 region.srcSubresource.aspectMask = aspectFlags;
8578 region.srcSubresource.mipLevel = srcImage->toVkLevel(srcLevelGL).get();
8579 region.srcSubresource.baseArrayLayer = isSrc3D ? 0 : srcZ;
8580 region.srcSubresource.layerCount = isSrc3D ? 1 : srcDepth;
8581
8582 region.dstSubresource.aspectMask = aspectFlags;
8583 region.dstSubresource.mipLevel = dstImage->toVkLevel(dstLevelGL).get();
8584 region.dstSubresource.baseArrayLayer = isDst3D ? 0 : dstZ;
8585 region.dstSubresource.layerCount = isDst3D ? 1 : srcDepth;
8586
8587 region.srcOffset.x = srcX;
8588 region.srcOffset.y = srcY;
8589 region.srcOffset.z = isSrc3D ? srcZ : 0;
8590 region.dstOffset.x = dstX;
8591 region.dstOffset.y = dstY;
8592 region.dstOffset.z = isDst3D ? dstZ : 0;
8593 region.extent.width = srcWidth;
8594 region.extent.height = srcHeight;
8595 region.extent.depth = (isSrc3D || isDst3D) ? srcDepth : 1;
8596
8597 CommandBufferAccess access;
8598 if (srcImage == dstImage)
8599 {
8600 access.onImageSelfCopy(srcLevelGL, 1, region.srcSubresource.baseArrayLayer,
8601 region.srcSubresource.layerCount, dstLevelGL, 1,
8602 region.dstSubresource.baseArrayLayer,
8603 region.dstSubresource.layerCount, aspectFlags, srcImage);
8604 }
8605 else
8606 {
8607 access.onImageTransferRead(aspectFlags, srcImage);
8608 access.onImageTransferWrite(dstLevelGL, 1, region.dstSubresource.baseArrayLayer,
8609 region.dstSubresource.layerCount, aspectFlags, dstImage);
8610 }
8611
8612 OutsideRenderPassCommandBuffer *commandBuffer;
8613 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
8614
8615 ASSERT(srcImage->valid() && dstImage->valid());
8616 ASSERT(srcImage->getCurrentLayout() == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL ||
8617 srcImage->getCurrentLayout() == VK_IMAGE_LAYOUT_GENERAL);
8618 ASSERT(dstImage->getCurrentLayout() == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL ||
8619 dstImage->getCurrentLayout() == VK_IMAGE_LAYOUT_GENERAL);
8620
8621 commandBuffer->copyImage(srcImage->getImage(), srcImage->getCurrentLayout(),
8622 dstImage->getImage(), dstImage->getCurrentLayout(), 1, ®ion);
8623 }
8624 else if (!srcImage->getIntendedFormat().isBlock && !dstImage->getIntendedFormat().isBlock)
8625 {
8626 // The source and destination image formats may be using a fallback in the case of RGB
8627 // images. A compute shader is used in such a case to perform the copy.
8628 UtilsVk &utilsVk = contextVk->getUtils();
8629
8630 UtilsVk::CopyImageBitsParameters params;
8631 params.srcOffset[0] = srcX;
8632 params.srcOffset[1] = srcY;
8633 params.srcOffset[2] = srcZ;
8634 params.srcLevel = srcLevelGL;
8635 params.dstOffset[0] = dstX;
8636 params.dstOffset[1] = dstY;
8637 params.dstOffset[2] = dstZ;
8638 params.dstLevel = dstLevelGL;
8639 params.copyExtents[0] = srcWidth;
8640 params.copyExtents[1] = srcHeight;
8641 params.copyExtents[2] = srcDepth;
8642
8643 ANGLE_TRY(utilsVk.copyImageBits(contextVk, dstImage, srcImage, params));
8644 }
8645 else
8646 {
8647 // No support for emulated compressed formats.
8648 UNIMPLEMENTED();
8649 ANGLE_VK_CHECK(contextVk, false, VK_ERROR_FEATURE_NOT_PRESENT);
8650 }
8651
8652 return angle::Result::Continue;
8653 }
8654
generateMipmapsWithBlit(ContextVk * contextVk,LevelIndex baseLevel,LevelIndex maxLevel)8655 angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk,
8656 LevelIndex baseLevel,
8657 LevelIndex maxLevel)
8658 {
8659 Renderer *renderer = contextVk->getRenderer();
8660
8661 CommandBufferAccess access;
8662 gl::LevelIndex baseLevelGL = toGLLevel(baseLevel);
8663 access.onImageTransferWrite(baseLevelGL + 1, maxLevel.get(), 0, mLayerCount,
8664 VK_IMAGE_ASPECT_COLOR_BIT, this);
8665
8666 OutsideRenderPassCommandBuffer *commandBuffer;
8667 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
8668
8669 // We are able to use blitImage since the image format we are using supports it.
8670 int32_t mipWidth = mExtents.width;
8671 int32_t mipHeight = mExtents.height;
8672 int32_t mipDepth = mExtents.depth;
8673
8674 // Manually manage the image memory barrier because it uses a lot more parameters than our
8675 // usual one.
8676 VkImageMemoryBarrier barrier = {};
8677 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
8678 barrier.image = mImage.getHandle();
8679 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
8680 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
8681 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8682 barrier.subresourceRange.baseArrayLayer = 0;
8683 barrier.subresourceRange.layerCount = mLayerCount;
8684 barrier.subresourceRange.levelCount = 1;
8685
8686 const VkFilter filter =
8687 gl_vk::GetFilter(CalculateGenerateMipmapFilter(contextVk, getActualFormatID()));
8688
8689 for (LevelIndex mipLevel(1); mipLevel <= LevelIndex(mLevelCount); ++mipLevel)
8690 {
8691 int32_t nextMipWidth = std::max<int32_t>(1, mipWidth >> 1);
8692 int32_t nextMipHeight = std::max<int32_t>(1, mipHeight >> 1);
8693 int32_t nextMipDepth = std::max<int32_t>(1, mipDepth >> 1);
8694
8695 if (mipLevel > baseLevel && mipLevel <= maxLevel)
8696 {
8697 barrier.subresourceRange.baseMipLevel = mipLevel.get() - 1;
8698 barrier.oldLayout = getCurrentLayout();
8699 barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
8700 barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
8701 barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
8702
8703 // We can do it for all layers at once.
8704 commandBuffer->imageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
8705 VK_PIPELINE_STAGE_TRANSFER_BIT, barrier);
8706 VkImageBlit blit = {};
8707 blit.srcOffsets[0] = {0, 0, 0};
8708 blit.srcOffsets[1] = {mipWidth, mipHeight, mipDepth};
8709 blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8710 blit.srcSubresource.mipLevel = mipLevel.get() - 1;
8711 blit.srcSubresource.baseArrayLayer = 0;
8712 blit.srcSubresource.layerCount = mLayerCount;
8713 blit.dstOffsets[0] = {0, 0, 0};
8714 blit.dstOffsets[1] = {nextMipWidth, nextMipHeight, nextMipDepth};
8715 blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8716 blit.dstSubresource.mipLevel = mipLevel.get();
8717 blit.dstSubresource.baseArrayLayer = 0;
8718 blit.dstSubresource.layerCount = mLayerCount;
8719
8720 commandBuffer->blitImage(mImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, mImage,
8721 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, filter);
8722 }
8723 mipWidth = nextMipWidth;
8724 mipHeight = nextMipHeight;
8725 mipDepth = nextMipDepth;
8726 }
8727
8728 // Transition all mip level to the same layout so we can declare our whole image layout to one
8729 // ImageLayout. FragmentShaderReadOnly is picked here since this is the most reasonable usage
8730 // after glGenerateMipmap call.
8731 barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
8732 barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
8733 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
8734 if (baseLevel.get() > 0)
8735 {
8736 // [0:baseLevel-1] from TRANSFER_DST to SHADER_READ
8737 barrier.subresourceRange.baseMipLevel = 0;
8738 barrier.subresourceRange.levelCount = baseLevel.get();
8739 commandBuffer->imageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
8740 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, barrier);
8741 }
8742 // [maxLevel:mLevelCount-1] from TRANSFER_DST to SHADER_READ
8743 ASSERT(mLevelCount > maxLevel.get());
8744 barrier.subresourceRange.baseMipLevel = maxLevel.get();
8745 barrier.subresourceRange.levelCount = mLevelCount - maxLevel.get();
8746 commandBuffer->imageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
8747 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, barrier);
8748 // [baseLevel:maxLevel-1] from TRANSFER_SRC to SHADER_READ
8749 barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
8750 barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
8751 barrier.subresourceRange.baseMipLevel = baseLevel.get();
8752 barrier.subresourceRange.levelCount = maxLevel.get() - baseLevel.get();
8753 commandBuffer->imageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
8754 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, barrier);
8755
8756 // This is just changing the internal state of the image helper so that the next call
8757 // to changeLayout will use this layout as the "oldLayout" argument.
8758 // mLastNonShaderReadOnlyLayout is used to ensure previous write are made visible to reads,
8759 // since the only write here is transfer, hence mLastNonShaderReadOnlyLayout is set to
8760 // ImageLayout::TransferDst.
8761 setCurrentImageLayout(renderer, ImageLayout::FragmentShaderReadOnly);
8762
8763 contextVk->trackImageWithOutsideRenderPassEvent(this);
8764
8765 return angle::Result::Continue;
8766 }
8767
resolve(ImageHelper * dst,const VkImageResolve & region,OutsideRenderPassCommandBuffer * commandBuffer)8768 void ImageHelper::resolve(ImageHelper *dst,
8769 const VkImageResolve ®ion,
8770 OutsideRenderPassCommandBuffer *commandBuffer)
8771 {
8772 ASSERT(mCurrentLayout == ImageLayout::TransferSrc ||
8773 mCurrentLayout == ImageLayout::SharedPresent);
8774 commandBuffer->resolveImage(getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst->getImage(),
8775 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
8776 }
8777
removeSingleSubresourceStagedUpdates(ContextVk * contextVk,gl::LevelIndex levelIndexGL,uint32_t layerIndex,uint32_t layerCount)8778 void ImageHelper::removeSingleSubresourceStagedUpdates(ContextVk *contextVk,
8779 gl::LevelIndex levelIndexGL,
8780 uint32_t layerIndex,
8781 uint32_t layerCount)
8782 {
8783 mCurrentSingleClearValue.reset();
8784
8785 // Find any staged updates for this index and remove them from the pending list.
8786 SubresourceUpdates *levelUpdates = getLevelUpdates(levelIndexGL);
8787 if (levelUpdates == nullptr)
8788 {
8789 return;
8790 }
8791
8792 for (size_t index = 0; index < levelUpdates->size();)
8793 {
8794 auto update = levelUpdates->begin() + index;
8795 if (update->matchesLayerRange(layerIndex, layerCount))
8796 {
8797 // Update total staging buffer size
8798 mTotalStagedBufferUpdateSize -= update->updateSource == UpdateSource::Buffer
8799 ? update->data.buffer.bufferHelper->getSize()
8800 : 0;
8801 update->release(contextVk->getRenderer());
8802 levelUpdates->erase(update);
8803 }
8804 else
8805 {
8806 index++;
8807 }
8808 }
8809 }
8810
removeSingleStagedClearAfterInvalidate(gl::LevelIndex levelIndexGL,uint32_t layerIndex,uint32_t layerCount)8811 void ImageHelper::removeSingleStagedClearAfterInvalidate(gl::LevelIndex levelIndexGL,
8812 uint32_t layerIndex,
8813 uint32_t layerCount)
8814 {
8815 // When this function is called, it's expected that there may be at most one
8816 // ClearAfterInvalidate update pending to this subresource, and that's a color clear due to
8817 // emulated channels after invalidate. This function removes that update.
8818
8819 SubresourceUpdates *levelUpdates = getLevelUpdates(levelIndexGL);
8820 if (levelUpdates == nullptr)
8821 {
8822 return;
8823 }
8824
8825 for (size_t index = 0; index < levelUpdates->size(); ++index)
8826 {
8827 auto update = levelUpdates->begin() + index;
8828 if (update->updateSource == UpdateSource::ClearAfterInvalidate &&
8829 update->matchesLayerRange(layerIndex, layerCount))
8830 {
8831 // It's a clear, so doesn't need to be released.
8832 levelUpdates->erase(update);
8833 // There's only one such clear possible.
8834 return;
8835 }
8836 }
8837 }
8838
removeStagedUpdates(ErrorContext * context,gl::LevelIndex levelGLStart,gl::LevelIndex levelGLEnd)8839 void ImageHelper::removeStagedUpdates(ErrorContext *context,
8840 gl::LevelIndex levelGLStart,
8841 gl::LevelIndex levelGLEnd)
8842 {
8843 ASSERT(validateSubresourceUpdateRefCountsConsistent());
8844
8845 // Remove all updates to levels [start, end].
8846 for (gl::LevelIndex level = levelGLStart; level <= levelGLEnd; ++level)
8847 {
8848 SubresourceUpdates *levelUpdates = getLevelUpdates(level);
8849 if (levelUpdates == nullptr)
8850 {
8851 ASSERT(static_cast<size_t>(level.get()) >= mSubresourceUpdates.size());
8852 return;
8853 }
8854
8855 for (SubresourceUpdate &update : *levelUpdates)
8856 {
8857 // Update total staging buffer size
8858 mTotalStagedBufferUpdateSize -= update.updateSource == UpdateSource::Buffer
8859 ? update.data.buffer.bufferHelper->getSize()
8860 : 0;
8861 update.release(context->getRenderer());
8862 }
8863
8864 levelUpdates->clear();
8865 }
8866
8867 ASSERT(validateSubresourceUpdateRefCountsConsistent());
8868 }
8869
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)8870 angle::Result ImageHelper::stageSubresourceUpdateImpl(ContextVk *contextVk,
8871 const gl::ImageIndex &index,
8872 const gl::Extents &glExtents,
8873 const gl::Offset &offset,
8874 const gl::InternalFormat &formatInfo,
8875 const gl::PixelUnpackState &unpack,
8876 GLenum type,
8877 const uint8_t *pixels,
8878 const Format &vkFormat,
8879 ImageAccess access,
8880 const GLuint inputRowPitch,
8881 const GLuint inputDepthPitch,
8882 const GLuint inputSkipBytes,
8883 ApplyImageUpdate applyUpdate,
8884 bool *updateAppliedImmediatelyOut)
8885 {
8886 *updateAppliedImmediatelyOut = false;
8887
8888 const angle::Format &storageFormat = vkFormat.getActualImageFormat(access);
8889
8890 size_t outputRowPitch;
8891 size_t outputDepthPitch;
8892 size_t stencilAllocationSize = 0;
8893 uint32_t bufferRowLength;
8894 uint32_t bufferImageHeight;
8895 size_t allocationSize;
8896
8897 LoadImageFunctionInfo loadFunctionInfo = vkFormat.getTextureLoadFunction(access, type);
8898 LoadImageFunction stencilLoadFunction = nullptr;
8899
8900 bool useComputeTransCoding = false;
8901 if (storageFormat.isBlock)
8902 {
8903 const gl::InternalFormat &storageFormatInfo = vkFormat.getInternalFormatInfo(type);
8904 GLuint rowPitch;
8905 GLuint depthPitch;
8906 GLuint totalSize;
8907
8908 ANGLE_VK_CHECK_MATH(contextVk, storageFormatInfo.computeCompressedImageRowPitch(
8909 glExtents.width, &rowPitch));
8910 ANGLE_VK_CHECK_MATH(contextVk, storageFormatInfo.computeCompressedImageDepthPitch(
8911 glExtents.height, rowPitch, &depthPitch));
8912
8913 ANGLE_VK_CHECK_MATH(contextVk,
8914 storageFormatInfo.computeCompressedImageSize(glExtents, &totalSize));
8915
8916 outputRowPitch = rowPitch;
8917 outputDepthPitch = depthPitch;
8918 allocationSize = totalSize;
8919
8920 ANGLE_VK_CHECK_MATH(
8921 contextVk, storageFormatInfo.computeBufferRowLength(glExtents.width, &bufferRowLength));
8922 ANGLE_VK_CHECK_MATH(contextVk, storageFormatInfo.computeBufferImageHeight(
8923 glExtents.height, &bufferImageHeight));
8924
8925 if (contextVk->getFeatures().supportsComputeTranscodeEtcToBc.enabled &&
8926 IsETCFormat(vkFormat.getIntendedFormatID()) && IsBCFormat(storageFormat.id))
8927 {
8928 useComputeTransCoding =
8929 shouldUseComputeForTransCoding(vk::LevelIndex(index.getLevelIndex()));
8930 if (!useComputeTransCoding)
8931 {
8932 loadFunctionInfo = GetEtcToBcTransCodingFunc(vkFormat.getIntendedFormatID());
8933 }
8934 }
8935 }
8936 else
8937 {
8938 ASSERT(storageFormat.pixelBytes != 0);
8939 const bool stencilOnly = formatInfo.sizedInternalFormat == GL_STENCIL_INDEX8;
8940
8941 if (!stencilOnly && storageFormat.id == angle::FormatID::D24_UNORM_S8_UINT)
8942 {
8943 switch (type)
8944 {
8945 case GL_UNSIGNED_INT_24_8:
8946 stencilLoadFunction = angle::LoadX24S8ToS8;
8947 break;
8948 case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
8949 stencilLoadFunction = angle::LoadX32S8ToS8;
8950 break;
8951 }
8952 }
8953 if (!stencilOnly && storageFormat.id == angle::FormatID::D32_FLOAT_S8X24_UINT)
8954 {
8955 // If depth is D32FLOAT_S8, we must pack D32F tightly (no stencil) for CopyBufferToImage
8956 outputRowPitch = sizeof(float) * glExtents.width;
8957
8958 // The generic load functions don't handle tightly packing D32FS8 to D32F & S8 so call
8959 // special case load functions.
8960 switch (type)
8961 {
8962 case GL_UNSIGNED_INT:
8963 loadFunctionInfo.loadFunction = angle::LoadD32ToD32F;
8964 stencilLoadFunction = nullptr;
8965 break;
8966 case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
8967 loadFunctionInfo.loadFunction = angle::LoadD32FS8X24ToD32F;
8968 stencilLoadFunction = angle::LoadX32S8ToS8;
8969 break;
8970 case GL_UNSIGNED_INT_24_8:
8971 loadFunctionInfo.loadFunction = angle::LoadD24S8ToD32F;
8972 stencilLoadFunction = angle::LoadX24S8ToS8;
8973 break;
8974 default:
8975 UNREACHABLE();
8976 }
8977 }
8978 else if (!stencilOnly)
8979 {
8980 outputRowPitch = storageFormat.pixelBytes * glExtents.width;
8981 }
8982 else
8983 {
8984 // Some Vulkan implementations do not support S8_UINT, so stencil-only data is
8985 // uploaded using one of combined depth-stencil formats there. Since the uploaded
8986 // stencil data must be tightly packed, the actual storage format should be ignored
8987 // with regards to its load function and output row pitch.
8988 loadFunctionInfo.loadFunction = angle::LoadToNative<GLubyte, 1>;
8989 outputRowPitch = glExtents.width;
8990 }
8991 outputDepthPitch = outputRowPitch * glExtents.height;
8992
8993 bufferRowLength = glExtents.width;
8994 bufferImageHeight = glExtents.height;
8995
8996 allocationSize = outputDepthPitch * glExtents.depth;
8997
8998 // Note: because the LoadImageFunctionInfo functions are limited to copying a single
8999 // component, we have to special case packed depth/stencil use and send the stencil as a
9000 // separate chunk.
9001 if (storageFormat.hasDepthAndStencilBits() && formatInfo.depthBits > 0 &&
9002 formatInfo.stencilBits > 0)
9003 {
9004 // Note: Stencil is always one byte
9005 stencilAllocationSize = glExtents.width * glExtents.height * glExtents.depth;
9006 allocationSize += stencilAllocationSize;
9007 }
9008 }
9009
9010 const uint8_t *source = pixels + static_cast<ptrdiff_t>(inputSkipBytes);
9011
9012 // If possible, copy the buffer to the image directly on the host, to avoid having to use a temp
9013 // image (and do a double copy).
9014 if (applyUpdate != ApplyImageUpdate::Defer && !loadFunctionInfo.requiresConversion &&
9015 inputRowPitch == outputRowPitch && inputDepthPitch == outputDepthPitch)
9016 {
9017 bool copied = false;
9018 ANGLE_TRY(updateSubresourceOnHost(contextVk, applyUpdate, index, glExtents, offset, source,
9019 bufferRowLength, bufferImageHeight, &copied));
9020 if (copied)
9021 {
9022 *updateAppliedImmediatelyOut = true;
9023 return angle::Result::Continue;
9024 }
9025 }
9026
9027 std::unique_ptr<RefCounted<BufferHelper>> stagingBuffer =
9028 std::make_unique<RefCounted<BufferHelper>>();
9029 BufferHelper *currentBuffer = &stagingBuffer->get();
9030
9031 uint8_t *stagingPointer;
9032 VkDeviceSize stagingOffset;
9033 ANGLE_TRY(contextVk->initBufferForImageCopy(currentBuffer, allocationSize,
9034 MemoryCoherency::CachedNonCoherent,
9035 storageFormat.id, &stagingOffset, &stagingPointer));
9036
9037 loadFunctionInfo.loadFunction(
9038 contextVk->getImageLoadContext(), glExtents.width, glExtents.height, glExtents.depth,
9039 source, inputRowPitch, inputDepthPitch, stagingPointer, outputRowPitch, outputDepthPitch);
9040
9041 // YUV formats need special handling.
9042 if (storageFormat.isYUV)
9043 {
9044 gl::YuvFormatInfo yuvInfo(formatInfo.internalFormat, glExtents);
9045
9046 constexpr VkImageAspectFlagBits kPlaneAspectFlags[3] = {
9047 VK_IMAGE_ASPECT_PLANE_0_BIT, VK_IMAGE_ASPECT_PLANE_1_BIT, VK_IMAGE_ASPECT_PLANE_2_BIT};
9048
9049 // We only support mip level 0 and layerCount of 1 for YUV formats.
9050 ASSERT(index.getLevelIndex() == 0);
9051 ASSERT(index.getLayerCount() == 1);
9052
9053 for (uint32_t plane = 0; plane < yuvInfo.planeCount; plane++)
9054 {
9055 VkBufferImageCopy copy = {};
9056 copy.bufferOffset = stagingOffset + yuvInfo.planeOffset[plane];
9057 copy.bufferRowLength = 0;
9058 copy.bufferImageHeight = 0;
9059 copy.imageSubresource.mipLevel = 0;
9060 copy.imageSubresource.layerCount = 1;
9061 gl_vk::GetOffset(offset, ©.imageOffset);
9062 gl_vk::GetExtent(yuvInfo.planeExtent[plane], ©.imageExtent);
9063 copy.imageSubresource.baseArrayLayer = 0;
9064 copy.imageSubresource.aspectMask = kPlaneAspectFlags[plane];
9065 appendSubresourceUpdate(
9066 gl::LevelIndex(0),
9067 SubresourceUpdate(stagingBuffer.get(), currentBuffer, copy, storageFormat.id));
9068 }
9069
9070 stagingBuffer.release();
9071 return angle::Result::Continue;
9072 }
9073
9074 VkBufferImageCopy copy = {};
9075 VkImageAspectFlags aspectFlags = GetFormatAspectFlags(storageFormat);
9076
9077 copy.bufferOffset = stagingOffset;
9078 copy.bufferRowLength = bufferRowLength;
9079 copy.bufferImageHeight = bufferImageHeight;
9080
9081 gl::LevelIndex updateLevelGL(index.getLevelIndex());
9082 copy.imageSubresource.mipLevel = updateLevelGL.get();
9083 copy.imageSubresource.layerCount = index.getLayerCount();
9084
9085 gl_vk::GetOffset(offset, ©.imageOffset);
9086 gl_vk::GetExtent(glExtents, ©.imageExtent);
9087
9088 if (gl::IsArrayTextureType(index.getType()))
9089 {
9090 copy.imageSubresource.baseArrayLayer = offset.z;
9091 copy.imageOffset.z = 0;
9092 copy.imageExtent.depth = 1;
9093 }
9094 else
9095 {
9096 copy.imageSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0;
9097 }
9098
9099 if (stencilAllocationSize > 0)
9100 {
9101 // Note: Stencil is always one byte
9102 ASSERT((aspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) != 0);
9103
9104 // Skip over depth data.
9105 stagingPointer += outputDepthPitch * glExtents.depth;
9106 stagingOffset += outputDepthPitch * glExtents.depth;
9107
9108 // recompute pitch for stencil data
9109 outputRowPitch = glExtents.width;
9110 outputDepthPitch = outputRowPitch * glExtents.height;
9111
9112 ASSERT(stencilLoadFunction != nullptr);
9113 stencilLoadFunction(contextVk->getImageLoadContext(), glExtents.width, glExtents.height,
9114 glExtents.depth, source, inputRowPitch, inputDepthPitch, stagingPointer,
9115 outputRowPitch, outputDepthPitch);
9116
9117 VkBufferImageCopy stencilCopy = {};
9118
9119 stencilCopy.bufferOffset = stagingOffset;
9120 stencilCopy.bufferRowLength = bufferRowLength;
9121 stencilCopy.bufferImageHeight = bufferImageHeight;
9122 stencilCopy.imageSubresource.mipLevel = copy.imageSubresource.mipLevel;
9123 stencilCopy.imageSubresource.baseArrayLayer = copy.imageSubresource.baseArrayLayer;
9124 stencilCopy.imageSubresource.layerCount = copy.imageSubresource.layerCount;
9125 stencilCopy.imageOffset = copy.imageOffset;
9126 stencilCopy.imageExtent = copy.imageExtent;
9127 stencilCopy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
9128 appendSubresourceUpdate(updateLevelGL, SubresourceUpdate(stagingBuffer.get(), currentBuffer,
9129 stencilCopy, storageFormat.id));
9130
9131 aspectFlags &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
9132 }
9133
9134 if (HasBothDepthAndStencilAspects(aspectFlags))
9135 {
9136 // We still have both depth and stencil aspect bits set. That means we have a destination
9137 // buffer that is packed depth stencil and that the application is only loading one aspect.
9138 // Figure out which aspect the user is touching and remove the unused aspect bit.
9139 if (formatInfo.stencilBits > 0)
9140 {
9141 aspectFlags &= ~VK_IMAGE_ASPECT_DEPTH_BIT;
9142 }
9143 else
9144 {
9145 aspectFlags &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
9146 }
9147 }
9148
9149 if (aspectFlags)
9150 {
9151 copy.imageSubresource.aspectMask = aspectFlags;
9152 appendSubresourceUpdate(
9153 updateLevelGL, SubresourceUpdate(stagingBuffer.get(), currentBuffer, copy,
9154 useComputeTransCoding ? vkFormat.getIntendedFormatID()
9155 : storageFormat.id));
9156 pruneSupersededUpdatesForLevel(contextVk, updateLevelGL, PruneReason::MemoryOptimization);
9157 }
9158
9159 stagingBuffer.release();
9160 return angle::Result::Continue;
9161 }
9162
updateSubresourceOnHost(ErrorContext * 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)9163 angle::Result ImageHelper::updateSubresourceOnHost(ErrorContext *context,
9164 ApplyImageUpdate applyUpdate,
9165 const gl::ImageIndex &index,
9166 const gl::Extents &glExtents,
9167 const gl::Offset &offset,
9168 const uint8_t *source,
9169 const GLuint memoryRowLength,
9170 const GLuint memoryImageHeight,
9171 bool *copiedOut)
9172 {
9173 // If the image is not set up for host copy, it can't be done.
9174 if (!valid() || (mUsage & VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT) == 0)
9175 {
9176 return angle::Result::Continue;
9177 }
9178
9179 Renderer *renderer = context->getRenderer();
9180 const VkPhysicalDeviceHostImageCopyPropertiesEXT &hostImageCopyProperties =
9181 renderer->getPhysicalDeviceHostImageCopyProperties();
9182
9183 // The image should be unused by the GPU.
9184 if (!renderer->hasResourceUseFinished(getResourceUse()))
9185 {
9186 ANGLE_TRY(renderer->checkCompletedCommandsAndCleanup(context));
9187 if (!renderer->hasResourceUseFinished(getResourceUse()))
9188 {
9189 return angle::Result::Continue;
9190 }
9191 }
9192
9193 // The image should not have any pending updates to this subresource.
9194 //
9195 // TODO: if there are any pending updates, see if they can be pruned given the incoming update.
9196 // This would most likely be the case where a clear is automatically staged for robustness or
9197 // other reasons, which would now be superseded by the data upload. http://anglebug.com/42266771
9198 const gl::LevelIndex updateLevelGL(index.getLevelIndex());
9199 const uint32_t layerIndex = index.hasLayer() ? index.getLayerIndex() : 0;
9200 const uint32_t layerCount = index.getLayerCount();
9201 if (hasStagedUpdatesForSubresource(updateLevelGL, layerIndex, layerCount))
9202 {
9203 return angle::Result::Continue;
9204 }
9205
9206 // The image should be in a layout this is copiable. If UNDEFINED, it can be transitioned to a
9207 // layout that is copyable.
9208 const VkImageAspectFlags aspectMask = getAspectFlags();
9209 if (mCurrentLayout == ImageLayout::Undefined)
9210 {
9211 VkHostImageLayoutTransitionInfoEXT transition = {};
9212 transition.sType = VK_STRUCTURE_TYPE_HOST_IMAGE_LAYOUT_TRANSITION_INFO_EXT;
9213 transition.image = mImage.getHandle();
9214 transition.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
9215 // The GENERAL layout is always guaranteed to be in
9216 // VkPhysicalDeviceHostImageCopyPropertiesEXT::pCopyDstLayouts
9217 transition.newLayout = VK_IMAGE_LAYOUT_GENERAL;
9218 transition.subresourceRange.aspectMask = aspectMask;
9219 transition.subresourceRange.baseMipLevel = 0;
9220 transition.subresourceRange.levelCount = mLevelCount;
9221 transition.subresourceRange.baseArrayLayer = 0;
9222 transition.subresourceRange.layerCount = mLayerCount;
9223
9224 ANGLE_VK_TRY(context, vkTransitionImageLayoutEXT(renderer->getDevice(), 1, &transition));
9225 mCurrentLayout = ImageLayout::HostCopy;
9226 }
9227 else if (mCurrentLayout != ImageLayout::HostCopy &&
9228 !IsAnyLayout(getCurrentLayout(), hostImageCopyProperties.pCopyDstLayouts,
9229 hostImageCopyProperties.copyDstLayoutCount))
9230 {
9231 return angle::Result::Continue;
9232 }
9233
9234 const bool isArray = gl::IsArrayTextureType(index.getType());
9235 const uint32_t baseArrayLayer = isArray ? offset.z : layerIndex;
9236
9237 onWrite(updateLevelGL, 1, baseArrayLayer, layerCount, aspectMask);
9238 *copiedOut = true;
9239
9240 // Perform the copy without holding the lock. This is important for applications that perform
9241 // the copy on a separate thread, and doing all the work while holding the lock effectively
9242 // destroys all parallelism. Note that the texture may not be used by the other thread without
9243 // appropriate synchronization (such as through glFenceSync), and because the copy is happening
9244 // in this call (just without holding the lock), the sync function won't be called until the
9245 // copy is done.
9246 auto doCopy = [context, image = mImage.getHandle(), source, memoryRowLength, memoryImageHeight,
9247 aspectMask, levelVk = toVkLevel(updateLevelGL), isArray, baseArrayLayer,
9248 layerCount, offset, glExtents, layout = getCurrentLayout()](void *resultOut) {
9249 ANGLE_TRACE_EVENT0("gpu.angle", "Upload image data on host");
9250 ANGLE_UNUSED_VARIABLE(resultOut);
9251
9252 VkMemoryToImageCopyEXT copyRegion = {};
9253 copyRegion.sType = VK_STRUCTURE_TYPE_MEMORY_TO_IMAGE_COPY_EXT;
9254 copyRegion.pHostPointer = source;
9255 copyRegion.memoryRowLength = memoryRowLength;
9256 copyRegion.memoryImageHeight = memoryImageHeight;
9257 copyRegion.imageSubresource.aspectMask = aspectMask;
9258 copyRegion.imageSubresource.mipLevel = levelVk.get();
9259 copyRegion.imageSubresource.baseArrayLayer = baseArrayLayer;
9260 copyRegion.imageSubresource.layerCount = layerCount;
9261 gl_vk::GetOffset(offset, ©Region.imageOffset);
9262 gl_vk::GetExtent(glExtents, ©Region.imageExtent);
9263
9264 if (isArray)
9265 {
9266 copyRegion.imageOffset.z = 0;
9267 copyRegion.imageExtent.depth = 1;
9268 }
9269
9270 VkCopyMemoryToImageInfoEXT copyInfo = {};
9271 copyInfo.sType = VK_STRUCTURE_TYPE_COPY_MEMORY_TO_IMAGE_INFO_EXT;
9272 copyInfo.dstImage = image;
9273 copyInfo.dstImageLayout = layout;
9274 copyInfo.regionCount = 1;
9275 copyInfo.pRegions = ©Region;
9276
9277 VkResult result = vkCopyMemoryToImageEXT(context->getDevice(), ©Info);
9278 if (result != VK_SUCCESS)
9279 {
9280 context->handleError(result, __FILE__, ANGLE_FUNCTION, __LINE__);
9281 }
9282 };
9283
9284 switch (applyUpdate)
9285 {
9286 // If possible, perform the copy in an unlocked tail call. Then the other threads of the
9287 // application are free to draw.
9288 case ApplyImageUpdate::ImmediatelyInUnlockedTailCall:
9289 egl::Display::GetCurrentThreadUnlockedTailCall()->add(doCopy);
9290 break;
9291
9292 // In some cases, the copy cannot be delayed. For example because the contents are
9293 // immediately needed (such as when the generate mipmap hint is set), or because unlocked
9294 // tail calls are not allowed (this is the case with incomplete textures which are lazily
9295 // created at draw, but unlocked tail calls are avoided on draw calls due to overhead).
9296 case ApplyImageUpdate::Immediately:
9297 doCopy(nullptr);
9298 break;
9299
9300 default:
9301 UNREACHABLE();
9302 doCopy(nullptr);
9303 }
9304
9305 return angle::Result::Continue;
9306 }
9307
reformatStagedBufferUpdates(ContextVk * contextVk,angle::FormatID srcFormatID,angle::FormatID dstFormatID)9308 angle::Result ImageHelper::reformatStagedBufferUpdates(ContextVk *contextVk,
9309 angle::FormatID srcFormatID,
9310 angle::FormatID dstFormatID)
9311 {
9312 const angle::Format &srcFormat = angle::Format::Get(srcFormatID);
9313 const angle::Format &dstFormat = angle::Format::Get(dstFormatID);
9314 const gl::InternalFormat &dstFormatInfo =
9315 gl::GetSizedInternalFormatInfo(dstFormat.glInternalFormat);
9316
9317 for (SubresourceUpdates &levelUpdates : mSubresourceUpdates)
9318 {
9319 for (SubresourceUpdate &update : levelUpdates)
9320 {
9321 // Right now whenever we stage update from a source image, the formats always match.
9322 ASSERT(valid() || update.updateSource != UpdateSource::Image ||
9323 update.data.image.formatID == srcFormatID);
9324
9325 if (update.updateSource == UpdateSource::Buffer &&
9326 update.data.buffer.formatID == srcFormatID)
9327 {
9328 const VkBufferImageCopy © = update.data.buffer.copyRegion;
9329
9330 // Source and dst data are tightly packed
9331 GLuint srcDataRowPitch = copy.imageExtent.width * srcFormat.pixelBytes;
9332 GLuint dstDataRowPitch = copy.imageExtent.width * dstFormat.pixelBytes;
9333
9334 GLuint srcDataDepthPitch = srcDataRowPitch * copy.imageExtent.height;
9335 GLuint dstDataDepthPitch = dstDataRowPitch * copy.imageExtent.height;
9336
9337 // Retrieve source buffer
9338 vk::BufferHelper *srcBuffer = update.data.buffer.bufferHelper;
9339 ASSERT(srcBuffer->isMapped());
9340 // The bufferOffset is relative to the buffer block. We have to use the buffer
9341 // block's memory pointer to get the source data pointer.
9342 uint8_t *srcData = srcBuffer->getBlockMemory() + copy.bufferOffset;
9343
9344 // Allocate memory with dstFormat
9345 std::unique_ptr<RefCounted<BufferHelper>> stagingBuffer =
9346 std::make_unique<RefCounted<BufferHelper>>();
9347 BufferHelper *dstBuffer = &stagingBuffer->get();
9348
9349 uint8_t *dstData;
9350 VkDeviceSize dstBufferOffset;
9351 size_t dstBufferSize = dstDataDepthPitch * copy.imageExtent.depth;
9352 ANGLE_TRY(contextVk->initBufferForImageCopy(
9353 dstBuffer, dstBufferSize, MemoryCoherency::CachedNonCoherent, dstFormatID,
9354 &dstBufferOffset, &dstData));
9355
9356 rx::PixelReadFunction pixelReadFunction = srcFormat.pixelReadFunction;
9357 rx::PixelWriteFunction pixelWriteFunction = dstFormat.pixelWriteFunction;
9358
9359 CopyImageCHROMIUM(srcData, srcDataRowPitch, srcFormat.pixelBytes, srcDataDepthPitch,
9360 pixelReadFunction, dstData, dstDataRowPitch, dstFormat.pixelBytes,
9361 dstDataDepthPitch, pixelWriteFunction, dstFormatInfo.format,
9362 dstFormatInfo.componentType, copy.imageExtent.width,
9363 copy.imageExtent.height, copy.imageExtent.depth, false, false,
9364 false);
9365
9366 // Replace srcBuffer with dstBuffer
9367 update.data.buffer.bufferHelper = dstBuffer;
9368 update.data.buffer.formatID = dstFormatID;
9369 update.data.buffer.copyRegion.bufferOffset = dstBufferOffset;
9370
9371 // Update total staging buffer size
9372 mTotalStagedBufferUpdateSize -= srcBuffer->getSize();
9373 mTotalStagedBufferUpdateSize += dstBuffer->getSize();
9374
9375 // Let update structure owns the staging buffer
9376 if (update.refCounted.buffer)
9377 {
9378 update.refCounted.buffer->releaseRef();
9379 if (!update.refCounted.buffer->isReferenced())
9380 {
9381 update.refCounted.buffer->get().release(contextVk);
9382 SafeDelete(update.refCounted.buffer);
9383 }
9384 }
9385 update.refCounted.buffer = stagingBuffer.release();
9386 update.refCounted.buffer->addRef();
9387 }
9388 }
9389 }
9390
9391 return angle::Result::Continue;
9392 }
9393
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)9394 angle::Result ImageHelper::calculateBufferInfo(ContextVk *contextVk,
9395 const gl::Extents &glExtents,
9396 const gl::InternalFormat &formatInfo,
9397 const gl::PixelUnpackState &unpack,
9398 GLenum type,
9399 bool is3D,
9400 GLuint *inputRowPitch,
9401 GLuint *inputDepthPitch,
9402 GLuint *inputSkipBytes)
9403 {
9404 // YUV formats need special handling.
9405 if (gl::IsYuvFormat(formatInfo.internalFormat))
9406 {
9407 gl::YuvFormatInfo yuvInfo(formatInfo.internalFormat, glExtents);
9408
9409 // row pitch = Y plane row pitch
9410 *inputRowPitch = yuvInfo.planePitch[0];
9411 // depth pitch = Y plane size + chroma plane size
9412 *inputDepthPitch = yuvInfo.planeSize[0] + yuvInfo.planeSize[1] + yuvInfo.planeSize[2];
9413 *inputSkipBytes = 0;
9414
9415 return angle::Result::Continue;
9416 }
9417
9418 ANGLE_VK_CHECK_MATH(contextVk,
9419 formatInfo.computeRowPitch(type, glExtents.width, unpack.alignment,
9420 unpack.rowLength, inputRowPitch));
9421
9422 ANGLE_VK_CHECK_MATH(contextVk,
9423 formatInfo.computeDepthPitch(glExtents.height, unpack.imageHeight,
9424 *inputRowPitch, inputDepthPitch));
9425
9426 ANGLE_VK_CHECK_MATH(
9427 contextVk, formatInfo.computeSkipBytes(type, *inputRowPitch, *inputDepthPitch, unpack, is3D,
9428 inputSkipBytes));
9429
9430 return angle::Result::Continue;
9431 }
9432
onRenderPassAttach(const QueueSerial & queueSerial)9433 void ImageHelper::onRenderPassAttach(const QueueSerial &queueSerial)
9434 {
9435 setQueueSerial(queueSerial);
9436 // updatePipelineStageAccessHistory uses mCurrentLayout which we dont know yet (deferred until
9437 // endRenderPass time). So update it directly since we know attachment will be accessed by
9438 // fragment and attachment stages.
9439 mPipelineStageAccessHeuristic.onAccess(PipelineStageGroup::FragmentOnly);
9440 }
9441
onWrite(gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags)9442 void ImageHelper::onWrite(gl::LevelIndex levelStart,
9443 uint32_t levelCount,
9444 uint32_t layerStart,
9445 uint32_t layerCount,
9446 VkImageAspectFlags aspectFlags)
9447 {
9448 mCurrentSingleClearValue.reset();
9449
9450 // Mark contents of the given subresource as defined.
9451 setContentDefined(toVkLevel(levelStart), levelCount, layerStart, layerCount, aspectFlags);
9452
9453 setSubresourcesWrittenSinceBarrier(levelStart, levelCount, layerStart, layerCount);
9454 }
9455
hasSubresourceDefinedContent(gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount) const9456 bool ImageHelper::hasSubresourceDefinedContent(gl::LevelIndex level,
9457 uint32_t layerIndex,
9458 uint32_t layerCount) const
9459 {
9460 if (layerIndex >= kMaxContentDefinedLayerCount)
9461 {
9462 return true;
9463 }
9464
9465 uint8_t layerRangeBits =
9466 GetContentDefinedLayerRangeBits(layerIndex, layerCount, kMaxContentDefinedLayerCount);
9467 return (getLevelContentDefined(toVkLevel(level)) & LevelContentDefinedMask(layerRangeBits))
9468 .any();
9469 }
9470
hasSubresourceDefinedStencilContent(gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount) const9471 bool ImageHelper::hasSubresourceDefinedStencilContent(gl::LevelIndex level,
9472 uint32_t layerIndex,
9473 uint32_t layerCount) const
9474 {
9475 if (layerIndex >= kMaxContentDefinedLayerCount)
9476 {
9477 return true;
9478 }
9479
9480 uint8_t layerRangeBits =
9481 GetContentDefinedLayerRangeBits(layerIndex, layerCount, kMaxContentDefinedLayerCount);
9482 return (getLevelStencilContentDefined(toVkLevel(level)) &
9483 LevelContentDefinedMask(layerRangeBits))
9484 .any();
9485 }
9486
invalidateEntireLevelContent(vk::ErrorContext * context,gl::LevelIndex level)9487 void ImageHelper::invalidateEntireLevelContent(vk::ErrorContext *context, gl::LevelIndex level)
9488 {
9489 invalidateSubresourceContentImpl(
9490 context, level, 0, mLayerCount,
9491 static_cast<VkImageAspectFlagBits>(getAspectFlags() & ~VK_IMAGE_ASPECT_STENCIL_BIT),
9492 &getLevelContentDefined(toVkLevel(level)), nullptr, nullptr);
9493 }
9494
invalidateSubresourceContent(ContextVk * contextVk,gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount,bool * preferToKeepContentsDefinedOut)9495 void ImageHelper::invalidateSubresourceContent(ContextVk *contextVk,
9496 gl::LevelIndex level,
9497 uint32_t layerIndex,
9498 uint32_t layerCount,
9499 bool *preferToKeepContentsDefinedOut)
9500 {
9501 const VkImageAspectFlagBits aspect =
9502 static_cast<VkImageAspectFlagBits>(getAspectFlags() & ~VK_IMAGE_ASPECT_STENCIL_BIT);
9503 bool layerLimitReached = false;
9504 invalidateSubresourceContentImpl(contextVk, level, layerIndex, layerCount, aspect,
9505 &getLevelContentDefined(toVkLevel(level)),
9506 preferToKeepContentsDefinedOut, &layerLimitReached);
9507 if (layerLimitReached)
9508 {
9509 const char *aspectName = (aspect == VK_IMAGE_ASPECT_DEPTH_BIT ? "depth" : "color");
9510 ANGLE_VK_PERF_WARNING(
9511 contextVk, GL_DEBUG_SEVERITY_LOW,
9512 "glInvalidateFramebuffer (%s) ineffective on attachments with layer >= 8", aspectName);
9513 }
9514 }
9515
invalidateEntireLevelStencilContent(vk::ErrorContext * context,gl::LevelIndex level)9516 void ImageHelper::invalidateEntireLevelStencilContent(vk::ErrorContext *context,
9517 gl::LevelIndex level)
9518 {
9519 invalidateSubresourceContentImpl(context, level, 0, mLayerCount, VK_IMAGE_ASPECT_STENCIL_BIT,
9520 &getLevelStencilContentDefined(toVkLevel(level)), nullptr,
9521 nullptr);
9522 }
9523
invalidateSubresourceStencilContent(ContextVk * contextVk,gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount,bool * preferToKeepContentsDefinedOut)9524 void ImageHelper::invalidateSubresourceStencilContent(ContextVk *contextVk,
9525 gl::LevelIndex level,
9526 uint32_t layerIndex,
9527 uint32_t layerCount,
9528 bool *preferToKeepContentsDefinedOut)
9529 {
9530 bool layerLimitReached = false;
9531 invalidateSubresourceContentImpl(contextVk, level, layerIndex, layerCount,
9532 VK_IMAGE_ASPECT_STENCIL_BIT,
9533 &getLevelStencilContentDefined(toVkLevel(level)),
9534 preferToKeepContentsDefinedOut, &layerLimitReached);
9535 if (layerLimitReached)
9536 {
9537 ANGLE_VK_PERF_WARNING(
9538 contextVk, GL_DEBUG_SEVERITY_LOW,
9539 "glInvalidateFramebuffer (stencil) ineffective on attachments with layer >= 8");
9540 }
9541 }
9542
invalidateSubresourceContentImpl(vk::ErrorContext * context,gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount,VkImageAspectFlagBits aspect,LevelContentDefinedMask * contentDefinedMask,bool * preferToKeepContentsDefinedOut,bool * layerLimitReachedOut)9543 void ImageHelper::invalidateSubresourceContentImpl(vk::ErrorContext *context,
9544 gl::LevelIndex level,
9545 uint32_t layerIndex,
9546 uint32_t layerCount,
9547 VkImageAspectFlagBits aspect,
9548 LevelContentDefinedMask *contentDefinedMask,
9549 bool *preferToKeepContentsDefinedOut,
9550 bool *layerLimitReachedOut)
9551 {
9552 // If the aspect being invalidated doesn't exist, skip invalidation altogether.
9553 if ((getAspectFlags() & aspect) == 0)
9554 {
9555 if (preferToKeepContentsDefinedOut)
9556 {
9557 // Let the caller know that this invalidate request was ignored.
9558 *preferToKeepContentsDefinedOut = true;
9559 }
9560 return;
9561 }
9562
9563 // If the color format is emulated and has extra channels, those channels need to stay cleared.
9564 // On some devices, it's cheaper to skip invalidating the framebuffer attachment, while on
9565 // others it's cheaper to invalidate but then re-clear the image.
9566 //
9567 // For depth/stencil formats, each channel is separately invalidated, so the invalidate is
9568 // simply skipped for the emulated channel on all devices.
9569 const bool hasEmulatedChannels = hasEmulatedImageChannels();
9570 bool skip = false;
9571 switch (aspect)
9572 {
9573 case VK_IMAGE_ASPECT_DEPTH_BIT:
9574 skip = hasEmulatedDepthChannel();
9575 break;
9576 case VK_IMAGE_ASPECT_STENCIL_BIT:
9577 skip = hasEmulatedStencilChannel();
9578 break;
9579 case VK_IMAGE_ASPECT_COLOR_BIT:
9580 skip = hasEmulatedChannels &&
9581 context->getFeatures().preferSkippingInvalidateForEmulatedFormats.enabled;
9582 break;
9583 default:
9584 UNREACHABLE();
9585 skip = true;
9586 }
9587
9588 if (preferToKeepContentsDefinedOut)
9589 {
9590 *preferToKeepContentsDefinedOut = skip;
9591 }
9592 if (skip)
9593 {
9594 return;
9595 }
9596
9597 if (layerIndex >= kMaxContentDefinedLayerCount)
9598 {
9599 ASSERT(layerLimitReachedOut != nullptr);
9600 *layerLimitReachedOut = true;
9601 return;
9602 }
9603
9604 uint8_t layerRangeBits =
9605 GetContentDefinedLayerRangeBits(layerIndex, layerCount, kMaxContentDefinedLayerCount);
9606 *contentDefinedMask &= static_cast<uint8_t>(~layerRangeBits);
9607
9608 // If there are emulated channels, stage a clear to make sure those channels continue to contain
9609 // valid values.
9610 if (hasEmulatedChannels && aspect == VK_IMAGE_ASPECT_COLOR_BIT)
9611 {
9612 VkClearValue clearValue;
9613 clearValue.color = kEmulatedInitColorValue;
9614
9615 prependSubresourceUpdate(
9616 level, SubresourceUpdate(aspect, clearValue, level, layerIndex, layerCount));
9617 mSubresourceUpdates[level.get()].front().updateSource = UpdateSource::ClearAfterInvalidate;
9618 }
9619 }
9620
restoreSubresourceContent(gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount)9621 void ImageHelper::restoreSubresourceContent(gl::LevelIndex level,
9622 uint32_t layerIndex,
9623 uint32_t layerCount)
9624 {
9625 restoreSubresourceContentImpl(
9626 level, layerIndex, layerCount,
9627 static_cast<VkImageAspectFlagBits>(getAspectFlags() & ~VK_IMAGE_ASPECT_STENCIL_BIT),
9628 &getLevelContentDefined(toVkLevel(level)));
9629 }
9630
restoreSubresourceStencilContent(gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount)9631 void ImageHelper::restoreSubresourceStencilContent(gl::LevelIndex level,
9632 uint32_t layerIndex,
9633 uint32_t layerCount)
9634 {
9635 restoreSubresourceContentImpl(level, layerIndex, layerCount, VK_IMAGE_ASPECT_STENCIL_BIT,
9636 &getLevelStencilContentDefined(toVkLevel(level)));
9637 }
9638
restoreSubresourceContentImpl(gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount,VkImageAspectFlagBits aspect,LevelContentDefinedMask * contentDefinedMask)9639 void ImageHelper::restoreSubresourceContentImpl(gl::LevelIndex level,
9640 uint32_t layerIndex,
9641 uint32_t layerCount,
9642 VkImageAspectFlagBits aspect,
9643 LevelContentDefinedMask *contentDefinedMask)
9644 {
9645 if (layerIndex >= kMaxContentDefinedLayerCount)
9646 {
9647 return;
9648 }
9649
9650 uint8_t layerRangeBits =
9651 GetContentDefinedLayerRangeBits(layerIndex, layerCount, kMaxContentDefinedLayerCount);
9652
9653 switch (aspect)
9654 {
9655 case VK_IMAGE_ASPECT_DEPTH_BIT:
9656 // Emulated depth channel should never have been marked invalid, so it can retain its
9657 // cleared value.
9658 ASSERT(!hasEmulatedDepthChannel() ||
9659 (contentDefinedMask->bits() & layerRangeBits) == layerRangeBits);
9660 break;
9661 case VK_IMAGE_ASPECT_STENCIL_BIT:
9662 // Emulated stencil channel should never have been marked invalid, so it can retain its
9663 // cleared value.
9664 ASSERT(!hasEmulatedStencilChannel() ||
9665 (contentDefinedMask->bits() & layerRangeBits) == layerRangeBits);
9666 break;
9667 case VK_IMAGE_ASPECT_COLOR_BIT:
9668 {
9669 // This function is called on attachments during a render pass when it's determined that
9670 // they should no longer be considered invalidated. For an attachment with emulated
9671 // format that has extra channels, invalidateSubresourceContentImpl may have proactively
9672 // inserted a clear so that the extra channels continue to have defined values.
9673 // |FramebufferVk::invalidateImpl| closes the render pass right away however in that
9674 // case, so it should be impossible for the contents of such formats to need to be
9675 // restored.
9676 const bool hasClearAfterInvalidateUpdate =
9677 getLevelUpdates(level) != nullptr && getLevelUpdates(level)->size() != 0 &&
9678 getLevelUpdates(level)->at(0).updateSource == UpdateSource::ClearAfterInvalidate;
9679 ASSERT(!hasEmulatedImageChannels() || !hasClearAfterInvalidateUpdate);
9680
9681 break;
9682 }
9683 default:
9684 UNREACHABLE();
9685 break;
9686 }
9687
9688 // Additionally, as the resource has been rewritten to in the render pass, its no longer cleared
9689 // to the cached value.
9690 mCurrentSingleClearValue.reset();
9691
9692 *contentDefinedMask |= layerRangeBits;
9693 }
9694
stagePartialClear(ContextVk * contextVk,const gl::Box & clearArea,const ClearTextureMode clearMode,gl::TextureType textureType,uint32_t levelIndex,uint32_t layerIndex,uint32_t layerCount,GLenum type,const gl::InternalFormat & formatInfo,const Format & vkFormat,ImageAccess access,const uint8_t * data)9695 angle::Result ImageHelper::stagePartialClear(ContextVk *contextVk,
9696 const gl::Box &clearArea,
9697 const ClearTextureMode clearMode,
9698 gl::TextureType textureType,
9699 uint32_t levelIndex,
9700 uint32_t layerIndex,
9701 uint32_t layerCount,
9702 GLenum type,
9703 const gl::InternalFormat &formatInfo,
9704 const Format &vkFormat,
9705 ImageAccess access,
9706 const uint8_t *data)
9707 {
9708 // If the input data pointer is null, the texture is filled with zeros.
9709 const angle::Format &intendedFormat = vkFormat.getIntendedFormat();
9710 const angle::Format &actualFormat = vkFormat.getActualImageFormat(access);
9711 auto intendedPixelSize = static_cast<uint32_t>(intendedFormat.pixelBytes);
9712 auto actualPixelSize = static_cast<uint32_t>(actualFormat.pixelBytes);
9713
9714 uint8_t intendedData[16] = {0};
9715 if (data != nullptr)
9716 {
9717 memcpy(intendedData, data, intendedPixelSize);
9718 }
9719
9720 // The appropriate loading function is used to take the original value as a single pixel and
9721 // convert it into the format actually used for this image.
9722 std::vector<uint8_t> actualData(actualPixelSize, 0);
9723 LoadImageFunctionInfo loadFunctionInfo = vkFormat.getTextureLoadFunction(access, type);
9724
9725 bool stencilOnly = formatInfo.sizedInternalFormat == GL_STENCIL_INDEX8;
9726 if (stencilOnly)
9727 {
9728 // Some Vulkan implementations do not support S8_UINT, so stencil-only data is
9729 // uploaded using one of combined depth-stencil formats there. Since the uploaded
9730 // stencil data must be tightly packed, the actual storage format should be ignored
9731 // with regards to its load function and output row pitch.
9732 loadFunctionInfo.loadFunction = angle::LoadToNative<GLubyte, 1>;
9733 }
9734
9735 loadFunctionInfo.loadFunction(contextVk->getImageLoadContext(), 1, 1, 1, intendedData, 1, 1,
9736 actualData.data(), 1, 1);
9737
9738 // VkClearValue is used for renderable images.
9739 VkClearValue clearValue = {};
9740 if (formatInfo.isDepthOrStencil())
9741 {
9742 GetVkClearDepthStencilValueFromBytes(intendedData, intendedFormat, &clearValue);
9743 }
9744 else
9745 {
9746 GetVkClearColorValueFromBytes(actualData.data(), actualFormat, &clearValue);
9747 }
9748
9749 // Stage a ClearPartial update.
9750 VkImageAspectFlags aspectFlags = 0;
9751 if (!formatInfo.isDepthOrStencil())
9752 {
9753 aspectFlags |= VK_IMAGE_ASPECT_COLOR_BIT;
9754 }
9755 else
9756 {
9757 aspectFlags |= formatInfo.depthBits > 0 ? VK_IMAGE_ASPECT_DEPTH_BIT : 0;
9758 aspectFlags |= formatInfo.stencilBits > 0 ? VK_IMAGE_ASPECT_STENCIL_BIT : 0;
9759 }
9760
9761 if (clearMode == ClearTextureMode::FullClear)
9762 {
9763 bool useLayerAsDepth = textureType == gl::TextureType::CubeMap ||
9764 textureType == gl::TextureType::CubeMapArray ||
9765 textureType == gl::TextureType::_2DArray ||
9766 textureType == gl::TextureType::_2DMultisampleArray;
9767 const gl::ImageIndex index = gl::ImageIndex::MakeFromType(
9768 textureType, levelIndex, 0, useLayerAsDepth ? clearArea.depth : 1);
9769
9770 appendSubresourceUpdate(gl::LevelIndex(levelIndex),
9771 SubresourceUpdate(aspectFlags, clearValue, index));
9772 }
9773 else
9774 {
9775 appendSubresourceUpdate(gl::LevelIndex(levelIndex),
9776 SubresourceUpdate(aspectFlags, clearValue, textureType, levelIndex,
9777 layerIndex, layerCount, clearArea));
9778 }
9779 return angle::Result::Continue;
9780 }
9781
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)9782 angle::Result ImageHelper::stageSubresourceUpdate(ContextVk *contextVk,
9783 const gl::ImageIndex &index,
9784 const gl::Extents &glExtents,
9785 const gl::Offset &offset,
9786 const gl::InternalFormat &formatInfo,
9787 const gl::PixelUnpackState &unpack,
9788 GLenum type,
9789 const uint8_t *pixels,
9790 const Format &vkFormat,
9791 ImageAccess access,
9792 ApplyImageUpdate applyUpdate,
9793 bool *updateAppliedImmediatelyOut)
9794 {
9795 GLuint inputRowPitch = 0;
9796 GLuint inputDepthPitch = 0;
9797 GLuint inputSkipBytes = 0;
9798 ANGLE_TRY(calculateBufferInfo(contextVk, glExtents, formatInfo, unpack, type, index.usesTex3D(),
9799 &inputRowPitch, &inputDepthPitch, &inputSkipBytes));
9800
9801 ANGLE_TRY(stageSubresourceUpdateImpl(
9802 contextVk, index, glExtents, offset, formatInfo, unpack, type, pixels, vkFormat, access,
9803 inputRowPitch, inputDepthPitch, inputSkipBytes, applyUpdate, updateAppliedImmediatelyOut));
9804
9805 return angle::Result::Continue;
9806 }
9807
stageSubresourceUpdateAndGetData(ContextVk * contextVk,size_t allocationSize,const gl::ImageIndex & imageIndex,const gl::Extents & glExtents,const gl::Offset & offset,uint8_t ** dstData,angle::FormatID formatID)9808 angle::Result ImageHelper::stageSubresourceUpdateAndGetData(ContextVk *contextVk,
9809 size_t allocationSize,
9810 const gl::ImageIndex &imageIndex,
9811 const gl::Extents &glExtents,
9812 const gl::Offset &offset,
9813 uint8_t **dstData,
9814 angle::FormatID formatID)
9815 {
9816 std::unique_ptr<RefCounted<BufferHelper>> stagingBuffer =
9817 std::make_unique<RefCounted<BufferHelper>>();
9818 BufferHelper *currentBuffer = &stagingBuffer->get();
9819
9820 VkDeviceSize stagingOffset;
9821 ANGLE_TRY(contextVk->initBufferForImageCopy(currentBuffer, allocationSize,
9822 MemoryCoherency::CachedNonCoherent, formatID,
9823 &stagingOffset, dstData));
9824
9825 gl::LevelIndex updateLevelGL(imageIndex.getLevelIndex());
9826
9827 VkBufferImageCopy copy = {};
9828 copy.bufferOffset = stagingOffset;
9829 copy.bufferRowLength = glExtents.width;
9830 copy.bufferImageHeight = glExtents.height;
9831 copy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
9832 copy.imageSubresource.mipLevel = updateLevelGL.get();
9833 copy.imageSubresource.baseArrayLayer = imageIndex.hasLayer() ? imageIndex.getLayerIndex() : 0;
9834 copy.imageSubresource.layerCount = imageIndex.getLayerCount();
9835
9836 // Note: Only support color now
9837 ASSERT((mActualFormatID == angle::FormatID::NONE) ||
9838 (getAspectFlags() == VK_IMAGE_ASPECT_COLOR_BIT));
9839
9840 gl_vk::GetOffset(offset, ©.imageOffset);
9841 gl_vk::GetExtent(glExtents, ©.imageExtent);
9842
9843 appendSubresourceUpdate(
9844 updateLevelGL, SubresourceUpdate(stagingBuffer.release(), currentBuffer, copy, formatID));
9845 return angle::Result::Continue;
9846 }
9847
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)9848 angle::Result ImageHelper::stageSubresourceUpdateFromFramebuffer(
9849 const gl::Context *context,
9850 const gl::ImageIndex &index,
9851 const gl::Rectangle &sourceArea,
9852 const gl::Offset &dstOffset,
9853 const gl::Extents &dstExtent,
9854 const gl::InternalFormat &formatInfo,
9855 ImageAccess access,
9856 FramebufferVk *framebufferVk)
9857 {
9858 ContextVk *contextVk = GetImpl(context);
9859
9860 // If the extents and offset is outside the source image, we need to clip.
9861 gl::Rectangle clippedRectangle;
9862 const gl::Extents readExtents = framebufferVk->getReadImageExtents();
9863 if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, readExtents.width, readExtents.height),
9864 &clippedRectangle))
9865 {
9866 // Empty source area, nothing to do.
9867 return angle::Result::Continue;
9868 }
9869
9870 bool isViewportFlipEnabled = contextVk->isViewportFlipEnabledForDrawFBO();
9871 if (isViewportFlipEnabled)
9872 {
9873 clippedRectangle.y = readExtents.height - clippedRectangle.y - clippedRectangle.height;
9874 }
9875
9876 // 1- obtain a buffer handle to copy to
9877 Renderer *renderer = contextVk->getRenderer();
9878
9879 const Format &vkFormat = renderer->getFormat(formatInfo.sizedInternalFormat);
9880 const angle::Format &storageFormat = vkFormat.getActualImageFormat(access);
9881 LoadImageFunctionInfo loadFunction = vkFormat.getTextureLoadFunction(access, formatInfo.type);
9882
9883 size_t outputRowPitch = storageFormat.pixelBytes * clippedRectangle.width;
9884 size_t outputDepthPitch = outputRowPitch * clippedRectangle.height;
9885
9886 std::unique_ptr<RefCounted<BufferHelper>> stagingBuffer =
9887 std::make_unique<RefCounted<BufferHelper>>();
9888 BufferHelper *currentBuffer = &stagingBuffer->get();
9889
9890 uint8_t *stagingPointer;
9891 VkDeviceSize stagingOffset;
9892
9893 // The destination is only one layer deep.
9894 size_t allocationSize = outputDepthPitch;
9895 ANGLE_TRY(contextVk->initBufferForImageCopy(currentBuffer, allocationSize,
9896 MemoryCoherency::CachedNonCoherent,
9897 storageFormat.id, &stagingOffset, &stagingPointer));
9898
9899 const angle::Format ©Format =
9900 GetFormatFromFormatType(formatInfo.internalFormat, formatInfo.type);
9901 PackPixelsParams params(clippedRectangle, copyFormat, static_cast<GLuint>(outputRowPitch),
9902 isViewportFlipEnabled, nullptr, 0);
9903
9904 RenderTargetVk *readRenderTarget = framebufferVk->getColorReadRenderTarget();
9905
9906 // 2- copy the source image region to the pixel buffer using a cpu readback
9907 if (loadFunction.requiresConversion)
9908 {
9909 // When a conversion is required, we need to use the loadFunction to read from a temporary
9910 // buffer instead so its an even slower path.
9911 size_t bufferSize =
9912 storageFormat.pixelBytes * clippedRectangle.width * clippedRectangle.height;
9913 angle::MemoryBuffer *memoryBuffer = nullptr;
9914 ANGLE_VK_CHECK_ALLOC(contextVk, context->getScratchBuffer(bufferSize, &memoryBuffer));
9915
9916 // Read into the scratch buffer
9917 ANGLE_TRY(framebufferVk->readPixelsImpl(contextVk, clippedRectangle, params,
9918 VK_IMAGE_ASPECT_COLOR_BIT, readRenderTarget,
9919 memoryBuffer->data()));
9920
9921 // Load from scratch buffer to our pixel buffer
9922 loadFunction.loadFunction(contextVk->getImageLoadContext(), clippedRectangle.width,
9923 clippedRectangle.height, 1, memoryBuffer->data(), outputRowPitch,
9924 0, stagingPointer, outputRowPitch, 0);
9925 }
9926 else
9927 {
9928 // We read directly from the framebuffer into our pixel buffer.
9929 ANGLE_TRY(framebufferVk->readPixelsImpl(contextVk, clippedRectangle, params,
9930 VK_IMAGE_ASPECT_COLOR_BIT, readRenderTarget,
9931 stagingPointer));
9932 }
9933
9934 gl::LevelIndex updateLevelGL(index.getLevelIndex());
9935
9936 // 3- enqueue the destination image subresource update
9937 VkBufferImageCopy copyToImage = {};
9938 copyToImage.bufferOffset = static_cast<VkDeviceSize>(stagingOffset);
9939 copyToImage.bufferRowLength = 0; // Tightly packed data can be specified as 0.
9940 copyToImage.bufferImageHeight = clippedRectangle.height;
9941 copyToImage.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
9942 copyToImage.imageSubresource.mipLevel = updateLevelGL.get();
9943 copyToImage.imageSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0;
9944 copyToImage.imageSubresource.layerCount = index.getLayerCount();
9945 gl_vk::GetOffset(dstOffset, ©ToImage.imageOffset);
9946 gl_vk::GetExtent(dstExtent, ©ToImage.imageExtent);
9947
9948 // 3- enqueue the destination image subresource update
9949 appendSubresourceUpdate(updateLevelGL, SubresourceUpdate(stagingBuffer.release(), currentBuffer,
9950 copyToImage, storageFormat.id));
9951
9952 return angle::Result::Continue;
9953 }
9954
stageSubresourceUpdateFromImage(RefCounted<ImageHelper> * image,const gl::ImageIndex & index,LevelIndex srcMipLevel,const gl::Offset & destOffset,const gl::Extents & glExtents,const VkImageType imageType)9955 void ImageHelper::stageSubresourceUpdateFromImage(RefCounted<ImageHelper> *image,
9956 const gl::ImageIndex &index,
9957 LevelIndex srcMipLevel,
9958 const gl::Offset &destOffset,
9959 const gl::Extents &glExtents,
9960 const VkImageType imageType)
9961 {
9962 gl::LevelIndex updateLevelGL(index.getLevelIndex());
9963 VkImageAspectFlags imageAspectFlags = vk::GetFormatAspectFlags(image->get().getActualFormat());
9964
9965 VkImageCopy copyToImage = {};
9966 copyToImage.srcSubresource.aspectMask = imageAspectFlags;
9967 copyToImage.srcSubresource.mipLevel = srcMipLevel.get();
9968 copyToImage.srcSubresource.layerCount = index.getLayerCount();
9969 copyToImage.dstSubresource.aspectMask = imageAspectFlags;
9970 copyToImage.dstSubresource.mipLevel = updateLevelGL.get();
9971
9972 if (imageType == VK_IMAGE_TYPE_3D)
9973 {
9974 // These values must be set explicitly to follow the Vulkan spec:
9975 // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VkImageCopy.html
9976 // If either of the calling command's srcImage or dstImage parameters are of VkImageType
9977 // VK_IMAGE_TYPE_3D, the baseArrayLayer and layerCount members of the corresponding
9978 // subresource must be 0 and 1, respectively
9979 copyToImage.dstSubresource.baseArrayLayer = 0;
9980 copyToImage.dstSubresource.layerCount = 1;
9981 // Preserve the assumption that destOffset.z == "dstSubresource.baseArrayLayer"
9982 ASSERT(destOffset.z == (index.hasLayer() ? index.getLayerIndex() : 0));
9983 }
9984 else
9985 {
9986 copyToImage.dstSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0;
9987 copyToImage.dstSubresource.layerCount = index.getLayerCount();
9988 }
9989
9990 gl_vk::GetOffset(destOffset, ©ToImage.dstOffset);
9991 gl_vk::GetExtent(glExtents, ©ToImage.extent);
9992
9993 appendSubresourceUpdate(
9994 updateLevelGL, SubresourceUpdate(image, copyToImage, image->get().getActualFormatID()));
9995 }
9996
stageSubresourceUpdatesFromAllImageLevels(RefCounted<ImageHelper> * image,gl::LevelIndex baseLevel)9997 void ImageHelper::stageSubresourceUpdatesFromAllImageLevels(RefCounted<ImageHelper> *image,
9998 gl::LevelIndex baseLevel)
9999 {
10000 for (LevelIndex levelVk(0); levelVk < LevelIndex(image->get().getLevelCount()); ++levelVk)
10001 {
10002 const gl::LevelIndex levelGL = vk_gl::GetLevelIndex(levelVk, baseLevel);
10003 const gl::ImageIndex index =
10004 gl::ImageIndex::Make2DArrayRange(levelGL.get(), 0, image->get().getLayerCount());
10005
10006 stageSubresourceUpdateFromImage(image, index, levelVk, gl::kOffsetZero,
10007 image->get().getLevelExtents(levelVk),
10008 image->get().getType());
10009 }
10010 }
10011
stageClear(const gl::ImageIndex & index,VkImageAspectFlags aspectFlags,const VkClearValue & clearValue)10012 void ImageHelper::stageClear(const gl::ImageIndex &index,
10013 VkImageAspectFlags aspectFlags,
10014 const VkClearValue &clearValue)
10015 {
10016 gl::LevelIndex updateLevelGL(index.getLevelIndex());
10017 appendSubresourceUpdate(updateLevelGL, SubresourceUpdate(aspectFlags, clearValue, index));
10018 }
10019
stageRobustResourceClear(const gl::ImageIndex & index)10020 void ImageHelper::stageRobustResourceClear(const gl::ImageIndex &index)
10021 {
10022 const VkImageAspectFlags aspectFlags = getAspectFlags();
10023
10024 ASSERT(mActualFormatID != angle::FormatID::NONE);
10025 VkClearValue clearValue = GetRobustResourceClearValue(getIntendedFormat(), getActualFormat());
10026
10027 gl::LevelIndex updateLevelGL(index.getLevelIndex());
10028 appendSubresourceUpdate(updateLevelGL, SubresourceUpdate(aspectFlags, clearValue, index));
10029 }
10030
stageResourceClearWithFormat(ContextVk * contextVk,const gl::ImageIndex & index,const gl::Extents & glExtents,const angle::Format & intendedFormat,const angle::Format & imageFormat,const VkClearValue & clearValue)10031 angle::Result ImageHelper::stageResourceClearWithFormat(ContextVk *contextVk,
10032 const gl::ImageIndex &index,
10033 const gl::Extents &glExtents,
10034 const angle::Format &intendedFormat,
10035 const angle::Format &imageFormat,
10036 const VkClearValue &clearValue)
10037 {
10038 // Robust clears must only be staged if we do not have any prior data for this subresource.
10039 ASSERT(!hasStagedUpdatesForSubresource(gl::LevelIndex(index.getLevelIndex()),
10040 index.getLayerIndex(), index.getLayerCount()));
10041
10042 const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(imageFormat);
10043
10044 gl::LevelIndex updateLevelGL(index.getLevelIndex());
10045
10046 if (imageFormat.isBlock)
10047 {
10048 // This only supports doing an initial clear to 0, not clearing to a specific encoded RGBA
10049 // value
10050 ASSERT((clearValue.color.int32[0] == 0) && (clearValue.color.int32[1] == 0) &&
10051 (clearValue.color.int32[2] == 0) && (clearValue.color.int32[3] == 0));
10052
10053 const gl::InternalFormat &formatInfo =
10054 gl::GetSizedInternalFormatInfo(imageFormat.glInternalFormat);
10055 GLuint totalSize;
10056 ANGLE_VK_CHECK_MATH(contextVk,
10057 formatInfo.computeCompressedImageSize(glExtents, &totalSize));
10058
10059 std::unique_ptr<RefCounted<BufferHelper>> stagingBuffer =
10060 std::make_unique<RefCounted<BufferHelper>>();
10061 BufferHelper *currentBuffer = &stagingBuffer->get();
10062
10063 uint8_t *stagingPointer;
10064 VkDeviceSize stagingOffset;
10065 ANGLE_TRY(contextVk->initBufferForImageCopy(
10066 currentBuffer, totalSize, MemoryCoherency::CachedNonCoherent, imageFormat.id,
10067 &stagingOffset, &stagingPointer));
10068 memset(stagingPointer, 0, totalSize);
10069
10070 VkBufferImageCopy copyRegion = {};
10071 copyRegion.bufferOffset = stagingOffset;
10072 copyRegion.imageExtent.width = glExtents.width;
10073 copyRegion.imageExtent.height = glExtents.height;
10074 copyRegion.imageExtent.depth = glExtents.depth;
10075 copyRegion.imageSubresource.mipLevel = updateLevelGL.get();
10076 copyRegion.imageSubresource.aspectMask = aspectFlags;
10077 copyRegion.imageSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0;
10078 copyRegion.imageSubresource.layerCount = index.getLayerCount();
10079
10080 // The update structure owns the staging buffer.
10081 appendSubresourceUpdate(
10082 updateLevelGL,
10083 SubresourceUpdate(stagingBuffer.release(), currentBuffer, copyRegion, imageFormat.id));
10084 }
10085 else
10086 {
10087 appendSubresourceUpdate(updateLevelGL, SubresourceUpdate(aspectFlags, clearValue, index));
10088 }
10089
10090 return angle::Result::Continue;
10091 }
10092
stageRobustResourceClearWithFormat(ContextVk * contextVk,const gl::ImageIndex & index,const gl::Extents & glExtents,const angle::Format & intendedFormat,const angle::Format & imageFormat)10093 angle::Result ImageHelper::stageRobustResourceClearWithFormat(ContextVk *contextVk,
10094 const gl::ImageIndex &index,
10095 const gl::Extents &glExtents,
10096 const angle::Format &intendedFormat,
10097 const angle::Format &imageFormat)
10098 {
10099 VkClearValue clearValue = GetRobustResourceClearValue(intendedFormat, imageFormat);
10100 gl::ImageIndex fullResourceIndex = index;
10101 gl::Extents fullResourceExtents = glExtents;
10102
10103 if (gl::IsArrayTextureType(index.getType()))
10104 {
10105 // For 2Darray textures gl::Extents::depth is the layer count.
10106 fullResourceIndex = gl::ImageIndex::MakeFromType(
10107 index.getType(), index.getLevelIndex(), gl::ImageIndex::kEntireLevel, glExtents.depth);
10108 // Vulkan requires depth of 1 for 2Darray textures.
10109 fullResourceExtents.depth = 1;
10110 }
10111
10112 return stageResourceClearWithFormat(contextVk, fullResourceIndex, fullResourceExtents,
10113 intendedFormat, imageFormat, clearValue);
10114 }
10115
stageClearIfEmulatedFormat(bool isRobustResourceInitEnabled,bool isExternalImage)10116 void ImageHelper::stageClearIfEmulatedFormat(bool isRobustResourceInitEnabled, bool isExternalImage)
10117 {
10118 // Skip staging extra clears if robust resource init is enabled.
10119 if (!hasEmulatedImageChannels() || isRobustResourceInitEnabled)
10120 {
10121 return;
10122 }
10123
10124 VkClearValue clearValue = {};
10125 if (getIntendedFormat().hasDepthOrStencilBits())
10126 {
10127 clearValue.depthStencil = kRobustInitDepthStencilValue;
10128 }
10129 else
10130 {
10131 clearValue.color = kEmulatedInitColorValue;
10132 }
10133
10134 const VkImageAspectFlags aspectFlags = getAspectFlags();
10135
10136 // If the image has an emulated channel and robust resource init is not enabled, always clear
10137 // it. These channels will be masked out in future writes, and shouldn't contain uninitialized
10138 // values.
10139 //
10140 // For external images, we cannot clear the image entirely, as it may contain data in the
10141 // non-emulated channels. For depth/stencil images, clear is already per aspect, but for color
10142 // images we would need to take a special path where we only clear the emulated channels.
10143
10144 // Block images are not cleared, since no emulated channels are present if decoded.
10145 if (isExternalImage && getIntendedFormat().isBlock)
10146 {
10147 return;
10148 }
10149
10150 const bool clearOnlyEmulatedChannels =
10151 isExternalImage && !getIntendedFormat().hasDepthOrStencilBits();
10152 const VkColorComponentFlags colorMaskFlags =
10153 clearOnlyEmulatedChannels ? getEmulatedChannelsMask() : 0;
10154
10155 for (LevelIndex level(0); level < LevelIndex(mLevelCount); ++level)
10156 {
10157 gl::LevelIndex updateLevelGL = toGLLevel(level);
10158 gl::ImageIndex index =
10159 gl::ImageIndex::Make2DArrayRange(updateLevelGL.get(), 0, mLayerCount);
10160
10161 if (clearOnlyEmulatedChannels)
10162 {
10163 prependSubresourceUpdate(updateLevelGL,
10164 SubresourceUpdate(colorMaskFlags, clearValue.color, index));
10165 }
10166 else
10167 {
10168 prependSubresourceUpdate(updateLevelGL,
10169 SubresourceUpdate(aspectFlags, clearValue, index));
10170 }
10171 }
10172 }
10173
verifyEmulatedClearsAreBeforeOtherUpdates(const SubresourceUpdates & updates)10174 bool ImageHelper::verifyEmulatedClearsAreBeforeOtherUpdates(const SubresourceUpdates &updates)
10175 {
10176 bool isIteratingEmulatedClears = true;
10177
10178 for (const SubresourceUpdate &update : updates)
10179 {
10180 // If anything other than ClearEmulatedChannelsOnly is visited, there cannot be any
10181 // ClearEmulatedChannelsOnly updates after that.
10182 if (update.updateSource != UpdateSource::ClearEmulatedChannelsOnly)
10183 {
10184 isIteratingEmulatedClears = false;
10185 }
10186 else if (!isIteratingEmulatedClears)
10187 {
10188 // If ClearEmulatedChannelsOnly is visited after another update, that's an error.
10189 return false;
10190 }
10191 }
10192
10193 // Additionally, verify that emulated clear is not applied multiple times.
10194 if (updates.size() >= 2 && updates[1].updateSource == UpdateSource::ClearEmulatedChannelsOnly)
10195 {
10196 return false;
10197 }
10198
10199 return true;
10200 }
10201
stageSelfAsSubresourceUpdates(ContextVk * contextVk,uint32_t levelCount,gl::TextureType textureType,const gl::CubeFaceArray<gl::TexLevelMask> & skipLevels)10202 void ImageHelper::stageSelfAsSubresourceUpdates(
10203 ContextVk *contextVk,
10204 uint32_t levelCount,
10205 gl::TextureType textureType,
10206 const gl::CubeFaceArray<gl::TexLevelMask> &skipLevels)
10207
10208 {
10209 // Nothing to do if every level must be skipped
10210 const gl::TexLevelMask levelsMask(angle::BitMask<uint32_t>(levelCount)
10211 << mFirstAllocatedLevel.get());
10212 const gl::TexLevelMask skipLevelsAllFaces = AggregateSkipLevels(skipLevels);
10213
10214 if ((~skipLevelsAllFaces & levelsMask).none())
10215 {
10216 return;
10217 }
10218
10219 // Because we are cloning this object to another object, we must finalize the layout if it is
10220 // being used by current renderpass as attachment. Otherwise we are copying the incorrect layout
10221 // since it is determined at endRenderPass time.
10222 contextVk->finalizeImageLayout(this, {});
10223
10224 std::unique_ptr<RefCounted<ImageHelper>> prevImage =
10225 std::make_unique<RefCounted<ImageHelper>>();
10226
10227 // Move the necessary information for staged update to work, and keep the rest as part of this
10228 // object.
10229
10230 // Usage info
10231 prevImage->get().Resource::operator=(std::move(*this));
10232
10233 // Vulkan objects
10234 prevImage->get().mImage = std::move(mImage);
10235 prevImage->get().mDeviceMemory = std::move(mDeviceMemory);
10236 prevImage->get().mVmaAllocation = std::move(mVmaAllocation);
10237
10238 // Barrier information. Note: mLevelCount is set to levelCount so that only the necessary
10239 // levels are transitioned when flushing the update.
10240 prevImage->get().mIntendedFormatID = mIntendedFormatID;
10241 prevImage->get().mActualFormatID = mActualFormatID;
10242 prevImage->get().mCurrentLayout = mCurrentLayout;
10243 prevImage->get().mCurrentDeviceQueueIndex = mCurrentDeviceQueueIndex;
10244 prevImage->get().mLastNonShaderReadOnlyLayout = mLastNonShaderReadOnlyLayout;
10245 prevImage->get().mCurrentShaderReadStageMask = mCurrentShaderReadStageMask;
10246 prevImage->get().mLevelCount = levelCount;
10247 prevImage->get().mLayerCount = mLayerCount;
10248 prevImage->get().mImageSerial = mImageSerial;
10249 prevImage->get().mAllocationSize = mAllocationSize;
10250 prevImage->get().mMemoryAllocationType = mMemoryAllocationType;
10251 prevImage->get().mMemoryTypeIndex = mMemoryTypeIndex;
10252
10253 // Reset information for current (invalid) image.
10254 mCurrentLayout = ImageLayout::Undefined;
10255 mCurrentDeviceQueueIndex = kInvalidDeviceQueueIndex;
10256 mIsReleasedToExternal = false;
10257 mIsForeignImage = false;
10258 mLastNonShaderReadOnlyLayout = ImageLayout::Undefined;
10259 mCurrentShaderReadStageMask = 0;
10260 mImageSerial = kInvalidImageSerial;
10261 mMemoryAllocationType = MemoryAllocationType::InvalidEnum;
10262
10263 setEntireContentUndefined();
10264
10265 // Stage updates from the previous image.
10266 for (LevelIndex levelVk(0); levelVk < LevelIndex(levelCount); ++levelVk)
10267 {
10268 gl::LevelIndex levelGL = toGLLevel(levelVk);
10269 if (!skipLevelsAllFaces.test(levelGL.get()))
10270 {
10271 const gl::ImageIndex index =
10272 gl::ImageIndex::Make2DArrayRange(levelGL.get(), 0, mLayerCount);
10273
10274 stageSubresourceUpdateFromImage(prevImage.get(), index, levelVk, gl::kOffsetZero,
10275 getLevelExtents(levelVk), mImageType);
10276 }
10277 else if (textureType == gl::TextureType::CubeMap)
10278 {
10279 for (uint32_t face = 0; face < gl::kCubeFaceCount; ++face)
10280 {
10281 if (!skipLevels[face][levelGL.get()])
10282 {
10283 const gl::ImageIndex index =
10284 gl::ImageIndex::Make2DArrayRange(levelGL.get(), face, 1);
10285
10286 stageSubresourceUpdateFromImage(prevImage.get(), index, levelVk,
10287 gl::kOffsetZero, getLevelExtents(levelVk),
10288 mImageType);
10289 }
10290 }
10291 }
10292 }
10293
10294 ASSERT(levelCount > 0);
10295 prevImage.release();
10296 }
10297
flushSingleSubresourceStagedUpdates(ContextVk * contextVk,gl::LevelIndex levelGL,uint32_t layer,uint32_t layerCount,ClearValuesArray * deferredClears,uint32_t deferredClearIndex)10298 angle::Result ImageHelper::flushSingleSubresourceStagedUpdates(ContextVk *contextVk,
10299 gl::LevelIndex levelGL,
10300 uint32_t layer,
10301 uint32_t layerCount,
10302 ClearValuesArray *deferredClears,
10303 uint32_t deferredClearIndex)
10304 {
10305 SubresourceUpdates *levelUpdates = getLevelUpdates(levelGL);
10306 if (levelUpdates == nullptr || levelUpdates->empty())
10307 {
10308 return angle::Result::Continue;
10309 }
10310
10311 // Handle deferred clears. Search the updates list for a matching clear index.
10312 if (deferredClears)
10313 {
10314 Optional<size_t> foundClear;
10315
10316 for (size_t updateIndex = 0; updateIndex < levelUpdates->size(); ++updateIndex)
10317 {
10318 SubresourceUpdate &update = (*levelUpdates)[updateIndex];
10319
10320 if (update.intersectsLayerRange(layer, layerCount))
10321 {
10322 // On any data update or the clear does not match exact layer range, we'll need to
10323 // do a full upload.
10324 const bool isClear = IsClearOfAllChannels(update.updateSource);
10325 if (isClear && update.matchesLayerRange(layer, layerCount))
10326 {
10327 foundClear = updateIndex;
10328 }
10329 else
10330 {
10331 foundClear.reset();
10332 break;
10333 }
10334 }
10335 }
10336
10337 // If we have a valid index we defer the clear using the clear reference.
10338 if (foundClear.valid())
10339 {
10340 size_t foundIndex = foundClear.value();
10341 const ClearUpdate &update = (*levelUpdates)[foundIndex].data.clear;
10342
10343 // Note that this set command handles combined or separate depth/stencil clears.
10344 deferredClears->store(deferredClearIndex, update.aspectFlags, update.value);
10345
10346 // Do not call onWrite as it removes mCurrentSingleClearValue, but instead call
10347 // setContentDefined directly.
10348 setContentDefined(toVkLevel(levelGL), 1, layer, layerCount, update.aspectFlags);
10349
10350 // We process the updates again to erase any clears for this level.
10351 removeSingleSubresourceStagedUpdates(contextVk, levelGL, layer, layerCount);
10352 return angle::Result::Continue;
10353 }
10354
10355 // Otherwise we proceed with a normal update.
10356 }
10357
10358 return flushStagedUpdates(contextVk, levelGL, levelGL + 1, layer, layer + layerCount, {});
10359 }
10360
flushStagedClearEmulatedChannelsUpdates(ContextVk * contextVk,gl::LevelIndex levelGLStart,gl::LevelIndex levelGLLimit,bool * otherUpdatesToFlushOut)10361 angle::Result ImageHelper::flushStagedClearEmulatedChannelsUpdates(ContextVk *contextVk,
10362 gl::LevelIndex levelGLStart,
10363 gl::LevelIndex levelGLLimit,
10364 bool *otherUpdatesToFlushOut)
10365 {
10366 *otherUpdatesToFlushOut = false;
10367 for (gl::LevelIndex updateMipLevelGL = levelGLStart; updateMipLevelGL < levelGLLimit;
10368 ++updateMipLevelGL)
10369 {
10370 // It is expected that the checked mip levels in this loop do not surpass the size of
10371 // mSubresourceUpdates.
10372 SubresourceUpdates *levelUpdates = getLevelUpdates(updateMipLevelGL);
10373 ASSERT(levelUpdates != nullptr);
10374
10375 // The levels with no updates should be skipped.
10376 if (levelUpdates->empty())
10377 {
10378 continue;
10379 }
10380
10381 // Since ClearEmulatedChannelsOnly is expected in the beginning and there cannot be more
10382 // than one such update type, we can process the first update and move on if there is
10383 // another update type in the list.
10384 ASSERT(verifyEmulatedClearsAreBeforeOtherUpdates(*levelUpdates));
10385 SubresourceUpdate *update = &(*levelUpdates).front();
10386
10387 if (update->updateSource != UpdateSource::ClearEmulatedChannelsOnly)
10388 {
10389 *otherUpdatesToFlushOut = true;
10390 continue;
10391 }
10392
10393 // If found, ClearEmulatedChannelsOnly should be flushed before the others and removed from
10394 // the update list.
10395 ASSERT(update->updateSource == UpdateSource::ClearEmulatedChannelsOnly);
10396 uint32_t updateBaseLayer, updateLayerCount;
10397 update->getDestSubresource(mLayerCount, &updateBaseLayer, &updateLayerCount);
10398
10399 const LevelIndex updateMipLevelVk = toVkLevel(updateMipLevelGL);
10400 update->data.clear.levelIndex = updateMipLevelVk.get();
10401 ANGLE_TRY(clearEmulatedChannels(contextVk, update->data.clear.colorMaskFlags,
10402 update->data.clear.value, updateMipLevelVk, updateBaseLayer,
10403 updateLayerCount));
10404 // Do not call onWrite. Even though some channels of the image are cleared, don't consider
10405 // the contents defined. Also, since clearing emulated channels is a one-time thing that's
10406 // superseded by Clears, |mCurrentSingleClearValue| is irrelevant and can't have a value.
10407 ASSERT(!mCurrentSingleClearValue.valid());
10408
10409 levelUpdates->pop_front();
10410 if (!levelUpdates->empty())
10411 {
10412 ASSERT(levelUpdates->begin()->updateSource != UpdateSource::ClearEmulatedChannelsOnly);
10413 *otherUpdatesToFlushOut = true;
10414 }
10415 }
10416
10417 return angle::Result::Continue;
10418 }
10419
flushStagedUpdatesImpl(ContextVk * contextVk,gl::LevelIndex levelGLStart,gl::LevelIndex levelGLEnd,uint32_t layerStart,uint32_t layerEnd,const gl::TexLevelMask & skipLevelsAllFaces)10420 angle::Result ImageHelper::flushStagedUpdatesImpl(ContextVk *contextVk,
10421 gl::LevelIndex levelGLStart,
10422 gl::LevelIndex levelGLEnd,
10423 uint32_t layerStart,
10424 uint32_t layerEnd,
10425 const gl::TexLevelMask &skipLevelsAllFaces)
10426 {
10427 Renderer *renderer = contextVk->getRenderer();
10428
10429 const angle::FormatID &actualformat = getActualFormatID();
10430 const angle::FormatID &intendedFormat = getIntendedFormatID();
10431
10432 const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(getActualFormat());
10433
10434 // Start in TransferDst. Don't yet mark any subresource as having defined contents; that is
10435 // done with fine granularity as updates are applied. This is achieved by specifying a layer
10436 // that is outside the tracking range. Under some circumstances, ComputeWrite is also required.
10437 // This need not be applied if the only updates are ClearEmulatedChannels.
10438 CommandBufferAccess transferAccess;
10439 OutsideRenderPassCommandBufferHelper *commandBuffer = nullptr;
10440 bool transCoding = renderer->getFeatures().supportsComputeTranscodeEtcToBc.enabled &&
10441 IsETCFormat(intendedFormat) && IsBCFormat(actualformat);
10442
10443 if (transCoding)
10444 {
10445 transferAccess.onImageTransferDstAndComputeWrite(
10446 levelGLStart, 1, kMaxContentDefinedLayerCount, 0, aspectFlags, this);
10447 }
10448 else
10449 {
10450 transferAccess.onImageTransferWrite(levelGLStart, 1, kMaxContentDefinedLayerCount, 0,
10451 aspectFlags, this);
10452 }
10453 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBufferHelper(transferAccess, &commandBuffer));
10454
10455 // Flush the staged updates in each mip level.
10456 for (gl::LevelIndex updateMipLevelGL = levelGLStart; updateMipLevelGL < levelGLEnd;
10457 ++updateMipLevelGL)
10458 {
10459 // If updates to this level are specifically asked to be skipped, skip
10460 // them. This can happen when recreating an image that has been partially incompatibly
10461 // redefined, in which case only updates to the levels that haven't been redefined
10462 // should be flushed.
10463 if (skipLevelsAllFaces.test(updateMipLevelGL.get()))
10464 {
10465 continue;
10466 }
10467
10468 // It is expected that the checked mip levels in this loop do not surpass the size of
10469 // mSubresourceUpdates.
10470 SubresourceUpdates *levelUpdates = getLevelUpdates(updateMipLevelGL);
10471 SubresourceUpdates updatesToKeep;
10472 ASSERT(levelUpdates != nullptr);
10473
10474 // Because updates may have overlapping layer ranges, we must first figure out the actual
10475 // layer ranges that will be flushed. The updatesToKeep list must compare against this
10476 // adjusted layer range. Otherwise you may end up keeping the update even though it is
10477 // overlapped with the update that gets flushed, and then content gets overwritten when
10478 // updatesToKeep gets flushed out.
10479 uint32_t adjustedLayerStart = layerStart, adjustedLayerEnd = layerEnd;
10480 if (levelUpdates->size() > 1)
10481 {
10482 adjustLayerRange(*levelUpdates, &adjustedLayerStart, &adjustedLayerEnd);
10483 }
10484
10485 for (SubresourceUpdate &update : *levelUpdates)
10486 {
10487 ASSERT(IsClearOfAllChannels(update.updateSource) ||
10488 (update.updateSource == UpdateSource::ClearPartial) ||
10489 (update.updateSource == UpdateSource::Buffer &&
10490 update.data.buffer.bufferHelper != nullptr) ||
10491 (update.updateSource == UpdateSource::Image &&
10492 update.refCounted.image != nullptr && update.refCounted.image->isReferenced() &&
10493 update.refCounted.image->get().valid()));
10494
10495 uint32_t updateBaseLayer, updateLayerCount;
10496 update.getDestSubresource(mLayerCount, &updateBaseLayer, &updateLayerCount);
10497
10498 // If the update layers don't intersect the requested layers, skip the update.
10499 const bool areUpdateLayersOutsideRange =
10500 updateBaseLayer + updateLayerCount <= adjustedLayerStart ||
10501 updateBaseLayer >= adjustedLayerEnd;
10502 if (areUpdateLayersOutsideRange)
10503 {
10504 updatesToKeep.emplace_back(std::move(update));
10505 continue;
10506 }
10507
10508 const LevelIndex updateMipLevelVk = toVkLevel(updateMipLevelGL);
10509
10510 // It seems we haven't fully support glCopyImageSubData
10511 // when compressed format emulated by uncompressed format.
10512 // make assumption that there is no data source come from image.
10513 ASSERT(!transCoding || (transCoding && update.updateSource == UpdateSource::Buffer));
10514 // The updates were holding gl::LevelIndex values so that they would not need
10515 // modification when the base level of the texture changes. Now that the update is
10516 // about to take effect, we need to change miplevel to LevelIndex.
10517 switch (update.updateSource)
10518 {
10519 case UpdateSource::Clear:
10520 case UpdateSource::ClearAfterInvalidate:
10521 {
10522 update.data.clear.levelIndex = updateMipLevelVk.get();
10523 break;
10524 }
10525 case UpdateSource::ClearPartial:
10526 {
10527 update.data.clearPartial.levelIndex = updateMipLevelVk.get();
10528 break;
10529 }
10530 case UpdateSource::Buffer:
10531 {
10532 if (!transCoding && !isDataFormatMatchForCopy(update.data.buffer.formatID))
10533 {
10534 // TODO: http://anglebug.com/42264884, we should handle this in higher level
10535 // code. If we have incompatible updates, skip but keep it.
10536 updatesToKeep.emplace_back(std::move(update));
10537 continue;
10538 }
10539 update.data.buffer.copyRegion.imageSubresource.mipLevel =
10540 updateMipLevelVk.get();
10541 break;
10542 }
10543 case UpdateSource::Image:
10544 {
10545 if (!isDataFormatMatchForCopy(update.data.image.formatID))
10546 {
10547 // If we have incompatible updates, skip but keep it.
10548 updatesToKeep.emplace_back(std::move(update));
10549 continue;
10550 }
10551 update.data.image.copyRegion.dstSubresource.mipLevel = updateMipLevelVk.get();
10552 break;
10553 }
10554 default:
10555 {
10556 UNREACHABLE();
10557 break;
10558 }
10559 }
10560
10561 // When a barrier is necessary when uploading updates to a level, we could instead move
10562 // to the next level and continue uploads in parallel. Once all levels need a barrier,
10563 // a single barrier can be issued and we could continue with the rest of the updates
10564 // from the first level. In case of multiple layer updates within the same level, a
10565 // barrier might be needed if there are multiple updates in the same parts of the image.
10566 ImageLayout barrierLayout =
10567 transCoding ? ImageLayout::TransferDstAndComputeWrite : ImageLayout::TransferDst;
10568 if (updateLayerCount >= kMaxParallelLayerWrites)
10569 {
10570 // If there are more subresources than bits we can track, always insert a barrier.
10571 recordWriteBarrier(contextVk, aspectFlags, barrierLayout, updateMipLevelGL, 1,
10572 updateBaseLayer, updateLayerCount, commandBuffer);
10573 mSubresourcesWrittenSinceBarrier[updateMipLevelGL.get()].set();
10574 }
10575 else
10576 {
10577 ImageLayerWriteMask subresourceHash =
10578 GetImageLayerWriteMask(updateBaseLayer, updateLayerCount);
10579
10580 if (areLevelSubresourcesWrittenWithinMaskRange(updateMipLevelGL.get(),
10581 subresourceHash))
10582 {
10583 // If there's overlap in subresource upload, issue a barrier.
10584 recordWriteBarrier(contextVk, aspectFlags, barrierLayout, updateMipLevelGL, 1,
10585 updateBaseLayer, updateLayerCount, commandBuffer);
10586 mSubresourcesWrittenSinceBarrier[updateMipLevelGL.get()].reset();
10587 }
10588 mSubresourcesWrittenSinceBarrier[updateMipLevelGL.get()] |= subresourceHash;
10589 }
10590
10591 // Add the necessary commands to the outside command buffer.
10592 switch (update.updateSource)
10593 {
10594 case UpdateSource::Clear:
10595 case UpdateSource::ClearAfterInvalidate:
10596 {
10597 clear(renderer, update.data.clear.aspectFlags, update.data.clear.value,
10598 updateMipLevelVk, updateBaseLayer, updateLayerCount,
10599 &commandBuffer->getCommandBuffer());
10600 contextVk->getPerfCounters().fullImageClears++;
10601 // Remember the latest operation is a clear call.
10602 mCurrentSingleClearValue = update.data.clear;
10603
10604 // Do not call onWrite as it removes mCurrentSingleClearValue, but instead call
10605 // setContentDefined directly.
10606 setContentDefined(updateMipLevelVk, 1, updateBaseLayer, updateLayerCount,
10607 update.data.clear.aspectFlags);
10608 break;
10609 }
10610 case UpdateSource::ClearPartial:
10611 {
10612 ClearPartialUpdate &clearPartialUpdate = update.data.clearPartial;
10613 gl::Box clearArea =
10614 gl::Box(clearPartialUpdate.offset, clearPartialUpdate.extent);
10615
10616 // clearTexture() uses LOAD_OP_CLEAR in a render pass to clear the texture. If
10617 // the texture has the depth dimension or multiple layers, the clear will be
10618 // performed layer by layer. In case of the former, the z-dimension will be used
10619 // as the layer index.
10620 UtilsVk::ClearTextureParameters params = {};
10621 params.aspectFlags = clearPartialUpdate.aspectFlags;
10622 params.level = updateMipLevelVk;
10623 params.clearArea = clearArea;
10624 params.clearValue = clearPartialUpdate.clearValue;
10625
10626 bool shouldUseDepthAsLayer =
10627 clearPartialUpdate.textureType == gl::TextureType::_3D;
10628 uint32_t clearBaseLayer =
10629 shouldUseDepthAsLayer ? clearArea.z : clearPartialUpdate.layerIndex;
10630 uint32_t clearLayerCount =
10631 shouldUseDepthAsLayer ? clearArea.depth : clearPartialUpdate.layerCount;
10632
10633 for (uint32_t layerIndex = clearBaseLayer;
10634 layerIndex < clearBaseLayer + clearLayerCount; ++layerIndex)
10635 {
10636 params.layer = layerIndex;
10637 ANGLE_TRY(contextVk->getUtils().clearTexture(contextVk, this, params));
10638 }
10639
10640 // Queue serial index becomes invalid after starting render pass for the op
10641 // above. Therefore, the outside command buffer should be re-acquired.
10642 ANGLE_TRY(
10643 contextVk->getOutsideRenderPassCommandBufferHelper({}, &commandBuffer));
10644 setContentDefined(updateMipLevelVk, 1, updateBaseLayer, updateLayerCount,
10645 clearPartialUpdate.aspectFlags);
10646 break;
10647 }
10648 case UpdateSource::Buffer:
10649 {
10650 BufferUpdate &bufferUpdate = update.data.buffer;
10651
10652 BufferHelper *currentBuffer = bufferUpdate.bufferHelper;
10653 ASSERT(currentBuffer && currentBuffer->valid());
10654 ANGLE_TRY(currentBuffer->flush(renderer));
10655
10656 CommandBufferAccess bufferAccess;
10657 VkBufferImageCopy *copyRegion = &update.data.buffer.copyRegion;
10658
10659 if (transCoding && update.data.buffer.formatID != actualformat)
10660 {
10661 bufferAccess.onBufferComputeShaderRead(currentBuffer);
10662 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBufferHelper(
10663 bufferAccess, &commandBuffer));
10664 ANGLE_TRY(contextVk->getUtils().transCodeEtcToBc(contextVk, currentBuffer,
10665 this, copyRegion));
10666 }
10667 else
10668 {
10669 bufferAccess.onBufferTransferRead(currentBuffer);
10670 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBufferHelper(
10671 bufferAccess, &commandBuffer));
10672 commandBuffer->getCommandBuffer().copyBufferToImage(
10673 currentBuffer->getBuffer().getHandle(), mImage, getCurrentLayout(), 1,
10674 copyRegion);
10675 }
10676 bool commandBufferWasFlushed = false;
10677 ANGLE_TRY(contextVk->onCopyUpdate(currentBuffer->getSize(),
10678 &commandBufferWasFlushed));
10679 onWrite(updateMipLevelGL, 1, updateBaseLayer, updateLayerCount,
10680 copyRegion->imageSubresource.aspectMask);
10681
10682 // Update total staging buffer size.
10683 mTotalStagedBufferUpdateSize -= bufferUpdate.bufferHelper->getSize();
10684
10685 if (commandBufferWasFlushed)
10686 {
10687 ANGLE_TRY(
10688 contextVk->getOutsideRenderPassCommandBufferHelper({}, &commandBuffer));
10689 }
10690 break;
10691 }
10692 case UpdateSource::Image:
10693 {
10694 CommandBufferAccess imageAccess;
10695 imageAccess.onImageTransferRead(aspectFlags, &update.refCounted.image->get());
10696 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBufferHelper(imageAccess,
10697 &commandBuffer));
10698
10699 VkImageCopy *copyRegion = &update.data.image.copyRegion;
10700 commandBuffer->getCommandBuffer().copyImage(
10701 update.refCounted.image->get().getImage(),
10702 update.refCounted.image->get().getCurrentLayout(), mImage,
10703 getCurrentLayout(), 1, copyRegion);
10704 onWrite(updateMipLevelGL, 1, updateBaseLayer, updateLayerCount,
10705 copyRegion->dstSubresource.aspectMask);
10706 break;
10707 }
10708 default:
10709 {
10710 UNREACHABLE();
10711 break;
10712 }
10713 }
10714
10715 update.release(renderer);
10716 }
10717
10718 // Only remove the updates that were actually applied to the image.
10719 *levelUpdates = std::move(updatesToKeep);
10720 }
10721
10722 // After applying the updates, the image serial should match the current queue serial of the
10723 // outside command buffer.
10724 if (mUse.getSerials()[commandBuffer->getQueueSerial().getIndex()] !=
10725 commandBuffer->getQueueSerial().getSerial())
10726 {
10727 // There has been a submission after the retainImage() call. Update the queue serial again.
10728 setQueueSerial(commandBuffer->getQueueSerial());
10729 }
10730
10731 return angle::Result::Continue;
10732 }
10733
flushStagedUpdates(ContextVk * contextVk,gl::LevelIndex levelGLStart,gl::LevelIndex levelGLEnd,uint32_t layerStart,uint32_t layerEnd,const gl::CubeFaceArray<gl::TexLevelMask> & skipLevels)10734 angle::Result ImageHelper::flushStagedUpdates(ContextVk *contextVk,
10735 gl::LevelIndex levelGLStart,
10736 gl::LevelIndex levelGLEnd,
10737 uint32_t layerStart,
10738 uint32_t layerEnd,
10739 const gl::CubeFaceArray<gl::TexLevelMask> &skipLevels)
10740 {
10741 Renderer *renderer = contextVk->getRenderer();
10742
10743 if (!hasStagedUpdatesInLevels(levelGLStart, levelGLEnd))
10744 {
10745 return angle::Result::Continue;
10746 }
10747
10748 const gl::TexLevelMask skipLevelsAllFaces = AggregateSkipLevels(skipLevels);
10749 removeSupersededUpdates(contextVk, skipLevelsAllFaces);
10750
10751 // If a clear is requested and we know it was previously cleared with the same value, we drop
10752 // the clear.
10753 if (mCurrentSingleClearValue.valid())
10754 {
10755 SubresourceUpdates *levelUpdates =
10756 getLevelUpdates(gl::LevelIndex(mCurrentSingleClearValue.value().levelIndex));
10757 if (levelUpdates && levelUpdates->size() == 1)
10758 {
10759 SubresourceUpdate &update = (*levelUpdates)[0];
10760 if (IsClearOfAllChannels(update.updateSource) &&
10761 mCurrentSingleClearValue.value() == update.data.clear)
10762 {
10763 ASSERT(levelGLStart + 1 == levelGLEnd);
10764 setContentDefined(toVkLevel(levelGLStart), 1, layerStart, layerEnd - layerStart,
10765 update.data.clear.aspectFlags);
10766 ANGLE_VK_PERF_WARNING(contextVk, GL_DEBUG_SEVERITY_LOW,
10767 "Repeated Clear on framebuffer attachment dropped");
10768 update.release(renderer);
10769 levelUpdates->clear();
10770 return angle::Result::Continue;
10771 }
10772 }
10773 }
10774
10775 ASSERT(validateSubresourceUpdateRefCountsConsistent());
10776
10777 // Process the clear emulated channels from the updates first. They are expected to be at the
10778 // beginning of the level updates.
10779 bool otherUpdatesToFlushOut = false;
10780 clipLevelToUpdateListUpperLimit(&levelGLEnd);
10781 ANGLE_TRY(flushStagedClearEmulatedChannelsUpdates(contextVk, levelGLStart, levelGLEnd,
10782 &otherUpdatesToFlushOut));
10783
10784 // If updates remain after processing ClearEmulatedChannelsOnly updates, we should acquire the
10785 // outside command buffer and apply the necessary barriers. Otherwise, this function can return
10786 // early, skipping the next loop.
10787 if (otherUpdatesToFlushOut)
10788 {
10789 ANGLE_TRY(flushStagedUpdatesImpl(contextVk, levelGLStart, levelGLEnd, layerStart, layerEnd,
10790 skipLevelsAllFaces));
10791 }
10792
10793 // Compact mSubresourceUpdates, then check if there are any updates left.
10794 size_t compactSize;
10795 for (compactSize = mSubresourceUpdates.size(); compactSize > 0; --compactSize)
10796 {
10797 if (!mSubresourceUpdates[compactSize - 1].empty())
10798 {
10799 break;
10800 }
10801 }
10802 mSubresourceUpdates.resize(compactSize);
10803
10804 ASSERT(validateSubresourceUpdateRefCountsConsistent());
10805
10806 // If no updates left, release the staging buffers to save memory.
10807 if (mSubresourceUpdates.empty())
10808 {
10809 ASSERT(mTotalStagedBufferUpdateSize == 0);
10810 onStateChange(angle::SubjectMessage::InitializationComplete);
10811 }
10812
10813 return angle::Result::Continue;
10814 }
10815
flushAllStagedUpdates(ContextVk * contextVk)10816 angle::Result ImageHelper::flushAllStagedUpdates(ContextVk *contextVk)
10817 {
10818 return flushStagedUpdates(contextVk, mFirstAllocatedLevel, mFirstAllocatedLevel + mLevelCount,
10819 0, mLayerCount, {});
10820 }
10821
hasStagedUpdatesForSubresource(gl::LevelIndex levelGL,uint32_t layer,uint32_t layerCount) const10822 bool ImageHelper::hasStagedUpdatesForSubresource(gl::LevelIndex levelGL,
10823 uint32_t layer,
10824 uint32_t layerCount) const
10825 {
10826 // Check to see if any updates are staged for the given level and layer
10827
10828 const SubresourceUpdates *levelUpdates = getLevelUpdates(levelGL);
10829 if (levelUpdates == nullptr || levelUpdates->empty())
10830 {
10831 return false;
10832 }
10833
10834 for (const SubresourceUpdate &update : *levelUpdates)
10835 {
10836 uint32_t updateBaseLayer, updateLayerCount;
10837 update.getDestSubresource(mLayerCount, &updateBaseLayer, &updateLayerCount);
10838
10839 const uint32_t updateLayerEnd = updateBaseLayer + updateLayerCount;
10840 const uint32_t layerEnd = layer + layerCount;
10841
10842 if ((layer >= updateBaseLayer && layer < updateLayerEnd) ||
10843 (layerEnd > updateBaseLayer && layerEnd <= updateLayerEnd))
10844 {
10845 // The layers intersect with the update range
10846 return true;
10847 }
10848 }
10849
10850 return false;
10851 }
10852
removeStagedClearUpdatesAndReturnColor(gl::LevelIndex levelGL,const VkClearColorValue ** color)10853 bool ImageHelper::removeStagedClearUpdatesAndReturnColor(gl::LevelIndex levelGL,
10854 const VkClearColorValue **color)
10855 {
10856 SubresourceUpdates *levelUpdates = getLevelUpdates(levelGL);
10857 if (levelUpdates == nullptr || levelUpdates->empty())
10858 {
10859 return false;
10860 }
10861
10862 bool result = false;
10863
10864 for (size_t index = 0; index < levelUpdates->size();)
10865 {
10866 auto update = levelUpdates->begin() + index;
10867 if (IsClearOfAllChannels(update->updateSource))
10868 {
10869 if (color != nullptr)
10870 {
10871 *color = &update->data.clear.value.color;
10872 }
10873 levelUpdates->erase(update);
10874 result = true;
10875 }
10876 }
10877
10878 return result;
10879 }
10880
adjustLayerRange(const SubresourceUpdates & levelUpdates,uint32_t * layerStart,uint32_t * layerEnd)10881 void ImageHelper::adjustLayerRange(const SubresourceUpdates &levelUpdates,
10882 uint32_t *layerStart,
10883 uint32_t *layerEnd)
10884 {
10885 for (const SubresourceUpdate &update : levelUpdates)
10886 {
10887 uint32_t updateBaseLayer, updateLayerCount;
10888 update.getDestSubresource(mLayerCount, &updateBaseLayer, &updateLayerCount);
10889 uint32_t updateLayerEnd = updateBaseLayer + updateLayerCount;
10890
10891 // In some cases, the update has the bigger layer range than the request. If the update
10892 // layers intersect the requested layers, then expand the layer range to the maximum from
10893 // the update and from the request.
10894 const bool areUpdateLayersWithinRange =
10895 updateBaseLayer < *layerEnd && updateLayerEnd > *layerStart;
10896 if (areUpdateLayersWithinRange)
10897 {
10898 *layerStart = std::min(*layerStart, updateBaseLayer);
10899 *layerEnd = std::max(*layerEnd, updateLayerEnd);
10900 }
10901 }
10902 }
10903
getLastAllocatedLevel() const10904 gl::LevelIndex ImageHelper::getLastAllocatedLevel() const
10905 {
10906 return mFirstAllocatedLevel + mLevelCount - 1;
10907 }
10908
hasStagedUpdatesInAllocatedLevels() const10909 bool ImageHelper::hasStagedUpdatesInAllocatedLevels() const
10910 {
10911 return hasStagedUpdatesInLevels(mFirstAllocatedLevel, getLastAllocatedLevel() + 1);
10912 }
10913
hasStagedUpdatesInLevels(gl::LevelIndex levelStart,gl::LevelIndex levelEnd) const10914 bool ImageHelper::hasStagedUpdatesInLevels(gl::LevelIndex levelStart, gl::LevelIndex levelEnd) const
10915 {
10916 for (gl::LevelIndex level = levelStart; level < levelEnd; ++level)
10917 {
10918 const SubresourceUpdates *levelUpdates = getLevelUpdates(level);
10919 if (levelUpdates == nullptr)
10920 {
10921 ASSERT(static_cast<size_t>(level.get()) >= mSubresourceUpdates.size());
10922 return false;
10923 }
10924
10925 if (!levelUpdates->empty())
10926 {
10927 return true;
10928 }
10929 }
10930 return false;
10931 }
10932
hasStagedImageUpdatesWithMismatchedFormat(gl::LevelIndex levelStart,gl::LevelIndex levelEnd,angle::FormatID formatID) const10933 bool ImageHelper::hasStagedImageUpdatesWithMismatchedFormat(gl::LevelIndex levelStart,
10934 gl::LevelIndex levelEnd,
10935 angle::FormatID formatID) const
10936 {
10937 for (gl::LevelIndex level = levelStart; level < levelEnd; ++level)
10938 {
10939 const SubresourceUpdates *levelUpdates = getLevelUpdates(level);
10940 if (levelUpdates == nullptr)
10941 {
10942 continue;
10943 }
10944
10945 for (const SubresourceUpdate &update : *levelUpdates)
10946 {
10947 if (update.updateSource == UpdateSource::Image &&
10948 update.data.image.formatID != formatID)
10949 {
10950 return true;
10951 }
10952 }
10953 }
10954 return false;
10955 }
10956
hasBufferSourcedStagedUpdatesInAllLevels() const10957 bool ImageHelper::hasBufferSourcedStagedUpdatesInAllLevels() const
10958 {
10959 for (gl::LevelIndex level = mFirstAllocatedLevel; level <= getLastAllocatedLevel(); ++level)
10960 {
10961 const SubresourceUpdates *levelUpdates = getLevelUpdates(level);
10962 if (levelUpdates == nullptr || levelUpdates->empty())
10963 {
10964 return false;
10965 }
10966
10967 bool hasUpdateSourceWithBufferOrPartialClear = false;
10968 for (const SubresourceUpdate &update : *levelUpdates)
10969 {
10970 if (update.updateSource == UpdateSource::Buffer ||
10971 update.updateSource == UpdateSource::ClearPartial)
10972 {
10973 hasUpdateSourceWithBufferOrPartialClear = true;
10974 break;
10975 }
10976 }
10977 if (!hasUpdateSourceWithBufferOrPartialClear)
10978 {
10979 return false;
10980 }
10981 }
10982 return true;
10983 }
10984
validateSubresourceUpdateBufferRefConsistent(RefCounted<BufferHelper> * buffer) const10985 bool ImageHelper::validateSubresourceUpdateBufferRefConsistent(
10986 RefCounted<BufferHelper> *buffer) const
10987 {
10988 if (buffer == nullptr)
10989 {
10990 return true;
10991 }
10992
10993 uint32_t refs = 0;
10994
10995 for (const SubresourceUpdates &levelUpdates : mSubresourceUpdates)
10996 {
10997 for (const SubresourceUpdate &update : levelUpdates)
10998 {
10999 if (update.updateSource == UpdateSource::Buffer && update.refCounted.buffer == buffer)
11000 {
11001 ++refs;
11002 }
11003 }
11004 }
11005
11006 return buffer->isRefCountAsExpected(refs);
11007 }
11008
validateSubresourceUpdateImageRefConsistent(RefCounted<ImageHelper> * image) const11009 bool ImageHelper::validateSubresourceUpdateImageRefConsistent(RefCounted<ImageHelper> *image) const
11010 {
11011 if (image == nullptr)
11012 {
11013 return true;
11014 }
11015
11016 uint32_t refs = 0;
11017
11018 for (const SubresourceUpdates &levelUpdates : mSubresourceUpdates)
11019 {
11020 for (const SubresourceUpdate &update : levelUpdates)
11021 {
11022 if (update.updateSource == UpdateSource::Image && update.refCounted.image == image)
11023 {
11024 ++refs;
11025 }
11026 }
11027 }
11028
11029 return image->isRefCountAsExpected(refs);
11030 }
11031
validateSubresourceUpdateRefCountsConsistent() const11032 bool ImageHelper::validateSubresourceUpdateRefCountsConsistent() const
11033 {
11034 for (const SubresourceUpdates &levelUpdates : mSubresourceUpdates)
11035 {
11036 for (const SubresourceUpdate &update : levelUpdates)
11037 {
11038 if (update.updateSource == UpdateSource::Image)
11039 {
11040 if (!validateSubresourceUpdateImageRefConsistent(update.refCounted.image))
11041 {
11042 return false;
11043 }
11044 }
11045 else if (update.updateSource == UpdateSource::Buffer)
11046 {
11047 if (!validateSubresourceUpdateBufferRefConsistent(update.refCounted.buffer))
11048 {
11049 return false;
11050 }
11051 }
11052 }
11053 }
11054
11055 return true;
11056 }
11057
pruneSupersededUpdatesForLevel(ContextVk * contextVk,const gl::LevelIndex level,const PruneReason reason)11058 void ImageHelper::pruneSupersededUpdatesForLevel(ContextVk *contextVk,
11059 const gl::LevelIndex level,
11060 const PruneReason reason)
11061 {
11062 constexpr VkDeviceSize kSubresourceUpdateSizeBeforePruning = 16 * 1024 * 1024; // 16 MB
11063 constexpr int kUpdateCountThreshold = 1024;
11064 SubresourceUpdates *levelUpdates = getLevelUpdates(level);
11065
11066 // If we are below pruning threshold, nothing to do.
11067 const int updateCount = static_cast<int>(levelUpdates->size());
11068 const bool withinThreshold = updateCount < kUpdateCountThreshold &&
11069 mTotalStagedBufferUpdateSize < kSubresourceUpdateSizeBeforePruning;
11070 if (updateCount == 1 || (reason == PruneReason::MemoryOptimization && withinThreshold))
11071 {
11072 return;
11073 }
11074
11075 // Start from the most recent update and define a boundingBox that covers the region to be
11076 // updated. Walk through all earlier updates and if its update region is contained within the
11077 // boundingBox, mark it as superseded, otherwise reset the boundingBox and continue.
11078 //
11079 // Color, depth and stencil are the only types supported for now. The boundingBox for color and
11080 // depth types is at index 0 and index 1 has the boundingBox for stencil type.
11081 VkDeviceSize supersededUpdateSize = 0;
11082 std::array<gl::Box, 2> boundingBox = {gl::Box(gl::kOffsetZero, gl::Extents())};
11083
11084 auto canDropUpdate = [this, contextVk, level, &supersededUpdateSize,
11085 &boundingBox](SubresourceUpdate &update) {
11086 VkDeviceSize updateSize = 0;
11087 VkImageAspectFlags aspectMask = update.getDestAspectFlags();
11088 gl::Box currentUpdateBox(gl::kOffsetZero, gl::Extents());
11089
11090 const bool isColor =
11091 (aspectMask & (VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_PLANE_0_BIT |
11092 VK_IMAGE_ASPECT_PLANE_1_BIT | VK_IMAGE_ASPECT_PLANE_2_BIT)) != 0;
11093 const bool isDepth = (aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) != 0;
11094 const bool isStencil = (aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) != 0;
11095 ASSERT(isColor || isDepth || isStencil);
11096 int aspectIndex = (isColor || isDepth) ? 0 : 1;
11097
11098 if (update.updateSource == UpdateSource::Buffer)
11099 {
11100 currentUpdateBox = gl::Box(update.data.buffer.copyRegion.imageOffset,
11101 update.data.buffer.copyRegion.imageExtent);
11102 updateSize = update.data.buffer.bufferHelper->getSize();
11103 }
11104 else if (update.updateSource == UpdateSource::Image)
11105 {
11106 currentUpdateBox = gl::Box(update.data.image.copyRegion.dstOffset,
11107 update.data.image.copyRegion.extent);
11108 }
11109 else if (update.updateSource == UpdateSource::ClearPartial)
11110 {
11111 currentUpdateBox = gl::Box(
11112 update.data.clearPartial.offset.x, update.data.clearPartial.offset.z,
11113 update.data.clearPartial.offset.z, update.data.clearPartial.extent.width,
11114 update.data.clearPartial.extent.height, update.data.clearPartial.extent.depth);
11115 }
11116 else
11117 {
11118 ASSERT(IsClear(update.updateSource));
11119 currentUpdateBox = gl::Box(gl::kOffsetZero, getLevelExtents(toVkLevel(level)));
11120 }
11121
11122 // Account for updates to layered images
11123 uint32_t layerIndex = 0;
11124 uint32_t layerCount = 0;
11125 update.getDestSubresource(mLayerCount, &layerIndex, &layerCount);
11126 if (layerIndex > 0 || layerCount > 1)
11127 {
11128 currentUpdateBox.z = layerIndex;
11129 currentUpdateBox.depth = layerCount;
11130 }
11131
11132 // Check if current update region is superseded by the accumulated update region
11133 if (boundingBox[aspectIndex].contains(currentUpdateBox))
11134 {
11135 ANGLE_VK_PERF_WARNING(contextVk, GL_DEBUG_SEVERITY_LOW,
11136 "Dropped texture update that is superseded by a more recent one");
11137
11138 // Release the superseded update
11139 update.release(contextVk->getRenderer());
11140
11141 // Update pruning size
11142 supersededUpdateSize += updateSize;
11143
11144 return true;
11145 }
11146 else
11147 {
11148 // Extend boundingBox to best accommodate current update's box.
11149 boundingBox[aspectIndex].extend(currentUpdateBox);
11150 // If the volume of the current update box is larger than the extended boundingBox
11151 // use that as the new boundingBox instead.
11152 if (currentUpdateBox.volume() > boundingBox[aspectIndex].volume())
11153 {
11154 boundingBox[aspectIndex] = currentUpdateBox;
11155 }
11156 return false;
11157 }
11158 };
11159
11160 levelUpdates->erase(
11161 levelUpdates->begin(),
11162 std::remove_if(levelUpdates->rbegin(), levelUpdates->rend(), canDropUpdate).base());
11163
11164 // Update total staging buffer size
11165 mTotalStagedBufferUpdateSize -= supersededUpdateSize;
11166 }
11167
removeSupersededUpdates(ContextVk * contextVk,const gl::TexLevelMask skipLevelsAllFaces)11168 void ImageHelper::removeSupersededUpdates(ContextVk *contextVk,
11169 const gl::TexLevelMask skipLevelsAllFaces)
11170 {
11171 ASSERT(validateSubresourceUpdateRefCountsConsistent());
11172
11173 for (LevelIndex levelVk(0); levelVk < LevelIndex(mLevelCount); ++levelVk)
11174 {
11175 gl::LevelIndex levelGL = toGLLevel(levelVk);
11176 SubresourceUpdates *levelUpdates = getLevelUpdates(levelGL);
11177 if (levelUpdates == nullptr || levelUpdates->size() == 0 ||
11178 skipLevelsAllFaces.test(levelGL.get()))
11179 {
11180 // There are no valid updates to process, continue.
11181 continue;
11182 }
11183
11184 // ClearEmulatedChannelsOnly updates can only be in the beginning of the list of updates.
11185 // They don't entirely clear the image, so they cannot supersede any update.
11186 ASSERT(verifyEmulatedClearsAreBeforeOtherUpdates(*levelUpdates));
11187
11188 pruneSupersededUpdatesForLevel(contextVk, levelGL, PruneReason::MinimizeWorkBeforeFlush);
11189 }
11190
11191 ASSERT(validateSubresourceUpdateRefCountsConsistent());
11192 }
11193
copyImageDataToBuffer(ContextVk * contextVk,gl::LevelIndex sourceLevelGL,uint32_t layerCount,uint32_t baseLayer,const gl::Box & sourceArea,BufferHelper * dstBuffer,uint8_t ** outDataPtr)11194 angle::Result ImageHelper::copyImageDataToBuffer(ContextVk *contextVk,
11195 gl::LevelIndex sourceLevelGL,
11196 uint32_t layerCount,
11197 uint32_t baseLayer,
11198 const gl::Box &sourceArea,
11199 BufferHelper *dstBuffer,
11200 uint8_t **outDataPtr)
11201 {
11202 ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::copyImageDataToBuffer");
11203 const angle::Format &imageFormat = getActualFormat();
11204
11205 // As noted in the OpenGL ES 3.2 specs, table 8.13, CopyTexImage cannot
11206 // be used for depth textures. There is no way for the image or buffer
11207 // used in this function to be of some combined depth and stencil format.
11208 ASSERT(getAspectFlags() == VK_IMAGE_ASPECT_COLOR_BIT);
11209
11210 uint32_t pixelBytes = imageFormat.pixelBytes;
11211 size_t bufferSize =
11212 sourceArea.width * sourceArea.height * sourceArea.depth * pixelBytes * layerCount;
11213
11214 const VkImageAspectFlags aspectFlags = getAspectFlags();
11215
11216 // Allocate staging buffer prefer coherent
11217 ASSERT(dstBuffer != nullptr && !dstBuffer->valid());
11218 VkDeviceSize dstOffset;
11219 ANGLE_TRY(contextVk->initBufferForImageCopy(dstBuffer, bufferSize,
11220 MemoryCoherency::CachedPreferCoherent,
11221 imageFormat.id, &dstOffset, outDataPtr));
11222 ANGLE_TRY(dstBuffer->flush(contextVk->getRenderer()));
11223
11224 VkBuffer bufferHandle = dstBuffer->getBuffer().getHandle();
11225
11226 LevelIndex sourceLevelVk = toVkLevel(sourceLevelGL);
11227
11228 VkBufferImageCopy regions = {};
11229 uint32_t regionCount = 1;
11230 // Default to non-combined DS case
11231 regions.bufferOffset = dstOffset;
11232 regions.bufferRowLength = 0;
11233 regions.bufferImageHeight = 0;
11234 regions.imageExtent.width = sourceArea.width;
11235 regions.imageExtent.height = sourceArea.height;
11236 regions.imageExtent.depth = sourceArea.depth;
11237 regions.imageOffset.x = sourceArea.x;
11238 regions.imageOffset.y = sourceArea.y;
11239 regions.imageOffset.z = sourceArea.z;
11240 regions.imageSubresource.aspectMask = aspectFlags;
11241 regions.imageSubresource.baseArrayLayer = baseLayer;
11242 regions.imageSubresource.layerCount = layerCount;
11243 regions.imageSubresource.mipLevel = sourceLevelVk.get();
11244
11245 CommandBufferAccess access;
11246 access.onBufferTransferWrite(dstBuffer);
11247 access.onImageTransferRead(aspectFlags, this);
11248
11249 OutsideRenderPassCommandBuffer *commandBuffer;
11250 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
11251
11252 commandBuffer->copyImageToBuffer(mImage, getCurrentLayout(), bufferHandle, regionCount,
11253 ®ions);
11254
11255 return angle::Result::Continue;
11256 }
11257
copySurfaceImageToBuffer(DisplayVk * displayVk,gl::LevelIndex sourceLevelGL,uint32_t layerCount,uint32_t baseLayer,const gl::Box & sourceArea,vk::BufferHelper * bufferHelper)11258 angle::Result ImageHelper::copySurfaceImageToBuffer(DisplayVk *displayVk,
11259 gl::LevelIndex sourceLevelGL,
11260 uint32_t layerCount,
11261 uint32_t baseLayer,
11262 const gl::Box &sourceArea,
11263 vk::BufferHelper *bufferHelper)
11264 {
11265 ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::copySurfaceImageToBuffer");
11266
11267 Renderer *renderer = displayVk->getRenderer();
11268
11269 VkBufferImageCopy region = {};
11270 region.bufferOffset = 0;
11271 region.bufferRowLength = 0;
11272 region.bufferImageHeight = 0;
11273 region.imageExtent.width = sourceArea.width;
11274 region.imageExtent.height = sourceArea.height;
11275 region.imageExtent.depth = sourceArea.depth;
11276 region.imageOffset.x = sourceArea.x;
11277 region.imageOffset.y = sourceArea.y;
11278 region.imageOffset.z = sourceArea.z;
11279 region.imageSubresource.aspectMask = getAspectFlags();
11280 region.imageSubresource.baseArrayLayer = baseLayer;
11281 region.imageSubresource.layerCount = layerCount;
11282 region.imageSubresource.mipLevel = toVkLevel(sourceLevelGL).get();
11283
11284 ScopedPrimaryCommandBuffer scopedCommandBuffer(renderer->getDevice());
11285 ANGLE_TRY(renderer->getCommandBufferOneOff(displayVk, ProtectionType::Unprotected,
11286 &scopedCommandBuffer));
11287 PrimaryCommandBuffer &primaryCommandBuffer = scopedCommandBuffer.get();
11288
11289 VkSemaphore acquireNextImageSemaphore;
11290 recordBarrierOneOffImpl(renderer, getAspectFlags(), ImageLayout::TransferSrc,
11291 displayVk->getDeviceQueueIndex(), &primaryCommandBuffer,
11292 &acquireNextImageSemaphore);
11293 primaryCommandBuffer.copyImageToBuffer(mImage, getCurrentLayout(),
11294 bufferHelper->getBuffer().getHandle(), 1, ®ion);
11295
11296 ANGLE_VK_TRY(displayVk, primaryCommandBuffer.end());
11297
11298 QueueSerial submitQueueSerial;
11299 ANGLE_TRY(renderer->queueSubmitOneOff(
11300 displayVk, std::move(scopedCommandBuffer), ProtectionType::Unprotected,
11301 egl::ContextPriority::Medium, acquireNextImageSemaphore,
11302 kSwapchainAcquireImageWaitStageFlags, &submitQueueSerial));
11303
11304 return renderer->finishQueueSerial(displayVk, submitQueueSerial);
11305 }
11306
copyBufferToSurfaceImage(DisplayVk * displayVk,gl::LevelIndex sourceLevelGL,uint32_t layerCount,uint32_t baseLayer,const gl::Box & sourceArea,vk::BufferHelper * bufferHelper)11307 angle::Result ImageHelper::copyBufferToSurfaceImage(DisplayVk *displayVk,
11308 gl::LevelIndex sourceLevelGL,
11309 uint32_t layerCount,
11310 uint32_t baseLayer,
11311 const gl::Box &sourceArea,
11312 vk::BufferHelper *bufferHelper)
11313 {
11314 ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::copyBufferToSurfaceImage");
11315
11316 Renderer *renderer = displayVk->getRenderer();
11317
11318 VkBufferImageCopy region = {};
11319 region.bufferOffset = 0;
11320 region.bufferRowLength = 0;
11321 region.bufferImageHeight = 0;
11322 region.imageExtent.width = sourceArea.width;
11323 region.imageExtent.height = sourceArea.height;
11324 region.imageExtent.depth = sourceArea.depth;
11325 region.imageOffset.x = sourceArea.x;
11326 region.imageOffset.y = sourceArea.y;
11327 region.imageOffset.z = sourceArea.z;
11328 region.imageSubresource.aspectMask = getAspectFlags();
11329 region.imageSubresource.baseArrayLayer = baseLayer;
11330 region.imageSubresource.layerCount = layerCount;
11331 region.imageSubresource.mipLevel = toVkLevel(sourceLevelGL).get();
11332
11333 ScopedPrimaryCommandBuffer scopedCommandBuffer(renderer->getDevice());
11334 ANGLE_TRY(renderer->getCommandBufferOneOff(displayVk, ProtectionType::Unprotected,
11335 &scopedCommandBuffer));
11336 PrimaryCommandBuffer &commandBuffer = scopedCommandBuffer.get();
11337
11338 VkSemaphore acquireNextImageSemaphore;
11339 recordBarrierOneOffImpl(renderer, getAspectFlags(), ImageLayout::TransferDst,
11340 displayVk->getDeviceQueueIndex(), &commandBuffer,
11341 &acquireNextImageSemaphore);
11342 commandBuffer.copyBufferToImage(bufferHelper->getBuffer().getHandle(), mImage,
11343 getCurrentLayout(), 1, ®ion);
11344
11345 ANGLE_VK_TRY(displayVk, commandBuffer.end());
11346
11347 QueueSerial submitQueueSerial;
11348 ANGLE_TRY(renderer->queueSubmitOneOff(
11349 displayVk, std::move(scopedCommandBuffer), ProtectionType::Unprotected,
11350 egl::ContextPriority::Medium, acquireNextImageSemaphore,
11351 kSwapchainAcquireImageWaitStageFlags, &submitQueueSerial));
11352
11353 return renderer->finishQueueSerial(displayVk, submitQueueSerial);
11354 }
11355
11356 // 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)11357 angle::Result ImageHelper::GetReadPixelsParams(ContextVk *contextVk,
11358 const gl::PixelPackState &packState,
11359 gl::Buffer *packBuffer,
11360 GLenum format,
11361 GLenum type,
11362 const gl::Rectangle &area,
11363 const gl::Rectangle &clippedArea,
11364 PackPixelsParams *paramsOut,
11365 GLuint *skipBytesOut)
11366 {
11367 const gl::InternalFormat &sizedFormatInfo = gl::GetInternalFormatInfo(format, type);
11368
11369 GLuint outputPitch = 0;
11370 ANGLE_VK_CHECK_MATH(contextVk,
11371 sizedFormatInfo.computeRowPitch(type, area.width, packState.alignment,
11372 packState.rowLength, &outputPitch));
11373 ANGLE_VK_CHECK_MATH(contextVk, sizedFormatInfo.computeSkipBytes(type, outputPitch, 0, packState,
11374 false, skipBytesOut));
11375
11376 ANGLE_TRY(GetPackPixelsParams(sizedFormatInfo, outputPitch, packState, packBuffer, area,
11377 clippedArea, paramsOut, skipBytesOut));
11378 return angle::Result::Continue;
11379 }
11380
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)11381 angle::Result ImageHelper::readPixelsForGetImage(ContextVk *contextVk,
11382 const gl::PixelPackState &packState,
11383 gl::Buffer *packBuffer,
11384 gl::LevelIndex levelGL,
11385 uint32_t layer,
11386 uint32_t layerCount,
11387 GLenum format,
11388 GLenum type,
11389 void *pixels)
11390 {
11391 const angle::Format &angleFormat = GetFormatFromFormatType(format, type);
11392
11393 VkImageAspectFlagBits aspectFlags = {};
11394 if (angleFormat.redBits > 0 || angleFormat.blueBits > 0 || angleFormat.greenBits > 0 ||
11395 angleFormat.alphaBits > 0 || angleFormat.luminanceBits > 0)
11396 {
11397 aspectFlags = static_cast<VkImageAspectFlagBits>(aspectFlags | VK_IMAGE_ASPECT_COLOR_BIT);
11398 }
11399 else
11400 {
11401 if (angleFormat.depthBits > 0)
11402 {
11403 aspectFlags =
11404 static_cast<VkImageAspectFlagBits>(aspectFlags | VK_IMAGE_ASPECT_DEPTH_BIT);
11405 }
11406 if (angleFormat.stencilBits > 0)
11407 {
11408 aspectFlags =
11409 static_cast<VkImageAspectFlagBits>(aspectFlags | VK_IMAGE_ASPECT_STENCIL_BIT);
11410 }
11411 }
11412
11413 ASSERT(aspectFlags != 0);
11414
11415 PackPixelsParams params;
11416 GLuint outputSkipBytes = 0;
11417
11418 const LevelIndex levelVk = toVkLevel(levelGL);
11419 const gl::Extents mipExtents = getLevelExtents(levelVk);
11420 gl::Rectangle area(0, 0, mipExtents.width, mipExtents.height);
11421
11422 ANGLE_TRY(GetReadPixelsParams(contextVk, packState, packBuffer, format, type, area, area,
11423 ¶ms, &outputSkipBytes));
11424
11425 if (mExtents.depth > 1 || layerCount > 1)
11426 {
11427 ASSERT(layer == 0);
11428 ASSERT(layerCount == 1 || mipExtents.depth == 1);
11429
11430 uint32_t lastLayer = std::max(static_cast<uint32_t>(mipExtents.depth), layerCount);
11431
11432 // Depth > 1 means this is a 3D texture and we need to copy all layers
11433 for (uint32_t mipLayer = 0; mipLayer < lastLayer; mipLayer++)
11434 {
11435 ANGLE_TRY(readPixels(contextVk, area, params, aspectFlags, levelGL, mipLayer,
11436 static_cast<uint8_t *>(pixels) + outputSkipBytes));
11437
11438 outputSkipBytes += mipExtents.width * mipExtents.height *
11439 gl::GetInternalFormatInfo(format, type).pixelBytes;
11440 }
11441 }
11442 else
11443 {
11444 ANGLE_TRY(readPixels(contextVk, area, params, aspectFlags, levelGL, layer,
11445 static_cast<uint8_t *>(pixels) + outputSkipBytes));
11446 }
11447
11448 return angle::Result::Continue;
11449 }
11450
readPixelsForCompressedGetImage(ContextVk * contextVk,const gl::PixelPackState & packState,gl::Buffer * packBuffer,gl::LevelIndex levelGL,uint32_t layer,uint32_t layerCount,void * pixels)11451 angle::Result ImageHelper::readPixelsForCompressedGetImage(ContextVk *contextVk,
11452 const gl::PixelPackState &packState,
11453 gl::Buffer *packBuffer,
11454 gl::LevelIndex levelGL,
11455 uint32_t layer,
11456 uint32_t layerCount,
11457 void *pixels)
11458 {
11459 PackPixelsParams params;
11460 GLuint outputSkipBytes = 0;
11461
11462 const LevelIndex levelVk = toVkLevel(levelGL);
11463 gl::Extents mipExtents = getLevelExtents(levelVk);
11464 gl::Rectangle area(0, 0, mipExtents.width, mipExtents.height);
11465
11466 VkImageAspectFlagBits aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT;
11467
11468 const angle::Format *readFormat = &getActualFormat();
11469
11470 // TODO(anglebug.com/42264702): Implement encoding for emuluated compression formats
11471 ANGLE_VK_CHECK(contextVk, readFormat->isBlock, VK_ERROR_FORMAT_NOT_SUPPORTED);
11472
11473 if (mExtents.depth > 1 || layerCount > 1)
11474 {
11475 ASSERT(layer == 0);
11476 ASSERT(layerCount == 1 || mipExtents.depth == 1);
11477
11478 uint32_t lastLayer = std::max(static_cast<uint32_t>(mipExtents.depth), layerCount);
11479
11480 const vk::Format &vkFormat = contextVk->getRenderer()->getFormat(readFormat->id);
11481 const gl::InternalFormat &storageFormatInfo =
11482 vkFormat.getInternalFormatInfo(readFormat->componentType);
11483
11484 // Calculate size for one layer
11485 mipExtents.depth = 1;
11486 GLuint layerSize;
11487 ANGLE_VK_CHECK_MATH(contextVk,
11488 storageFormatInfo.computeCompressedImageSize(mipExtents, &layerSize));
11489
11490 // Depth > 1 means this is a 3D texture and we need to copy all layers
11491 for (uint32_t mipLayer = 0; mipLayer < lastLayer; mipLayer++)
11492 {
11493 ANGLE_TRY(readPixels(contextVk, area, params, aspectFlags, levelGL, mipLayer,
11494 static_cast<uint8_t *>(pixels) + outputSkipBytes));
11495 outputSkipBytes += layerSize;
11496 }
11497 }
11498 else
11499 {
11500 ANGLE_TRY(readPixels(contextVk, area, params, aspectFlags, levelGL, layer,
11501 static_cast<uint8_t *>(pixels) + outputSkipBytes));
11502 }
11503
11504 return angle::Result::Continue;
11505 }
11506
readPixelsWithCompute(ContextVk * contextVk,ImageHelper * src,const PackPixelsParams & packPixelsParams,const VkOffset3D & srcOffset,const VkExtent3D & srcExtent,ptrdiff_t pixelsOffset,const VkImageSubresourceLayers & srcSubresource)11507 angle::Result ImageHelper::readPixelsWithCompute(ContextVk *contextVk,
11508 ImageHelper *src,
11509 const PackPixelsParams &packPixelsParams,
11510 const VkOffset3D &srcOffset,
11511 const VkExtent3D &srcExtent,
11512 ptrdiff_t pixelsOffset,
11513 const VkImageSubresourceLayers &srcSubresource)
11514 {
11515 ASSERT(srcOffset.z == 0 || srcSubresource.baseArrayLayer == 0);
11516
11517 UtilsVk::CopyImageToBufferParameters params = {};
11518 params.srcOffset[0] = srcOffset.x;
11519 params.srcOffset[1] = srcOffset.y;
11520 params.srcLayer = std::max<uint32_t>(srcOffset.z, srcSubresource.baseArrayLayer);
11521 params.srcMip = LevelIndex(srcSubresource.mipLevel);
11522 params.size[0] = srcExtent.width;
11523 params.size[1] = srcExtent.height;
11524 params.outputOffset = packPixelsParams.offset + pixelsOffset;
11525 params.outputPitch = packPixelsParams.outputPitch;
11526 params.reverseRowOrder = packPixelsParams.reverseRowOrder;
11527 params.outputFormat = packPixelsParams.destFormat;
11528
11529 BufferHelper &packBuffer = GetImpl(packPixelsParams.packBuffer)->getBuffer();
11530
11531 return contextVk->getUtils().copyImageToBuffer(contextVk, &packBuffer, src, params);
11532 }
11533
canCopyWithTransformForReadPixels(const PackPixelsParams & packPixelsParams,const VkExtent3D & srcExtent,const angle::Format * readFormat,ptrdiff_t pixelsOffset)11534 bool ImageHelper::canCopyWithTransformForReadPixels(const PackPixelsParams &packPixelsParams,
11535 const VkExtent3D &srcExtent,
11536 const angle::Format *readFormat,
11537 ptrdiff_t pixelsOffset)
11538 {
11539 ASSERT(mActualFormatID != angle::FormatID::NONE && mIntendedFormatID != angle::FormatID::NONE);
11540
11541 // Only allow copies to PBOs with identical format.
11542 const bool isSameFormatCopy = *readFormat == *packPixelsParams.destFormat;
11543
11544 // Disallow any transformation.
11545 const bool needsTransformation =
11546 packPixelsParams.rotation != SurfaceRotation::Identity || packPixelsParams.reverseRowOrder;
11547
11548 // Disallow copies when the output pitch cannot be correctly specified in Vulkan.
11549 const bool isPitchMultipleOfTexelSize =
11550 packPixelsParams.outputPitch % readFormat->pixelBytes == 0;
11551
11552 // Disallow copies when PBO offset violates Vulkan bufferOffset alignment requirements.
11553 const BufferHelper &packBuffer = GetImpl(packPixelsParams.packBuffer)->getBuffer();
11554 const VkDeviceSize offset = packBuffer.getOffset() + packPixelsParams.offset + pixelsOffset;
11555 const bool isOffsetMultipleOfTexelSize = offset % readFormat->pixelBytes == 0;
11556
11557 // Disallow copies when PBO row length is smaller than the source area width.
11558 const bool isRowLengthEnough =
11559 packPixelsParams.outputPitch >= srcExtent.width * readFormat->pixelBytes;
11560
11561 // Don't allow copies from emulated formats for simplicity.
11562 return !hasEmulatedImageFormat() && isSameFormatCopy && !needsTransformation &&
11563 isPitchMultipleOfTexelSize && isOffsetMultipleOfTexelSize && isRowLengthEnough;
11564 }
11565
canCopyWithComputeForReadPixels(const PackPixelsParams & packPixelsParams,const VkExtent3D & srcExtent,const angle::Format * readFormat,ptrdiff_t pixelsOffset)11566 bool ImageHelper::canCopyWithComputeForReadPixels(const PackPixelsParams &packPixelsParams,
11567 const VkExtent3D &srcExtent,
11568 const angle::Format *readFormat,
11569 ptrdiff_t pixelsOffset)
11570 {
11571 ASSERT(mActualFormatID != angle::FormatID::NONE && mIntendedFormatID != angle::FormatID::NONE);
11572 const angle::Format *writeFormat = packPixelsParams.destFormat;
11573
11574 // For now, only float formats are supported with 4-byte 4-channel normalized pixels for output.
11575 const bool isFloat =
11576 !readFormat->isSint() && !readFormat->isUint() && !readFormat->hasDepthOrStencilBits();
11577 const bool isFourByteOutput = writeFormat->pixelBytes == 4 && writeFormat->channelCount == 4;
11578 const bool isNormalizedOutput = writeFormat->isUnorm() || writeFormat->isSnorm();
11579
11580 // Disallow rotation.
11581 const bool needsTransformation = packPixelsParams.rotation != SurfaceRotation::Identity;
11582
11583 // Disallow copies when the output pitch cannot be correctly specified in Vulkan.
11584 const bool isPitchMultipleOfTexelSize =
11585 packPixelsParams.outputPitch % readFormat->pixelBytes == 0;
11586
11587 // Disallow copies when the output offset is not aligned to uint32_t
11588 const bool isOffsetMultipleOfUint =
11589 (packPixelsParams.offset + pixelsOffset) % readFormat->pixelBytes == 0;
11590
11591 // Disallow copies when PBO row length is smaller than the source area width.
11592 const bool isRowLengthEnough =
11593 packPixelsParams.outputPitch >= srcExtent.width * readFormat->pixelBytes;
11594
11595 return isFloat && isFourByteOutput && isNormalizedOutput && !needsTransformation &&
11596 isPitchMultipleOfTexelSize && isOffsetMultipleOfUint && isRowLengthEnough;
11597 }
11598
readPixels(ContextVk * contextVk,const gl::Rectangle & area,const PackPixelsParams & packPixelsParams,VkImageAspectFlagBits copyAspectFlags,gl::LevelIndex levelGL,uint32_t layer,void * pixels)11599 angle::Result ImageHelper::readPixels(ContextVk *contextVk,
11600 const gl::Rectangle &area,
11601 const PackPixelsParams &packPixelsParams,
11602 VkImageAspectFlagBits copyAspectFlags,
11603 gl::LevelIndex levelGL,
11604 uint32_t layer,
11605 void *pixels)
11606 {
11607 ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::readPixels");
11608
11609 const angle::Format &readFormat = getActualFormat();
11610
11611 if (readFormat.depthBits == 0)
11612 {
11613 copyAspectFlags =
11614 static_cast<VkImageAspectFlagBits>(copyAspectFlags & ~VK_IMAGE_ASPECT_DEPTH_BIT);
11615 }
11616 if (readFormat.stencilBits == 0)
11617 {
11618 copyAspectFlags =
11619 static_cast<VkImageAspectFlagBits>(copyAspectFlags & ~VK_IMAGE_ASPECT_STENCIL_BIT);
11620 }
11621
11622 if (copyAspectFlags == IMAGE_ASPECT_DEPTH_STENCIL)
11623 {
11624 const angle::Format &depthFormat =
11625 GetDepthStencilImageToBufferFormat(readFormat, VK_IMAGE_ASPECT_DEPTH_BIT);
11626 const angle::Format &stencilFormat =
11627 GetDepthStencilImageToBufferFormat(readFormat, VK_IMAGE_ASPECT_STENCIL_BIT);
11628
11629 int depthOffset = 0;
11630 int stencilOffset = 0;
11631 switch (readFormat.id)
11632 {
11633 case angle::FormatID::D24_UNORM_S8_UINT:
11634 depthOffset = 1;
11635 stencilOffset = 0;
11636 break;
11637
11638 case angle::FormatID::D32_FLOAT_S8X24_UINT:
11639 depthOffset = 0;
11640 stencilOffset = 4;
11641 break;
11642
11643 default:
11644 UNREACHABLE();
11645 }
11646
11647 ASSERT(depthOffset > 0 || stencilOffset > 0);
11648 ASSERT(depthOffset + depthFormat.depthBits / 8 <= readFormat.pixelBytes);
11649 ASSERT(stencilOffset + stencilFormat.stencilBits / 8 <= readFormat.pixelBytes);
11650
11651 // Read the depth values, tightly-packed
11652 angle::MemoryBuffer depthBuffer;
11653 ANGLE_VK_CHECK_ALLOC(contextVk,
11654 depthBuffer.resize(depthFormat.pixelBytes * area.width * area.height));
11655 ANGLE_TRY(
11656 readPixelsImpl(contextVk, area,
11657 PackPixelsParams(area, depthFormat, depthFormat.pixelBytes * area.width,
11658 false, nullptr, 0),
11659 VK_IMAGE_ASPECT_DEPTH_BIT, levelGL, layer, depthBuffer.data()));
11660
11661 // Read the stencil values, tightly-packed
11662 angle::MemoryBuffer stencilBuffer;
11663 ANGLE_VK_CHECK_ALLOC(
11664 contextVk, stencilBuffer.resize(stencilFormat.pixelBytes * area.width * area.height));
11665 ANGLE_TRY(readPixelsImpl(
11666 contextVk, area,
11667 PackPixelsParams(area, stencilFormat, stencilFormat.pixelBytes * area.width, false,
11668 nullptr, 0),
11669 VK_IMAGE_ASPECT_STENCIL_BIT, levelGL, layer, stencilBuffer.data()));
11670
11671 // Interleave them together
11672 angle::MemoryBuffer readPixelBuffer;
11673 ANGLE_VK_CHECK_ALLOC(
11674 contextVk, readPixelBuffer.resize(readFormat.pixelBytes * area.width * area.height));
11675 readPixelBuffer.fill(0);
11676 for (int i = 0; i < area.width * area.height; i++)
11677 {
11678 uint8_t *readPixel = readPixelBuffer.data() + i * readFormat.pixelBytes;
11679 memcpy(readPixel + depthOffset, depthBuffer.data() + i * depthFormat.pixelBytes,
11680 depthFormat.depthBits / 8);
11681 memcpy(readPixel + stencilOffset, stencilBuffer.data() + i * stencilFormat.pixelBytes,
11682 stencilFormat.stencilBits / 8);
11683 }
11684
11685 // Pack the interleaved depth and stencil into user-provided
11686 // destination, per user's pack pixels params
11687
11688 // The compressed format path in packReadPixelBuffer isn't applicable
11689 // to our case, let's make extra sure we won't hit it
11690 ASSERT(!readFormat.isBlock);
11691 return packReadPixelBuffer(contextVk, area, packPixelsParams, readFormat, readFormat,
11692 readPixelBuffer.data(), levelGL, pixels);
11693 }
11694
11695 return readPixelsImpl(contextVk, area, packPixelsParams, copyAspectFlags, levelGL, layer,
11696 pixels);
11697 }
11698
readPixelsImpl(ContextVk * contextVk,const gl::Rectangle & area,const PackPixelsParams & packPixelsParams,VkImageAspectFlagBits copyAspectFlags,gl::LevelIndex levelGL,uint32_t layer,void * pixels)11699 angle::Result ImageHelper::readPixelsImpl(ContextVk *contextVk,
11700 const gl::Rectangle &area,
11701 const PackPixelsParams &packPixelsParams,
11702 VkImageAspectFlagBits copyAspectFlags,
11703 gl::LevelIndex levelGL,
11704 uint32_t layer,
11705 void *pixels)
11706 {
11707 ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::readPixelsImpl");
11708
11709 Renderer *renderer = contextVk->getRenderer();
11710
11711 bool isExternalFormat = getExternalFormat() != 0;
11712 ASSERT(!isExternalFormat || (mActualFormatID >= angle::FormatID::EXTERNAL0 &&
11713 mActualFormatID <= angle::FormatID::EXTERNAL7));
11714
11715 // If the source image is multisampled, we need to resolve it into a temporary image before
11716 // performing a readback.
11717 bool isMultisampled = mSamples > 1;
11718 RendererScoped<ImageHelper> resolvedImage(contextVk->getRenderer());
11719
11720 ImageHelper *src = this;
11721
11722 ASSERT(!hasStagedUpdatesForSubresource(levelGL, layer, 1));
11723
11724 if (isMultisampled)
11725 {
11726 ANGLE_TRY(resolvedImage.get().init2DStaging(
11727 contextVk, contextVk->getState().hasProtectedContent(), renderer->getMemoryProperties(),
11728 gl::Extents(area.width, area.height, 1), mIntendedFormatID, mActualFormatID,
11729 VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
11730 VK_IMAGE_USAGE_SAMPLED_BIT,
11731 1));
11732 }
11733 else if (isExternalFormat)
11734 {
11735 ANGLE_TRY(resolvedImage.get().init2DStaging(
11736 contextVk, contextVk->getState().hasProtectedContent(), renderer->getMemoryProperties(),
11737 gl::Extents(area.width, area.height, 1), angle::FormatID::R8G8B8A8_UNORM,
11738 angle::FormatID::R8G8B8A8_UNORM,
11739 VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
11740 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
11741 1));
11742 }
11743
11744 VkImageAspectFlags layoutChangeAspectFlags = src->getAspectFlags();
11745
11746 const angle::Format *rgbaFormat = &angle::Format::Get(angle::FormatID::R8G8B8A8_UNORM);
11747 const angle::Format *readFormat = isExternalFormat ? rgbaFormat : &getActualFormat();
11748 const vk::Format &vkFormat = contextVk->getRenderer()->getFormat(readFormat->id);
11749 const gl::InternalFormat &storageFormatInfo =
11750 vkFormat.getInternalFormatInfo(readFormat->componentType);
11751
11752 if (copyAspectFlags != VK_IMAGE_ASPECT_COLOR_BIT)
11753 {
11754 readFormat = &GetDepthStencilImageToBufferFormat(*readFormat, copyAspectFlags);
11755 }
11756
11757 VkOffset3D srcOffset = {area.x, area.y, 0};
11758
11759 VkImageSubresourceLayers srcSubresource = {};
11760 srcSubresource.aspectMask = copyAspectFlags;
11761 srcSubresource.mipLevel = toVkLevel(levelGL).get();
11762 srcSubresource.baseArrayLayer = layer;
11763 srcSubresource.layerCount = 1;
11764
11765 VkExtent3D srcExtent = {static_cast<uint32_t>(area.width), static_cast<uint32_t>(area.height),
11766 1};
11767
11768 if (mExtents.depth > 1)
11769 {
11770 // Depth > 1 means this is a 3D texture and we need special handling
11771 srcOffset.z = layer;
11772 srcSubresource.baseArrayLayer = 0;
11773 }
11774
11775 if (isExternalFormat)
11776 {
11777 // Make sure the render pass is closed, per UtilsVk::copyImage's requirements.
11778 ANGLE_TRY(
11779 contextVk->flushCommandsAndEndRenderPass(RenderPassClosureReason::PrepareForImageCopy));
11780
11781 CommandBufferAccess access;
11782 OutsideRenderPassCommandBuffer *commandBuffer;
11783 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
11784
11785 // Create some temp views because copyImage works in terms of them
11786 gl::TextureType textureType = Get2DTextureType(1, resolvedImage.get().getSamples());
11787
11788 // Surely we have a view of this already!
11789 vk::ImageView srcView;
11790 ANGLE_TRY(src->initLayerImageView(contextVk, textureType, VK_IMAGE_ASPECT_COLOR_BIT,
11791 gl::SwizzleState(), &srcView, vk::LevelIndex(0), 1, 0,
11792 mLayerCount));
11793 vk::ImageView stagingView;
11794 ANGLE_TRY(resolvedImage.get().initLayerImageView(
11795 contextVk, textureType, VK_IMAGE_ASPECT_COLOR_BIT, gl::SwizzleState(), &stagingView,
11796 vk::LevelIndex(0), 1, 0, mLayerCount));
11797
11798 UtilsVk::CopyImageParameters params = {};
11799 params.srcOffset[0] = srcOffset.x;
11800 params.srcOffset[1] = srcOffset.y;
11801 params.srcExtents[0] = srcExtent.width;
11802 params.srcExtents[1] = srcExtent.height;
11803 params.srcHeight = srcExtent.height;
11804 ANGLE_TRY(contextVk->getUtils().copyImage(contextVk, &resolvedImage.get(), &stagingView,
11805 src, &srcView, params));
11806
11807 CommandBufferAccess readAccess;
11808 readAccess.onImageTransferRead(layoutChangeAspectFlags, &resolvedImage.get());
11809 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(readAccess, &commandBuffer));
11810
11811 // Make the resolved image the target of buffer copy
11812 src = &resolvedImage.get();
11813 srcOffset = {0, 0, 0};
11814 srcSubresource.baseArrayLayer = 0;
11815 srcSubresource.layerCount = 1;
11816 srcSubresource.mipLevel = 0;
11817
11818 // Mark our temp views as garbage immediately
11819 contextVk->addGarbage(&srcView);
11820 contextVk->addGarbage(&stagingView);
11821 }
11822
11823 if (isMultisampled)
11824 {
11825 CommandBufferAccess access;
11826 access.onImageTransferRead(layoutChangeAspectFlags, this);
11827 access.onImageTransferWrite(gl::LevelIndex(0), 1, 0, 1, layoutChangeAspectFlags,
11828 &resolvedImage.get());
11829
11830 OutsideRenderPassCommandBuffer *commandBuffer;
11831 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
11832
11833 // Note: resolve only works on color images (not depth/stencil).
11834 ASSERT(copyAspectFlags == VK_IMAGE_ASPECT_COLOR_BIT);
11835
11836 VkImageResolve resolveRegion = {};
11837 resolveRegion.srcSubresource = srcSubresource;
11838 resolveRegion.srcOffset = srcOffset;
11839 resolveRegion.dstSubresource.aspectMask = copyAspectFlags;
11840 resolveRegion.dstSubresource.mipLevel = 0;
11841 resolveRegion.dstSubresource.baseArrayLayer = 0;
11842 resolveRegion.dstSubresource.layerCount = 1;
11843 resolveRegion.dstOffset = {};
11844 resolveRegion.extent = srcExtent;
11845
11846 resolve(&resolvedImage.get(), resolveRegion, commandBuffer);
11847
11848 // Make the resolved image the target of buffer copy.
11849 src = &resolvedImage.get();
11850 srcOffset = {0, 0, 0};
11851 srcSubresource.baseArrayLayer = 0;
11852 srcSubresource.layerCount = 1;
11853 srcSubresource.mipLevel = 0;
11854 }
11855
11856 // If PBO and if possible, copy directly on the GPU.
11857 if (packPixelsParams.packBuffer)
11858 {
11859 ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::readPixelsImpl - PBO");
11860
11861 const ptrdiff_t pixelsOffset = reinterpret_cast<ptrdiff_t>(pixels);
11862 if (canCopyWithTransformForReadPixels(packPixelsParams, srcExtent, readFormat,
11863 pixelsOffset))
11864 {
11865 BufferHelper &packBuffer = GetImpl(packPixelsParams.packBuffer)->getBuffer();
11866 VkDeviceSize packBufferOffset = packBuffer.getOffset();
11867
11868 CommandBufferAccess copyAccess;
11869 copyAccess.onBufferTransferWrite(&packBuffer);
11870 copyAccess.onImageTransferRead(layoutChangeAspectFlags, src);
11871
11872 OutsideRenderPassCommandBuffer *copyCommandBuffer;
11873 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(copyAccess, ©CommandBuffer));
11874
11875 ASSERT(packPixelsParams.outputPitch % readFormat->pixelBytes == 0);
11876
11877 VkBufferImageCopy region = {};
11878 region.bufferImageHeight = srcExtent.height;
11879 region.bufferOffset = packBufferOffset + packPixelsParams.offset + pixelsOffset;
11880 region.bufferRowLength = packPixelsParams.outputPitch / readFormat->pixelBytes;
11881 region.imageExtent = srcExtent;
11882 region.imageOffset = srcOffset;
11883 region.imageSubresource = srcSubresource;
11884
11885 copyCommandBuffer->copyImageToBuffer(src->getImage(), src->getCurrentLayout(),
11886 packBuffer.getBuffer().getHandle(), 1, ®ion);
11887 return angle::Result::Continue;
11888 }
11889 if (canCopyWithComputeForReadPixels(packPixelsParams, srcExtent, readFormat, pixelsOffset))
11890 {
11891 ANGLE_TRY(readPixelsWithCompute(contextVk, src, packPixelsParams, srcOffset, srcExtent,
11892 pixelsOffset, srcSubresource));
11893 return angle::Result::Continue;
11894 }
11895 }
11896
11897 ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::readPixelsImpl - CPU Readback");
11898
11899 RendererScoped<vk::BufferHelper> readBuffer(renderer);
11900 vk::BufferHelper *stagingBuffer = &readBuffer.get();
11901
11902 uint8_t *readPixelBuffer = nullptr;
11903 VkDeviceSize stagingOffset = 0;
11904 size_t allocationSize = readFormat->pixelBytes * area.width * area.height;
11905
11906 ANGLE_TRY(contextVk->initBufferForImageCopy(stagingBuffer, allocationSize,
11907 MemoryCoherency::CachedPreferCoherent,
11908 readFormat->id, &stagingOffset, &readPixelBuffer));
11909 ANGLE_TRY(stagingBuffer->flush(renderer));
11910 VkBuffer bufferHandle = stagingBuffer->getBuffer().getHandle();
11911
11912 VkBufferImageCopy region = {};
11913 region.bufferImageHeight = srcExtent.height;
11914 region.bufferOffset = stagingOffset;
11915 region.bufferRowLength = srcExtent.width;
11916 region.imageExtent = srcExtent;
11917 region.imageOffset = srcOffset;
11918 region.imageSubresource = srcSubresource;
11919
11920 // For compressed textures, vkCmdCopyImageToBuffer requires
11921 // a region that is a multiple of the block size.
11922 if (readFormat->isBlock)
11923 {
11924 region.bufferRowLength =
11925 roundUp(region.bufferRowLength, storageFormatInfo.compressedBlockWidth);
11926 region.bufferImageHeight =
11927 roundUp(region.bufferImageHeight, storageFormatInfo.compressedBlockHeight);
11928 }
11929
11930 CommandBufferAccess readbackAccess;
11931 readbackAccess.onBufferTransferWrite(stagingBuffer);
11932 readbackAccess.onImageTransferRead(layoutChangeAspectFlags, src);
11933
11934 OutsideRenderPassCommandBuffer *readbackCommandBuffer;
11935 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(readbackAccess, &readbackCommandBuffer));
11936
11937 readbackCommandBuffer->copyImageToBuffer(src->getImage(), src->getCurrentLayout(), bufferHandle,
11938 1, ®ion);
11939
11940 ANGLE_VK_PERF_WARNING(contextVk, GL_DEBUG_SEVERITY_HIGH, "GPU stall due to ReadPixels");
11941
11942 // Triggers a full finish.
11943 ANGLE_TRY(contextVk->finishImpl(RenderPassClosureReason::GLReadPixels));
11944 // invalidate must be called after wait for finish.
11945 ANGLE_TRY(stagingBuffer->invalidate(renderer));
11946
11947 return packReadPixelBuffer(contextVk, area, packPixelsParams, getActualFormat(), *readFormat,
11948 readPixelBuffer, levelGL, pixels);
11949 }
11950
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)11951 angle::Result ImageHelper::packReadPixelBuffer(ContextVk *contextVk,
11952 const gl::Rectangle &area,
11953 const PackPixelsParams &packPixelsParams,
11954 const angle::Format &readFormat,
11955 const angle::Format &aspectFormat,
11956 const uint8_t *readPixelBuffer,
11957 gl::LevelIndex levelGL,
11958 void *pixels)
11959 {
11960 const vk::Format &vkFormat = contextVk->getRenderer()->getFormat(readFormat.id);
11961 const gl::InternalFormat &storageFormatInfo =
11962 vkFormat.getInternalFormatInfo(readFormat.componentType);
11963
11964 if (readFormat.isBlock)
11965 {
11966 ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::packReadPixelBuffer - Block");
11967
11968 ASSERT(readFormat == aspectFormat);
11969
11970 const LevelIndex levelVk = toVkLevel(levelGL);
11971 gl::Extents levelExtents = getLevelExtents(levelVk);
11972
11973 // Calculate size of one layer
11974 levelExtents.depth = 1;
11975 GLuint layerSize;
11976 ANGLE_VK_CHECK_MATH(contextVk,
11977 storageFormatInfo.computeCompressedImageSize(levelExtents, &layerSize));
11978 memcpy(pixels, readPixelBuffer, layerSize);
11979 }
11980 else if (packPixelsParams.packBuffer)
11981 {
11982 ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::packReadPixelBuffer - PBO");
11983
11984 // Must map the PBO in order to read its contents (and then unmap it later)
11985 BufferVk *packBufferVk = GetImpl(packPixelsParams.packBuffer);
11986 void *mapPtr = nullptr;
11987 ANGLE_TRY(packBufferVk->mapImpl(contextVk, GL_MAP_WRITE_BIT, &mapPtr));
11988 uint8_t *dst = static_cast<uint8_t *>(mapPtr) + reinterpret_cast<ptrdiff_t>(pixels);
11989 PackPixels(packPixelsParams, aspectFormat, area.width * aspectFormat.pixelBytes,
11990 readPixelBuffer, dst);
11991 ANGLE_TRY(packBufferVk->unmapImpl(contextVk));
11992 }
11993 else
11994 {
11995 PackPixels(packPixelsParams, aspectFormat, area.width * aspectFormat.pixelBytes,
11996 readPixelBuffer, static_cast<uint8_t *>(pixels));
11997 }
11998
11999 return angle::Result::Continue;
12000 }
12001
12002 // ImageHelper::SubresourceUpdate implementation
SubresourceUpdate()12003 ImageHelper::SubresourceUpdate::SubresourceUpdate() : updateSource(UpdateSource::Buffer)
12004 {
12005 data.buffer.bufferHelper = nullptr;
12006 refCounted.buffer = nullptr;
12007 }
12008
SubresourceUpdate(const VkImageAspectFlags aspectFlags,const VkClearValue & clearValue,const gl::TextureType textureType,const uint32_t levelIndex,const uint32_t layerIndex,const uint32_t layerCount,const gl::Box & clearArea)12009 ImageHelper::SubresourceUpdate::SubresourceUpdate(const VkImageAspectFlags aspectFlags,
12010 const VkClearValue &clearValue,
12011 const gl::TextureType textureType,
12012 const uint32_t levelIndex,
12013 const uint32_t layerIndex,
12014 const uint32_t layerCount,
12015 const gl::Box &clearArea)
12016 : updateSource(UpdateSource::ClearPartial)
12017 {
12018 data.clearPartial.aspectFlags = aspectFlags;
12019 data.clearPartial.levelIndex = levelIndex;
12020 data.clearPartial.textureType = textureType;
12021 data.clearPartial.layerIndex = layerIndex;
12022 data.clearPartial.layerCount = layerCount;
12023 data.clearPartial.offset = {clearArea.x, clearArea.y, clearArea.z};
12024 data.clearPartial.extent = {static_cast<uint32_t>(clearArea.width),
12025 static_cast<uint32_t>(clearArea.height),
12026 static_cast<uint32_t>(clearArea.depth)};
12027 data.clearPartial.clearValue = clearValue;
12028 }
12029
~SubresourceUpdate()12030 ImageHelper::SubresourceUpdate::~SubresourceUpdate() {}
12031
SubresourceUpdate(RefCounted<BufferHelper> * bufferIn,BufferHelper * bufferHelperIn,const VkBufferImageCopy & copyRegionIn,angle::FormatID formatID)12032 ImageHelper::SubresourceUpdate::SubresourceUpdate(RefCounted<BufferHelper> *bufferIn,
12033 BufferHelper *bufferHelperIn,
12034 const VkBufferImageCopy ©RegionIn,
12035 angle::FormatID formatID)
12036 : updateSource(UpdateSource::Buffer)
12037 {
12038 refCounted.buffer = bufferIn;
12039 if (refCounted.buffer != nullptr)
12040 {
12041 refCounted.buffer->addRef();
12042 }
12043 data.buffer.bufferHelper = bufferHelperIn;
12044 data.buffer.copyRegion = copyRegionIn;
12045 data.buffer.formatID = formatID;
12046 }
12047
SubresourceUpdate(RefCounted<ImageHelper> * imageIn,const VkImageCopy & copyRegionIn,angle::FormatID formatID)12048 ImageHelper::SubresourceUpdate::SubresourceUpdate(RefCounted<ImageHelper> *imageIn,
12049 const VkImageCopy ©RegionIn,
12050 angle::FormatID formatID)
12051 : updateSource(UpdateSource::Image)
12052 {
12053 refCounted.image = imageIn;
12054 refCounted.image->addRef();
12055 data.image.copyRegion = copyRegionIn;
12056 data.image.formatID = formatID;
12057 }
12058
SubresourceUpdate(VkImageAspectFlags aspectFlags,const VkClearValue & clearValue,const gl::ImageIndex & imageIndex)12059 ImageHelper::SubresourceUpdate::SubresourceUpdate(VkImageAspectFlags aspectFlags,
12060 const VkClearValue &clearValue,
12061 const gl::ImageIndex &imageIndex)
12062 : SubresourceUpdate(
12063 aspectFlags,
12064 clearValue,
12065 gl::LevelIndex(imageIndex.getLevelIndex()),
12066 imageIndex.hasLayer() ? imageIndex.getLayerIndex() : 0,
12067 imageIndex.hasLayer() ? imageIndex.getLayerCount() : VK_REMAINING_ARRAY_LAYERS)
12068 {}
12069
SubresourceUpdate(VkImageAspectFlags aspectFlags,const VkClearValue & clearValue,gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount)12070 ImageHelper::SubresourceUpdate::SubresourceUpdate(VkImageAspectFlags aspectFlags,
12071 const VkClearValue &clearValue,
12072 gl::LevelIndex level,
12073 uint32_t layerIndex,
12074 uint32_t layerCount)
12075 : updateSource(UpdateSource::Clear)
12076 {
12077 refCounted.image = nullptr;
12078 data.clear.aspectFlags = aspectFlags;
12079 data.clear.value = clearValue;
12080 data.clear.levelIndex = level.get();
12081 data.clear.layerIndex = layerIndex;
12082 data.clear.layerCount = layerCount;
12083 data.clear.colorMaskFlags = 0;
12084 }
12085
SubresourceUpdate(VkColorComponentFlags colorMaskFlags,const VkClearColorValue & clearValue,const gl::ImageIndex & imageIndex)12086 ImageHelper::SubresourceUpdate::SubresourceUpdate(VkColorComponentFlags colorMaskFlags,
12087 const VkClearColorValue &clearValue,
12088 const gl::ImageIndex &imageIndex)
12089 : updateSource(UpdateSource::ClearEmulatedChannelsOnly)
12090 {
12091 refCounted.image = nullptr;
12092 data.clear.aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT;
12093 data.clear.value.color = clearValue;
12094 data.clear.levelIndex = imageIndex.getLevelIndex();
12095 data.clear.layerIndex = imageIndex.hasLayer() ? imageIndex.getLayerIndex() : 0;
12096 data.clear.layerCount =
12097 imageIndex.hasLayer() ? imageIndex.getLayerCount() : VK_REMAINING_ARRAY_LAYERS;
12098 data.clear.colorMaskFlags = colorMaskFlags;
12099 }
12100
SubresourceUpdate(const SubresourceUpdate & other)12101 ImageHelper::SubresourceUpdate::SubresourceUpdate(const SubresourceUpdate &other)
12102 : updateSource(other.updateSource)
12103 {
12104 switch (updateSource)
12105 {
12106 case UpdateSource::Clear:
12107 case UpdateSource::ClearEmulatedChannelsOnly:
12108 case UpdateSource::ClearAfterInvalidate:
12109 data.clear = other.data.clear;
12110 refCounted.buffer = nullptr;
12111 break;
12112 case UpdateSource::ClearPartial:
12113 data.clearPartial = other.data.clearPartial;
12114 break;
12115 case UpdateSource::Buffer:
12116 data.buffer = other.data.buffer;
12117 refCounted.buffer = other.refCounted.buffer;
12118 break;
12119 case UpdateSource::Image:
12120 data.image = other.data.image;
12121 refCounted.image = other.refCounted.image;
12122 break;
12123 default:
12124 UNREACHABLE();
12125 }
12126 }
12127
SubresourceUpdate(SubresourceUpdate && other)12128 ImageHelper::SubresourceUpdate::SubresourceUpdate(SubresourceUpdate &&other)
12129 : updateSource(other.updateSource)
12130 {
12131 switch (updateSource)
12132 {
12133 case UpdateSource::Clear:
12134 case UpdateSource::ClearEmulatedChannelsOnly:
12135 case UpdateSource::ClearAfterInvalidate:
12136 data.clear = other.data.clear;
12137 refCounted.buffer = nullptr;
12138 break;
12139 case UpdateSource::ClearPartial:
12140 data.clearPartial = other.data.clearPartial;
12141 break;
12142 case UpdateSource::Buffer:
12143 data.buffer = other.data.buffer;
12144 refCounted.buffer = other.refCounted.buffer;
12145 other.refCounted.buffer = nullptr;
12146 break;
12147 case UpdateSource::Image:
12148 data.image = other.data.image;
12149 refCounted.image = other.refCounted.image;
12150 other.refCounted.image = nullptr;
12151 break;
12152 default:
12153 UNREACHABLE();
12154 }
12155 }
12156
operator =(SubresourceUpdate && other)12157 ImageHelper::SubresourceUpdate &ImageHelper::SubresourceUpdate::operator=(SubresourceUpdate &&other)
12158 {
12159 // Given that the update is a union of three structs, we can't use std::swap on the fields. For
12160 // example, |this| may be an Image update and |other| may be a Buffer update.
12161 // The following could work:
12162 //
12163 // SubresourceUpdate oldThis;
12164 // Set oldThis to this->field based on updateSource
12165 // Set this->otherField to other.otherField based on other.updateSource
12166 // Set other.field to oldThis->field based on updateSource
12167 // std::Swap(updateSource, other.updateSource);
12168 //
12169 // It's much simpler to just swap the memory instead.
12170
12171 SubresourceUpdate oldThis;
12172 memcpy(&oldThis, this, sizeof(*this));
12173 memcpy(this, &other, sizeof(*this));
12174 memcpy(&other, &oldThis, sizeof(*this));
12175
12176 return *this;
12177 }
12178
release(Renderer * renderer)12179 void ImageHelper::SubresourceUpdate::release(Renderer *renderer)
12180 {
12181 if (updateSource == UpdateSource::Image)
12182 {
12183 refCounted.image->releaseRef();
12184
12185 if (!refCounted.image->isReferenced())
12186 {
12187 // Staging images won't be used in render pass attachments.
12188 refCounted.image->get().releaseImage(renderer);
12189 refCounted.image->get().releaseStagedUpdates(renderer);
12190 SafeDelete(refCounted.image);
12191 }
12192
12193 refCounted.image = nullptr;
12194 }
12195 else if (updateSource == UpdateSource::Buffer && refCounted.buffer != nullptr)
12196 {
12197 refCounted.buffer->releaseRef();
12198
12199 if (!refCounted.buffer->isReferenced())
12200 {
12201 refCounted.buffer->get().release(renderer);
12202 SafeDelete(refCounted.buffer);
12203 }
12204
12205 refCounted.buffer = nullptr;
12206 }
12207 }
12208
matchesLayerRange(uint32_t layerIndex,uint32_t layerCount) const12209 bool ImageHelper::SubresourceUpdate::matchesLayerRange(uint32_t layerIndex,
12210 uint32_t layerCount) const
12211 {
12212 uint32_t updateBaseLayer, updateLayerCount;
12213 getDestSubresource(gl::ImageIndex::kEntireLevel, &updateBaseLayer, &updateLayerCount);
12214
12215 return updateBaseLayer == layerIndex &&
12216 (updateLayerCount == layerCount || updateLayerCount == VK_REMAINING_ARRAY_LAYERS);
12217 }
12218
intersectsLayerRange(uint32_t layerIndex,uint32_t layerCount) const12219 bool ImageHelper::SubresourceUpdate::intersectsLayerRange(uint32_t layerIndex,
12220 uint32_t layerCount) const
12221 {
12222 uint32_t updateBaseLayer, updateLayerCount;
12223 getDestSubresource(gl::ImageIndex::kEntireLevel, &updateBaseLayer, &updateLayerCount);
12224 uint32_t updateLayerEnd = updateBaseLayer + updateLayerCount;
12225
12226 return updateBaseLayer < (layerIndex + layerCount) && updateLayerEnd > layerIndex;
12227 }
12228
getDestSubresource(uint32_t imageLayerCount,uint32_t * baseLayerOut,uint32_t * layerCountOut) const12229 void ImageHelper::SubresourceUpdate::getDestSubresource(uint32_t imageLayerCount,
12230 uint32_t *baseLayerOut,
12231 uint32_t *layerCountOut) const
12232 {
12233 if (IsClear(updateSource))
12234 {
12235 *baseLayerOut = data.clear.layerIndex;
12236 *layerCountOut = data.clear.layerCount;
12237
12238 if (*layerCountOut == static_cast<uint32_t>(gl::ImageIndex::kEntireLevel))
12239 {
12240 *layerCountOut = imageLayerCount;
12241 }
12242 }
12243 else if (updateSource == UpdateSource::ClearPartial)
12244 {
12245 *baseLayerOut = data.clearPartial.layerIndex;
12246 *layerCountOut = data.clearPartial.layerCount;
12247
12248 if (*layerCountOut == static_cast<uint32_t>(gl::ImageIndex::kEntireLevel))
12249 {
12250 *layerCountOut = imageLayerCount;
12251 }
12252 }
12253 else
12254 {
12255 const VkImageSubresourceLayers &dstSubresource =
12256 updateSource == UpdateSource::Buffer ? data.buffer.copyRegion.imageSubresource
12257 : data.image.copyRegion.dstSubresource;
12258 *baseLayerOut = dstSubresource.baseArrayLayer;
12259 *layerCountOut = dstSubresource.layerCount;
12260
12261 ASSERT(*layerCountOut != static_cast<uint32_t>(gl::ImageIndex::kEntireLevel));
12262 }
12263 }
12264
getDestAspectFlags() const12265 VkImageAspectFlags ImageHelper::SubresourceUpdate::getDestAspectFlags() const
12266 {
12267 if (IsClear(updateSource))
12268 {
12269 return data.clear.aspectFlags;
12270 }
12271 else if (updateSource == UpdateSource::ClearPartial)
12272 {
12273 return data.clearPartial.aspectFlags;
12274 }
12275 else if (updateSource == UpdateSource::Buffer)
12276 {
12277 return data.buffer.copyRegion.imageSubresource.aspectMask;
12278 }
12279 else
12280 {
12281 ASSERT(updateSource == UpdateSource::Image);
12282 return data.image.copyRegion.dstSubresource.aspectMask;
12283 }
12284 }
12285
getLevelUpdateCount(gl::LevelIndex level) const12286 size_t ImageHelper::getLevelUpdateCount(gl::LevelIndex level) const
12287 {
12288 return static_cast<size_t>(level.get()) < mSubresourceUpdates.size()
12289 ? mSubresourceUpdates[level.get()].size()
12290 : 0;
12291 }
12292
clipLevelToUpdateListUpperLimit(gl::LevelIndex * level) const12293 void ImageHelper::clipLevelToUpdateListUpperLimit(gl::LevelIndex *level) const
12294 {
12295 gl::LevelIndex levelLimit(static_cast<int>(mSubresourceUpdates.size()));
12296 *level = std::min(*level, levelLimit);
12297 }
12298
getLevelUpdates(gl::LevelIndex level)12299 ImageHelper::SubresourceUpdates *ImageHelper::getLevelUpdates(gl::LevelIndex level)
12300 {
12301 return static_cast<size_t>(level.get()) < mSubresourceUpdates.size()
12302 ? &mSubresourceUpdates[level.get()]
12303 : nullptr;
12304 }
12305
getLevelUpdates(gl::LevelIndex level) const12306 const ImageHelper::SubresourceUpdates *ImageHelper::getLevelUpdates(gl::LevelIndex level) const
12307 {
12308 return static_cast<size_t>(level.get()) < mSubresourceUpdates.size()
12309 ? &mSubresourceUpdates[level.get()]
12310 : nullptr;
12311 }
12312
appendSubresourceUpdate(gl::LevelIndex level,SubresourceUpdate && update)12313 void ImageHelper::appendSubresourceUpdate(gl::LevelIndex level, SubresourceUpdate &&update)
12314 {
12315 if (mSubresourceUpdates.size() <= static_cast<size_t>(level.get()))
12316 {
12317 mSubresourceUpdates.resize(level.get() + 1);
12318 }
12319 // Update total staging buffer size
12320 mTotalStagedBufferUpdateSize += update.updateSource == UpdateSource::Buffer
12321 ? update.data.buffer.bufferHelper->getSize()
12322 : 0;
12323 mSubresourceUpdates[level.get()].emplace_back(std::move(update));
12324 onStateChange(angle::SubjectMessage::SubjectChanged);
12325 }
12326
prependSubresourceUpdate(gl::LevelIndex level,SubresourceUpdate && update)12327 void ImageHelper::prependSubresourceUpdate(gl::LevelIndex level, SubresourceUpdate &&update)
12328 {
12329 if (mSubresourceUpdates.size() <= static_cast<size_t>(level.get()))
12330 {
12331 mSubresourceUpdates.resize(level.get() + 1);
12332 }
12333
12334 // Update total staging buffer size
12335 mTotalStagedBufferUpdateSize += update.updateSource == UpdateSource::Buffer
12336 ? update.data.buffer.bufferHelper->getSize()
12337 : 0;
12338 mSubresourceUpdates[level.get()].emplace_front(std::move(update));
12339 onStateChange(angle::SubjectMessage::SubjectChanged);
12340 }
12341
hasEmulatedImageChannels() const12342 bool ImageHelper::hasEmulatedImageChannels() const
12343 {
12344 const angle::Format &angleFmt = getIntendedFormat();
12345 const angle::Format &textureFmt = getActualFormat();
12346
12347 // Block formats may be decoded and emulated with a non-block format.
12348 if (angleFmt.isBlock)
12349 {
12350 return !textureFmt.isBlock;
12351 }
12352
12353 // The red channel is never emulated.
12354 ASSERT((angleFmt.redBits != 0 || angleFmt.luminanceBits != 0 || angleFmt.alphaBits != 0) ==
12355 (textureFmt.redBits != 0));
12356
12357 return (angleFmt.alphaBits == 0 && textureFmt.alphaBits > 0) ||
12358 (angleFmt.blueBits == 0 && textureFmt.blueBits > 0) ||
12359 (angleFmt.greenBits == 0 && textureFmt.greenBits > 0) ||
12360 (angleFmt.depthBits == 0 && textureFmt.depthBits > 0) ||
12361 (angleFmt.stencilBits == 0 && textureFmt.stencilBits > 0);
12362 }
12363
hasEmulatedDepthChannel() const12364 bool ImageHelper::hasEmulatedDepthChannel() const
12365 {
12366 return getIntendedFormat().depthBits == 0 && getActualFormat().depthBits > 0;
12367 }
12368
hasEmulatedStencilChannel() const12369 bool ImageHelper::hasEmulatedStencilChannel() const
12370 {
12371 return getIntendedFormat().stencilBits == 0 && getActualFormat().stencilBits > 0;
12372 }
12373
hasInefficientlyEmulatedImageFormat() const12374 bool ImageHelper::hasInefficientlyEmulatedImageFormat() const
12375 {
12376 if (hasEmulatedImageFormat())
12377 {
12378 // ETC2 compression is compatible with ETC1
12379 return !(mIntendedFormatID == angle::FormatID::ETC1_R8G8B8_UNORM_BLOCK &&
12380 mActualFormatID == angle::FormatID::ETC2_R8G8B8_UNORM_BLOCK);
12381 }
12382 return false;
12383 }
12384
getEmulatedChannelsMask() const12385 VkColorComponentFlags ImageHelper::getEmulatedChannelsMask() const
12386 {
12387 const angle::Format &angleFmt = getIntendedFormat();
12388 const angle::Format &textureFmt = getActualFormat();
12389
12390 ASSERT(!angleFmt.hasDepthOrStencilBits());
12391
12392 VkColorComponentFlags emulatedChannelsMask = 0;
12393
12394 if (angleFmt.alphaBits == 0 && textureFmt.alphaBits > 0)
12395 {
12396 emulatedChannelsMask |= VK_COLOR_COMPONENT_A_BIT;
12397 }
12398 if (angleFmt.blueBits == 0 && textureFmt.blueBits > 0)
12399 {
12400 emulatedChannelsMask |= VK_COLOR_COMPONENT_B_BIT;
12401 }
12402 if (angleFmt.greenBits == 0 && textureFmt.greenBits > 0)
12403 {
12404 emulatedChannelsMask |= VK_COLOR_COMPONENT_G_BIT;
12405 }
12406
12407 // The red channel is never emulated.
12408 ASSERT((angleFmt.redBits != 0 || angleFmt.luminanceBits != 0 || angleFmt.alphaBits != 0) ==
12409 (textureFmt.redBits != 0));
12410
12411 return emulatedChannelsMask;
12412 }
12413
GetLayerMode(const vk::ImageHelper & image,uint32_t layerCount)12414 LayerMode GetLayerMode(const vk::ImageHelper &image, uint32_t layerCount)
12415 {
12416 const uint32_t imageLayerCount = GetImageLayerCountForView(image);
12417 const bool allLayers = layerCount == imageLayerCount;
12418
12419 ASSERT(allLayers || (layerCount > 0 && layerCount <= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS));
12420 return allLayers ? LayerMode::All : static_cast<LayerMode>(layerCount);
12421 }
12422
GetComputePipelineOptions(vk::PipelineRobustness robustness,vk::PipelineProtectedAccess protectedAccess)12423 ComputePipelineOptions GetComputePipelineOptions(vk::PipelineRobustness robustness,
12424 vk::PipelineProtectedAccess protectedAccess)
12425 {
12426 vk::ComputePipelineOptions pipelineOptions = {};
12427
12428 if (robustness == vk::PipelineRobustness::Robust)
12429 {
12430 pipelineOptions.robustness = 1;
12431 }
12432 if (protectedAccess == vk::PipelineProtectedAccess::Protected)
12433 {
12434 pipelineOptions.protectedAccess = 1;
12435 }
12436
12437 return pipelineOptions;
12438 }
12439
12440 // ImageViewHelper implementation.
ImageViewHelper()12441 ImageViewHelper::ImageViewHelper()
12442 : mCurrentBaseMaxLevelHash(0),
12443 mIsCopyImageViewShared(false),
12444 mReadColorspace(ImageViewColorspace::Invalid),
12445 mWriteColorspace(ImageViewColorspace::Invalid)
12446 {}
12447
ImageViewHelper(ImageViewHelper && other)12448 ImageViewHelper::ImageViewHelper(ImageViewHelper &&other)
12449 {
12450 std::swap(mCurrentBaseMaxLevelHash, other.mCurrentBaseMaxLevelHash);
12451 std::swap(mReadColorspace, other.mReadColorspace);
12452 std::swap(mWriteColorspace, other.mWriteColorspace);
12453 std::swap(mColorspaceState, other.mColorspaceState);
12454
12455 std::swap(mPerLevelRangeLinearReadImageViews, other.mPerLevelRangeLinearReadImageViews);
12456 std::swap(mPerLevelRangeSRGBReadImageViews, other.mPerLevelRangeSRGBReadImageViews);
12457 std::swap(mPerLevelRangeLinearCopyImageViews, other.mPerLevelRangeLinearCopyImageViews);
12458 std::swap(mPerLevelRangeSRGBCopyImageViews, other.mPerLevelRangeSRGBCopyImageViews);
12459 std::swap(mIsCopyImageViewShared, other.mIsCopyImageViewShared);
12460 std::swap(mPerLevelRangeStencilReadImageViews, other.mPerLevelRangeStencilReadImageViews);
12461 std::swap(mPerLevelRangeSamplerExternal2DY2YEXTImageViews,
12462 other.mPerLevelRangeSamplerExternal2DY2YEXTImageViews);
12463
12464 std::swap(mLayerLevelDrawImageViews, other.mLayerLevelDrawImageViews);
12465 std::swap(mLayerLevelDrawImageViewsLinear, other.mLayerLevelDrawImageViewsLinear);
12466 std::swap(mSubresourceDrawImageViews, other.mSubresourceDrawImageViews);
12467
12468 std::swap(mLayerLevelDepthOnlyImageViews, other.mLayerLevelDepthOnlyImageViews);
12469 std::swap(mLayerLevelStencilOnlyImageViews, other.mLayerLevelStencilOnlyImageViews);
12470 std::swap(mSubresourceDepthOnlyImageViews, other.mSubresourceDepthOnlyImageViews);
12471 std::swap(mSubresourceStencilOnlyImageViews, other.mSubresourceStencilOnlyImageViews);
12472
12473 std::swap(mLevelStorageImageViews, other.mLevelStorageImageViews);
12474 std::swap(mLayerLevelStorageImageViews, other.mLayerLevelStorageImageViews);
12475 std::swap(mFragmentShadingRateImageView, other.mFragmentShadingRateImageView);
12476 std::swap(mImageViewSerial, other.mImageViewSerial);
12477 }
12478
~ImageViewHelper()12479 ImageViewHelper::~ImageViewHelper() {}
12480
init(Renderer * renderer)12481 void ImageViewHelper::init(Renderer *renderer)
12482 {
12483 if (!mImageViewSerial.valid())
12484 {
12485 mImageViewSerial = renderer->getResourceSerialFactory().generateImageOrBufferViewSerial();
12486 }
12487 }
12488
release(Renderer * renderer,const ResourceUse & use)12489 void ImageViewHelper::release(Renderer *renderer, const ResourceUse &use)
12490 {
12491 mCurrentBaseMaxLevelHash = 0;
12492 mReadColorspace = ImageViewColorspace::Invalid;
12493 mWriteColorspace = ImageViewColorspace::Invalid;
12494 // Clear shared flag
12495 mIsCopyImageViewShared = false;
12496 mColorspaceState.reset();
12497
12498 GarbageObjects garbage;
12499 // Reserve reasonable amount of storage
12500 garbage.reserve(4);
12501
12502 // Release the read views
12503 ReleaseImageViews(&mPerLevelRangeLinearReadImageViews, &garbage);
12504 ReleaseImageViews(&mPerLevelRangeSRGBReadImageViews, &garbage);
12505 ReleaseImageViews(&mPerLevelRangeLinearCopyImageViews, &garbage);
12506 ReleaseImageViews(&mPerLevelRangeSRGBCopyImageViews, &garbage);
12507 ReleaseImageViews(&mPerLevelRangeStencilReadImageViews, &garbage);
12508 ReleaseImageViews(&mPerLevelRangeSamplerExternal2DY2YEXTImageViews, &garbage);
12509
12510 // Release the draw views
12511 ReleaseLayerLevelImageViews(&mLayerLevelDrawImageViews, &garbage);
12512 ReleaseLayerLevelImageViews(&mLayerLevelDrawImageViewsLinear, &garbage);
12513 ReleaseSubresourceImageViews(&mSubresourceDrawImageViews, &garbage);
12514
12515 // Release the depth-xor-stencil input views
12516 ReleaseLayerLevelImageViews(&mLayerLevelDepthOnlyImageViews, &garbage);
12517 ReleaseLayerLevelImageViews(&mLayerLevelStencilOnlyImageViews, &garbage);
12518 ReleaseSubresourceImageViews(&mSubresourceDepthOnlyImageViews, &garbage);
12519 ReleaseSubresourceImageViews(&mSubresourceStencilOnlyImageViews, &garbage);
12520
12521 // Release the storage views
12522 ReleaseImageViews(&mLevelStorageImageViews, &garbage);
12523 ReleaseLayerLevelImageViews(&mLayerLevelStorageImageViews, &garbage);
12524
12525 // Release fragment shading rate view
12526 if (mFragmentShadingRateImageView.valid())
12527 {
12528 garbage.emplace_back(GetGarbage(&mFragmentShadingRateImageView));
12529 }
12530
12531 if (!garbage.empty())
12532 {
12533 renderer->collectGarbage(use, std::move(garbage));
12534 }
12535
12536 // Update image view serial.
12537 mImageViewSerial = renderer->getResourceSerialFactory().generateImageOrBufferViewSerial();
12538 }
12539
isImageViewGarbageEmpty() const12540 bool ImageViewHelper::isImageViewGarbageEmpty() const
12541 {
12542 return mPerLevelRangeLinearReadImageViews.empty() &&
12543 mPerLevelRangeLinearCopyImageViews.empty() && mPerLevelRangeSRGBReadImageViews.empty() &&
12544 mPerLevelRangeSRGBCopyImageViews.empty() &&
12545 mPerLevelRangeStencilReadImageViews.empty() &&
12546 mPerLevelRangeSamplerExternal2DY2YEXTImageViews.empty() &&
12547 mLayerLevelDrawImageViews.empty() && mLayerLevelDrawImageViewsLinear.empty() &&
12548 mSubresourceDrawImageViews.empty() && mLayerLevelDepthOnlyImageViews.empty() &&
12549 mLayerLevelStencilOnlyImageViews.empty() && mSubresourceDepthOnlyImageViews.empty() &&
12550 mSubresourceStencilOnlyImageViews.empty() && mLayerLevelStorageImageViews.empty();
12551 }
12552
destroy(VkDevice device)12553 void ImageViewHelper::destroy(VkDevice device)
12554 {
12555 mCurrentBaseMaxLevelHash = 0;
12556 mReadColorspace = ImageViewColorspace::Invalid;
12557 mWriteColorspace = ImageViewColorspace::Invalid;
12558 mColorspaceState.reset();
12559
12560 // Release the read views
12561 DestroyImageViews(&mPerLevelRangeLinearReadImageViews, device);
12562 DestroyImageViews(&mPerLevelRangeSRGBReadImageViews, device);
12563 DestroyImageViews(&mPerLevelRangeLinearCopyImageViews, device);
12564 DestroyImageViews(&mPerLevelRangeSRGBCopyImageViews, device);
12565 DestroyImageViews(&mPerLevelRangeStencilReadImageViews, device);
12566 DestroyImageViews(&mPerLevelRangeSamplerExternal2DY2YEXTImageViews, device);
12567
12568 // Release the draw views
12569 DestroyLayerLevelImageViews(&mLayerLevelDrawImageViews, device);
12570 DestroyLayerLevelImageViews(&mLayerLevelDrawImageViewsLinear, device);
12571 DestroySubresourceImageViews(&mSubresourceDrawImageViews, device);
12572
12573 // Release the depth-xor-stencil input views
12574 DestroyLayerLevelImageViews(&mLayerLevelDepthOnlyImageViews, device);
12575 DestroyLayerLevelImageViews(&mLayerLevelStencilOnlyImageViews, device);
12576 DestroySubresourceImageViews(&mSubresourceDepthOnlyImageViews, device);
12577 DestroySubresourceImageViews(&mSubresourceStencilOnlyImageViews, device);
12578
12579 // Release the storage views
12580 DestroyImageViews(&mLevelStorageImageViews, device);
12581 DestroyLayerLevelImageViews(&mLayerLevelStorageImageViews, device);
12582
12583 // Destroy fragment shading rate view
12584 mFragmentShadingRateImageView.destroy(device);
12585
12586 mImageViewSerial = kInvalidImageOrBufferViewSerial;
12587 }
12588
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)12589 angle::Result ImageViewHelper::initReadViews(ContextVk *contextVk,
12590 gl::TextureType viewType,
12591 const ImageHelper &image,
12592 const gl::SwizzleState &formatSwizzle,
12593 const gl::SwizzleState &readSwizzle,
12594 LevelIndex baseLevel,
12595 uint32_t levelCount,
12596 uint32_t baseLayer,
12597 uint32_t layerCount,
12598 bool requiresSRGBViews,
12599 VkImageUsageFlags imageUsageFlags)
12600 {
12601 ASSERT(levelCount > 0);
12602
12603 const uint32_t maxLevel = levelCount - 1;
12604 ASSERT(maxLevel < 16);
12605 ASSERT(baseLevel.get() < 16);
12606 mCurrentBaseMaxLevelHash = static_cast<uint8_t>(baseLevel.get() << 4 | maxLevel);
12607 updateColorspace(image);
12608
12609 if (mCurrentBaseMaxLevelHash >= mPerLevelRangeLinearReadImageViews.size())
12610 {
12611 const uint32_t maxViewCount = mCurrentBaseMaxLevelHash + 1;
12612
12613 mPerLevelRangeLinearReadImageViews.resize(maxViewCount);
12614 mPerLevelRangeSRGBReadImageViews.resize(maxViewCount);
12615 mPerLevelRangeLinearCopyImageViews.resize(maxViewCount);
12616 mPerLevelRangeSRGBCopyImageViews.resize(maxViewCount);
12617 mPerLevelRangeStencilReadImageViews.resize(maxViewCount);
12618 mPerLevelRangeSamplerExternal2DY2YEXTImageViews.resize(maxViewCount);
12619 }
12620
12621 // Determine if we already have ImageViews for the new max level
12622 if (getReadImageView().valid())
12623 {
12624 return angle::Result::Continue;
12625 }
12626
12627 // Since we don't have a readImageView, we must create ImageViews for the new max level
12628 if (requiresSRGBViews)
12629 {
12630 // Initialize image views for both linear and srgb colorspaces
12631 ANGLE_TRY(initLinearAndSrgbReadViewsImpl(contextVk, viewType, image, formatSwizzle,
12632 readSwizzle, baseLevel, levelCount, baseLayer,
12633 layerCount, imageUsageFlags));
12634 }
12635 else
12636 {
12637 // Initialize image view for image's format's colorspace
12638 ANGLE_TRY(initReadViewsImpl(contextVk, viewType, image, formatSwizzle, readSwizzle,
12639 baseLevel, levelCount, baseLayer, layerCount, imageUsageFlags));
12640 }
12641
12642 return angle::Result::Continue;
12643 }
12644
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)12645 angle::Result ImageViewHelper::initReadViewsImpl(ContextVk *contextVk,
12646 gl::TextureType viewType,
12647 const ImageHelper &image,
12648 const gl::SwizzleState &formatSwizzle,
12649 const gl::SwizzleState &readSwizzle,
12650 LevelIndex baseLevel,
12651 uint32_t levelCount,
12652 uint32_t baseLayer,
12653 uint32_t layerCount,
12654 VkImageUsageFlags imageUsageFlags)
12655 {
12656 ASSERT(mImageViewSerial.valid());
12657 ASSERT(mReadColorspace != ImageViewColorspace::Invalid);
12658
12659 const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(image.getIntendedFormat());
12660
12661 if (HasBothDepthAndStencilAspects(aspectFlags))
12662 {
12663 ANGLE_TRY(image.initLayerImageViewWithUsage(
12664 contextVk, viewType, VK_IMAGE_ASPECT_DEPTH_BIT, readSwizzle, &getReadImageView(),
12665 baseLevel, levelCount, baseLayer, layerCount, imageUsageFlags));
12666 ANGLE_TRY(image.initLayerImageViewWithUsage(
12667 contextVk, viewType, VK_IMAGE_ASPECT_STENCIL_BIT, readSwizzle,
12668 &mPerLevelRangeStencilReadImageViews[mCurrentBaseMaxLevelHash], baseLevel, levelCount,
12669 baseLayer, layerCount, imageUsageFlags));
12670 }
12671 else
12672 {
12673 ANGLE_TRY(image.initLayerImageViewWithUsage(contextVk, viewType, aspectFlags, readSwizzle,
12674 &getReadImageView(), baseLevel, levelCount,
12675 baseLayer, layerCount, imageUsageFlags));
12676
12677 if (image.getActualFormat().isYUV)
12678 {
12679 ANGLE_TRY(image.initLayerImageViewWithYuvModeOverride(
12680 contextVk, viewType, aspectFlags, readSwizzle,
12681 &getSamplerExternal2DY2YEXTImageView(), baseLevel, levelCount, baseLayer,
12682 layerCount, gl::YuvSamplingMode::Y2Y, imageUsageFlags));
12683 }
12684 }
12685
12686 gl::TextureType fetchType = viewType;
12687 if (viewType == gl::TextureType::CubeMap || viewType == gl::TextureType::_2DArray ||
12688 viewType == gl::TextureType::_2DMultisampleArray)
12689 {
12690 fetchType = Get2DTextureType(layerCount, image.getSamples());
12691 }
12692
12693 if (!image.getActualFormat().isBlock)
12694 {
12695 if (fetchType != viewType || readSwizzle != formatSwizzle ||
12696 HasBothDepthAndStencilAspects(aspectFlags))
12697 {
12698 ANGLE_TRY(image.initLayerImageViewWithUsage(
12699 contextVk, fetchType, aspectFlags, formatSwizzle, &getCopyImageViewStorage(),
12700 baseLevel, levelCount, baseLayer, layerCount, imageUsageFlags));
12701 }
12702 else
12703 {
12704 mIsCopyImageViewShared = true;
12705 }
12706 }
12707 return angle::Result::Continue;
12708 }
12709
initLinearAndSrgbReadViewsImpl(ContextVk * contextVk,gl::TextureType viewType,const ImageHelper & image,const gl::SwizzleState & formatSwizzle,const gl::SwizzleState & readSwizzle,LevelIndex baseLevel,uint32_t levelCount,uint32_t baseLayer,uint32_t layerCount,VkImageUsageFlags imageUsageFlags)12710 angle::Result ImageViewHelper::initLinearAndSrgbReadViewsImpl(ContextVk *contextVk,
12711 gl::TextureType viewType,
12712 const ImageHelper &image,
12713 const gl::SwizzleState &formatSwizzle,
12714 const gl::SwizzleState &readSwizzle,
12715 LevelIndex baseLevel,
12716 uint32_t levelCount,
12717 uint32_t baseLayer,
12718 uint32_t layerCount,
12719 VkImageUsageFlags imageUsageFlags)
12720 {
12721 ASSERT(mReadColorspace != ImageViewColorspace::Invalid);
12722
12723 // When we select the linear/srgb counterpart formats, we must first make sure they're
12724 // actually supported by the ICD. If they are not supported by the ICD, then we treat that as if
12725 // there is no counterpart format.
12726 const bool imageFormatIsSrgb = image.getActualFormat().isSRGB;
12727 const angle::FormatID imageFormat = image.getActualFormatID();
12728 angle::FormatID srgbFormat = imageFormatIsSrgb ? imageFormat : ConvertToSRGB(imageFormat);
12729 if (srgbFormat != angle::FormatID::NONE &&
12730 !HasNonRenderableTextureFormatSupport(contextVk->getRenderer(), srgbFormat))
12731 {
12732 srgbFormat = angle::FormatID::NONE;
12733 }
12734
12735 angle::FormatID linearFormat = !imageFormatIsSrgb ? imageFormat : ConvertToLinear(imageFormat);
12736 ASSERT(linearFormat != angle::FormatID::NONE);
12737
12738 const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(image.getIntendedFormat());
12739
12740 if (HasBothDepthAndStencilAspects(aspectFlags))
12741 {
12742 ANGLE_TRY(image.initReinterpretedLayerImageView(
12743 contextVk, viewType, VK_IMAGE_ASPECT_DEPTH_BIT, readSwizzle,
12744 &mPerLevelRangeLinearReadImageViews[mCurrentBaseMaxLevelHash], baseLevel, levelCount,
12745 baseLayer, layerCount, imageUsageFlags, linearFormat));
12746
12747 ANGLE_TRY(image.initReinterpretedLayerImageView(
12748 contextVk, viewType, VK_IMAGE_ASPECT_STENCIL_BIT, readSwizzle,
12749 &mPerLevelRangeStencilReadImageViews[mCurrentBaseMaxLevelHash], baseLevel, levelCount,
12750 baseLayer, layerCount, imageUsageFlags, linearFormat));
12751 }
12752 else
12753 {
12754 if (!mPerLevelRangeLinearReadImageViews[mCurrentBaseMaxLevelHash].valid())
12755 {
12756 ANGLE_TRY(image.initReinterpretedLayerImageView(
12757 contextVk, viewType, aspectFlags, readSwizzle,
12758 &mPerLevelRangeLinearReadImageViews[mCurrentBaseMaxLevelHash], baseLevel,
12759 levelCount, baseLayer, layerCount, imageUsageFlags, linearFormat));
12760 }
12761
12762 if (srgbFormat != angle::FormatID::NONE &&
12763 !mPerLevelRangeSRGBReadImageViews[mCurrentBaseMaxLevelHash].valid())
12764 {
12765 ANGLE_TRY(image.initReinterpretedLayerImageView(
12766 contextVk, viewType, aspectFlags, readSwizzle,
12767 &mPerLevelRangeSRGBReadImageViews[mCurrentBaseMaxLevelHash], baseLevel, levelCount,
12768 baseLayer, layerCount, imageUsageFlags, srgbFormat));
12769 }
12770
12771 if (image.getActualFormat().isYUV)
12772 {
12773 ANGLE_TRY(image.initLayerImageViewWithYuvModeOverride(
12774 contextVk, viewType, aspectFlags, readSwizzle,
12775 &getSamplerExternal2DY2YEXTImageView(), baseLevel, levelCount, baseLayer,
12776 layerCount, gl::YuvSamplingMode::Y2Y, imageUsageFlags));
12777 }
12778 }
12779
12780 gl::TextureType fetchType = viewType;
12781
12782 if (viewType == gl::TextureType::CubeMap || viewType == gl::TextureType::_2DArray ||
12783 viewType == gl::TextureType::_2DMultisampleArray)
12784 {
12785 fetchType = Get2DTextureType(layerCount, image.getSamples());
12786 }
12787
12788 if (!image.getActualFormat().isBlock)
12789 {
12790 if (fetchType != viewType || formatSwizzle != readSwizzle ||
12791 HasBothDepthAndStencilAspects(aspectFlags))
12792 {
12793 if (!mPerLevelRangeLinearCopyImageViews[mCurrentBaseMaxLevelHash].valid())
12794 {
12795 ANGLE_TRY(image.initReinterpretedLayerImageView(
12796 contextVk, fetchType, aspectFlags, formatSwizzle,
12797 &mPerLevelRangeLinearCopyImageViews[mCurrentBaseMaxLevelHash], baseLevel,
12798 levelCount, baseLayer, layerCount, imageUsageFlags, linearFormat));
12799 }
12800 if (srgbFormat != angle::FormatID::NONE &&
12801 !mPerLevelRangeSRGBCopyImageViews[mCurrentBaseMaxLevelHash].valid())
12802 {
12803 ANGLE_TRY(image.initReinterpretedLayerImageView(
12804 contextVk, fetchType, aspectFlags, formatSwizzle,
12805 &mPerLevelRangeSRGBCopyImageViews[mCurrentBaseMaxLevelHash], baseLevel,
12806 levelCount, baseLayer, layerCount, imageUsageFlags, srgbFormat));
12807 }
12808 }
12809 else
12810 {
12811 mIsCopyImageViewShared = true;
12812 }
12813 }
12814
12815 return angle::Result::Continue;
12816 }
12817
getLevelStorageImageView(ErrorContext * context,gl::TextureType viewType,const ImageHelper & image,LevelIndex levelVk,uint32_t layer,VkImageUsageFlags imageUsageFlags,angle::FormatID formatID,const ImageView ** imageViewOut)12818 angle::Result ImageViewHelper::getLevelStorageImageView(ErrorContext *context,
12819 gl::TextureType viewType,
12820 const ImageHelper &image,
12821 LevelIndex levelVk,
12822 uint32_t layer,
12823 VkImageUsageFlags imageUsageFlags,
12824 angle::FormatID formatID,
12825 const ImageView **imageViewOut)
12826 {
12827 ASSERT(mImageViewSerial.valid());
12828
12829 ImageView *imageView =
12830 GetLevelImageView(&mLevelStorageImageViews, levelVk, image.getLevelCount());
12831
12832 *imageViewOut = imageView;
12833 if (imageView->valid())
12834 {
12835 return angle::Result::Continue;
12836 }
12837
12838 // Create the view. Note that storage images are not affected by swizzle parameters.
12839 return image.initReinterpretedLayerImageView(context, viewType, image.getAspectFlags(),
12840 gl::SwizzleState(), imageView, levelVk, 1, layer,
12841 image.getLayerCount(), imageUsageFlags, formatID);
12842 }
12843
getLevelLayerStorageImageView(ErrorContext * contextVk,const ImageHelper & image,LevelIndex levelVk,uint32_t layer,VkImageUsageFlags imageUsageFlags,angle::FormatID formatID,const ImageView ** imageViewOut)12844 angle::Result ImageViewHelper::getLevelLayerStorageImageView(ErrorContext *contextVk,
12845 const ImageHelper &image,
12846 LevelIndex levelVk,
12847 uint32_t layer,
12848 VkImageUsageFlags imageUsageFlags,
12849 angle::FormatID formatID,
12850 const ImageView **imageViewOut)
12851 {
12852 ASSERT(image.valid());
12853 ASSERT(mImageViewSerial.valid());
12854 ASSERT(!image.getActualFormat().isBlock);
12855
12856 ImageView *imageView =
12857 GetLevelLayerImageView(&mLayerLevelStorageImageViews, levelVk, layer, image.getLevelCount(),
12858 GetImageLayerCountForView(image));
12859 *imageViewOut = imageView;
12860
12861 if (imageView->valid())
12862 {
12863 return angle::Result::Continue;
12864 }
12865
12866 // Create the view. Note that storage images are not affected by swizzle parameters.
12867 gl::TextureType viewType = Get2DTextureType(1, image.getSamples());
12868 return image.initReinterpretedLayerImageView(contextVk, viewType, image.getAspectFlags(),
12869 gl::SwizzleState(), imageView, levelVk, 1, layer,
12870 1, imageUsageFlags, formatID);
12871 }
12872
getLevelLayerDrawImageViewImpl(ErrorContext * context,const ImageHelper & image,LevelIndex levelVk,uint32_t layer,uint32_t layerCount,ImageView * imageViewOut)12873 angle::Result ImageViewHelper::getLevelLayerDrawImageViewImpl(ErrorContext *context,
12874 const ImageHelper &image,
12875 LevelIndex levelVk,
12876 uint32_t layer,
12877 uint32_t layerCount,
12878 ImageView *imageViewOut)
12879 {
12880 ASSERT(imageViewOut != nullptr);
12881
12882 // If we are initializing an imageview for use with EXT_srgb_write_control, we need to override
12883 // the format to its linear counterpart. Formats that cannot be reinterpreted are exempt from
12884 // this requirement.
12885 angle::FormatID actualFormat = image.getActualFormatID();
12886 angle::FormatID linearFormat = ConvertToLinear(actualFormat);
12887 angle::FormatID sRGBFormat = ConvertToSRGB(actualFormat);
12888 if (mWriteColorspace == ImageViewColorspace::Linear && linearFormat != angle::FormatID::NONE)
12889 {
12890 actualFormat = linearFormat;
12891 }
12892 else if (mWriteColorspace == ImageViewColorspace::SRGB && sRGBFormat != angle::FormatID::NONE)
12893 {
12894 actualFormat = sRGBFormat;
12895 }
12896
12897 // Note that these views are specifically made to be used as framebuffer attachments, and
12898 // therefore don't have swizzle.
12899 return image.initReinterpretedLayerImageView(
12900 context, Get2DTextureType(layerCount, image.getSamples()), image.getAspectFlags(),
12901 gl::SwizzleState(), imageViewOut, levelVk, 1, layer, layerCount,
12902 vk::ImageHelper::kDefaultImageViewUsageFlags, actualFormat);
12903 }
12904
getLevelDrawImageView(ErrorContext * context,const ImageHelper & image,LevelIndex levelVk,uint32_t layer,uint32_t layerCount,const ImageView ** imageViewOut)12905 angle::Result ImageViewHelper::getLevelDrawImageView(ErrorContext *context,
12906 const ImageHelper &image,
12907 LevelIndex levelVk,
12908 uint32_t layer,
12909 uint32_t layerCount,
12910 const ImageView **imageViewOut)
12911 {
12912 ASSERT(image.valid());
12913 ASSERT(mImageViewSerial.valid());
12914 ASSERT(!image.getActualFormat().isBlock);
12915
12916 if (mWriteColorspace == ImageViewColorspace::Invalid)
12917 {
12918 updateColorspace(image);
12919 }
12920 ASSERT(mWriteColorspace != ImageViewColorspace::Invalid);
12921
12922 ImageSubresourceRange range = MakeImageSubresourceDrawRange(image.toGLLevel(levelVk), layer,
12923 GetLayerMode(image, layerCount),
12924 mReadColorspace, mWriteColorspace);
12925
12926 std::unique_ptr<ImageView> &view = mSubresourceDrawImageViews[range];
12927 if (view)
12928 {
12929 *imageViewOut = view.get();
12930 return angle::Result::Continue;
12931 }
12932
12933 view = std::make_unique<ImageView>();
12934 *imageViewOut = view.get();
12935
12936 return getLevelLayerDrawImageViewImpl(context, image, levelVk, layer, layerCount, view.get());
12937 }
12938
getLevelLayerDrawImageView(ErrorContext * context,const ImageHelper & image,LevelIndex levelVk,uint32_t layer,const ImageView ** imageViewOut)12939 angle::Result ImageViewHelper::getLevelLayerDrawImageView(ErrorContext *context,
12940 const ImageHelper &image,
12941 LevelIndex levelVk,
12942 uint32_t layer,
12943 const ImageView **imageViewOut)
12944 {
12945 ASSERT(image.valid());
12946 ASSERT(mImageViewSerial.valid());
12947 ASSERT(!image.getActualFormat().isBlock);
12948
12949 if (mWriteColorspace == ImageViewColorspace::Invalid)
12950 {
12951 updateColorspace(image);
12952 }
12953 ASSERT(mWriteColorspace != ImageViewColorspace::Invalid);
12954
12955 LayerLevelImageViewVector &imageViews = (mWriteColorspace == ImageViewColorspace::Linear)
12956 ? mLayerLevelDrawImageViewsLinear
12957 : mLayerLevelDrawImageViews;
12958
12959 // Lazily allocate the storage for image views
12960 ImageView *imageView = GetLevelLayerImageView(
12961 &imageViews, levelVk, layer, image.getLevelCount(), GetImageLayerCountForView(image));
12962 *imageViewOut = imageView;
12963
12964 if (imageView->valid())
12965 {
12966 return angle::Result::Continue;
12967 }
12968
12969 return getLevelLayerDrawImageViewImpl(context, image, levelVk, layer, 1, imageView);
12970 }
12971
getLevelDepthOrStencilImageView(ErrorContext * context,const ImageHelper & image,LevelIndex levelVk,uint32_t layer,uint32_t layerCount,VkImageAspectFlagBits aspect,const ImageView ** imageViewOut)12972 angle::Result ImageViewHelper::getLevelDepthOrStencilImageView(ErrorContext *context,
12973 const ImageHelper &image,
12974 LevelIndex levelVk,
12975 uint32_t layer,
12976 uint32_t layerCount,
12977 VkImageAspectFlagBits aspect,
12978 const ImageView **imageViewOut)
12979 {
12980 ASSERT(image.valid());
12981 ASSERT(mImageViewSerial.valid());
12982 ASSERT((image.getAspectFlags() & aspect) != 0);
12983
12984 ImageSubresourceRange range = MakeImageSubresourceDrawRange(
12985 image.toGLLevel(levelVk), layer, GetLayerMode(image, layerCount),
12986 ImageViewColorspace::Linear, ImageViewColorspace::Linear);
12987
12988 SubresourceImageViewMap &imageViews = aspect == VK_IMAGE_ASPECT_DEPTH_BIT
12989 ? mSubresourceDepthOnlyImageViews
12990 : mSubresourceStencilOnlyImageViews;
12991
12992 std::unique_ptr<ImageView> &view = imageViews[range];
12993 if (view)
12994 {
12995 *imageViewOut = view.get();
12996 return angle::Result::Continue;
12997 }
12998
12999 view = std::make_unique<ImageView>();
13000 *imageViewOut = view.get();
13001
13002 return getLevelLayerDepthOrStencilImageViewImpl(context, image, levelVk, layer, layerCount,
13003 aspect, view.get());
13004 }
13005
getLevelLayerDepthOrStencilImageView(ErrorContext * context,const ImageHelper & image,LevelIndex levelVk,uint32_t layer,VkImageAspectFlagBits aspect,const ImageView ** imageViewOut)13006 angle::Result ImageViewHelper::getLevelLayerDepthOrStencilImageView(ErrorContext *context,
13007 const ImageHelper &image,
13008 LevelIndex levelVk,
13009 uint32_t layer,
13010 VkImageAspectFlagBits aspect,
13011 const ImageView **imageViewOut)
13012 {
13013 ASSERT(image.valid());
13014 ASSERT(mImageViewSerial.valid());
13015 ASSERT((image.getAspectFlags() & aspect) != 0);
13016
13017 LayerLevelImageViewVector &imageViews = aspect == VK_IMAGE_ASPECT_DEPTH_BIT
13018 ? mLayerLevelDepthOnlyImageViews
13019 : mLayerLevelStencilOnlyImageViews;
13020
13021 // Lazily allocate the storage for image views
13022 ImageView *imageView = GetLevelLayerImageView(
13023 &imageViews, levelVk, layer, image.getLevelCount(), GetImageLayerCountForView(image));
13024 *imageViewOut = imageView;
13025
13026 if (imageView->valid())
13027 {
13028 return angle::Result::Continue;
13029 }
13030
13031 return getLevelLayerDepthOrStencilImageViewImpl(context, image, levelVk, layer, 1, aspect,
13032 imageView);
13033 }
13034
getLevelLayerDepthOrStencilImageViewImpl(ErrorContext * context,const ImageHelper & image,LevelIndex levelVk,uint32_t layer,uint32_t layerCount,VkImageAspectFlagBits aspect,ImageView * imageViewOut)13035 angle::Result ImageViewHelper::getLevelLayerDepthOrStencilImageViewImpl(
13036 ErrorContext *context,
13037 const ImageHelper &image,
13038 LevelIndex levelVk,
13039 uint32_t layer,
13040 uint32_t layerCount,
13041 VkImageAspectFlagBits aspect,
13042 ImageView *imageViewOut)
13043 {
13044 // Note that these views are specifically made to be used as input attachments, and
13045 // therefore don't have swizzle.
13046 return image.initReinterpretedLayerImageView(
13047 context, Get2DTextureType(layerCount, image.getSamples()), aspect, gl::SwizzleState(),
13048 imageViewOut, levelVk, 1, layer, layerCount, vk::ImageHelper::kDefaultImageViewUsageFlags,
13049 image.getActualFormatID());
13050 }
13051
initFragmentShadingRateView(ContextVk * contextVk,ImageHelper * image)13052 angle::Result ImageViewHelper::initFragmentShadingRateView(ContextVk *contextVk, ImageHelper *image)
13053 {
13054 ASSERT(image->valid());
13055 ASSERT(mImageViewSerial.valid());
13056
13057 // Determine if we already have ImageView
13058 if (mFragmentShadingRateImageView.valid())
13059 {
13060 return angle::Result::Continue;
13061 }
13062
13063 // Fragment shading rate image view always have -
13064 // - gl::TextureType == gl::TextureType::_2D
13065 // - VkImageAspectFlags == VK_IMAGE_ASPECT_COLOR_BIT
13066 // - gl::SwizzleState == gl::SwizzleState()
13067 // - baseMipLevelVk == vk::LevelIndex(0)
13068 // - levelCount == 1
13069 // - baseArrayLayer == 0
13070 // - layerCount == 1
13071 return image->initLayerImageViewWithUsage(
13072 contextVk, gl::TextureType::_2D, VK_IMAGE_ASPECT_COLOR_BIT, gl::SwizzleState(),
13073 &mFragmentShadingRateImageView, vk::LevelIndex(0), 1, 0, 1, image->getUsage());
13074 }
13075
getColorspaceOverrideFormatForWrite(angle::FormatID format) const13076 angle::FormatID ImageViewHelper::getColorspaceOverrideFormatForWrite(angle::FormatID format) const
13077 {
13078 ASSERT(mWriteColorspace != ImageViewColorspace::Invalid);
13079
13080 angle::FormatID colorspaceOverrideFormat = format;
13081 angle::FormatID linearFormat = ConvertToLinear(format);
13082 angle::FormatID sRGBFormat = ConvertToSRGB(format);
13083 if (mWriteColorspace == ImageViewColorspace::Linear && linearFormat != angle::FormatID::NONE)
13084 {
13085 colorspaceOverrideFormat = linearFormat;
13086 }
13087 else if (mWriteColorspace == ImageViewColorspace::SRGB && sRGBFormat != angle::FormatID::NONE)
13088 {
13089 colorspaceOverrideFormat = sRGBFormat;
13090 }
13091
13092 return colorspaceOverrideFormat;
13093 }
13094
updateColorspace(const ImageHelper & image) const13095 void ImageViewHelper::updateColorspace(const ImageHelper &image) const
13096 {
13097 const angle::Format &imageFormat = image.getActualFormat();
13098 ImageViewColorspace imageViewColorspace = ImageViewColorspace::Invalid;
13099 mReadColorspace = ImageViewColorspace::Invalid;
13100 mWriteColorspace = ImageViewColorspace::Invalid;
13101
13102 // Initialize colorspace based on image's format's colorspace
13103 imageViewColorspace =
13104 imageFormat.isSRGB ? ImageViewColorspace::SRGB : ImageViewColorspace::Linear;
13105
13106 // Process EGL image colorspace override state
13107 if (!imageFormat.isSRGB && mColorspaceState.eglImageColorspace == egl::ImageColorspace::SRGB)
13108 {
13109 imageViewColorspace = ImageViewColorspace::SRGB;
13110 }
13111 else if (imageFormat.isSRGB &&
13112 mColorspaceState.eglImageColorspace == egl::ImageColorspace::Linear)
13113 {
13114 imageViewColorspace = ImageViewColorspace::Linear;
13115 }
13116 ASSERT(imageViewColorspace != ImageViewColorspace::Invalid);
13117
13118 mReadColorspace = imageViewColorspace;
13119 mWriteColorspace = imageViewColorspace;
13120
13121 // Process srgb decode and srgb override state
13122 if (mReadColorspace == ImageViewColorspace::Linear)
13123 {
13124 if (mColorspaceState.srgbOverride == gl::SrgbOverride::SRGB &&
13125 rx::ConvertToSRGB(imageFormat.id) != angle::FormatID::NONE &&
13126 mColorspaceState.srgbDecode != gl::SrgbDecode::Skip)
13127 {
13128 mReadColorspace = ImageViewColorspace::SRGB;
13129 }
13130 }
13131 else
13132 {
13133 ASSERT(mReadColorspace == ImageViewColorspace::SRGB);
13134
13135 if (mColorspaceState.srgbDecode == gl::SrgbDecode::Skip &&
13136 !mColorspaceState.hasStaticTexelFetchAccess)
13137 {
13138 mReadColorspace = ImageViewColorspace::Linear;
13139 }
13140 }
13141
13142 // Process srgb write control state
13143 if (mWriteColorspace == ImageViewColorspace::SRGB &&
13144 mColorspaceState.srgbWriteControl == gl::SrgbWriteControlMode::Linear)
13145 {
13146 mWriteColorspace = ImageViewColorspace::Linear;
13147 }
13148
13149 ASSERT(mReadColorspace != ImageViewColorspace::Invalid);
13150 ASSERT(mWriteColorspace != ImageViewColorspace::Invalid);
13151 }
13152
getSubresourceSerial(gl::LevelIndex levelGL,uint32_t levelCount,uint32_t layer,LayerMode layerMode) const13153 ImageOrBufferViewSubresourceSerial ImageViewHelper::getSubresourceSerial(gl::LevelIndex levelGL,
13154 uint32_t levelCount,
13155 uint32_t layer,
13156 LayerMode layerMode) const
13157 {
13158 return getSubresourceSerialForColorspace(levelGL, levelCount, layer, layerMode,
13159 mReadColorspace);
13160 }
13161
getSubresourceSerialForColorspace(gl::LevelIndex levelGL,uint32_t levelCount,uint32_t layer,LayerMode layerMode,ImageViewColorspace readColorspace) const13162 ImageOrBufferViewSubresourceSerial ImageViewHelper::getSubresourceSerialForColorspace(
13163 gl::LevelIndex levelGL,
13164 uint32_t levelCount,
13165 uint32_t layer,
13166 LayerMode layerMode,
13167 ImageViewColorspace readColorspace) const
13168 {
13169 ASSERT(mImageViewSerial.valid());
13170
13171 ImageOrBufferViewSubresourceSerial serial;
13172 serial.viewSerial = mImageViewSerial;
13173 serial.subresource = MakeImageSubresourceReadRange(levelGL, levelCount, layer, layerMode,
13174 readColorspace, mWriteColorspace);
13175 return serial;
13176 }
13177
getSubresourceDrawRange(gl::LevelIndex level,uint32_t layer,LayerMode layerMode) const13178 ImageSubresourceRange ImageViewHelper::getSubresourceDrawRange(gl::LevelIndex level,
13179 uint32_t layer,
13180 LayerMode layerMode) const
13181 {
13182 return MakeImageSubresourceDrawRange(level, layer, layerMode, mReadColorspace,
13183 mWriteColorspace);
13184 }
13185
13186 // BufferViewHelper implementation.
BufferViewHelper()13187 BufferViewHelper::BufferViewHelper() : mInitialized(false), mOffset(0), mSize(0) {}
13188
BufferViewHelper(BufferViewHelper && other)13189 BufferViewHelper::BufferViewHelper(BufferViewHelper &&other) : Resource(std::move(other))
13190 {
13191 std::swap(mInitialized, other.mInitialized);
13192 std::swap(mOffset, other.mOffset);
13193 std::swap(mSize, other.mSize);
13194 std::swap(mViews, other.mViews);
13195 std::swap(mViewSerial, other.mViewSerial);
13196 }
13197
~BufferViewHelper()13198 BufferViewHelper::~BufferViewHelper() {}
13199
init(Renderer * renderer,VkDeviceSize offset,VkDeviceSize size)13200 void BufferViewHelper::init(Renderer *renderer, VkDeviceSize offset, VkDeviceSize size)
13201 {
13202 ASSERT(mViews.empty());
13203
13204 mOffset = offset;
13205 mSize = size;
13206
13207 if (!mViewSerial.valid())
13208 {
13209 mViewSerial = renderer->getResourceSerialFactory().generateImageOrBufferViewSerial();
13210 }
13211
13212 mInitialized = true;
13213 }
13214
release(Renderer * renderer)13215 void BufferViewHelper::release(Renderer *renderer)
13216 {
13217 if (!mInitialized)
13218 {
13219 return;
13220 }
13221
13222 GarbageObjects garbage;
13223
13224 for (auto &formatAndView : mViews)
13225 {
13226 BufferView &view = formatAndView.second;
13227 ASSERT(view.valid());
13228
13229 garbage.emplace_back(GetGarbage(&view));
13230 }
13231
13232 if (!garbage.empty())
13233 {
13234 renderer->collectGarbage(mUse, std::move(garbage));
13235 // Update image view serial.
13236 mViewSerial = renderer->getResourceSerialFactory().generateImageOrBufferViewSerial();
13237 }
13238
13239 mUse.reset();
13240 mViews.clear();
13241 mOffset = 0;
13242 mSize = 0;
13243 mInitialized = false;
13244 }
13245
release(ContextVk * contextVk)13246 void BufferViewHelper::release(ContextVk *contextVk)
13247 {
13248 if (!mInitialized)
13249 {
13250 return;
13251 }
13252
13253 contextVk->flushDescriptorSetUpdates();
13254 return release(contextVk->getRenderer());
13255 }
13256
destroy(VkDevice device)13257 void BufferViewHelper::destroy(VkDevice device)
13258 {
13259 for (auto &formatAndView : mViews)
13260 {
13261 BufferView &view = formatAndView.second;
13262 view.destroy(device);
13263 }
13264
13265 mViews.clear();
13266
13267 mOffset = 0;
13268 mSize = 0;
13269
13270 mViewSerial = kInvalidImageOrBufferViewSerial;
13271 }
13272
getView(ErrorContext * context,const BufferHelper & buffer,VkDeviceSize bufferOffset,const Format & format,const BufferView ** viewOut)13273 angle::Result BufferViewHelper::getView(ErrorContext *context,
13274 const BufferHelper &buffer,
13275 VkDeviceSize bufferOffset,
13276 const Format &format,
13277 const BufferView **viewOut)
13278 {
13279 ASSERT(format.valid());
13280
13281 vk::Renderer *renderer = context->getRenderer();
13282 VkFormat viewVkFormat = format.getActualBufferVkFormat(renderer, false);
13283
13284 auto iter = mViews.find(viewVkFormat);
13285 if (iter != mViews.end())
13286 {
13287 *viewOut = &iter->second;
13288 return angle::Result::Continue;
13289 }
13290
13291 // If the size is not a multiple of pixelBytes, remove the extra bytes. The last element cannot
13292 // be read anyway, and this is a requirement of Vulkan (for size to be a multiple of format
13293 // texel block size).
13294 const angle::Format &bufferFormat = format.getActualBufferFormat(false);
13295 const GLuint pixelBytes = bufferFormat.pixelBytes;
13296 VkDeviceSize size = mSize - mSize % pixelBytes;
13297
13298 VkBufferViewCreateInfo viewCreateInfo = {};
13299 viewCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO;
13300 viewCreateInfo.buffer = buffer.getBuffer().getHandle();
13301 viewCreateInfo.format = viewVkFormat;
13302 viewCreateInfo.offset = mOffset + bufferOffset;
13303 viewCreateInfo.range = size;
13304
13305 BufferView view;
13306 ANGLE_VK_TRY(context, view.init(context->getDevice(), viewCreateInfo));
13307
13308 // Cache the view
13309 auto insertIter = mViews.insert({viewVkFormat, std::move(view)});
13310 *viewOut = &insertIter.first->second;
13311 ASSERT(insertIter.second);
13312
13313 return angle::Result::Continue;
13314 }
13315
getSerial() const13316 ImageOrBufferViewSubresourceSerial BufferViewHelper::getSerial() const
13317 {
13318 ASSERT(mViewSerial.valid());
13319
13320 ImageOrBufferViewSubresourceSerial serial = {};
13321 serial.viewSerial = mViewSerial;
13322 return serial;
13323 }
13324
13325 // ShaderProgramHelper implementation.
13326 ShaderProgramHelper::ShaderProgramHelper() = default;
13327 ShaderProgramHelper::~ShaderProgramHelper() = default;
13328
valid(const gl::ShaderType shaderType) const13329 bool ShaderProgramHelper::valid(const gl::ShaderType shaderType) const
13330 {
13331 return mShaders[shaderType];
13332 }
13333
destroy(Renderer * renderer)13334 void ShaderProgramHelper::destroy(Renderer *renderer)
13335 {
13336 for (ShaderModulePtr &shader : mShaders)
13337 {
13338 shader.reset();
13339 }
13340 }
13341
release(ContextVk * contextVk)13342 void ShaderProgramHelper::release(ContextVk *contextVk)
13343 {
13344 for (ShaderModulePtr &shader : mShaders)
13345 {
13346 shader.reset();
13347 }
13348 }
13349
setShader(gl::ShaderType shaderType,const ShaderModulePtr & shader)13350 void ShaderProgramHelper::setShader(gl::ShaderType shaderType, const ShaderModulePtr &shader)
13351 {
13352 // The shaders must be set once and are not expected to change.
13353 ASSERT(!mShaders[shaderType]);
13354 ASSERT(shader && shader->valid());
13355 mShaders[shaderType] = shader;
13356 }
13357
createMonolithicPipelineCreationTask(vk::ErrorContext * context,PipelineCacheAccess * pipelineCache,const GraphicsPipelineDesc & desc,const PipelineLayout & pipelineLayout,const SpecializationConstants & specConsts,PipelineHelper * pipeline) const13358 void ShaderProgramHelper::createMonolithicPipelineCreationTask(
13359 vk::ErrorContext *context,
13360 PipelineCacheAccess *pipelineCache,
13361 const GraphicsPipelineDesc &desc,
13362 const PipelineLayout &pipelineLayout,
13363 const SpecializationConstants &specConsts,
13364 PipelineHelper *pipeline) const
13365 {
13366 std::shared_ptr<CreateMonolithicPipelineTask> monolithicPipelineCreationTask =
13367 std::make_shared<CreateMonolithicPipelineTask>(context->getRenderer(), *pipelineCache,
13368 pipelineLayout, mShaders, specConsts, desc);
13369
13370 pipeline->setMonolithicPipelineCreationTask(std::move(monolithicPipelineCreationTask));
13371 }
13372
getOrCreateComputePipeline(vk::ErrorContext * context,ComputePipelineCache * computePipelines,PipelineCacheAccess * pipelineCache,const PipelineLayout & pipelineLayout,ComputePipelineOptions pipelineOptions,PipelineSource source,PipelineHelper ** pipelineOut,const char * shaderName,VkSpecializationInfo * specializationInfo) const13373 angle::Result ShaderProgramHelper::getOrCreateComputePipeline(
13374 vk::ErrorContext *context,
13375 ComputePipelineCache *computePipelines,
13376 PipelineCacheAccess *pipelineCache,
13377 const PipelineLayout &pipelineLayout,
13378 ComputePipelineOptions pipelineOptions,
13379 PipelineSource source,
13380 PipelineHelper **pipelineOut,
13381 const char *shaderName,
13382 VkSpecializationInfo *specializationInfo) const
13383 {
13384 return computePipelines->getOrCreatePipeline(context, pipelineCache, pipelineLayout,
13385 pipelineOptions, source, pipelineOut, shaderName,
13386 specializationInfo, mShaders);
13387 }
13388
13389 // ActiveHandleCounter implementation.
ActiveHandleCounter()13390 ActiveHandleCounter::ActiveHandleCounter() : mActiveCounts{}, mAllocatedCounts{} {}
13391
13392 ActiveHandleCounter::~ActiveHandleCounter() = default;
13393
13394 // CommandBufferAccess implementation.
13395 CommandBufferAccess::CommandBufferAccess() = default;
13396 CommandBufferAccess::~CommandBufferAccess() = default;
13397
onBufferRead(VkAccessFlags readAccessType,PipelineStage readStage,BufferHelper * buffer)13398 void CommandBufferAccess::onBufferRead(VkAccessFlags readAccessType,
13399 PipelineStage readStage,
13400 BufferHelper *buffer)
13401 {
13402 ASSERT(!buffer->isReleasedToExternal());
13403 mReadBuffers.emplace_back(buffer, readAccessType, readStage);
13404 }
13405
onBufferWrite(VkAccessFlags writeAccessType,PipelineStage writeStage,BufferHelper * buffer)13406 void CommandBufferAccess::onBufferWrite(VkAccessFlags writeAccessType,
13407 PipelineStage writeStage,
13408 BufferHelper *buffer)
13409 {
13410 ASSERT(!buffer->isReleasedToExternal());
13411 mWriteBuffers.emplace_back(buffer, writeAccessType, writeStage);
13412 }
13413
onImageRead(VkImageAspectFlags aspectFlags,ImageLayout imageLayout,ImageHelper * image)13414 void CommandBufferAccess::onImageRead(VkImageAspectFlags aspectFlags,
13415 ImageLayout imageLayout,
13416 ImageHelper *image)
13417 {
13418 ASSERT(!image->isReleasedToExternal());
13419 ASSERT(image->getImageSerial().valid());
13420 mReadImages.emplace_back(image, aspectFlags, imageLayout);
13421 }
13422
onImageWrite(gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,ImageHelper * image)13423 void CommandBufferAccess::onImageWrite(gl::LevelIndex levelStart,
13424 uint32_t levelCount,
13425 uint32_t layerStart,
13426 uint32_t layerCount,
13427 VkImageAspectFlags aspectFlags,
13428 ImageLayout imageLayout,
13429 ImageHelper *image)
13430 {
13431 ASSERT(!image->isReleasedToExternal());
13432 ASSERT(image->getImageSerial().valid());
13433 mWriteImages.emplace_back(CommandBufferImageAccess{image, aspectFlags, imageLayout}, levelStart,
13434 levelCount, layerStart, layerCount);
13435 }
13436
onImageReadSubresources(gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,ImageHelper * image)13437 void CommandBufferAccess::onImageReadSubresources(gl::LevelIndex levelStart,
13438 uint32_t levelCount,
13439 uint32_t layerStart,
13440 uint32_t layerCount,
13441 VkImageAspectFlags aspectFlags,
13442 ImageLayout imageLayout,
13443 ImageHelper *image)
13444 {
13445 ASSERT(!image->isReleasedToExternal());
13446 ASSERT(image->getImageSerial().valid());
13447 mReadImageSubresources.emplace_back(CommandBufferImageAccess{image, aspectFlags, imageLayout},
13448 levelStart, levelCount, layerStart, layerCount);
13449 }
13450
onBufferExternalAcquireRelease(BufferHelper * buffer)13451 void CommandBufferAccess::onBufferExternalAcquireRelease(BufferHelper *buffer)
13452 {
13453 mExternalAcquireReleaseBuffers.emplace_back(CommandBufferBufferExternalAcquireRelease{buffer});
13454 }
13455
onResourceAccess(Resource * resource)13456 void CommandBufferAccess::onResourceAccess(Resource *resource)
13457 {
13458 mAccessResources.emplace_back(CommandBufferResourceAccess{resource});
13459 }
13460
13461 // DescriptorMetaCache implementation.
13462 MetaDescriptorPool::MetaDescriptorPool() = default;
13463
~MetaDescriptorPool()13464 MetaDescriptorPool::~MetaDescriptorPool()
13465 {
13466 ASSERT(mPayload.empty());
13467 }
13468
destroy(Renderer * renderer)13469 void MetaDescriptorPool::destroy(Renderer *renderer)
13470 {
13471 for (auto &iter : mPayload)
13472 {
13473 DynamicDescriptorPoolPointer &pool = iter.second;
13474 ASSERT(pool.unique());
13475 }
13476 mPayload.clear();
13477 }
13478
bindCachedDescriptorPool(ErrorContext * context,const DescriptorSetLayoutDesc & descriptorSetLayoutDesc,uint32_t descriptorCountMultiplier,DescriptorSetLayoutCache * descriptorSetLayoutCache,DynamicDescriptorPoolPointer * dynamicDescriptorPoolOut)13479 angle::Result MetaDescriptorPool::bindCachedDescriptorPool(
13480 ErrorContext *context,
13481 const DescriptorSetLayoutDesc &descriptorSetLayoutDesc,
13482 uint32_t descriptorCountMultiplier,
13483 DescriptorSetLayoutCache *descriptorSetLayoutCache,
13484 DynamicDescriptorPoolPointer *dynamicDescriptorPoolOut)
13485 {
13486 if (descriptorSetLayoutDesc.empty())
13487 {
13488 // No need for descriptorSet pool.
13489 return angle::Result::Continue;
13490 }
13491
13492 auto cacheIter = mPayload.find(descriptorSetLayoutDesc);
13493 if (cacheIter != mPayload.end())
13494 {
13495 *dynamicDescriptorPoolOut = cacheIter->second;
13496 return angle::Result::Continue;
13497 }
13498
13499 DescriptorSetLayoutPtr descriptorSetLayout;
13500 ANGLE_TRY(descriptorSetLayoutCache->getDescriptorSetLayout(context, descriptorSetLayoutDesc,
13501 &descriptorSetLayout));
13502
13503 DynamicDescriptorPool newDescriptorPool;
13504 ANGLE_TRY(InitDynamicDescriptorPool(context, descriptorSetLayoutDesc, *descriptorSetLayout,
13505 descriptorCountMultiplier, &newDescriptorPool));
13506
13507 ASSERT(newDescriptorPool.valid());
13508 DynamicDescriptorPoolPointer newDynamicDescriptorPoolPtr(context->getDevice(),
13509 std::move(newDescriptorPool));
13510 mPayload.emplace(descriptorSetLayoutDesc, newDynamicDescriptorPoolPtr);
13511 *dynamicDescriptorPoolOut = std::move(newDynamicDescriptorPoolPtr);
13512
13513 return angle::Result::Continue;
13514 }
13515
13516 static_assert(static_cast<uint32_t>(PresentMode::ImmediateKHR) == VK_PRESENT_MODE_IMMEDIATE_KHR,
13517 "PresentMode must be updated");
13518 static_assert(static_cast<uint32_t>(PresentMode::MailboxKHR) == VK_PRESENT_MODE_MAILBOX_KHR,
13519 "PresentMode must be updated");
13520 static_assert(static_cast<uint32_t>(PresentMode::FifoKHR) == VK_PRESENT_MODE_FIFO_KHR,
13521 "PresentMode must be updated");
13522 static_assert(static_cast<uint32_t>(PresentMode::FifoRelaxedKHR) ==
13523 VK_PRESENT_MODE_FIFO_RELAXED_KHR,
13524 "PresentMode must be updated");
13525 static_assert(static_cast<uint32_t>(PresentMode::SharedDemandRefreshKHR) ==
13526 VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR,
13527 "PresentMode must be updated");
13528 static_assert(static_cast<uint32_t>(PresentMode::SharedContinuousRefreshKHR) ==
13529 VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR,
13530 "PresentMode must be updated");
13531
ConvertPresentModeToVkPresentMode(PresentMode presentMode)13532 VkPresentModeKHR ConvertPresentModeToVkPresentMode(PresentMode presentMode)
13533 {
13534 return static_cast<VkPresentModeKHR>(presentMode);
13535 }
13536
ConvertVkPresentModeToPresentMode(VkPresentModeKHR vkPresentMode)13537 PresentMode ConvertVkPresentModeToPresentMode(VkPresentModeKHR vkPresentMode)
13538 {
13539 return static_cast<PresentMode>(vkPresentMode);
13540 }
13541
13542 } // namespace vk
13543 } // namespace rx
13544