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 utilitiy classes that manage Vulkan resources.
8
9 #include "libANGLE/renderer/vulkan/vk_helpers.h"
10
11 #include "common/utilities.h"
12 #include "image_util/loadimage.h"
13 #include "libANGLE/Context.h"
14 #include "libANGLE/renderer/renderer_utils.h"
15 #include "libANGLE/renderer/vulkan/BufferVk.h"
16 #include "libANGLE/renderer/vulkan/ContextVk.h"
17 #include "libANGLE/renderer/vulkan/DisplayVk.h"
18 #include "libANGLE/renderer/vulkan/FramebufferVk.h"
19 #include "libANGLE/renderer/vulkan/RenderTargetVk.h"
20 #include "libANGLE/renderer/vulkan/RendererVk.h"
21 #include "libANGLE/renderer/vulkan/vk_utils.h"
22 #include "libANGLE/trace.h"
23
24 namespace rx
25 {
26 namespace vk
27 {
28 namespace
29 {
30 // ANGLE_robust_resource_initialization requires color textures to be initialized to zero.
31 constexpr VkClearColorValue kRobustInitColorValue = {{0, 0, 0, 0}};
32 // When emulating a texture, we want the emulated channels to be 0, with alpha 1.
33 constexpr VkClearColorValue kEmulatedInitColorValue = {{0, 0, 0, 1.0f}};
34 // ANGLE_robust_resource_initialization requires depth to be initialized to 1 and stencil to 0.
35 // We are fine with these values for emulated depth/stencil textures too.
36 constexpr VkClearDepthStencilValue kRobustInitDepthStencilValue = {1.0f, 0};
37
38 constexpr VkBufferUsageFlags kLineLoopDynamicBufferUsage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT |
39 VK_BUFFER_USAGE_TRANSFER_DST_BIT |
40 VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
41 constexpr int kLineLoopDynamicBufferInitialSize = 1024 * 1024;
42 constexpr VkBufferUsageFlags kLineLoopDynamicIndirectBufferUsage =
43 VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
44 VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
45 constexpr int kLineLoopDynamicIndirectBufferInitialSize = sizeof(VkDrawIndirectCommand) * 16;
46
47 // This is an arbitrary max. We can change this later if necessary.
48 constexpr uint32_t kDefaultDescriptorPoolMaxSets = 128;
49
50 constexpr angle::PackedEnumMap<PipelineStage, VkPipelineStageFlagBits> kPipelineStageFlagBitMap = {
51 {PipelineStage::TopOfPipe, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT},
52 {PipelineStage::DrawIndirect, VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT},
53 {PipelineStage::VertexInput, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT},
54 {PipelineStage::VertexShader, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT},
55 {PipelineStage::GeometryShader, VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT},
56 {PipelineStage::TransformFeedback, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT},
57 {PipelineStage::EarlyFragmentTest, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT},
58 {PipelineStage::FragmentShader, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT},
59 {PipelineStage::LateFragmentTest, VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT},
60 {PipelineStage::ColorAttachmentOutput, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT},
61 {PipelineStage::ComputeShader, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT},
62 {PipelineStage::Transfer, VK_PIPELINE_STAGE_TRANSFER_BIT},
63 {PipelineStage::BottomOfPipe, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT},
64 {PipelineStage::Host, VK_PIPELINE_STAGE_HOST_BIT}};
65
66 constexpr size_t kDefaultPoolAllocatorPageSize = 16 * 1024;
67
68 struct ImageMemoryBarrierData
69 {
70 // The Vk layout corresponding to the ImageLayout key.
71 VkImageLayout layout;
72 // The stage in which the image is used (or Bottom/Top if not using any specific stage). Unless
73 // Bottom/Top (Bottom used for transition to and Top used for transition from), the two values
74 // should match.
75 VkPipelineStageFlags dstStageMask;
76 VkPipelineStageFlags srcStageMask;
77 // Access mask when transitioning into this layout.
78 VkAccessFlags dstAccessMask;
79 // Access mask when transitioning out from this layout. Note that source access mask never
80 // needs a READ bit, as WAR hazards don't need memory barriers (just execution barriers).
81 VkAccessFlags srcAccessMask;
82
83 // If access is read-only, the memory barrier can be skipped altogether if retransitioning to
84 // the same layout. This is because read-after-read does not need an execution or memory
85 // barrier.
86 //
87 // Otherwise, some same-layout transitions require a memory barrier.
88 bool sameLayoutTransitionRequiresBarrier;
89 // CommandBufferHelper tracks an array of PipelineBarriers. This indicates which array element
90 // this should be merged into. Right now we track individual barrier for every PipelineStage. If
91 // layout has a single stage mask bit, we use that stage as index. If layout has multiple stage
92 // mask bits, we pick the lowest stage as the index since it is the first stage that needs
93 // barrier.
94 PipelineStage barrierIndex;
95 };
96
97 constexpr VkPipelineStageFlags kAllShadersPipelineStageFlags =
98 VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
99 VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
100 // clang-format off
101 constexpr angle::PackedEnumMap<ImageLayout, ImageMemoryBarrierData> kImageMemoryBarrierData = {
102 {
103 ImageLayout::Undefined,
104 {
105 VK_IMAGE_LAYOUT_UNDEFINED,
106 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
107 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
108 // Transition to: we don't expect to transition into Undefined.
109 0,
110 // Transition from: there's no data in the image to care about.
111 0,
112 false,
113 PipelineStage::InvalidEnum,
114 },
115 },
116 {
117 ImageLayout::ExternalPreInitialized,
118 {
119 VK_IMAGE_LAYOUT_PREINITIALIZED,
120 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
121 VK_PIPELINE_STAGE_HOST_BIT | VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
122 // Transition to: we don't expect to transition into PreInitialized.
123 0,
124 // Transition from: all writes must finish before barrier.
125 VK_ACCESS_MEMORY_WRITE_BIT,
126 false,
127 PipelineStage::InvalidEnum,
128 },
129 },
130 {
131 ImageLayout::ExternalShadersReadOnly,
132 {
133 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
134 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
135 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
136 // Transition to: all reads must happen after barrier.
137 VK_ACCESS_SHADER_READ_BIT,
138 // Transition from: RAR and WAR don't need memory barrier.
139 0,
140 false,
141 // In case of multiple destination stages, We barrier the earliest stage
142 PipelineStage::TopOfPipe,
143 },
144 },
145 {
146 ImageLayout::ExternalShadersWrite,
147 {
148 VK_IMAGE_LAYOUT_GENERAL,
149 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
150 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
151 // Transition to: all reads and writes must happen after barrier.
152 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
153 // Transition from: all writes must finish before barrier.
154 VK_ACCESS_SHADER_WRITE_BIT,
155 true,
156 // In case of multiple destination stages, We barrier the earliest stage
157 PipelineStage::TopOfPipe,
158 },
159 },
160 {
161 ImageLayout::TransferSrc,
162 {
163 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
164 VK_PIPELINE_STAGE_TRANSFER_BIT,
165 VK_PIPELINE_STAGE_TRANSFER_BIT,
166 // Transition to: all reads must happen after barrier.
167 VK_ACCESS_TRANSFER_READ_BIT,
168 // Transition from: RAR and WAR don't need memory barrier.
169 0,
170 false,
171 PipelineStage::Transfer,
172 },
173 },
174 {
175 ImageLayout::TransferDst,
176 {
177 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
178 VK_PIPELINE_STAGE_TRANSFER_BIT,
179 VK_PIPELINE_STAGE_TRANSFER_BIT,
180 // Transition to: all writes must happen after barrier.
181 VK_ACCESS_TRANSFER_WRITE_BIT,
182 // Transition from: all writes must finish before barrier.
183 VK_ACCESS_TRANSFER_WRITE_BIT,
184 true,
185 PipelineStage::Transfer,
186 },
187 },
188 {
189 ImageLayout::VertexShaderReadOnly,
190 {
191 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
192 VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
193 VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
194 // Transition to: all reads must happen after barrier.
195 VK_ACCESS_SHADER_READ_BIT,
196 // Transition from: RAR and WAR don't need memory barrier.
197 0,
198 false,
199 PipelineStage::VertexShader,
200 },
201 },
202 {
203 ImageLayout::VertexShaderWrite,
204 {
205 VK_IMAGE_LAYOUT_GENERAL,
206 VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
207 VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
208 // Transition to: all reads and writes must happen after barrier.
209 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
210 // Transition from: all writes must finish before barrier.
211 VK_ACCESS_SHADER_WRITE_BIT,
212 true,
213 PipelineStage::VertexShader,
214 },
215 },
216 {
217 ImageLayout::GeometryShaderReadOnly,
218 {
219 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
220 VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT,
221 VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT,
222 // Transition to: all reads must happen after barrier.
223 VK_ACCESS_SHADER_READ_BIT,
224 // Transition from: RAR and WAR don't need memory barrier.
225 0,
226 false,
227 PipelineStage::GeometryShader,
228 },
229 },
230 {
231 ImageLayout::GeometryShaderWrite,
232 {
233 VK_IMAGE_LAYOUT_GENERAL,
234 VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT,
235 VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT,
236 // Transition to: all reads and writes must happen after barrier.
237 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
238 // Transition from: all writes must finish before barrier.
239 VK_ACCESS_SHADER_WRITE_BIT,
240 true,
241 PipelineStage::GeometryShader,
242 },
243 },
244 {
245 ImageLayout::FragmentShaderReadOnly,
246 {
247 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
248 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
249 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
250 // Transition to: all reads must happen after barrier.
251 VK_ACCESS_SHADER_READ_BIT,
252 // Transition from: RAR and WAR don't need memory barrier.
253 0,
254 false,
255 PipelineStage::FragmentShader,
256 },
257 },
258 {
259 ImageLayout::FragmentShaderWrite,
260 {
261 VK_IMAGE_LAYOUT_GENERAL,
262 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
263 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
264 // Transition to: all reads and writes must happen after barrier.
265 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
266 // Transition from: all writes must finish before barrier.
267 VK_ACCESS_SHADER_WRITE_BIT,
268 true,
269 PipelineStage::FragmentShader,
270 },
271 },
272 {
273 ImageLayout::ComputeShaderReadOnly,
274 {
275 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
276 VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
277 VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
278 // Transition to: all reads must happen after barrier.
279 VK_ACCESS_SHADER_READ_BIT,
280 // Transition from: RAR and WAR don't need memory barrier.
281 0,
282 false,
283 PipelineStage::ComputeShader,
284 },
285 },
286 {
287 ImageLayout::ComputeShaderWrite,
288 {
289 VK_IMAGE_LAYOUT_GENERAL,
290 VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
291 VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
292 // Transition to: all reads and writes must happen after barrier.
293 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
294 // Transition from: all writes must finish before barrier.
295 VK_ACCESS_SHADER_WRITE_BIT,
296 true,
297 vk::PipelineStage::ComputeShader,
298 },
299 },
300 {
301 ImageLayout::AllGraphicsShadersReadOnly,
302 {
303 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
304 kAllShadersPipelineStageFlags,
305 kAllShadersPipelineStageFlags,
306 // Transition to: all reads must happen after barrier.
307 VK_ACCESS_SHADER_READ_BIT,
308 // Transition from: RAR and WAR don't need memory barrier.
309 0,
310 false,
311 // In case of multiple destination stages, We barrier the earliest stage
312 PipelineStage::VertexShader,
313 },
314 },
315 {
316 ImageLayout::AllGraphicsShadersReadWrite,
317 {
318 VK_IMAGE_LAYOUT_GENERAL,
319 kAllShadersPipelineStageFlags,
320 kAllShadersPipelineStageFlags,
321 // Transition to: all reads and writes must happen after barrier.
322 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
323 // Transition from: all writes must finish before barrier.
324 VK_ACCESS_SHADER_WRITE_BIT,
325 true,
326 // In case of multiple destination stages, We barrier the earliest stage
327 PipelineStage::VertexShader,
328 },
329 },
330 {
331 ImageLayout::ColorAttachment,
332 {
333 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
334 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
335 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
336 // Transition to: all reads and writes must happen after barrier.
337 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
338 // Transition from: all writes must finish before barrier.
339 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
340 true,
341 PipelineStage::ColorAttachmentOutput,
342 },
343 },
344 {
345 ImageLayout::DepthStencilAttachment,
346 {
347 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
348 VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
349 VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
350 // Transition to: all reads and writes must happen after barrier.
351 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
352 // Transition from: all writes must finish before barrier.
353 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
354 true,
355 PipelineStage::EarlyFragmentTest,
356 },
357 },
358 {
359 ImageLayout::Present,
360 {
361 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
362 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
363 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
364 // transition to: vkQueuePresentKHR automatically performs the appropriate memory barriers:
365 //
366 // > Any writes to memory backing the images referenced by the pImageIndices and
367 // > pSwapchains members of pPresentInfo, that are available before vkQueuePresentKHR
368 // > is executed, are automatically made visible to the read access performed by the
369 // > presentation engine.
370 0,
371 // Transition from: RAR and WAR don't need memory barrier.
372 0,
373 false,
374 PipelineStage::BottomOfPipe,
375 },
376 },
377 };
378 // clang-format on
379
GetImageCreateFlags(gl::TextureType textureType)380 VkImageCreateFlags GetImageCreateFlags(gl::TextureType textureType)
381 {
382 switch (textureType)
383 {
384 case gl::TextureType::CubeMap:
385 return VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
386
387 case gl::TextureType::_3D:
388 return VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
389
390 default:
391 return 0;
392 }
393 }
394
HandlePrimitiveRestart(ContextVk * contextVk,gl::DrawElementsType glIndexType,GLsizei indexCount,const uint8_t * srcPtr,uint8_t * outPtr)395 void HandlePrimitiveRestart(ContextVk *contextVk,
396 gl::DrawElementsType glIndexType,
397 GLsizei indexCount,
398 const uint8_t *srcPtr,
399 uint8_t *outPtr)
400 {
401 switch (glIndexType)
402 {
403 case gl::DrawElementsType::UnsignedByte:
404 if (contextVk->getFeatures().supportsIndexTypeUint8.enabled)
405 {
406 CopyLineLoopIndicesWithRestart<uint8_t, uint8_t>(indexCount, srcPtr, outPtr);
407 }
408 else
409 {
410 CopyLineLoopIndicesWithRestart<uint8_t, uint16_t>(indexCount, srcPtr, outPtr);
411 }
412 break;
413 case gl::DrawElementsType::UnsignedShort:
414 CopyLineLoopIndicesWithRestart<uint16_t, uint16_t>(indexCount, srcPtr, outPtr);
415 break;
416 case gl::DrawElementsType::UnsignedInt:
417 CopyLineLoopIndicesWithRestart<uint32_t, uint32_t>(indexCount, srcPtr, outPtr);
418 break;
419 default:
420 UNREACHABLE();
421 }
422 }
423
HasBothDepthAndStencilAspects(VkImageAspectFlags aspectFlags)424 bool HasBothDepthAndStencilAspects(VkImageAspectFlags aspectFlags)
425 {
426 constexpr VkImageAspectFlags kDepthStencilAspects =
427 VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_DEPTH_BIT;
428 return (aspectFlags & kDepthStencilAspects) == kDepthStencilAspects;
429 }
430
GetImageLayerCountForView(const ImageHelper & image)431 uint32_t GetImageLayerCountForView(const ImageHelper &image)
432 {
433 // Depth > 1 means this is a 3D texture and depth is our layer count
434 return image.getExtents().depth > 1 ? image.getExtents().depth : image.getLayerCount();
435 }
436
GetLevelImageView(ImageViewVector * imageViews,uint32_t level,uint32_t levelCount)437 ImageView *GetLevelImageView(ImageViewVector *imageViews, uint32_t level, uint32_t levelCount)
438 {
439 // Lazily allocate the storage for image views. We allocate the full level count because we
440 // don't want to trigger any std::vecotr reallocations. Reallocations could invalidate our
441 // view pointers.
442 if (imageViews->empty())
443 {
444 imageViews->resize(levelCount);
445 }
446 ASSERT(imageViews->size() > level);
447
448 return &(*imageViews)[level];
449 }
450
451 // Special rules apply to VkBufferImageCopy with depth/stencil. The components are tightly packed
452 // into a depth or stencil section of the destination buffer. See the spec:
453 // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VkBufferImageCopy.html
GetDepthStencilImageToBufferFormat(const angle::Format & imageFormat,VkImageAspectFlagBits copyAspect)454 const angle::Format &GetDepthStencilImageToBufferFormat(const angle::Format &imageFormat,
455 VkImageAspectFlagBits copyAspect)
456 {
457 if (copyAspect == VK_IMAGE_ASPECT_STENCIL_BIT)
458 {
459 ASSERT(imageFormat.id == angle::FormatID::D24_UNORM_S8_UINT ||
460 imageFormat.id == angle::FormatID::D32_FLOAT_S8X24_UINT ||
461 imageFormat.id == angle::FormatID::S8_UINT);
462 return angle::Format::Get(angle::FormatID::S8_UINT);
463 }
464
465 ASSERT(copyAspect == VK_IMAGE_ASPECT_DEPTH_BIT);
466
467 switch (imageFormat.id)
468 {
469 case angle::FormatID::D16_UNORM:
470 return imageFormat;
471 case angle::FormatID::D24_UNORM_X8_UINT:
472 return imageFormat;
473 case angle::FormatID::D24_UNORM_S8_UINT:
474 return angle::Format::Get(angle::FormatID::D24_UNORM_X8_UINT);
475 case angle::FormatID::D32_FLOAT:
476 return imageFormat;
477 case angle::FormatID::D32_FLOAT_S8X24_UINT:
478 return angle::Format::Get(angle::FormatID::D32_FLOAT);
479 default:
480 UNREACHABLE();
481 return imageFormat;
482 }
483 }
484
GetRobustResourceClearValue(const vk::Format & format)485 VkClearValue GetRobustResourceClearValue(const vk::Format &format)
486 {
487 VkClearValue clearValue;
488 if (format.intendedFormat().hasDepthOrStencilBits())
489 {
490 clearValue.depthStencil = kRobustInitDepthStencilValue;
491 }
492 else
493 {
494 clearValue.color =
495 format.hasEmulatedImageChannels() ? kEmulatedInitColorValue : kRobustInitColorValue;
496 }
497 return clearValue;
498 }
499
500 #if !defined(ANGLE_PLATFORM_MACOS) && !defined(ANGLE_PLATFORM_ANDROID)
IsExternalQueueFamily(uint32_t queueFamilyIndex)501 bool IsExternalQueueFamily(uint32_t queueFamilyIndex)
502 {
503 return queueFamilyIndex == VK_QUEUE_FAMILY_EXTERNAL ||
504 queueFamilyIndex == VK_QUEUE_FAMILY_FOREIGN_EXT;
505 }
506 #endif
507
508 } // anonymous namespace
509
ConvertImageLayoutToVkImageLayout(ImageLayout imageLayout)510 VkImageLayout ConvertImageLayoutToVkImageLayout(ImageLayout imageLayout)
511 {
512 return kImageMemoryBarrierData[imageLayout].layout;
513 }
514
515 // CommandBufferHelper implementation.
CommandBufferHelper()516 CommandBufferHelper::CommandBufferHelper()
517 : mPipelineBarriers(),
518 mPipelineBarrierMask(),
519 mCounter(0),
520 mClearValues{},
521 mRenderPassStarted(false),
522 mTransformFeedbackCounterBuffers{},
523 mValidTransformFeedbackBufferCount(0),
524 mRebindTransformFeedbackBuffers(false),
525 mIsRenderPassCommandBuffer(false),
526 mMergeBarriers(false)
527 {}
528
~CommandBufferHelper()529 CommandBufferHelper::~CommandBufferHelper()
530 {
531 mFramebuffer.setHandle(VK_NULL_HANDLE);
532 }
533
initialize(bool isRenderPassCommandBuffer,bool mergeBarriers)534 void CommandBufferHelper::initialize(bool isRenderPassCommandBuffer, bool mergeBarriers)
535 {
536 mAllocator.initialize(kDefaultPoolAllocatorPageSize, 1);
537 // Push a scope into the pool allocator so we can easily free and re-init on reset()
538 mAllocator.push();
539 mCommandBuffer.initialize(&mAllocator);
540 mIsRenderPassCommandBuffer = isRenderPassCommandBuffer;
541 mMergeBarriers = mergeBarriers;
542 }
543
bufferRead(vk::ResourceUseList * resourceUseList,VkAccessFlags readAccessType,vk::PipelineStage readStage,vk::BufferHelper * buffer)544 void CommandBufferHelper::bufferRead(vk::ResourceUseList *resourceUseList,
545 VkAccessFlags readAccessType,
546 vk::PipelineStage readStage,
547 vk::BufferHelper *buffer)
548 {
549 buffer->retain(resourceUseList);
550 VkPipelineStageFlagBits stageBits = kPipelineStageFlagBitMap[readStage];
551 if (buffer->updateReadBarrier(readAccessType, stageBits, &mPipelineBarriers[readStage]))
552 {
553 mPipelineBarrierMask.set(readStage);
554 }
555 }
556
bufferWrite(vk::ResourceUseList * resourceUseList,VkAccessFlags writeAccessType,vk::PipelineStage writeStage,vk::BufferHelper * buffer)557 void CommandBufferHelper::bufferWrite(vk::ResourceUseList *resourceUseList,
558 VkAccessFlags writeAccessType,
559 vk::PipelineStage writeStage,
560 vk::BufferHelper *buffer)
561 {
562 buffer->retain(resourceUseList);
563 VkPipelineStageFlagBits stageBits = kPipelineStageFlagBitMap[writeStage];
564 if (buffer->updateWriteBarrier(writeAccessType, stageBits, &mPipelineBarriers[writeStage]))
565 {
566 mPipelineBarrierMask.set(writeStage);
567 }
568 }
569
imageRead(vk::ResourceUseList * resourceUseList,VkImageAspectFlags aspectFlags,vk::ImageLayout imageLayout,vk::ImageHelper * image)570 void CommandBufferHelper::imageRead(vk::ResourceUseList *resourceUseList,
571 VkImageAspectFlags aspectFlags,
572 vk::ImageLayout imageLayout,
573 vk::ImageHelper *image)
574 {
575 image->retain(resourceUseList);
576 if (image->isLayoutChangeNecessary(imageLayout))
577 {
578 PipelineStage barrierIndex = kImageMemoryBarrierData[imageLayout].barrierIndex;
579 ASSERT(barrierIndex != PipelineStage::InvalidEnum);
580 PipelineBarrier *barrier = &mPipelineBarriers[barrierIndex];
581 if (image->updateLayoutAndBarrier(aspectFlags, imageLayout, barrier))
582 {
583 mPipelineBarrierMask.set(barrierIndex);
584 }
585 }
586 }
587
imageWrite(vk::ResourceUseList * resourceUseList,VkImageAspectFlags aspectFlags,vk::ImageLayout imageLayout,vk::ImageHelper * image)588 void CommandBufferHelper::imageWrite(vk::ResourceUseList *resourceUseList,
589 VkImageAspectFlags aspectFlags,
590 vk::ImageLayout imageLayout,
591 vk::ImageHelper *image)
592 {
593 image->retain(resourceUseList);
594 // Write always requires a barrier
595 PipelineStage barrierIndex = kImageMemoryBarrierData[imageLayout].barrierIndex;
596 ASSERT(barrierIndex != PipelineStage::InvalidEnum);
597 PipelineBarrier *barrier = &mPipelineBarriers[barrierIndex];
598 if (image->updateLayoutAndBarrier(aspectFlags, imageLayout, barrier))
599 {
600 mPipelineBarrierMask.set(barrierIndex);
601 }
602 }
603
executeBarriers(vk::PrimaryCommandBuffer * primary)604 void CommandBufferHelper::executeBarriers(vk::PrimaryCommandBuffer *primary)
605 {
606 // make a local copy for faster access
607 PipelineStagesMask mask = mPipelineBarrierMask;
608 if (mask.none())
609 {
610 return;
611 }
612
613 if (mMergeBarriers)
614 {
615 PipelineStagesMask::Iterator iter = mask.begin();
616 PipelineBarrier &barrier = mPipelineBarriers[*iter];
617 for (++iter; iter != mask.end(); ++iter)
618 {
619 barrier.merge(&mPipelineBarriers[*iter]);
620 }
621 barrier.execute(primary);
622 }
623 else
624 {
625 for (PipelineStage pipelineStage : mask)
626 {
627 PipelineBarrier &barrier = mPipelineBarriers[pipelineStage];
628 barrier.execute(primary);
629 }
630 }
631 mPipelineBarrierMask.reset();
632 }
633
beginRenderPass(const vk::Framebuffer & framebuffer,const gl::Rectangle & renderArea,const vk::RenderPassDesc & renderPassDesc,const vk::AttachmentOpsArray & renderPassAttachmentOps,const vk::ClearValuesArray & clearValues,vk::CommandBuffer ** commandBufferOut)634 void CommandBufferHelper::beginRenderPass(const vk::Framebuffer &framebuffer,
635 const gl::Rectangle &renderArea,
636 const vk::RenderPassDesc &renderPassDesc,
637 const vk::AttachmentOpsArray &renderPassAttachmentOps,
638 const vk::ClearValuesArray &clearValues,
639 vk::CommandBuffer **commandBufferOut)
640 {
641 ASSERT(mIsRenderPassCommandBuffer);
642 ASSERT(empty());
643
644 mRenderPassDesc = renderPassDesc;
645 mAttachmentOps = renderPassAttachmentOps;
646 mFramebuffer.setHandle(framebuffer.getHandle());
647 mRenderArea = renderArea;
648 mClearValues = clearValues;
649
650 *commandBufferOut = &mCommandBuffer;
651
652 mRenderPassStarted = true;
653 mCounter++;
654 }
655
beginTransformFeedback(size_t validBufferCount,const VkBuffer * counterBuffers,bool rebindBuffers)656 void CommandBufferHelper::beginTransformFeedback(size_t validBufferCount,
657 const VkBuffer *counterBuffers,
658 bool rebindBuffers)
659 {
660 ASSERT(mIsRenderPassCommandBuffer);
661 mValidTransformFeedbackBufferCount = static_cast<uint32_t>(validBufferCount);
662 mRebindTransformFeedbackBuffers = rebindBuffers;
663
664 for (size_t index = 0; index < validBufferCount; index++)
665 {
666 mTransformFeedbackCounterBuffers[index] = counterBuffers[index];
667 }
668 }
669
flushToPrimary(ContextVk * contextVk,vk::PrimaryCommandBuffer * primary)670 angle::Result CommandBufferHelper::flushToPrimary(ContextVk *contextVk,
671 vk::PrimaryCommandBuffer *primary)
672 {
673 ANGLE_TRACE_EVENT0("gpu.angle", "CommandBufferHelper::flushToPrimary");
674 ASSERT(!empty());
675 if (kEnableCommandStreamDiagnostics)
676 {
677 addCommandDiagnostics(contextVk);
678 }
679 // Commands that are added to primary before beginRenderPass command
680 executeBarriers(primary);
681
682 if (mIsRenderPassCommandBuffer)
683 {
684 mCommandBuffer.executeQueuedResetQueryPoolCommands(primary->getHandle());
685 // Pull a RenderPass from the cache.
686 RenderPassCache &renderPassCache = contextVk->getRenderPassCache();
687 Serial serial = contextVk->getCurrentQueueSerial();
688
689 vk::RenderPass *renderPass = nullptr;
690 ANGLE_TRY(renderPassCache.getRenderPassWithOps(contextVk, serial, mRenderPassDesc,
691 mAttachmentOps, &renderPass));
692
693 VkRenderPassBeginInfo beginInfo = {};
694 beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
695 beginInfo.renderPass = renderPass->getHandle();
696 beginInfo.framebuffer = mFramebuffer.getHandle();
697 beginInfo.renderArea.offset.x = static_cast<uint32_t>(mRenderArea.x);
698 beginInfo.renderArea.offset.y = static_cast<uint32_t>(mRenderArea.y);
699 beginInfo.renderArea.extent.width = static_cast<uint32_t>(mRenderArea.width);
700 beginInfo.renderArea.extent.height = static_cast<uint32_t>(mRenderArea.height);
701 beginInfo.clearValueCount = static_cast<uint32_t>(mRenderPassDesc.attachmentCount());
702 beginInfo.pClearValues = mClearValues.data();
703
704 // Run commands inside the RenderPass.
705 primary->beginRenderPass(beginInfo, VK_SUBPASS_CONTENTS_INLINE);
706 mCommandBuffer.executeCommands(primary->getHandle());
707 primary->endRenderPass();
708
709 if (mValidTransformFeedbackBufferCount != 0)
710 {
711 // Would be better to accumulate this barrier using the command APIs.
712 // TODO: Clean thus up before we close http://anglebug.com/3206
713 VkBufferMemoryBarrier bufferBarrier = {};
714 bufferBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
715 bufferBarrier.pNext = nullptr;
716 bufferBarrier.srcAccessMask = VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT;
717 bufferBarrier.dstAccessMask = VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT;
718 bufferBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
719 bufferBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
720 bufferBarrier.buffer = mTransformFeedbackCounterBuffers[0];
721 bufferBarrier.offset = 0;
722 bufferBarrier.size = VK_WHOLE_SIZE;
723
724 primary->pipelineBarrier(VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT,
725 VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, 0u, 0u, nullptr, 1u,
726 &bufferBarrier, 0u, nullptr);
727 }
728 }
729 else
730 {
731 mCommandBuffer.executeCommands(primary->getHandle());
732 }
733 // Restart the command buffer.
734 reset();
735
736 return angle::Result::Continue;
737 }
738
739 // Helper functions used below
GetLoadOpShorthand(uint32_t loadOp)740 char GetLoadOpShorthand(uint32_t loadOp)
741 {
742 switch (loadOp)
743 {
744 case VK_ATTACHMENT_LOAD_OP_CLEAR:
745 return 'C';
746 case VK_ATTACHMENT_LOAD_OP_LOAD:
747 return 'L';
748 default:
749 return 'D';
750 }
751 }
752
GetStoreOpShorthand(uint32_t storeOp)753 char GetStoreOpShorthand(uint32_t storeOp)
754 {
755 switch (storeOp)
756 {
757 case VK_ATTACHMENT_STORE_OP_STORE:
758 return 'S';
759 default:
760 return 'D';
761 }
762 }
763
addCommandDiagnostics(ContextVk * contextVk)764 void CommandBufferHelper::addCommandDiagnostics(ContextVk *contextVk)
765 {
766 std::ostringstream out;
767
768 out << "Memory Barrier: ";
769 for (PipelineBarrier &barrier : mPipelineBarriers)
770 {
771 if (!barrier.isEmpty())
772 {
773 barrier.addDiagnosticsString(out);
774 }
775 }
776 out << "\\l";
777
778 if (mIsRenderPassCommandBuffer)
779 {
780 size_t attachmentCount = mRenderPassDesc.attachmentCount();
781 size_t depthStencilAttachmentCount = mRenderPassDesc.hasDepthStencilAttachment();
782 size_t colorAttachmentCount = attachmentCount - depthStencilAttachmentCount;
783
784 std::string loadOps, storeOps;
785
786 if (colorAttachmentCount > 0)
787 {
788 loadOps += " Color: ";
789 storeOps += " Color: ";
790
791 for (size_t i = 0; i < colorAttachmentCount; ++i)
792 {
793 loadOps += GetLoadOpShorthand(mAttachmentOps[i].loadOp);
794 storeOps += GetStoreOpShorthand(mAttachmentOps[i].storeOp);
795 }
796 }
797
798 if (depthStencilAttachmentCount > 0)
799 {
800 ASSERT(depthStencilAttachmentCount == 1);
801
802 loadOps += " Depth/Stencil: ";
803 storeOps += " Depth/Stencil: ";
804 size_t dsIndex = colorAttachmentCount;
805
806 loadOps += GetLoadOpShorthand(mAttachmentOps[dsIndex].loadOp);
807 loadOps += GetLoadOpShorthand(mAttachmentOps[dsIndex].stencilLoadOp);
808
809 storeOps += GetStoreOpShorthand(mAttachmentOps[dsIndex].storeOp);
810 storeOps += GetStoreOpShorthand(mAttachmentOps[dsIndex].stencilStoreOp);
811 }
812
813 if (attachmentCount > 0)
814 {
815 out << "LoadOp: " << loadOps << "\\l";
816 out << "StoreOp: " << storeOps << "\\l";
817 }
818 }
819 out << mCommandBuffer.dumpCommands("\\l");
820 contextVk->addCommandBufferDiagnostics(out.str());
821 }
822
reset()823 void CommandBufferHelper::reset()
824 {
825 mAllocator.pop();
826 mAllocator.push();
827 mCommandBuffer.reset();
828 if (mIsRenderPassCommandBuffer)
829 {
830 mRenderPassStarted = false;
831 mValidTransformFeedbackBufferCount = 0;
832 mRebindTransformFeedbackBuffers = false;
833 }
834 // This state should never change for non-renderPass command buffer
835 ASSERT(mRenderPassStarted == false);
836 ASSERT(mValidTransformFeedbackBufferCount == 0);
837 ASSERT(mRebindTransformFeedbackBuffers == false);
838 }
839
releaseToContextQueue(ContextVk * contextVk)840 void CommandBufferHelper::releaseToContextQueue(ContextVk *contextVk)
841 {
842 contextVk->recycleCommandBuffer(this);
843 }
844
resumeTransformFeedbackIfStarted()845 void CommandBufferHelper::resumeTransformFeedbackIfStarted()
846 {
847 ASSERT(mIsRenderPassCommandBuffer);
848 if (mValidTransformFeedbackBufferCount == 0)
849 {
850 return;
851 }
852
853 uint32_t numCounterBuffers =
854 mRebindTransformFeedbackBuffers ? 0 : mValidTransformFeedbackBufferCount;
855
856 mRebindTransformFeedbackBuffers = false;
857
858 mCommandBuffer.beginTransformFeedback(numCounterBuffers,
859 mTransformFeedbackCounterBuffers.data());
860 }
861
pauseTransformFeedbackIfStarted()862 void CommandBufferHelper::pauseTransformFeedbackIfStarted()
863 {
864 ASSERT(mIsRenderPassCommandBuffer);
865 if (mValidTransformFeedbackBufferCount == 0)
866 {
867 return;
868 }
869
870 mCommandBuffer.endTransformFeedback(mValidTransformFeedbackBufferCount,
871 mTransformFeedbackCounterBuffers.data());
872 }
873
874 // DynamicBuffer implementation.
DynamicBuffer()875 DynamicBuffer::DynamicBuffer()
876 : mUsage(0),
877 mHostVisible(false),
878 mInitialSize(0),
879 mBuffer(nullptr),
880 mNextAllocationOffset(0),
881 mLastFlushOrInvalidateOffset(0),
882 mSize(0),
883 mAlignment(0),
884 mMemoryPropertyFlags(0)
885 {}
886
DynamicBuffer(DynamicBuffer && other)887 DynamicBuffer::DynamicBuffer(DynamicBuffer &&other)
888 : mUsage(other.mUsage),
889 mHostVisible(other.mHostVisible),
890 mInitialSize(other.mInitialSize),
891 mBuffer(other.mBuffer),
892 mNextAllocationOffset(other.mNextAllocationOffset),
893 mLastFlushOrInvalidateOffset(other.mLastFlushOrInvalidateOffset),
894 mSize(other.mSize),
895 mAlignment(other.mAlignment),
896 mMemoryPropertyFlags(other.mMemoryPropertyFlags),
897 mInFlightBuffers(std::move(other.mInFlightBuffers))
898 {
899 other.mBuffer = nullptr;
900 }
901
init(RendererVk * renderer,VkBufferUsageFlags usage,size_t alignment,size_t initialSize,bool hostVisible)902 void DynamicBuffer::init(RendererVk *renderer,
903 VkBufferUsageFlags usage,
904 size_t alignment,
905 size_t initialSize,
906 bool hostVisible)
907 {
908 VkMemoryPropertyFlags memoryPropertyFlags =
909 (hostVisible) ? VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT : VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
910
911 initWithFlags(renderer, usage, alignment, initialSize, memoryPropertyFlags);
912 }
913
initWithFlags(RendererVk * renderer,VkBufferUsageFlags usage,size_t alignment,size_t initialSize,VkMemoryPropertyFlags memoryPropertyFlags)914 void DynamicBuffer::initWithFlags(RendererVk *renderer,
915 VkBufferUsageFlags usage,
916 size_t alignment,
917 size_t initialSize,
918 VkMemoryPropertyFlags memoryPropertyFlags)
919 {
920 mUsage = usage;
921 mHostVisible = ((memoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0);
922 mMemoryPropertyFlags = memoryPropertyFlags;
923
924 // Check that we haven't overriden the initial size of the buffer in setMinimumSizeForTesting.
925 if (mInitialSize == 0)
926 {
927 mInitialSize = initialSize;
928 mSize = 0;
929 }
930
931 // Workaround for the mock ICD not supporting allocations greater than 0x1000.
932 // Could be removed if https://github.com/KhronosGroup/Vulkan-Tools/issues/84 is fixed.
933 if (renderer->isMockICDEnabled())
934 {
935 mSize = std::min<size_t>(mSize, 0x1000);
936 }
937
938 updateAlignment(renderer, alignment);
939 }
940
~DynamicBuffer()941 DynamicBuffer::~DynamicBuffer()
942 {
943 ASSERT(mBuffer == nullptr);
944 }
945
allocateNewBuffer(ContextVk * contextVk)946 angle::Result DynamicBuffer::allocateNewBuffer(ContextVk *contextVk)
947 {
948 std::unique_ptr<BufferHelper> buffer = std::make_unique<BufferHelper>();
949
950 VkBufferCreateInfo createInfo = {};
951 createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
952 createInfo.flags = 0;
953 createInfo.size = mSize;
954 createInfo.usage = mUsage;
955 createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
956 createInfo.queueFamilyIndexCount = 0;
957 createInfo.pQueueFamilyIndices = nullptr;
958
959 ANGLE_TRY(buffer->init(contextVk, createInfo, mMemoryPropertyFlags));
960
961 ASSERT(!mBuffer);
962 mBuffer = buffer.release();
963
964 return angle::Result::Continue;
965 }
966
allocate(ContextVk * contextVk,size_t sizeInBytes,uint8_t ** ptrOut,VkBuffer * bufferOut,VkDeviceSize * offsetOut,bool * newBufferAllocatedOut)967 angle::Result DynamicBuffer::allocate(ContextVk *contextVk,
968 size_t sizeInBytes,
969 uint8_t **ptrOut,
970 VkBuffer *bufferOut,
971 VkDeviceSize *offsetOut,
972 bool *newBufferAllocatedOut)
973 {
974 size_t sizeToAllocate = roundUp(sizeInBytes, mAlignment);
975
976 angle::base::CheckedNumeric<size_t> checkedNextWriteOffset = mNextAllocationOffset;
977 checkedNextWriteOffset += sizeToAllocate;
978
979 if (!checkedNextWriteOffset.IsValid() || checkedNextWriteOffset.ValueOrDie() >= mSize)
980 {
981 if (mBuffer)
982 {
983 ANGLE_TRY(flush(contextVk));
984 mBuffer->unmap(contextVk->getRenderer());
985
986 mInFlightBuffers.push_back(mBuffer);
987 mBuffer = nullptr;
988 }
989
990 if (sizeToAllocate > mSize)
991 {
992 mSize = std::max(mInitialSize, sizeToAllocate);
993
994 // Clear the free list since the free buffers are now too small.
995 for (BufferHelper *toFree : mBufferFreeList)
996 {
997 toFree->release(contextVk->getRenderer());
998 }
999 mBufferFreeList.clear();
1000 }
1001
1002 // The front of the free list should be the oldest. Thus if it is in use the rest of the
1003 // free list should be in use as well.
1004 if (mBufferFreeList.empty() ||
1005 mBufferFreeList.front()->isCurrentlyInUse(contextVk->getLastCompletedQueueSerial()))
1006 {
1007 ANGLE_TRY(allocateNewBuffer(contextVk));
1008 }
1009 else
1010 {
1011 mBuffer = mBufferFreeList.front();
1012 mBufferFreeList.erase(mBufferFreeList.begin());
1013 }
1014
1015 ASSERT(mBuffer->getSize() == mSize);
1016
1017 mNextAllocationOffset = 0;
1018 mLastFlushOrInvalidateOffset = 0;
1019
1020 if (newBufferAllocatedOut != nullptr)
1021 {
1022 *newBufferAllocatedOut = true;
1023 }
1024 }
1025 else if (newBufferAllocatedOut != nullptr)
1026 {
1027 *newBufferAllocatedOut = false;
1028 }
1029
1030 ASSERT(mBuffer != nullptr);
1031
1032 if (bufferOut != nullptr)
1033 {
1034 *bufferOut = mBuffer->getBuffer().getHandle();
1035 }
1036
1037 // Optionally map() the buffer if possible
1038 if (ptrOut)
1039 {
1040 ASSERT(mHostVisible);
1041 uint8_t *mappedMemory;
1042 ANGLE_TRY(mBuffer->map(contextVk, &mappedMemory));
1043 *ptrOut = mappedMemory + mNextAllocationOffset;
1044 }
1045
1046 if (offsetOut != nullptr)
1047 {
1048 *offsetOut = static_cast<VkDeviceSize>(mNextAllocationOffset);
1049 }
1050
1051 mNextAllocationOffset += static_cast<uint32_t>(sizeToAllocate);
1052 return angle::Result::Continue;
1053 }
1054
flush(ContextVk * contextVk)1055 angle::Result DynamicBuffer::flush(ContextVk *contextVk)
1056 {
1057 if (mHostVisible && (mNextAllocationOffset > mLastFlushOrInvalidateOffset))
1058 {
1059 ASSERT(mBuffer != nullptr);
1060 ANGLE_TRY(mBuffer->flush(contextVk->getRenderer(), mLastFlushOrInvalidateOffset,
1061 mNextAllocationOffset - mLastFlushOrInvalidateOffset));
1062 mLastFlushOrInvalidateOffset = mNextAllocationOffset;
1063 }
1064 return angle::Result::Continue;
1065 }
1066
invalidate(ContextVk * contextVk)1067 angle::Result DynamicBuffer::invalidate(ContextVk *contextVk)
1068 {
1069 if (mHostVisible && (mNextAllocationOffset > mLastFlushOrInvalidateOffset))
1070 {
1071 ASSERT(mBuffer != nullptr);
1072 ANGLE_TRY(mBuffer->invalidate(contextVk->getRenderer(), mLastFlushOrInvalidateOffset,
1073 mNextAllocationOffset - mLastFlushOrInvalidateOffset));
1074 mLastFlushOrInvalidateOffset = mNextAllocationOffset;
1075 }
1076 return angle::Result::Continue;
1077 }
1078
releaseBufferListToRenderer(RendererVk * renderer,std::vector<BufferHelper * > * buffers)1079 void DynamicBuffer::releaseBufferListToRenderer(RendererVk *renderer,
1080 std::vector<BufferHelper *> *buffers)
1081 {
1082 for (BufferHelper *toFree : *buffers)
1083 {
1084 toFree->release(renderer);
1085 delete toFree;
1086 }
1087
1088 buffers->clear();
1089 }
1090
destroyBufferList(RendererVk * renderer,std::vector<BufferHelper * > * buffers)1091 void DynamicBuffer::destroyBufferList(RendererVk *renderer, std::vector<BufferHelper *> *buffers)
1092 {
1093 for (BufferHelper *toFree : *buffers)
1094 {
1095 toFree->destroy(renderer);
1096 delete toFree;
1097 }
1098
1099 buffers->clear();
1100 }
1101
release(RendererVk * renderer)1102 void DynamicBuffer::release(RendererVk *renderer)
1103 {
1104 reset();
1105
1106 releaseBufferListToRenderer(renderer, &mInFlightBuffers);
1107 releaseBufferListToRenderer(renderer, &mBufferFreeList);
1108
1109 if (mBuffer)
1110 {
1111 mBuffer->release(renderer);
1112 SafeDelete(mBuffer);
1113 }
1114 }
1115
releaseInFlightBuffers(ContextVk * contextVk)1116 void DynamicBuffer::releaseInFlightBuffers(ContextVk *contextVk)
1117 {
1118 for (BufferHelper *toRelease : mInFlightBuffers)
1119 {
1120 // If the dynamic buffer was resized we cannot reuse the retained buffer.
1121 if (toRelease->getSize() < mSize)
1122 {
1123 toRelease->release(contextVk->getRenderer());
1124 }
1125 else
1126 {
1127 mBufferFreeList.push_back(toRelease);
1128 }
1129 }
1130
1131 mInFlightBuffers.clear();
1132 }
1133
destroy(RendererVk * renderer)1134 void DynamicBuffer::destroy(RendererVk *renderer)
1135 {
1136 reset();
1137
1138 destroyBufferList(renderer, &mInFlightBuffers);
1139 destroyBufferList(renderer, &mBufferFreeList);
1140
1141 if (mBuffer)
1142 {
1143 mBuffer->unmap(renderer);
1144 mBuffer->destroy(renderer);
1145 delete mBuffer;
1146 mBuffer = nullptr;
1147 }
1148 }
1149
updateAlignment(RendererVk * renderer,size_t alignment)1150 void DynamicBuffer::updateAlignment(RendererVk *renderer, size_t alignment)
1151 {
1152 ASSERT(alignment > 0);
1153
1154 size_t atomSize =
1155 static_cast<size_t>(renderer->getPhysicalDeviceProperties().limits.nonCoherentAtomSize);
1156
1157 // We need lcm(alignment, atomSize). Usually, one divides the other so std::max() could be used
1158 // instead. Only known case where this assumption breaks is for 3-component types with 16- or
1159 // 32-bit channels, so that's special-cased to avoid a full-fledged lcm implementation.
1160
1161 if (gl::isPow2(alignment))
1162 {
1163 ASSERT(alignment % atomSize == 0 || atomSize % alignment == 0);
1164 ASSERT(gl::isPow2(atomSize));
1165
1166 alignment = std::max(alignment, atomSize);
1167 }
1168 else
1169 {
1170 ASSERT(gl::isPow2(atomSize));
1171 ASSERT(alignment % 3 == 0);
1172 ASSERT(gl::isPow2(alignment / 3));
1173
1174 alignment = std::max(alignment / 3, atomSize) * 3;
1175 }
1176
1177 // If alignment has changed, make sure the next allocation is done at an aligned offset.
1178 if (alignment != mAlignment)
1179 {
1180 mNextAllocationOffset = roundUp(mNextAllocationOffset, static_cast<uint32_t>(alignment));
1181 }
1182
1183 mAlignment = alignment;
1184 }
1185
setMinimumSizeForTesting(size_t minSize)1186 void DynamicBuffer::setMinimumSizeForTesting(size_t minSize)
1187 {
1188 // This will really only have an effect next time we call allocate.
1189 mInitialSize = minSize;
1190
1191 // Forces a new allocation on the next allocate.
1192 mSize = 0;
1193 }
1194
reset()1195 void DynamicBuffer::reset()
1196 {
1197 mSize = 0;
1198 mNextAllocationOffset = 0;
1199 mLastFlushOrInvalidateOffset = 0;
1200 }
1201
1202 // DynamicShadowBuffer implementation.
DynamicShadowBuffer()1203 DynamicShadowBuffer::DynamicShadowBuffer() : mInitialSize(0), mSize(0) {}
1204
DynamicShadowBuffer(DynamicShadowBuffer && other)1205 DynamicShadowBuffer::DynamicShadowBuffer(DynamicShadowBuffer &&other)
1206 : mInitialSize(other.mInitialSize), mSize(other.mSize), mBuffer(std::move(other.mBuffer))
1207 {}
1208
init(size_t initialSize)1209 void DynamicShadowBuffer::init(size_t initialSize)
1210 {
1211 mInitialSize = initialSize;
1212 }
1213
~DynamicShadowBuffer()1214 DynamicShadowBuffer::~DynamicShadowBuffer()
1215 {
1216 ASSERT(mBuffer.empty());
1217 }
1218
allocate(size_t sizeInBytes)1219 angle::Result DynamicShadowBuffer::allocate(size_t sizeInBytes)
1220 {
1221 bool result = true;
1222
1223 // Delete the current buffer, if any
1224 if (!mBuffer.empty())
1225 {
1226 result &= mBuffer.resize(0);
1227 }
1228
1229 // Cache the new size
1230 mSize = std::max(mInitialSize, sizeInBytes);
1231
1232 // Allocate the buffer
1233 result &= mBuffer.resize(mSize);
1234
1235 // If allocation failed, release the buffer and return error.
1236 if (!result)
1237 {
1238 release();
1239 return angle::Result::Stop;
1240 }
1241
1242 return angle::Result::Continue;
1243 }
1244
release()1245 void DynamicShadowBuffer::release()
1246 {
1247 reset();
1248
1249 if (!mBuffer.empty())
1250 {
1251 (void)mBuffer.resize(0);
1252 }
1253 }
1254
destroy(VkDevice device)1255 void DynamicShadowBuffer::destroy(VkDevice device)
1256 {
1257 release();
1258 }
1259
reset()1260 void DynamicShadowBuffer::reset()
1261 {
1262 mSize = 0;
1263 }
1264
1265 // DescriptorPoolHelper implementation.
DescriptorPoolHelper()1266 DescriptorPoolHelper::DescriptorPoolHelper() : mFreeDescriptorSets(0) {}
1267
1268 DescriptorPoolHelper::~DescriptorPoolHelper() = default;
1269
hasCapacity(uint32_t descriptorSetCount) const1270 bool DescriptorPoolHelper::hasCapacity(uint32_t descriptorSetCount) const
1271 {
1272 return mFreeDescriptorSets >= descriptorSetCount;
1273 }
1274
init(Context * context,const std::vector<VkDescriptorPoolSize> & poolSizes,uint32_t maxSets)1275 angle::Result DescriptorPoolHelper::init(Context *context,
1276 const std::vector<VkDescriptorPoolSize> &poolSizes,
1277 uint32_t maxSets)
1278 {
1279 if (mDescriptorPool.valid())
1280 {
1281 // This could be improved by recycling the descriptor pool.
1282 mDescriptorPool.destroy(context->getDevice());
1283 }
1284
1285 VkDescriptorPoolCreateInfo descriptorPoolInfo = {};
1286 descriptorPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
1287 descriptorPoolInfo.flags = 0;
1288 descriptorPoolInfo.maxSets = maxSets;
1289 descriptorPoolInfo.poolSizeCount = static_cast<uint32_t>(poolSizes.size());
1290 descriptorPoolInfo.pPoolSizes = poolSizes.data();
1291
1292 mFreeDescriptorSets = maxSets;
1293
1294 ANGLE_VK_TRY(context, mDescriptorPool.init(context->getDevice(), descriptorPoolInfo));
1295 return angle::Result::Continue;
1296 }
1297
destroy(VkDevice device)1298 void DescriptorPoolHelper::destroy(VkDevice device)
1299 {
1300 mDescriptorPool.destroy(device);
1301 }
1302
release(ContextVk * contextVk)1303 void DescriptorPoolHelper::release(ContextVk *contextVk)
1304 {
1305 contextVk->addGarbage(&mDescriptorPool);
1306 }
1307
allocateSets(ContextVk * contextVk,const VkDescriptorSetLayout * descriptorSetLayout,uint32_t descriptorSetCount,VkDescriptorSet * descriptorSetsOut)1308 angle::Result DescriptorPoolHelper::allocateSets(ContextVk *contextVk,
1309 const VkDescriptorSetLayout *descriptorSetLayout,
1310 uint32_t descriptorSetCount,
1311 VkDescriptorSet *descriptorSetsOut)
1312 {
1313 VkDescriptorSetAllocateInfo allocInfo = {};
1314 allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
1315 allocInfo.descriptorPool = mDescriptorPool.getHandle();
1316 allocInfo.descriptorSetCount = descriptorSetCount;
1317 allocInfo.pSetLayouts = descriptorSetLayout;
1318
1319 ASSERT(mFreeDescriptorSets >= descriptorSetCount);
1320 mFreeDescriptorSets -= descriptorSetCount;
1321
1322 ANGLE_VK_TRY(contextVk, mDescriptorPool.allocateDescriptorSets(contextVk->getDevice(),
1323 allocInfo, descriptorSetsOut));
1324 return angle::Result::Continue;
1325 }
1326
1327 // DynamicDescriptorPool implementation.
DynamicDescriptorPool()1328 DynamicDescriptorPool::DynamicDescriptorPool()
1329 : mMaxSetsPerPool(kDefaultDescriptorPoolMaxSets), mCurrentPoolIndex(0)
1330 {}
1331
1332 DynamicDescriptorPool::~DynamicDescriptorPool() = default;
1333
init(ContextVk * contextVk,const VkDescriptorPoolSize * setSizes,uint32_t setSizeCount)1334 angle::Result DynamicDescriptorPool::init(ContextVk *contextVk,
1335 const VkDescriptorPoolSize *setSizes,
1336 uint32_t setSizeCount)
1337 {
1338 ASSERT(mCurrentPoolIndex == 0);
1339 ASSERT(mDescriptorPools.empty() || (mDescriptorPools.size() == 1 &&
1340 mDescriptorPools[0]->get().hasCapacity(mMaxSetsPerPool)));
1341
1342 mPoolSizes.assign(setSizes, setSizes + setSizeCount);
1343 for (uint32_t i = 0; i < setSizeCount; ++i)
1344 {
1345 mPoolSizes[i].descriptorCount *= mMaxSetsPerPool;
1346 }
1347
1348 mDescriptorPools.push_back(new RefCountedDescriptorPoolHelper());
1349 return mDescriptorPools[0]->get().init(contextVk, mPoolSizes, mMaxSetsPerPool);
1350 }
1351
destroy(VkDevice device)1352 void DynamicDescriptorPool::destroy(VkDevice device)
1353 {
1354 for (RefCountedDescriptorPoolHelper *pool : mDescriptorPools)
1355 {
1356 ASSERT(!pool->isReferenced());
1357 pool->get().destroy(device);
1358 delete pool;
1359 }
1360
1361 mDescriptorPools.clear();
1362 }
1363
release(ContextVk * contextVk)1364 void DynamicDescriptorPool::release(ContextVk *contextVk)
1365 {
1366 for (RefCountedDescriptorPoolHelper *pool : mDescriptorPools)
1367 {
1368 ASSERT(!pool->isReferenced());
1369 pool->get().release(contextVk);
1370 delete pool;
1371 }
1372
1373 mDescriptorPools.clear();
1374 }
1375
allocateSetsAndGetInfo(ContextVk * contextVk,const VkDescriptorSetLayout * descriptorSetLayout,uint32_t descriptorSetCount,RefCountedDescriptorPoolBinding * bindingOut,VkDescriptorSet * descriptorSetsOut,bool * newPoolAllocatedOut)1376 angle::Result DynamicDescriptorPool::allocateSetsAndGetInfo(
1377 ContextVk *contextVk,
1378 const VkDescriptorSetLayout *descriptorSetLayout,
1379 uint32_t descriptorSetCount,
1380 RefCountedDescriptorPoolBinding *bindingOut,
1381 VkDescriptorSet *descriptorSetsOut,
1382 bool *newPoolAllocatedOut)
1383 {
1384 *newPoolAllocatedOut = false;
1385
1386 if (!bindingOut->valid() || !bindingOut->get().hasCapacity(descriptorSetCount))
1387 {
1388 if (!mDescriptorPools[mCurrentPoolIndex]->get().hasCapacity(descriptorSetCount))
1389 {
1390 ANGLE_TRY(allocateNewPool(contextVk));
1391 *newPoolAllocatedOut = true;
1392 }
1393
1394 // Make sure the old binding knows the descriptor sets can still be in-use. We only need
1395 // to update the serial when we move to a new pool. This is because we only check serials
1396 // when we move to a new pool.
1397 if (bindingOut->valid())
1398 {
1399 Serial currentSerial = contextVk->getCurrentQueueSerial();
1400 bindingOut->get().updateSerial(currentSerial);
1401 }
1402
1403 bindingOut->set(mDescriptorPools[mCurrentPoolIndex]);
1404 }
1405
1406 return bindingOut->get().allocateSets(contextVk, descriptorSetLayout, descriptorSetCount,
1407 descriptorSetsOut);
1408 }
1409
allocateNewPool(ContextVk * contextVk)1410 angle::Result DynamicDescriptorPool::allocateNewPool(ContextVk *contextVk)
1411 {
1412 bool found = false;
1413
1414 for (size_t poolIndex = 0; poolIndex < mDescriptorPools.size(); ++poolIndex)
1415 {
1416 if (!mDescriptorPools[poolIndex]->isReferenced() &&
1417 !contextVk->isSerialInUse(mDescriptorPools[poolIndex]->get().getSerial()))
1418 {
1419 mCurrentPoolIndex = poolIndex;
1420 found = true;
1421 break;
1422 }
1423 }
1424
1425 if (!found)
1426 {
1427 mDescriptorPools.push_back(new RefCountedDescriptorPoolHelper());
1428 mCurrentPoolIndex = mDescriptorPools.size() - 1;
1429
1430 static constexpr size_t kMaxPools = 99999;
1431 ANGLE_VK_CHECK(contextVk, mDescriptorPools.size() < kMaxPools, VK_ERROR_TOO_MANY_OBJECTS);
1432 }
1433
1434 return mDescriptorPools[mCurrentPoolIndex]->get().init(contextVk, mPoolSizes, mMaxSetsPerPool);
1435 }
1436
setMaxSetsPerPoolForTesting(uint32_t maxSetsPerPool)1437 void DynamicDescriptorPool::setMaxSetsPerPoolForTesting(uint32_t maxSetsPerPool)
1438 {
1439 mMaxSetsPerPool = maxSetsPerPool;
1440 }
1441
1442 // DynamicallyGrowingPool implementation
1443 template <typename Pool>
DynamicallyGrowingPool()1444 DynamicallyGrowingPool<Pool>::DynamicallyGrowingPool()
1445 : mPoolSize(0), mCurrentPool(0), mCurrentFreeEntry(0)
1446 {}
1447
1448 template <typename Pool>
1449 DynamicallyGrowingPool<Pool>::~DynamicallyGrowingPool() = default;
1450
1451 template <typename Pool>
initEntryPool(Context * contextVk,uint32_t poolSize)1452 angle::Result DynamicallyGrowingPool<Pool>::initEntryPool(Context *contextVk, uint32_t poolSize)
1453 {
1454 ASSERT(mPools.empty() && mPoolStats.empty());
1455 mPoolSize = poolSize;
1456 return angle::Result::Continue;
1457 }
1458
1459 template <typename Pool>
destroyEntryPool()1460 void DynamicallyGrowingPool<Pool>::destroyEntryPool()
1461 {
1462 mPools.clear();
1463 mPoolStats.clear();
1464 }
1465
1466 template <typename Pool>
findFreeEntryPool(ContextVk * contextVk)1467 bool DynamicallyGrowingPool<Pool>::findFreeEntryPool(ContextVk *contextVk)
1468 {
1469 Serial lastCompletedQueueSerial = contextVk->getLastCompletedQueueSerial();
1470 for (size_t i = 0; i < mPools.size(); ++i)
1471 {
1472 if (mPoolStats[i].freedCount == mPoolSize &&
1473 mPoolStats[i].serial <= lastCompletedQueueSerial)
1474 {
1475 mCurrentPool = i;
1476 mCurrentFreeEntry = 0;
1477
1478 mPoolStats[i].freedCount = 0;
1479
1480 return true;
1481 }
1482 }
1483
1484 return false;
1485 }
1486
1487 template <typename Pool>
allocateNewEntryPool(ContextVk * contextVk,Pool && pool)1488 angle::Result DynamicallyGrowingPool<Pool>::allocateNewEntryPool(ContextVk *contextVk, Pool &&pool)
1489 {
1490 mPools.push_back(std::move(pool));
1491
1492 PoolStats poolStats = {0, Serial()};
1493 mPoolStats.push_back(poolStats);
1494
1495 mCurrentPool = mPools.size() - 1;
1496 mCurrentFreeEntry = 0;
1497
1498 return angle::Result::Continue;
1499 }
1500
1501 template <typename Pool>
onEntryFreed(ContextVk * contextVk,size_t poolIndex)1502 void DynamicallyGrowingPool<Pool>::onEntryFreed(ContextVk *contextVk, size_t poolIndex)
1503 {
1504 ASSERT(poolIndex < mPoolStats.size() && mPoolStats[poolIndex].freedCount < mPoolSize);
1505
1506 // Take note of the current serial to avoid reallocating a query in the same pool
1507 mPoolStats[poolIndex].serial = contextVk->getCurrentQueueSerial();
1508 ++mPoolStats[poolIndex].freedCount;
1509 }
1510
1511 // DynamicQueryPool implementation
1512 DynamicQueryPool::DynamicQueryPool() = default;
1513
1514 DynamicQueryPool::~DynamicQueryPool() = default;
1515
init(ContextVk * contextVk,VkQueryType type,uint32_t poolSize)1516 angle::Result DynamicQueryPool::init(ContextVk *contextVk, VkQueryType type, uint32_t poolSize)
1517 {
1518 ANGLE_TRY(initEntryPool(contextVk, poolSize));
1519
1520 mQueryType = type;
1521 ANGLE_TRY(allocateNewPool(contextVk));
1522
1523 return angle::Result::Continue;
1524 }
1525
destroy(VkDevice device)1526 void DynamicQueryPool::destroy(VkDevice device)
1527 {
1528 for (QueryPool &queryPool : mPools)
1529 {
1530 queryPool.destroy(device);
1531 }
1532
1533 destroyEntryPool();
1534 }
1535
allocateQuery(ContextVk * contextVk,QueryHelper * queryOut)1536 angle::Result DynamicQueryPool::allocateQuery(ContextVk *contextVk, QueryHelper *queryOut)
1537 {
1538 ASSERT(!queryOut->valid());
1539
1540 if (mCurrentFreeEntry >= mPoolSize)
1541 {
1542 // No more queries left in this pool, create another one.
1543 ANGLE_TRY(allocateNewPool(contextVk));
1544 }
1545
1546 uint32_t queryIndex = mCurrentFreeEntry++;
1547 queryOut->init(this, mCurrentPool, queryIndex);
1548
1549 return angle::Result::Continue;
1550 }
1551
freeQuery(ContextVk * contextVk,QueryHelper * query)1552 void DynamicQueryPool::freeQuery(ContextVk *contextVk, QueryHelper *query)
1553 {
1554 if (query->valid())
1555 {
1556 size_t poolIndex = query->mQueryPoolIndex;
1557 ASSERT(getQueryPool(poolIndex).valid());
1558
1559 onEntryFreed(contextVk, poolIndex);
1560
1561 query->deinit();
1562 }
1563 }
1564
allocateNewPool(ContextVk * contextVk)1565 angle::Result DynamicQueryPool::allocateNewPool(ContextVk *contextVk)
1566 {
1567 if (findFreeEntryPool(contextVk))
1568 {
1569 return angle::Result::Continue;
1570 }
1571
1572 VkQueryPoolCreateInfo queryPoolInfo = {};
1573 queryPoolInfo.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
1574 queryPoolInfo.flags = 0;
1575 queryPoolInfo.queryType = mQueryType;
1576 queryPoolInfo.queryCount = mPoolSize;
1577 queryPoolInfo.pipelineStatistics = 0;
1578
1579 QueryPool queryPool;
1580
1581 ANGLE_VK_TRY(contextVk, queryPool.init(contextVk->getDevice(), queryPoolInfo));
1582
1583 return allocateNewEntryPool(contextVk, std::move(queryPool));
1584 }
1585
1586 // QueryHelper implementation
QueryHelper()1587 QueryHelper::QueryHelper() : mDynamicQueryPool(nullptr), mQueryPoolIndex(0), mQuery(0) {}
1588
~QueryHelper()1589 QueryHelper::~QueryHelper() {}
1590
init(const DynamicQueryPool * dynamicQueryPool,const size_t queryPoolIndex,uint32_t query)1591 void QueryHelper::init(const DynamicQueryPool *dynamicQueryPool,
1592 const size_t queryPoolIndex,
1593 uint32_t query)
1594 {
1595 mDynamicQueryPool = dynamicQueryPool;
1596 mQueryPoolIndex = queryPoolIndex;
1597 mQuery = query;
1598 }
1599
deinit()1600 void QueryHelper::deinit()
1601 {
1602 mDynamicQueryPool = nullptr;
1603 mQueryPoolIndex = 0;
1604 mQuery = 0;
1605 mMostRecentSerial = Serial();
1606 }
1607
resetQueryPool(ContextVk * contextVk,CommandBuffer * outsideRenderPassCommandBuffer)1608 void QueryHelper::resetQueryPool(ContextVk *contextVk,
1609 CommandBuffer *outsideRenderPassCommandBuffer)
1610 {
1611 const QueryPool &queryPool = getQueryPool();
1612 outsideRenderPassCommandBuffer->resetQueryPool(queryPool.getHandle(), mQuery, 1);
1613 }
1614
beginQuery(ContextVk * contextVk)1615 angle::Result QueryHelper::beginQuery(ContextVk *contextVk)
1616 {
1617 vk::CommandBuffer *outsideRenderPassCommandBuffer;
1618 ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&outsideRenderPassCommandBuffer));
1619 const QueryPool &queryPool = getQueryPool();
1620 outsideRenderPassCommandBuffer->resetQueryPool(queryPool.getHandle(), mQuery, 1);
1621 outsideRenderPassCommandBuffer->beginQuery(queryPool.getHandle(), mQuery, 0);
1622 mMostRecentSerial = contextVk->getCurrentQueueSerial();
1623 return angle::Result::Continue;
1624 }
1625
endQuery(ContextVk * contextVk)1626 angle::Result QueryHelper::endQuery(ContextVk *contextVk)
1627 {
1628 vk::CommandBuffer *outsideRenderPassCommandBuffer;
1629 ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&outsideRenderPassCommandBuffer));
1630 outsideRenderPassCommandBuffer->endQuery(getQueryPool().getHandle(), mQuery);
1631 mMostRecentSerial = contextVk->getCurrentQueueSerial();
1632 return angle::Result::Continue;
1633 }
1634
beginOcclusionQuery(ContextVk * contextVk,CommandBuffer * renderPassCommandBuffer)1635 void QueryHelper::beginOcclusionQuery(ContextVk *contextVk, CommandBuffer *renderPassCommandBuffer)
1636 {
1637 const QueryPool &queryPool = getQueryPool();
1638 renderPassCommandBuffer->queueResetQueryPool(queryPool.getHandle(), mQuery, 1);
1639 renderPassCommandBuffer->beginQuery(queryPool.getHandle(), mQuery, 0);
1640 mMostRecentSerial = contextVk->getCurrentQueueSerial();
1641 }
1642
endOcclusionQuery(ContextVk * contextVk,CommandBuffer * renderPassCommandBuffer)1643 void QueryHelper::endOcclusionQuery(ContextVk *contextVk, CommandBuffer *renderPassCommandBuffer)
1644 {
1645 renderPassCommandBuffer->endQuery(getQueryPool().getHandle(), mQuery);
1646 mMostRecentSerial = contextVk->getCurrentQueueSerial();
1647 }
1648
flushAndWriteTimestamp(ContextVk * contextVk)1649 angle::Result QueryHelper::flushAndWriteTimestamp(ContextVk *contextVk)
1650 {
1651 vk::CommandBuffer *outsideRenderPassCommandBuffer;
1652 ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&outsideRenderPassCommandBuffer));
1653 writeTimestamp(contextVk, outsideRenderPassCommandBuffer);
1654 return angle::Result::Continue;
1655 }
1656
writeTimestamp(ContextVk * contextVk,PrimaryCommandBuffer * primary)1657 void QueryHelper::writeTimestamp(ContextVk *contextVk, PrimaryCommandBuffer *primary)
1658 {
1659 const QueryPool &queryPool = getQueryPool();
1660 primary->resetQueryPool(queryPool, mQuery, 1);
1661 primary->writeTimestamp(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, queryPool, mQuery);
1662 mMostRecentSerial = contextVk->getCurrentQueueSerial();
1663 }
1664
writeTimestamp(ContextVk * contextVk,CommandBuffer * commandBuffer)1665 void QueryHelper::writeTimestamp(ContextVk *contextVk, CommandBuffer *commandBuffer)
1666 {
1667 const QueryPool &queryPool = getQueryPool();
1668 commandBuffer->resetQueryPool(queryPool.getHandle(), mQuery, 1);
1669 commandBuffer->writeTimestamp(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, queryPool.getHandle(),
1670 mQuery);
1671 mMostRecentSerial = contextVk->getCurrentQueueSerial();
1672 }
1673
hasPendingWork(ContextVk * contextVk)1674 bool QueryHelper::hasPendingWork(ContextVk *contextVk)
1675 {
1676 // If the renderer has a queue serial higher than the stored one, the command buffers that
1677 // recorded this query have already been submitted, so there is no pending work.
1678 return mMostRecentSerial.valid() && (mMostRecentSerial == contextVk->getCurrentQueueSerial());
1679 }
1680
getUint64ResultNonBlocking(ContextVk * contextVk,uint64_t * resultOut,bool * availableOut)1681 angle::Result QueryHelper::getUint64ResultNonBlocking(ContextVk *contextVk,
1682 uint64_t *resultOut,
1683 bool *availableOut)
1684 {
1685 ASSERT(valid());
1686 VkResult result;
1687
1688 // Ensure that we only wait if we have inserted a query in command buffer. Otherwise you will
1689 // wait forever and trigger GPU timeout.
1690 if (mMostRecentSerial.valid())
1691 {
1692 VkDevice device = contextVk->getDevice();
1693 constexpr VkQueryResultFlags kFlags = VK_QUERY_RESULT_64_BIT;
1694 result = getQueryPool().getResults(device, mQuery, 1, sizeof(uint64_t), resultOut,
1695 sizeof(uint64_t), kFlags);
1696 }
1697 else
1698 {
1699 result = VK_SUCCESS;
1700 *resultOut = 0;
1701 }
1702
1703 if (result == VK_NOT_READY)
1704 {
1705 *availableOut = false;
1706 return angle::Result::Continue;
1707 }
1708 else
1709 {
1710 ANGLE_VK_TRY(contextVk, result);
1711 *availableOut = true;
1712 }
1713 return angle::Result::Continue;
1714 }
1715
getUint64Result(ContextVk * contextVk,uint64_t * resultOut)1716 angle::Result QueryHelper::getUint64Result(ContextVk *contextVk, uint64_t *resultOut)
1717 {
1718 ASSERT(valid());
1719 if (mMostRecentSerial.valid())
1720 {
1721 VkDevice device = contextVk->getDevice();
1722 constexpr VkQueryResultFlags kFlags = VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT;
1723 ANGLE_VK_TRY(contextVk, getQueryPool().getResults(device, mQuery, 1, sizeof(uint64_t),
1724 resultOut, sizeof(uint64_t), kFlags));
1725 }
1726 else
1727 {
1728 *resultOut = 0;
1729 }
1730 return angle::Result::Continue;
1731 }
1732
1733 // DynamicSemaphorePool implementation
1734 DynamicSemaphorePool::DynamicSemaphorePool() = default;
1735
1736 DynamicSemaphorePool::~DynamicSemaphorePool() = default;
1737
init(ContextVk * contextVk,uint32_t poolSize)1738 angle::Result DynamicSemaphorePool::init(ContextVk *contextVk, uint32_t poolSize)
1739 {
1740 ANGLE_TRY(initEntryPool(contextVk, poolSize));
1741 ANGLE_TRY(allocateNewPool(contextVk));
1742 return angle::Result::Continue;
1743 }
1744
destroy(VkDevice device)1745 void DynamicSemaphorePool::destroy(VkDevice device)
1746 {
1747 for (auto &semaphorePool : mPools)
1748 {
1749 for (Semaphore &semaphore : semaphorePool)
1750 {
1751 semaphore.destroy(device);
1752 }
1753 }
1754
1755 destroyEntryPool();
1756 }
1757
allocateSemaphore(ContextVk * contextVk,SemaphoreHelper * semaphoreOut)1758 angle::Result DynamicSemaphorePool::allocateSemaphore(ContextVk *contextVk,
1759 SemaphoreHelper *semaphoreOut)
1760 {
1761 ASSERT(!semaphoreOut->getSemaphore());
1762
1763 if (mCurrentFreeEntry >= mPoolSize)
1764 {
1765 // No more queries left in this pool, create another one.
1766 ANGLE_TRY(allocateNewPool(contextVk));
1767 }
1768
1769 semaphoreOut->init(mCurrentPool, &mPools[mCurrentPool][mCurrentFreeEntry++]);
1770
1771 return angle::Result::Continue;
1772 }
1773
freeSemaphore(ContextVk * contextVk,SemaphoreHelper * semaphore)1774 void DynamicSemaphorePool::freeSemaphore(ContextVk *contextVk, SemaphoreHelper *semaphore)
1775 {
1776 if (semaphore->getSemaphore())
1777 {
1778 onEntryFreed(contextVk, semaphore->getSemaphorePoolIndex());
1779 semaphore->deinit();
1780 }
1781 }
1782
allocateNewPool(ContextVk * contextVk)1783 angle::Result DynamicSemaphorePool::allocateNewPool(ContextVk *contextVk)
1784 {
1785 if (findFreeEntryPool(contextVk))
1786 {
1787 return angle::Result::Continue;
1788 }
1789
1790 std::vector<Semaphore> newPool(mPoolSize);
1791
1792 for (Semaphore &semaphore : newPool)
1793 {
1794 ANGLE_VK_TRY(contextVk, semaphore.init(contextVk->getDevice()));
1795 }
1796
1797 // This code is safe as long as the growth of the outer vector in vector<vector<T>> is done by
1798 // moving the inner vectors, making sure references to the inner vector remain intact.
1799 Semaphore *assertMove = mPools.size() > 0 ? mPools[0].data() : nullptr;
1800
1801 ANGLE_TRY(allocateNewEntryPool(contextVk, std::move(newPool)));
1802
1803 ASSERT(assertMove == nullptr || assertMove == mPools[0].data());
1804
1805 return angle::Result::Continue;
1806 }
1807
1808 // SemaphoreHelper implementation
SemaphoreHelper()1809 SemaphoreHelper::SemaphoreHelper() : mSemaphorePoolIndex(0), mSemaphore(0) {}
1810
~SemaphoreHelper()1811 SemaphoreHelper::~SemaphoreHelper() {}
1812
SemaphoreHelper(SemaphoreHelper && other)1813 SemaphoreHelper::SemaphoreHelper(SemaphoreHelper &&other)
1814 : mSemaphorePoolIndex(other.mSemaphorePoolIndex), mSemaphore(other.mSemaphore)
1815 {
1816 other.mSemaphore = nullptr;
1817 }
1818
operator =(SemaphoreHelper && other)1819 SemaphoreHelper &SemaphoreHelper::operator=(SemaphoreHelper &&other)
1820 {
1821 std::swap(mSemaphorePoolIndex, other.mSemaphorePoolIndex);
1822 std::swap(mSemaphore, other.mSemaphore);
1823 return *this;
1824 }
1825
init(const size_t semaphorePoolIndex,const Semaphore * semaphore)1826 void SemaphoreHelper::init(const size_t semaphorePoolIndex, const Semaphore *semaphore)
1827 {
1828 mSemaphorePoolIndex = semaphorePoolIndex;
1829 mSemaphore = semaphore;
1830 }
1831
deinit()1832 void SemaphoreHelper::deinit()
1833 {
1834 mSemaphorePoolIndex = 0;
1835 mSemaphore = nullptr;
1836 }
1837
1838 // LineLoopHelper implementation.
LineLoopHelper(RendererVk * renderer)1839 LineLoopHelper::LineLoopHelper(RendererVk *renderer)
1840 {
1841 // We need to use an alignment of the maximum size we're going to allocate, which is
1842 // VK_INDEX_TYPE_UINT32. When we switch from a drawElement to a drawArray call, the allocations
1843 // can vary in size. According to the Vulkan spec, when calling vkCmdBindIndexBuffer: 'The
1844 // sum of offset and the address of the range of VkDeviceMemory object that is backing buffer,
1845 // must be a multiple of the type indicated by indexType'.
1846 mDynamicIndexBuffer.init(renderer, kLineLoopDynamicBufferUsage, sizeof(uint32_t),
1847 kLineLoopDynamicBufferInitialSize, true);
1848 mDynamicIndirectBuffer.init(renderer, kLineLoopDynamicIndirectBufferUsage, sizeof(uint32_t),
1849 kLineLoopDynamicIndirectBufferInitialSize, true);
1850 }
1851
1852 LineLoopHelper::~LineLoopHelper() = default;
1853
getIndexBufferForDrawArrays(ContextVk * contextVk,uint32_t clampedVertexCount,GLint firstVertex,BufferHelper ** bufferOut,VkDeviceSize * offsetOut)1854 angle::Result LineLoopHelper::getIndexBufferForDrawArrays(ContextVk *contextVk,
1855 uint32_t clampedVertexCount,
1856 GLint firstVertex,
1857 BufferHelper **bufferOut,
1858 VkDeviceSize *offsetOut)
1859 {
1860 uint32_t *indices = nullptr;
1861 size_t allocateBytes = sizeof(uint32_t) * (static_cast<size_t>(clampedVertexCount) + 1);
1862
1863 mDynamicIndexBuffer.releaseInFlightBuffers(contextVk);
1864 ANGLE_TRY(mDynamicIndexBuffer.allocate(contextVk, allocateBytes,
1865 reinterpret_cast<uint8_t **>(&indices), nullptr,
1866 offsetOut, nullptr));
1867 *bufferOut = mDynamicIndexBuffer.getCurrentBuffer();
1868
1869 // Note: there could be an overflow in this addition.
1870 uint32_t unsignedFirstVertex = static_cast<uint32_t>(firstVertex);
1871 uint32_t vertexCount = (clampedVertexCount + unsignedFirstVertex);
1872 for (uint32_t vertexIndex = unsignedFirstVertex; vertexIndex < vertexCount; vertexIndex++)
1873 {
1874 *indices++ = vertexIndex;
1875 }
1876 *indices = unsignedFirstVertex;
1877
1878 // Since we are not using the VK_MEMORY_PROPERTY_HOST_COHERENT_BIT flag when creating the
1879 // device memory in the StreamingBuffer, we always need to make sure we flush it after
1880 // writing.
1881 ANGLE_TRY(mDynamicIndexBuffer.flush(contextVk));
1882
1883 return angle::Result::Continue;
1884 }
1885
getIndexBufferForElementArrayBuffer(ContextVk * contextVk,BufferVk * elementArrayBufferVk,gl::DrawElementsType glIndexType,int indexCount,intptr_t elementArrayOffset,BufferHelper ** bufferOut,VkDeviceSize * bufferOffsetOut,uint32_t * indexCountOut)1886 angle::Result LineLoopHelper::getIndexBufferForElementArrayBuffer(ContextVk *contextVk,
1887 BufferVk *elementArrayBufferVk,
1888 gl::DrawElementsType glIndexType,
1889 int indexCount,
1890 intptr_t elementArrayOffset,
1891 BufferHelper **bufferOut,
1892 VkDeviceSize *bufferOffsetOut,
1893 uint32_t *indexCountOut)
1894 {
1895 if (glIndexType == gl::DrawElementsType::UnsignedByte ||
1896 contextVk->getState().isPrimitiveRestartEnabled())
1897 {
1898 ANGLE_TRACE_EVENT0("gpu.angle", "LineLoopHelper::getIndexBufferForElementArrayBuffer");
1899
1900 void *srcDataMapping = nullptr;
1901 ANGLE_TRY(elementArrayBufferVk->mapImpl(contextVk, &srcDataMapping));
1902 ANGLE_TRY(streamIndices(contextVk, glIndexType, indexCount,
1903 static_cast<const uint8_t *>(srcDataMapping) + elementArrayOffset,
1904 bufferOut, bufferOffsetOut, indexCountOut));
1905 ANGLE_TRY(elementArrayBufferVk->unmapImpl(contextVk));
1906 return angle::Result::Continue;
1907 }
1908
1909 *indexCountOut = indexCount + 1;
1910
1911 uint32_t *indices = nullptr;
1912 size_t unitSize = contextVk->getVkIndexTypeSize(glIndexType);
1913 size_t allocateBytes = unitSize * (indexCount + 1) + 1;
1914
1915 mDynamicIndexBuffer.releaseInFlightBuffers(contextVk);
1916 ANGLE_TRY(mDynamicIndexBuffer.allocate(contextVk, allocateBytes,
1917 reinterpret_cast<uint8_t **>(&indices), nullptr,
1918 bufferOffsetOut, nullptr));
1919 *bufferOut = mDynamicIndexBuffer.getCurrentBuffer();
1920
1921 VkDeviceSize sourceOffset = static_cast<VkDeviceSize>(elementArrayOffset);
1922 uint64_t unitCount = static_cast<VkDeviceSize>(indexCount);
1923 angle::FixedVector<VkBufferCopy, 3> copies = {
1924 {sourceOffset, *bufferOffsetOut, unitCount * unitSize},
1925 {sourceOffset, *bufferOffsetOut + unitCount * unitSize, unitSize},
1926 };
1927 if (contextVk->getRenderer()->getFeatures().extraCopyBufferRegion.enabled)
1928 copies.push_back({sourceOffset, *bufferOffsetOut + (unitCount + 1) * unitSize, 1});
1929
1930 ANGLE_TRY(elementArrayBufferVk->copyToBufferImpl(
1931 contextVk, *bufferOut, static_cast<uint32_t>(copies.size()), copies.data()));
1932 ANGLE_TRY(mDynamicIndexBuffer.flush(contextVk));
1933 return angle::Result::Continue;
1934 }
1935
streamIndices(ContextVk * contextVk,gl::DrawElementsType glIndexType,GLsizei indexCount,const uint8_t * srcPtr,BufferHelper ** bufferOut,VkDeviceSize * bufferOffsetOut,uint32_t * indexCountOut)1936 angle::Result LineLoopHelper::streamIndices(ContextVk *contextVk,
1937 gl::DrawElementsType glIndexType,
1938 GLsizei indexCount,
1939 const uint8_t *srcPtr,
1940 BufferHelper **bufferOut,
1941 VkDeviceSize *bufferOffsetOut,
1942 uint32_t *indexCountOut)
1943 {
1944 size_t unitSize = contextVk->getVkIndexTypeSize(glIndexType);
1945
1946 uint8_t *indices = nullptr;
1947
1948 uint32_t numOutIndices = indexCount + 1;
1949 if (contextVk->getState().isPrimitiveRestartEnabled())
1950 {
1951 numOutIndices = GetLineLoopWithRestartIndexCount(glIndexType, indexCount, srcPtr);
1952 }
1953 *indexCountOut = numOutIndices;
1954 size_t allocateBytes = unitSize * numOutIndices;
1955 ANGLE_TRY(mDynamicIndexBuffer.allocate(contextVk, allocateBytes,
1956 reinterpret_cast<uint8_t **>(&indices), nullptr,
1957 bufferOffsetOut, nullptr));
1958 *bufferOut = mDynamicIndexBuffer.getCurrentBuffer();
1959
1960 if (contextVk->getState().isPrimitiveRestartEnabled())
1961 {
1962 HandlePrimitiveRestart(contextVk, glIndexType, indexCount, srcPtr, indices);
1963 }
1964 else
1965 {
1966 if (contextVk->shouldConvertUint8VkIndexType(glIndexType))
1967 {
1968 // If vulkan doesn't support uint8 index types, we need to emulate it.
1969 VkIndexType indexType = contextVk->getVkIndexType(glIndexType);
1970 ASSERT(indexType == VK_INDEX_TYPE_UINT16);
1971 uint16_t *indicesDst = reinterpret_cast<uint16_t *>(indices);
1972 for (int i = 0; i < indexCount; i++)
1973 {
1974 indicesDst[i] = srcPtr[i];
1975 }
1976
1977 indicesDst[indexCount] = srcPtr[0];
1978 }
1979 else
1980 {
1981 memcpy(indices, srcPtr, unitSize * indexCount);
1982 memcpy(indices + unitSize * indexCount, srcPtr, unitSize);
1983 }
1984 }
1985
1986 ANGLE_TRY(mDynamicIndexBuffer.flush(contextVk));
1987 return angle::Result::Continue;
1988 }
1989
streamIndicesIndirect(ContextVk * contextVk,gl::DrawElementsType glIndexType,BufferHelper * indexBuffer,BufferHelper * indirectBuffer,VkDeviceSize indirectBufferOffset,BufferHelper ** indexBufferOut,VkDeviceSize * indexBufferOffsetOut,BufferHelper ** indirectBufferOut,VkDeviceSize * indirectBufferOffsetOut)1990 angle::Result LineLoopHelper::streamIndicesIndirect(ContextVk *contextVk,
1991 gl::DrawElementsType glIndexType,
1992 BufferHelper *indexBuffer,
1993 BufferHelper *indirectBuffer,
1994 VkDeviceSize indirectBufferOffset,
1995 BufferHelper **indexBufferOut,
1996 VkDeviceSize *indexBufferOffsetOut,
1997 BufferHelper **indirectBufferOut,
1998 VkDeviceSize *indirectBufferOffsetOut)
1999 {
2000 size_t unitSize = contextVk->getVkIndexTypeSize(glIndexType);
2001 size_t allocateBytes = static_cast<size_t>(indexBuffer->getSize() + unitSize);
2002
2003 if (contextVk->getState().isPrimitiveRestartEnabled())
2004 {
2005 // If primitive restart, new index buffer is 135% the size of the original index buffer. The
2006 // smallest lineloop with primitive restart is 3 indices (point 1, point 2 and restart
2007 // value) when converted to linelist becomes 4 vertices. Expansion of 4/3. Any larger
2008 // lineloops would have less overhead and require less extra space. Any incomplete
2009 // primitives can be dropped or left incomplete and thus not increase the size of the
2010 // destination index buffer. Since we don't know the number of indices being used we'll use
2011 // the size of the index buffer as allocated as the index count.
2012 size_t numInputIndices = static_cast<size_t>(indexBuffer->getSize() / unitSize);
2013 size_t numNewInputIndices = ((numInputIndices * 4) / 3) + 1;
2014 allocateBytes = static_cast<size_t>(numNewInputIndices * unitSize);
2015 }
2016
2017 mDynamicIndexBuffer.releaseInFlightBuffers(contextVk);
2018 mDynamicIndirectBuffer.releaseInFlightBuffers(contextVk);
2019
2020 ANGLE_TRY(mDynamicIndexBuffer.allocate(contextVk, allocateBytes, nullptr, nullptr,
2021 indexBufferOffsetOut, nullptr));
2022 *indexBufferOut = mDynamicIndexBuffer.getCurrentBuffer();
2023
2024 ANGLE_TRY(mDynamicIndirectBuffer.allocate(contextVk, sizeof(VkDrawIndexedIndirectCommand),
2025 nullptr, nullptr, indirectBufferOffsetOut, nullptr));
2026 *indirectBufferOut = mDynamicIndirectBuffer.getCurrentBuffer();
2027
2028 BufferHelper *destIndexBuffer = mDynamicIndexBuffer.getCurrentBuffer();
2029 BufferHelper *destIndirectBuffer = mDynamicIndirectBuffer.getCurrentBuffer();
2030
2031 // Copy relevant section of the source into destination at allocated offset. Note that the
2032 // offset returned by allocate() above is in bytes. As is the indices offset pointer.
2033 UtilsVk::ConvertLineLoopIndexIndirectParameters params = {};
2034 params.indirectBufferOffset = static_cast<uint32_t>(indirectBufferOffset);
2035 params.dstIndirectBufferOffset = static_cast<uint32_t>(*indirectBufferOffsetOut);
2036 params.dstIndexBufferOffset = static_cast<uint32_t>(*indexBufferOffsetOut);
2037 params.indicesBitsWidth = static_cast<uint32_t>(unitSize * 8);
2038
2039 ANGLE_TRY(contextVk->getUtils().convertLineLoopIndexIndirectBuffer(
2040 contextVk, indirectBuffer, destIndirectBuffer, destIndexBuffer, indexBuffer, params));
2041
2042 return angle::Result::Continue;
2043 }
2044
streamArrayIndirect(ContextVk * contextVk,size_t vertexCount,BufferHelper * arrayIndirectBuffer,VkDeviceSize arrayIndirectBufferOffset,BufferHelper ** indexBufferOut,VkDeviceSize * indexBufferOffsetOut,BufferHelper ** indexIndirectBufferOut,VkDeviceSize * indexIndirectBufferOffsetOut)2045 angle::Result LineLoopHelper::streamArrayIndirect(ContextVk *contextVk,
2046 size_t vertexCount,
2047 BufferHelper *arrayIndirectBuffer,
2048 VkDeviceSize arrayIndirectBufferOffset,
2049 BufferHelper **indexBufferOut,
2050 VkDeviceSize *indexBufferOffsetOut,
2051 BufferHelper **indexIndirectBufferOut,
2052 VkDeviceSize *indexIndirectBufferOffsetOut)
2053 {
2054 auto unitSize = sizeof(uint32_t);
2055 size_t allocateBytes = static_cast<size_t>((vertexCount + 1) * unitSize);
2056
2057 mDynamicIndexBuffer.releaseInFlightBuffers(contextVk);
2058 mDynamicIndirectBuffer.releaseInFlightBuffers(contextVk);
2059
2060 ANGLE_TRY(mDynamicIndexBuffer.allocate(contextVk, allocateBytes, nullptr, nullptr,
2061 indexBufferOffsetOut, nullptr));
2062 *indexBufferOut = mDynamicIndexBuffer.getCurrentBuffer();
2063
2064 ANGLE_TRY(mDynamicIndirectBuffer.allocate(contextVk, sizeof(VkDrawIndexedIndirectCommand),
2065 nullptr, nullptr, indexIndirectBufferOffsetOut,
2066 nullptr));
2067 *indexIndirectBufferOut = mDynamicIndirectBuffer.getCurrentBuffer();
2068
2069 BufferHelper *destIndexBuffer = mDynamicIndexBuffer.getCurrentBuffer();
2070 BufferHelper *destIndirectBuffer = mDynamicIndirectBuffer.getCurrentBuffer();
2071
2072 // Copy relevant section of the source into destination at allocated offset. Note that the
2073 // offset returned by allocate() above is in bytes. As is the indices offset pointer.
2074 UtilsVk::ConvertLineLoopArrayIndirectParameters params = {};
2075 params.indirectBufferOffset = static_cast<uint32_t>(arrayIndirectBufferOffset);
2076 params.dstIndirectBufferOffset = static_cast<uint32_t>(*indexIndirectBufferOffsetOut);
2077 params.dstIndexBufferOffset = static_cast<uint32_t>(*indexBufferOffsetOut);
2078
2079 ANGLE_TRY(contextVk->getUtils().convertLineLoopArrayIndirectBuffer(
2080 contextVk, arrayIndirectBuffer, destIndirectBuffer, destIndexBuffer, params));
2081
2082 return angle::Result::Continue;
2083 }
2084
release(ContextVk * contextVk)2085 void LineLoopHelper::release(ContextVk *contextVk)
2086 {
2087 mDynamicIndexBuffer.release(contextVk->getRenderer());
2088 mDynamicIndirectBuffer.release(contextVk->getRenderer());
2089 }
2090
destroy(RendererVk * renderer)2091 void LineLoopHelper::destroy(RendererVk *renderer)
2092 {
2093 mDynamicIndexBuffer.destroy(renderer);
2094 mDynamicIndirectBuffer.destroy(renderer);
2095 }
2096
2097 // static
Draw(uint32_t count,uint32_t baseVertex,CommandBuffer * commandBuffer)2098 void LineLoopHelper::Draw(uint32_t count, uint32_t baseVertex, CommandBuffer *commandBuffer)
2099 {
2100 // Our first index is always 0 because that's how we set it up in createIndexBuffer*.
2101 commandBuffer->drawIndexedBaseVertex(count, baseVertex);
2102 }
2103
2104 // PipelineBarrier implementation.
addDiagnosticsString(std::ostringstream & out) const2105 void PipelineBarrier::addDiagnosticsString(std::ostringstream &out) const
2106 {
2107 if (mMemoryBarrierSrcAccess != 0 || mMemoryBarrierDstAccess != 0)
2108 {
2109 out << "Src: 0x" << std::hex << mMemoryBarrierSrcAccess << " → Dst: 0x" << std::hex
2110 << mMemoryBarrierDstAccess << std::endl;
2111 }
2112 }
2113
2114 // BufferHelper implementation.
BufferHelper()2115 BufferHelper::BufferHelper()
2116 : mMemoryPropertyFlags{},
2117 mSize(0),
2118 mMappedMemory(nullptr),
2119 mViewFormat(nullptr),
2120 mCurrentQueueFamilyIndex(std::numeric_limits<uint32_t>::max()),
2121 mCurrentWriteAccess(0),
2122 mCurrentReadAccess(0),
2123 mCurrentWriteStages(0),
2124 mCurrentReadStages(0)
2125 {}
2126
2127 BufferHelper::~BufferHelper() = default;
2128
init(Context * context,const VkBufferCreateInfo & requestedCreateInfo,VkMemoryPropertyFlags memoryPropertyFlags)2129 angle::Result BufferHelper::init(Context *context,
2130 const VkBufferCreateInfo &requestedCreateInfo,
2131 VkMemoryPropertyFlags memoryPropertyFlags)
2132 {
2133 RendererVk *renderer = context->getRenderer();
2134
2135 mSize = requestedCreateInfo.size;
2136
2137 VkBufferCreateInfo modifiedCreateInfo;
2138 const VkBufferCreateInfo *createInfo = &requestedCreateInfo;
2139
2140 if (renderer->getFeatures().padBuffersToMaxVertexAttribStride.enabled)
2141 {
2142 const VkDeviceSize maxVertexAttribStride = renderer->getMaxVertexAttribStride();
2143 ASSERT(maxVertexAttribStride);
2144 modifiedCreateInfo = requestedCreateInfo;
2145 modifiedCreateInfo.size += maxVertexAttribStride;
2146 createInfo = &modifiedCreateInfo;
2147 }
2148
2149 VkMemoryPropertyFlags requiredFlags =
2150 (memoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
2151 VkMemoryPropertyFlags preferredFlags =
2152 (memoryPropertyFlags & (~VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT));
2153
2154 const vk::Allocator &allocator = renderer->getAllocator();
2155 bool persistentlyMapped = renderer->getFeatures().persistentlyMappedBuffers.enabled;
2156
2157 // Check that the allocation is not too large.
2158 uint32_t memoryTypeIndex = 0;
2159 ANGLE_VK_TRY(context, allocator.findMemoryTypeIndexForBufferInfo(
2160 *createInfo, requiredFlags, preferredFlags, persistentlyMapped,
2161 &memoryTypeIndex));
2162
2163 VkDeviceSize heapSize =
2164 renderer->getMemoryProperties().getHeapSizeForMemoryType(memoryTypeIndex);
2165
2166 ANGLE_VK_CHECK(context, createInfo->size <= heapSize, VK_ERROR_OUT_OF_DEVICE_MEMORY);
2167
2168 ANGLE_VK_TRY(context, allocator.createBuffer(*createInfo, requiredFlags, preferredFlags,
2169 persistentlyMapped, &memoryTypeIndex, &mBuffer,
2170 &mAllocation));
2171
2172 allocator.getMemoryTypeProperties(memoryTypeIndex, &mMemoryPropertyFlags);
2173 mCurrentQueueFamilyIndex = renderer->getQueueFamilyIndex();
2174
2175 if (renderer->getFeatures().allocateNonZeroMemory.enabled)
2176 {
2177 // This memory can't be mapped, so the buffer must be marked as a transfer destination so we
2178 // can use a staging resource to initialize it to a non-zero value. If the memory is
2179 // mappable we do the initialization in AllocateBufferMemory.
2180 if ((mMemoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0 &&
2181 (requestedCreateInfo.usage & VK_BUFFER_USAGE_TRANSFER_DST_BIT) != 0)
2182 {
2183 ANGLE_TRY(initializeNonZeroMemory(context, createInfo->size));
2184 }
2185 else if ((mMemoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0)
2186 {
2187 // Can map the memory.
2188 // Pick an arbitrary value to initialize non-zero memory for sanitization.
2189 constexpr int kNonZeroInitValue = 55;
2190 ANGLE_TRY(InitMappableAllocation(allocator, &mAllocation, mSize, kNonZeroInitValue,
2191 mMemoryPropertyFlags));
2192 }
2193 }
2194
2195 return angle::Result::Continue;
2196 }
2197
initializeNonZeroMemory(Context * context,VkDeviceSize size)2198 angle::Result BufferHelper::initializeNonZeroMemory(Context *context, VkDeviceSize size)
2199 {
2200 // Staging buffer memory is non-zero-initialized in 'init'.
2201 StagingBuffer stagingBuffer;
2202 ANGLE_TRY(stagingBuffer.init(context, size, StagingUsage::Both));
2203
2204 RendererVk *renderer = context->getRenderer();
2205
2206 vk::PrimaryCommandBuffer commandBuffer;
2207 ANGLE_TRY(renderer->getCommandBufferOneOff(context, &commandBuffer));
2208
2209 // Queue a DMA copy.
2210 VkBufferCopy copyRegion = {};
2211 copyRegion.srcOffset = 0;
2212 copyRegion.dstOffset = 0;
2213 copyRegion.size = size;
2214
2215 commandBuffer.copyBuffer(stagingBuffer.getBuffer(), mBuffer, 1, ©Region);
2216
2217 ANGLE_VK_TRY(context, commandBuffer.end());
2218
2219 Serial serial;
2220 ANGLE_TRY(renderer->queueSubmitOneOff(context, std::move(commandBuffer),
2221 egl::ContextPriority::Medium, nullptr, &serial));
2222
2223 stagingBuffer.collectGarbage(renderer, serial);
2224 mUse.updateSerialOneOff(serial);
2225
2226 return angle::Result::Continue;
2227 }
2228
destroy(RendererVk * renderer)2229 void BufferHelper::destroy(RendererVk *renderer)
2230 {
2231 VkDevice device = renderer->getDevice();
2232 unmap(renderer);
2233 mSize = 0;
2234 mViewFormat = nullptr;
2235
2236 mBuffer.destroy(device);
2237 mBufferView.destroy(device);
2238 mAllocation.destroy(renderer->getAllocator());
2239 }
2240
release(RendererVk * renderer)2241 void BufferHelper::release(RendererVk *renderer)
2242 {
2243 unmap(renderer);
2244 mSize = 0;
2245 mViewFormat = nullptr;
2246
2247 renderer->collectGarbageAndReinit(&mUse, &mBuffer, &mBufferView, &mAllocation);
2248 }
2249
copyFromBuffer(ContextVk * contextVk,BufferHelper * srcBuffer,uint32_t regionCount,const VkBufferCopy * copyRegions)2250 angle::Result BufferHelper::copyFromBuffer(ContextVk *contextVk,
2251 BufferHelper *srcBuffer,
2252 uint32_t regionCount,
2253 const VkBufferCopy *copyRegions)
2254 {
2255 CommandBuffer *commandBuffer = nullptr;
2256 ANGLE_TRY(contextVk->onBufferTransferRead(srcBuffer));
2257 ANGLE_TRY(contextVk->onBufferTransferWrite(this));
2258 ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&commandBuffer));
2259
2260 commandBuffer->copyBuffer(srcBuffer->getBuffer(), mBuffer, regionCount, copyRegions);
2261
2262 return angle::Result::Continue;
2263 }
2264
initBufferView(ContextVk * contextVk,const Format & format)2265 angle::Result BufferHelper::initBufferView(ContextVk *contextVk, const Format &format)
2266 {
2267 ASSERT(format.valid());
2268
2269 if (mBufferView.valid())
2270 {
2271 ASSERT(mViewFormat->vkBufferFormat == format.vkBufferFormat);
2272 return angle::Result::Continue;
2273 }
2274
2275 VkBufferViewCreateInfo viewCreateInfo = {};
2276 viewCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO;
2277 viewCreateInfo.buffer = mBuffer.getHandle();
2278 viewCreateInfo.format = format.vkBufferFormat;
2279 viewCreateInfo.offset = 0;
2280 viewCreateInfo.range = mSize;
2281
2282 ANGLE_VK_TRY(contextVk, mBufferView.init(contextVk->getDevice(), viewCreateInfo));
2283 mViewFormat = &format;
2284
2285 return angle::Result::Continue;
2286 }
2287
mapImpl(ContextVk * contextVk)2288 angle::Result BufferHelper::mapImpl(ContextVk *contextVk)
2289 {
2290 ANGLE_VK_TRY(contextVk,
2291 mAllocation.map(contextVk->getRenderer()->getAllocator(), &mMappedMemory));
2292
2293 return angle::Result::Continue;
2294 }
2295
unmap(RendererVk * renderer)2296 void BufferHelper::unmap(RendererVk *renderer)
2297 {
2298 if (mMappedMemory)
2299 {
2300 mAllocation.unmap(renderer->getAllocator());
2301 mMappedMemory = nullptr;
2302 }
2303 }
2304
flush(RendererVk * renderer,VkDeviceSize offset,VkDeviceSize size)2305 angle::Result BufferHelper::flush(RendererVk *renderer, VkDeviceSize offset, VkDeviceSize size)
2306 {
2307 bool hostVisible = mMemoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
2308 bool hostCoherent = mMemoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
2309 if (hostVisible && !hostCoherent)
2310 {
2311 mAllocation.flush(renderer->getAllocator(), offset, size);
2312 }
2313 return angle::Result::Continue;
2314 }
2315
invalidate(RendererVk * renderer,VkDeviceSize offset,VkDeviceSize size)2316 angle::Result BufferHelper::invalidate(RendererVk *renderer, VkDeviceSize offset, VkDeviceSize size)
2317 {
2318 bool hostVisible = mMemoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
2319 bool hostCoherent = mMemoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
2320 if (hostVisible && !hostCoherent)
2321 {
2322 mAllocation.invalidate(renderer->getAllocator(), offset, size);
2323 }
2324 return angle::Result::Continue;
2325 }
2326
changeQueue(uint32_t newQueueFamilyIndex,CommandBuffer * commandBuffer)2327 void BufferHelper::changeQueue(uint32_t newQueueFamilyIndex, CommandBuffer *commandBuffer)
2328 {
2329 VkBufferMemoryBarrier bufferMemoryBarrier = {};
2330 bufferMemoryBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
2331 bufferMemoryBarrier.srcAccessMask = 0;
2332 bufferMemoryBarrier.dstAccessMask = 0;
2333 bufferMemoryBarrier.srcQueueFamilyIndex = mCurrentQueueFamilyIndex;
2334 bufferMemoryBarrier.dstQueueFamilyIndex = newQueueFamilyIndex;
2335 bufferMemoryBarrier.buffer = mBuffer.getHandle();
2336 bufferMemoryBarrier.offset = 0;
2337 bufferMemoryBarrier.size = VK_WHOLE_SIZE;
2338
2339 commandBuffer->bufferBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
2340 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, &bufferMemoryBarrier);
2341
2342 mCurrentQueueFamilyIndex = newQueueFamilyIndex;
2343 }
2344
acquireFromExternal(ContextVk * contextVk,uint32_t externalQueueFamilyIndex,uint32_t rendererQueueFamilyIndex,CommandBuffer * commandBuffer)2345 void BufferHelper::acquireFromExternal(ContextVk *contextVk,
2346 uint32_t externalQueueFamilyIndex,
2347 uint32_t rendererQueueFamilyIndex,
2348 CommandBuffer *commandBuffer)
2349 {
2350 mCurrentQueueFamilyIndex = externalQueueFamilyIndex;
2351
2352 changeQueue(rendererQueueFamilyIndex, commandBuffer);
2353 }
2354
releaseToExternal(ContextVk * contextVk,uint32_t rendererQueueFamilyIndex,uint32_t externalQueueFamilyIndex,CommandBuffer * commandBuffer)2355 void BufferHelper::releaseToExternal(ContextVk *contextVk,
2356 uint32_t rendererQueueFamilyIndex,
2357 uint32_t externalQueueFamilyIndex,
2358 CommandBuffer *commandBuffer)
2359 {
2360 ASSERT(mCurrentQueueFamilyIndex == rendererQueueFamilyIndex);
2361
2362 changeQueue(externalQueueFamilyIndex, commandBuffer);
2363 }
2364
isReleasedToExternal() const2365 bool BufferHelper::isReleasedToExternal() const
2366 {
2367 #if !defined(ANGLE_PLATFORM_MACOS) && !defined(ANGLE_PLATFORM_ANDROID)
2368 return IsExternalQueueFamily(mCurrentQueueFamilyIndex);
2369 #else
2370 // TODO(anglebug.com/4635): Implement external memory barriers on Mac/Android.
2371 return false;
2372 #endif
2373 }
2374
canAccumulateRead(ContextVk * contextVk,VkAccessFlags readAccessType)2375 bool BufferHelper::canAccumulateRead(ContextVk *contextVk, VkAccessFlags readAccessType)
2376 {
2377 // We only need to start a new command buffer when we need a new barrier.
2378 // For simplicity's sake for now we always start a new command buffer.
2379 // TODO(jmadill): Re-use the command buffer. http://anglebug.com/4429
2380 return false;
2381 }
2382
canAccumulateWrite(ContextVk * contextVk,VkAccessFlags writeAccessType)2383 bool BufferHelper::canAccumulateWrite(ContextVk *contextVk, VkAccessFlags writeAccessType)
2384 {
2385 // We only need to start a new command buffer when we need a new barrier.
2386 // For simplicity's sake for now we always start a new command buffer.
2387 // TODO(jmadill): Re-use the command buffer. http://anglebug.com/4429
2388 return false;
2389 }
2390
updateReadBarrier(VkAccessFlags readAccessType,VkPipelineStageFlags readStage,PipelineBarrier * barrier)2391 bool BufferHelper::updateReadBarrier(VkAccessFlags readAccessType,
2392 VkPipelineStageFlags readStage,
2393 PipelineBarrier *barrier)
2394 {
2395 bool barrierModified = false;
2396 // If there was a prior write and we are making a read that is either a new access type or from
2397 // a new stage, we need a barrier
2398 if (mCurrentWriteAccess != 0 && (((mCurrentReadAccess & readAccessType) != readAccessType) ||
2399 ((mCurrentReadStages & readStage) != readStage)))
2400 {
2401 barrier->mergeMemoryBarrier(mCurrentWriteStages, readStage, mCurrentWriteAccess,
2402 readAccessType);
2403 barrierModified = true;
2404 }
2405
2406 // Accumulate new read usage.
2407 mCurrentReadAccess |= readAccessType;
2408 mCurrentReadStages |= readStage;
2409 return barrierModified;
2410 }
2411
updateWriteBarrier(VkAccessFlags writeAccessType,VkPipelineStageFlags writeStage,PipelineBarrier * barrier)2412 bool BufferHelper::updateWriteBarrier(VkAccessFlags writeAccessType,
2413 VkPipelineStageFlags writeStage,
2414 PipelineBarrier *barrier)
2415 {
2416 bool barrierModified = false;
2417 // We don't need to check mCurrentReadStages here since if it is not zero, mCurrentReadAccess
2418 // must not be zero as well. stage is finer grain than accessType.
2419 ASSERT((!mCurrentReadStages && !mCurrentReadAccess) ||
2420 (mCurrentReadStages && mCurrentReadAccess));
2421 if (mCurrentReadAccess != 0 || mCurrentWriteAccess != 0)
2422 {
2423 barrier->mergeMemoryBarrier(mCurrentWriteStages | mCurrentReadStages, writeStage,
2424 mCurrentWriteAccess, writeAccessType);
2425 barrierModified = true;
2426 }
2427
2428 // Reset usages on the new write.
2429 mCurrentWriteAccess = writeAccessType;
2430 mCurrentReadAccess = 0;
2431 mCurrentWriteStages = writeStage;
2432 mCurrentReadStages = 0;
2433 return barrierModified;
2434 }
2435
2436 // ImageHelper implementation.
ImageHelper()2437 ImageHelper::ImageHelper()
2438 {
2439 resetCachedProperties();
2440 }
2441
ImageHelper(ImageHelper && other)2442 ImageHelper::ImageHelper(ImageHelper &&other)
2443 : mImage(std::move(other.mImage)),
2444 mDeviceMemory(std::move(other.mDeviceMemory)),
2445 mImageType(other.mImageType),
2446 mExtents(other.mExtents),
2447 mFormat(other.mFormat),
2448 mSamples(other.mSamples),
2449 mSerial(other.mSerial),
2450 mCurrentLayout(other.mCurrentLayout),
2451 mCurrentQueueFamilyIndex(other.mCurrentQueueFamilyIndex),
2452 mLastNonShaderReadOnlyLayout(other.mLastNonShaderReadOnlyLayout),
2453 mCurrentShaderReadStageMask(other.mCurrentShaderReadStageMask),
2454 mBaseLevel(other.mBaseLevel),
2455 mMaxLevel(other.mMaxLevel),
2456 mLayerCount(other.mLayerCount),
2457 mLevelCount(other.mLevelCount),
2458 mStagingBuffer(std::move(other.mStagingBuffer)),
2459 mSubresourceUpdates(std::move(other.mSubresourceUpdates))
2460 {
2461 ASSERT(this != &other);
2462 other.resetCachedProperties();
2463 }
2464
~ImageHelper()2465 ImageHelper::~ImageHelper()
2466 {
2467 ASSERT(!valid());
2468 }
2469
resetCachedProperties()2470 void ImageHelper::resetCachedProperties()
2471 {
2472 mImageType = VK_IMAGE_TYPE_2D;
2473 mExtents = {};
2474 mFormat = nullptr;
2475 mSamples = 1;
2476 mSerial = rx::kZeroSerial;
2477 mCurrentLayout = ImageLayout::Undefined;
2478 mCurrentQueueFamilyIndex = std::numeric_limits<uint32_t>::max();
2479 mLastNonShaderReadOnlyLayout = ImageLayout::Undefined;
2480 mCurrentShaderReadStageMask = 0;
2481 mBaseLevel = 0;
2482 mMaxLevel = 0;
2483 mLayerCount = 0;
2484 mLevelCount = 0;
2485 }
2486
initStagingBuffer(RendererVk * renderer,const Format & format,VkBufferUsageFlags usageFlags,size_t initialSize)2487 void ImageHelper::initStagingBuffer(RendererVk *renderer,
2488 const Format &format,
2489 VkBufferUsageFlags usageFlags,
2490 size_t initialSize)
2491 {
2492 mStagingBuffer.init(renderer, usageFlags, format.getImageCopyBufferAlignment(), initialSize,
2493 true);
2494 }
2495
init(Context * context,gl::TextureType textureType,const VkExtent3D & extents,const Format & format,GLint samples,VkImageUsageFlags usage,uint32_t baseLevel,uint32_t maxLevel,uint32_t mipLevels,uint32_t layerCount)2496 angle::Result ImageHelper::init(Context *context,
2497 gl::TextureType textureType,
2498 const VkExtent3D &extents,
2499 const Format &format,
2500 GLint samples,
2501 VkImageUsageFlags usage,
2502 uint32_t baseLevel,
2503 uint32_t maxLevel,
2504 uint32_t mipLevels,
2505 uint32_t layerCount)
2506 {
2507 mSerial = rx::kZeroSerial;
2508 return initExternal(context, textureType, extents, format, samples, usage,
2509 kVkImageCreateFlagsNone, ImageLayout::Undefined, nullptr, baseLevel,
2510 maxLevel, mipLevels, layerCount);
2511 }
2512
initExternal(Context * context,gl::TextureType textureType,const VkExtent3D & extents,const Format & format,GLint samples,VkImageUsageFlags usage,VkImageCreateFlags additionalCreateFlags,ImageLayout initialLayout,const void * externalImageCreateInfo,uint32_t baseLevel,uint32_t maxLevel,uint32_t mipLevels,uint32_t layerCount)2513 angle::Result ImageHelper::initExternal(Context *context,
2514 gl::TextureType textureType,
2515 const VkExtent3D &extents,
2516 const Format &format,
2517 GLint samples,
2518 VkImageUsageFlags usage,
2519 VkImageCreateFlags additionalCreateFlags,
2520 ImageLayout initialLayout,
2521 const void *externalImageCreateInfo,
2522 uint32_t baseLevel,
2523 uint32_t maxLevel,
2524 uint32_t mipLevels,
2525 uint32_t layerCount)
2526 {
2527 ASSERT(!valid());
2528
2529 mImageType = gl_vk::GetImageType(textureType);
2530 mExtents = extents;
2531 mFormat = &format;
2532 mSamples = samples;
2533 mBaseLevel = baseLevel;
2534 mMaxLevel = maxLevel;
2535 mLevelCount = mipLevels;
2536 mLayerCount = layerCount;
2537
2538 // Validate that mLayerCount is compatible with the texture type
2539 ASSERT(textureType != gl::TextureType::_3D || mLayerCount == 1);
2540 ASSERT(textureType != gl::TextureType::_2DArray || mExtents.depth == 1);
2541 ASSERT(textureType != gl::TextureType::External || mLayerCount == 1);
2542 ASSERT(textureType != gl::TextureType::Rectangle || mLayerCount == 1);
2543 ASSERT(textureType != gl::TextureType::CubeMap || mLayerCount == gl::kCubeFaceCount);
2544
2545 VkImageCreateInfo imageInfo = {};
2546 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
2547 imageInfo.pNext = externalImageCreateInfo;
2548 imageInfo.flags = GetImageCreateFlags(textureType) | additionalCreateFlags;
2549 imageInfo.imageType = mImageType;
2550 imageInfo.format = format.vkImageFormat;
2551 imageInfo.extent = mExtents;
2552 imageInfo.mipLevels = mipLevels;
2553 imageInfo.arrayLayers = mLayerCount;
2554 imageInfo.samples = gl_vk::GetSamples(samples);
2555 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
2556 imageInfo.usage = usage;
2557 imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
2558 imageInfo.queueFamilyIndexCount = 0;
2559 imageInfo.pQueueFamilyIndices = nullptr;
2560 imageInfo.initialLayout = kImageMemoryBarrierData[initialLayout].layout;
2561
2562 mCurrentLayout = initialLayout;
2563
2564 ANGLE_VK_TRY(context, mImage.init(context->getDevice(), imageInfo));
2565
2566 stageClearIfEmulatedFormat(context);
2567
2568 return angle::Result::Continue;
2569 }
2570
releaseImage(RendererVk * renderer)2571 void ImageHelper::releaseImage(RendererVk *renderer)
2572 {
2573 mSerial = rx::kZeroSerial;
2574 renderer->collectGarbageAndReinit(&mUse, &mImage, &mDeviceMemory);
2575 }
2576
releaseStagingBuffer(RendererVk * renderer)2577 void ImageHelper::releaseStagingBuffer(RendererVk *renderer)
2578 {
2579 // Remove updates that never made it to the texture.
2580 for (SubresourceUpdate &update : mSubresourceUpdates)
2581 {
2582 update.release(renderer);
2583 }
2584 mStagingBuffer.release(renderer);
2585 mSubresourceUpdates.clear();
2586 }
2587
resetImageWeakReference()2588 void ImageHelper::resetImageWeakReference()
2589 {
2590 mImage.reset();
2591 }
2592
initializeNonZeroMemory(Context * context,VkDeviceSize size)2593 angle::Result ImageHelper::initializeNonZeroMemory(Context *context, VkDeviceSize size)
2594 {
2595 // The staging buffer memory is non-zero-initialized in 'init'.
2596 vk::StagingBuffer stagingBuffer;
2597 ANGLE_TRY(stagingBuffer.init(context, size, vk::StagingUsage::Write));
2598
2599 RendererVk *renderer = context->getRenderer();
2600
2601 vk::PrimaryCommandBuffer commandBuffer;
2602 ANGLE_TRY(renderer->getCommandBufferOneOff(context, &commandBuffer));
2603
2604 // Queue a DMA copy.
2605 forceChangeLayoutAndQueue(getAspectFlags(), ImageLayout::TransferDst, mCurrentQueueFamilyIndex,
2606 &commandBuffer);
2607
2608 VkBufferImageCopy copyRegion = {};
2609 copyRegion.imageExtent = mExtents;
2610 copyRegion.imageSubresource.aspectMask = getAspectFlags();
2611 copyRegion.imageSubresource.layerCount = 1;
2612
2613 commandBuffer.copyBufferToImage(stagingBuffer.getBuffer().getHandle(), mImage,
2614 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Region);
2615
2616 ANGLE_VK_TRY(context, commandBuffer.end());
2617
2618 Serial serial;
2619 ANGLE_TRY(renderer->queueSubmitOneOff(context, std::move(commandBuffer),
2620 egl::ContextPriority::Medium, nullptr, &serial));
2621
2622 stagingBuffer.collectGarbage(renderer, serial);
2623 mUse.updateSerialOneOff(serial);
2624
2625 return angle::Result::Continue;
2626 }
2627
initMemory(Context * context,const MemoryProperties & memoryProperties,VkMemoryPropertyFlags flags)2628 angle::Result ImageHelper::initMemory(Context *context,
2629 const MemoryProperties &memoryProperties,
2630 VkMemoryPropertyFlags flags)
2631 {
2632 // TODO(jmadill): Memory sub-allocation. http://anglebug.com/2162
2633 VkDeviceSize size;
2634 ANGLE_TRY(AllocateImageMemory(context, flags, nullptr, &mImage, &mDeviceMemory, &size));
2635 mCurrentQueueFamilyIndex = context->getRenderer()->getQueueFamilyIndex();
2636
2637 RendererVk *renderer = context->getRenderer();
2638 if (renderer->getFeatures().allocateNonZeroMemory.enabled)
2639 {
2640 // Can't map the memory. Use a staging resource.
2641 if ((flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0)
2642 {
2643 // Only currently works with single-sampled color images with one mip/layer.
2644 if (mLevelCount == 1 && mLayerCount == 1 &&
2645 getAspectFlags() == VK_IMAGE_ASPECT_COLOR_BIT && mSamples == 1)
2646 {
2647 ANGLE_TRY(initializeNonZeroMemory(context, size));
2648 }
2649 else
2650 {
2651 UNIMPLEMENTED();
2652 }
2653 }
2654 }
2655
2656 return angle::Result::Continue;
2657 }
2658
initExternalMemory(Context * context,const MemoryProperties & memoryProperties,const VkMemoryRequirements & memoryRequirements,const void * extraAllocationInfo,uint32_t currentQueueFamilyIndex,VkMemoryPropertyFlags flags)2659 angle::Result ImageHelper::initExternalMemory(Context *context,
2660 const MemoryProperties &memoryProperties,
2661 const VkMemoryRequirements &memoryRequirements,
2662 const void *extraAllocationInfo,
2663 uint32_t currentQueueFamilyIndex,
2664
2665 VkMemoryPropertyFlags flags)
2666 {
2667 // TODO(jmadill): Memory sub-allocation. http://anglebug.com/2162
2668 ANGLE_TRY(AllocateImageMemoryWithRequirements(context, flags, memoryRequirements,
2669 extraAllocationInfo, &mImage, &mDeviceMemory));
2670 mCurrentQueueFamilyIndex = currentQueueFamilyIndex;
2671 return angle::Result::Continue;
2672 }
2673
initImageView(Context * context,gl::TextureType textureType,VkImageAspectFlags aspectMask,const gl::SwizzleState & swizzleMap,ImageView * imageViewOut,uint32_t baseMipLevel,uint32_t levelCount)2674 angle::Result ImageHelper::initImageView(Context *context,
2675 gl::TextureType textureType,
2676 VkImageAspectFlags aspectMask,
2677 const gl::SwizzleState &swizzleMap,
2678 ImageView *imageViewOut,
2679 uint32_t baseMipLevel,
2680 uint32_t levelCount)
2681 {
2682 return initLayerImageView(context, textureType, aspectMask, swizzleMap, imageViewOut,
2683 baseMipLevel, levelCount, 0, mLayerCount);
2684 }
2685
initLayerImageView(Context * context,gl::TextureType textureType,VkImageAspectFlags aspectMask,const gl::SwizzleState & swizzleMap,ImageView * imageViewOut,uint32_t baseMipLevel,uint32_t levelCount,uint32_t baseArrayLayer,uint32_t layerCount) const2686 angle::Result ImageHelper::initLayerImageView(Context *context,
2687 gl::TextureType textureType,
2688 VkImageAspectFlags aspectMask,
2689 const gl::SwizzleState &swizzleMap,
2690 ImageView *imageViewOut,
2691 uint32_t baseMipLevel,
2692 uint32_t levelCount,
2693 uint32_t baseArrayLayer,
2694 uint32_t layerCount) const
2695 {
2696 return initLayerImageViewImpl(context, textureType, aspectMask, swizzleMap, imageViewOut,
2697 baseMipLevel, levelCount, baseArrayLayer, layerCount,
2698 mFormat->vkImageFormat);
2699 }
initLayerImageViewImpl(Context * context,gl::TextureType textureType,VkImageAspectFlags aspectMask,const gl::SwizzleState & swizzleMap,ImageView * imageViewOut,uint32_t baseMipLevel,uint32_t levelCount,uint32_t baseArrayLayer,uint32_t layerCount,VkFormat imageFormat) const2700 angle::Result ImageHelper::initLayerImageViewImpl(Context *context,
2701 gl::TextureType textureType,
2702 VkImageAspectFlags aspectMask,
2703 const gl::SwizzleState &swizzleMap,
2704 ImageView *imageViewOut,
2705 uint32_t baseMipLevel,
2706 uint32_t levelCount,
2707 uint32_t baseArrayLayer,
2708 uint32_t layerCount,
2709 VkFormat imageFormat) const
2710 {
2711 VkImageViewCreateInfo viewInfo = {};
2712 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2713 viewInfo.flags = 0;
2714 viewInfo.image = mImage.getHandle();
2715 viewInfo.viewType = gl_vk::GetImageViewType(textureType);
2716 viewInfo.format = imageFormat;
2717 ASSERT(viewInfo.format != VK_FORMAT_UNDEFINED);
2718
2719 if (swizzleMap.swizzleRequired())
2720 {
2721 viewInfo.components.r = gl_vk::GetSwizzle(swizzleMap.swizzleRed);
2722 viewInfo.components.g = gl_vk::GetSwizzle(swizzleMap.swizzleGreen);
2723 viewInfo.components.b = gl_vk::GetSwizzle(swizzleMap.swizzleBlue);
2724 viewInfo.components.a = gl_vk::GetSwizzle(swizzleMap.swizzleAlpha);
2725 }
2726 else
2727 {
2728 viewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
2729 viewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
2730 viewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
2731 viewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
2732 }
2733 viewInfo.subresourceRange.aspectMask = aspectMask;
2734 viewInfo.subresourceRange.baseMipLevel = baseMipLevel;
2735 viewInfo.subresourceRange.levelCount = levelCount;
2736 viewInfo.subresourceRange.baseArrayLayer = baseArrayLayer;
2737 viewInfo.subresourceRange.layerCount = layerCount;
2738
2739 ANGLE_VK_TRY(context, imageViewOut->init(context->getDevice(), viewInfo));
2740 return angle::Result::Continue;
2741 }
2742
destroy(RendererVk * renderer)2743 void ImageHelper::destroy(RendererVk *renderer)
2744 {
2745 VkDevice device = renderer->getDevice();
2746
2747 mImage.destroy(device);
2748 mDeviceMemory.destroy(device);
2749 mStagingBuffer.destroy(renderer);
2750 mCurrentLayout = ImageLayout::Undefined;
2751 mImageType = VK_IMAGE_TYPE_2D;
2752 mLayerCount = 0;
2753 mLevelCount = 0;
2754 mSerial = rx::kZeroSerial;
2755 }
2756
init2DWeakReference(Context * context,VkImage handle,const gl::Extents & glExtents,const Format & format,GLint samples)2757 void ImageHelper::init2DWeakReference(Context *context,
2758 VkImage handle,
2759 const gl::Extents &glExtents,
2760 const Format &format,
2761 GLint samples)
2762 {
2763 ASSERT(!valid());
2764
2765 gl_vk::GetExtent(glExtents, &mExtents);
2766 mFormat = &format;
2767 mSamples = samples;
2768 mCurrentLayout = ImageLayout::Undefined;
2769 mLayerCount = 1;
2770 mLevelCount = 1;
2771
2772 mImage.setHandle(handle);
2773
2774 stageClearIfEmulatedFormat(context);
2775 }
2776
init2DStaging(Context * context,const MemoryProperties & memoryProperties,const gl::Extents & glExtents,const Format & format,VkImageUsageFlags usage,uint32_t layerCount)2777 angle::Result ImageHelper::init2DStaging(Context *context,
2778 const MemoryProperties &memoryProperties,
2779 const gl::Extents &glExtents,
2780 const Format &format,
2781 VkImageUsageFlags usage,
2782 uint32_t layerCount)
2783 {
2784 ASSERT(!valid());
2785
2786 gl_vk::GetExtent(glExtents, &mExtents);
2787 mImageType = VK_IMAGE_TYPE_2D;
2788 mFormat = &format;
2789 mSamples = 1;
2790 mLayerCount = layerCount;
2791 mLevelCount = 1;
2792
2793 mCurrentLayout = ImageLayout::Undefined;
2794
2795 VkImageCreateInfo imageInfo = {};
2796 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
2797 imageInfo.flags = 0;
2798 imageInfo.imageType = mImageType;
2799 imageInfo.format = format.vkImageFormat;
2800 imageInfo.extent = mExtents;
2801 imageInfo.mipLevels = 1;
2802 imageInfo.arrayLayers = mLayerCount;
2803 imageInfo.samples = gl_vk::GetSamples(mSamples);
2804 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
2805 imageInfo.usage = usage;
2806 imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
2807 imageInfo.queueFamilyIndexCount = 0;
2808 imageInfo.pQueueFamilyIndices = nullptr;
2809 imageInfo.initialLayout = getCurrentLayout();
2810
2811 ANGLE_VK_TRY(context, mImage.init(context->getDevice(), imageInfo));
2812
2813 // Allocate and bind device-local memory.
2814 VkMemoryPropertyFlags memoryPropertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
2815 ANGLE_TRY(initMemory(context, memoryProperties, memoryPropertyFlags));
2816
2817 return angle::Result::Continue;
2818 }
2819
getAspectFlags() const2820 VkImageAspectFlags ImageHelper::getAspectFlags() const
2821 {
2822 return GetFormatAspectFlags(mFormat->actualImageFormat());
2823 }
2824
isCombinedDepthStencilFormat() const2825 bool ImageHelper::isCombinedDepthStencilFormat() const
2826 {
2827 return ((VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT) & getAspectFlags()) ==
2828 (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT);
2829 }
2830
getCurrentLayout() const2831 VkImageLayout ImageHelper::getCurrentLayout() const
2832 {
2833 return kImageMemoryBarrierData[mCurrentLayout].layout;
2834 }
2835
getLevelExtents2D(uint32_t level) const2836 gl::Extents ImageHelper::getLevelExtents2D(uint32_t level) const
2837 {
2838 uint32_t width = std::max(mExtents.width >> level, 1u);
2839 uint32_t height = std::max(mExtents.height >> level, 1u);
2840
2841 return gl::Extents(width, height, 1);
2842 }
2843
isLayoutChangeNecessary(ImageLayout newLayout) const2844 bool ImageHelper::isLayoutChangeNecessary(ImageLayout newLayout) const
2845 {
2846 const ImageMemoryBarrierData &layoutData = kImageMemoryBarrierData[mCurrentLayout];
2847
2848 // If transitioning to the same layout, we don't need a barrier if the layout is read-only as
2849 // RAR (read-after-read) doesn't need a barrier. WAW (write-after-write) does require a memory
2850 // barrier though.
2851 bool sameLayoutAndNoNeedForBarrier =
2852 mCurrentLayout == newLayout && !layoutData.sameLayoutTransitionRequiresBarrier;
2853
2854 return !sameLayoutAndNoNeedForBarrier;
2855 }
2856
changeLayoutAndQueue(VkImageAspectFlags aspectMask,ImageLayout newLayout,uint32_t newQueueFamilyIndex,CommandBuffer * commandBuffer)2857 void ImageHelper::changeLayoutAndQueue(VkImageAspectFlags aspectMask,
2858 ImageLayout newLayout,
2859 uint32_t newQueueFamilyIndex,
2860 CommandBuffer *commandBuffer)
2861 {
2862 ASSERT(isQueueChangeNeccesary(newQueueFamilyIndex));
2863 forceChangeLayoutAndQueue(aspectMask, newLayout, newQueueFamilyIndex, commandBuffer);
2864 }
2865
acquireFromExternal(ContextVk * contextVk,uint32_t externalQueueFamilyIndex,uint32_t rendererQueueFamilyIndex,ImageLayout currentLayout,CommandBuffer * commandBuffer)2866 void ImageHelper::acquireFromExternal(ContextVk *contextVk,
2867 uint32_t externalQueueFamilyIndex,
2868 uint32_t rendererQueueFamilyIndex,
2869 ImageLayout currentLayout,
2870 CommandBuffer *commandBuffer)
2871 {
2872 // The image must be newly allocated or have been released to the external
2873 // queue. If this is not the case, it's an application bug, so ASSERT might
2874 // eventually need to change to a warning.
2875 ASSERT(mCurrentLayout == ImageLayout::Undefined ||
2876 mCurrentQueueFamilyIndex == externalQueueFamilyIndex);
2877
2878 mCurrentLayout = currentLayout;
2879 mCurrentQueueFamilyIndex = externalQueueFamilyIndex;
2880
2881 changeLayoutAndQueue(getAspectFlags(), mCurrentLayout, rendererQueueFamilyIndex, commandBuffer);
2882 }
2883
releaseToExternal(ContextVk * contextVk,uint32_t rendererQueueFamilyIndex,uint32_t externalQueueFamilyIndex,ImageLayout desiredLayout,CommandBuffer * commandBuffer)2884 void ImageHelper::releaseToExternal(ContextVk *contextVk,
2885 uint32_t rendererQueueFamilyIndex,
2886 uint32_t externalQueueFamilyIndex,
2887 ImageLayout desiredLayout,
2888 CommandBuffer *commandBuffer)
2889 {
2890 ASSERT(mCurrentQueueFamilyIndex == rendererQueueFamilyIndex);
2891
2892 changeLayoutAndQueue(getAspectFlags(), desiredLayout, externalQueueFamilyIndex, commandBuffer);
2893 }
2894
isReleasedToExternal() const2895 bool ImageHelper::isReleasedToExternal() const
2896 {
2897 #if !defined(ANGLE_PLATFORM_MACOS) && !defined(ANGLE_PLATFORM_ANDROID)
2898 return IsExternalQueueFamily(mCurrentQueueFamilyIndex);
2899 #else
2900 // TODO(anglebug.com/4635): Implement external memory barriers on Mac/Android.
2901 return false;
2902 #endif
2903 }
2904
getBaseLevel()2905 uint32_t ImageHelper::getBaseLevel()
2906 {
2907 return mBaseLevel;
2908 }
2909
setBaseAndMaxLevels(uint32_t baseLevel,uint32_t maxLevel)2910 void ImageHelper::setBaseAndMaxLevels(uint32_t baseLevel, uint32_t maxLevel)
2911 {
2912 mBaseLevel = baseLevel;
2913 mMaxLevel = maxLevel;
2914 }
2915
initImageMemoryBarrierStruct(VkImageAspectFlags aspectMask,ImageLayout newLayout,uint32_t newQueueFamilyIndex,VkImageMemoryBarrier * imageMemoryBarrier) const2916 ANGLE_INLINE void ImageHelper::initImageMemoryBarrierStruct(
2917 VkImageAspectFlags aspectMask,
2918 ImageLayout newLayout,
2919 uint32_t newQueueFamilyIndex,
2920 VkImageMemoryBarrier *imageMemoryBarrier) const
2921 {
2922 const ImageMemoryBarrierData &transitionFrom = kImageMemoryBarrierData[mCurrentLayout];
2923 const ImageMemoryBarrierData &transitionTo = kImageMemoryBarrierData[newLayout];
2924
2925 imageMemoryBarrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
2926 imageMemoryBarrier->srcAccessMask = transitionFrom.srcAccessMask;
2927 imageMemoryBarrier->dstAccessMask = transitionTo.dstAccessMask;
2928 imageMemoryBarrier->oldLayout = transitionFrom.layout;
2929 imageMemoryBarrier->newLayout = transitionTo.layout;
2930 imageMemoryBarrier->srcQueueFamilyIndex = mCurrentQueueFamilyIndex;
2931 imageMemoryBarrier->dstQueueFamilyIndex = newQueueFamilyIndex;
2932 imageMemoryBarrier->image = mImage.getHandle();
2933
2934 // Transition the whole resource.
2935 imageMemoryBarrier->subresourceRange.aspectMask = aspectMask;
2936 imageMemoryBarrier->subresourceRange.baseMipLevel = 0;
2937 imageMemoryBarrier->subresourceRange.levelCount = mLevelCount;
2938 imageMemoryBarrier->subresourceRange.baseArrayLayer = 0;
2939 imageMemoryBarrier->subresourceRange.layerCount = mLayerCount;
2940 }
2941
2942 // Generalized to accept both "primary" and "secondary" command buffers.
2943 template <typename CommandBufferT>
forceChangeLayoutAndQueue(VkImageAspectFlags aspectMask,ImageLayout newLayout,uint32_t newQueueFamilyIndex,CommandBufferT * commandBuffer)2944 void ImageHelper::forceChangeLayoutAndQueue(VkImageAspectFlags aspectMask,
2945 ImageLayout newLayout,
2946 uint32_t newQueueFamilyIndex,
2947 CommandBufferT *commandBuffer)
2948 {
2949 const ImageMemoryBarrierData &transitionFrom = kImageMemoryBarrierData[mCurrentLayout];
2950 const ImageMemoryBarrierData &transitionTo = kImageMemoryBarrierData[newLayout];
2951
2952 VkImageMemoryBarrier imageMemoryBarrier = {};
2953 initImageMemoryBarrierStruct(aspectMask, newLayout, newQueueFamilyIndex, &imageMemoryBarrier);
2954
2955 // There might be other shaderRead operations there other than the current layout.
2956 VkPipelineStageFlags srcStageMask = transitionFrom.srcStageMask;
2957 if (mCurrentShaderReadStageMask)
2958 {
2959 srcStageMask |= mCurrentShaderReadStageMask;
2960 mCurrentShaderReadStageMask = 0;
2961 mLastNonShaderReadOnlyLayout = ImageLayout::Undefined;
2962 }
2963 commandBuffer->imageBarrier(srcStageMask, transitionTo.dstStageMask, imageMemoryBarrier);
2964
2965 mCurrentLayout = newLayout;
2966 mCurrentQueueFamilyIndex = newQueueFamilyIndex;
2967 }
2968
updateLayoutAndBarrier(VkImageAspectFlags aspectMask,ImageLayout newLayout,PipelineBarrier * barrier)2969 bool ImageHelper::updateLayoutAndBarrier(VkImageAspectFlags aspectMask,
2970 ImageLayout newLayout,
2971 PipelineBarrier *barrier)
2972 {
2973 bool barrierModified = false;
2974 if (newLayout == mCurrentLayout)
2975 {
2976 const ImageMemoryBarrierData &layoutData = kImageMemoryBarrierData[mCurrentLayout];
2977 ASSERT(layoutData.sameLayoutTransitionRequiresBarrier);
2978 // No layout change, only memory barrier is required
2979 barrier->mergeMemoryBarrier(layoutData.srcStageMask, layoutData.dstStageMask,
2980 layoutData.srcAccessMask, layoutData.dstAccessMask);
2981 barrierModified = true;
2982 }
2983 else
2984 {
2985 const ImageMemoryBarrierData &transitionFrom = kImageMemoryBarrierData[mCurrentLayout];
2986 const ImageMemoryBarrierData &transitionTo = kImageMemoryBarrierData[newLayout];
2987 VkPipelineStageFlags srcStageMask = transitionFrom.srcStageMask;
2988 VkPipelineStageFlags dstStageMask = transitionTo.dstStageMask;
2989
2990 if (transitionTo.layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL &&
2991 transitionFrom.layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
2992 {
2993 // If we are switching between different shader stage reads, then there is no actual
2994 // layout change or access type change. We only need a barrier if we are making a read
2995 // that is from a new stage. Also note that we barrier against previous non-shaderRead
2996 // layout. We do not barrier between one shaderRead and another shaderRead.
2997 bool isNewReadStage = (mCurrentShaderReadStageMask & dstStageMask) != dstStageMask;
2998 if (isNewReadStage)
2999 {
3000 const ImageMemoryBarrierData &layoutData =
3001 kImageMemoryBarrierData[mLastNonShaderReadOnlyLayout];
3002 barrier->mergeMemoryBarrier(layoutData.srcStageMask, dstStageMask,
3003 layoutData.srcAccessMask, transitionTo.dstAccessMask);
3004 barrierModified = true;
3005 // Accumulate new read stage.
3006 mCurrentShaderReadStageMask |= dstStageMask;
3007 }
3008 }
3009 else
3010 {
3011 VkImageMemoryBarrier imageMemoryBarrier = {};
3012 initImageMemoryBarrierStruct(aspectMask, newLayout, mCurrentQueueFamilyIndex,
3013 &imageMemoryBarrier);
3014 // if we transition from shaderReadOnly, we must add in stashed shader stage masks since
3015 // there might be outstanding shader reads from stages other than current layout. We do
3016 // not insert barrier between one shaderRead to another shaderRead
3017 if (mCurrentShaderReadStageMask)
3018 {
3019 srcStageMask |= mCurrentShaderReadStageMask;
3020 mCurrentShaderReadStageMask = 0;
3021 mLastNonShaderReadOnlyLayout = ImageLayout::Undefined;
3022 }
3023 barrier->mergeImageBarrier(srcStageMask, dstStageMask, imageMemoryBarrier);
3024 barrierModified = true;
3025
3026 // If we are transition into shaderRead layout, remember the last
3027 // non-shaderRead layout here.
3028 if (transitionTo.layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
3029 {
3030 ASSERT(transitionFrom.layout != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
3031 mLastNonShaderReadOnlyLayout = mCurrentLayout;
3032 mCurrentShaderReadStageMask = dstStageMask;
3033 }
3034 }
3035 mCurrentLayout = newLayout;
3036 }
3037 return barrierModified;
3038 }
3039
clearColor(const VkClearColorValue & color,uint32_t baseMipLevel,uint32_t levelCount,uint32_t baseArrayLayer,uint32_t layerCount,CommandBuffer * commandBuffer)3040 void ImageHelper::clearColor(const VkClearColorValue &color,
3041 uint32_t baseMipLevel,
3042 uint32_t levelCount,
3043 uint32_t baseArrayLayer,
3044 uint32_t layerCount,
3045 CommandBuffer *commandBuffer)
3046 {
3047 ASSERT(valid());
3048
3049 ASSERT(mCurrentLayout == ImageLayout::TransferDst);
3050
3051 VkImageSubresourceRange range = {};
3052 range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
3053 range.baseMipLevel = baseMipLevel;
3054 range.levelCount = levelCount;
3055 range.baseArrayLayer = baseArrayLayer;
3056 range.layerCount = layerCount;
3057
3058 commandBuffer->clearColorImage(mImage, getCurrentLayout(), color, 1, &range);
3059 }
3060
clearDepthStencil(VkImageAspectFlags clearAspectFlags,const VkClearDepthStencilValue & depthStencil,uint32_t baseMipLevel,uint32_t levelCount,uint32_t baseArrayLayer,uint32_t layerCount,CommandBuffer * commandBuffer)3061 void ImageHelper::clearDepthStencil(VkImageAspectFlags clearAspectFlags,
3062 const VkClearDepthStencilValue &depthStencil,
3063 uint32_t baseMipLevel,
3064 uint32_t levelCount,
3065 uint32_t baseArrayLayer,
3066 uint32_t layerCount,
3067 CommandBuffer *commandBuffer)
3068 {
3069 ASSERT(valid());
3070
3071 ASSERT(mCurrentLayout == ImageLayout::TransferDst);
3072
3073 VkImageSubresourceRange clearRange = {
3074 /*aspectMask*/ clearAspectFlags,
3075 /*baseMipLevel*/ baseMipLevel,
3076 /*levelCount*/ levelCount,
3077 /*baseArrayLayer*/ baseArrayLayer,
3078 /*layerCount*/ layerCount,
3079 };
3080
3081 commandBuffer->clearDepthStencilImage(mImage, getCurrentLayout(), depthStencil, 1, &clearRange);
3082 }
3083
clear(VkImageAspectFlags aspectFlags,const VkClearValue & value,uint32_t mipLevel,uint32_t baseArrayLayer,uint32_t layerCount,CommandBuffer * commandBuffer)3084 void ImageHelper::clear(VkImageAspectFlags aspectFlags,
3085 const VkClearValue &value,
3086 uint32_t mipLevel,
3087 uint32_t baseArrayLayer,
3088 uint32_t layerCount,
3089 CommandBuffer *commandBuffer)
3090 {
3091 const angle::Format &angleFormat = mFormat->actualImageFormat();
3092 bool isDepthStencil = angleFormat.depthBits > 0 || angleFormat.stencilBits > 0;
3093
3094 if (isDepthStencil)
3095 {
3096 clearDepthStencil(aspectFlags, value.depthStencil, mipLevel, 1, baseArrayLayer, layerCount,
3097 commandBuffer);
3098 }
3099 else
3100 {
3101 ASSERT(!angleFormat.isBlock);
3102
3103 clearColor(value.color, mipLevel, 1, baseArrayLayer, layerCount, commandBuffer);
3104 }
3105 }
3106
getSize(const gl::ImageIndex & index) const3107 gl::Extents ImageHelper::getSize(const gl::ImageIndex &index) const
3108 {
3109 GLint mipLevel = index.getLevelIndex();
3110 // Level 0 should be the size of the extents, after that every time you increase a level
3111 // you shrink the extents by half.
3112 return gl::Extents(std::max(1u, mExtents.width >> mipLevel),
3113 std::max(1u, mExtents.height >> mipLevel), mExtents.depth);
3114 }
3115
getAssignSerial(ContextVk * contextVk)3116 Serial ImageHelper::getAssignSerial(ContextVk *contextVk)
3117 {
3118 if (mSerial.getValue() == 0)
3119 {
3120 mSerial = contextVk->generateAttachmentImageSerial();
3121 }
3122 return mSerial;
3123 }
3124
3125 // static
Copy(ImageHelper * srcImage,ImageHelper * dstImage,const gl::Offset & srcOffset,const gl::Offset & dstOffset,const gl::Extents & copySize,const VkImageSubresourceLayers & srcSubresource,const VkImageSubresourceLayers & dstSubresource,CommandBuffer * commandBuffer)3126 void ImageHelper::Copy(ImageHelper *srcImage,
3127 ImageHelper *dstImage,
3128 const gl::Offset &srcOffset,
3129 const gl::Offset &dstOffset,
3130 const gl::Extents ©Size,
3131 const VkImageSubresourceLayers &srcSubresource,
3132 const VkImageSubresourceLayers &dstSubresource,
3133 CommandBuffer *commandBuffer)
3134 {
3135 ASSERT(commandBuffer->valid() && srcImage->valid() && dstImage->valid());
3136
3137 ASSERT(srcImage->getCurrentLayout() == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
3138 ASSERT(dstImage->getCurrentLayout() == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
3139
3140 VkImageCopy region = {};
3141 region.srcSubresource = srcSubresource;
3142 region.srcOffset.x = srcOffset.x;
3143 region.srcOffset.y = srcOffset.y;
3144 region.srcOffset.z = srcOffset.z;
3145 region.dstSubresource = dstSubresource;
3146 region.dstOffset.x = dstOffset.x;
3147 region.dstOffset.y = dstOffset.y;
3148 region.dstOffset.z = dstOffset.z;
3149 region.extent.width = copySize.width;
3150 region.extent.height = copySize.height;
3151 region.extent.depth = copySize.depth;
3152
3153 commandBuffer->copyImage(srcImage->getImage(), srcImage->getCurrentLayout(),
3154 dstImage->getImage(), dstImage->getCurrentLayout(), 1, ®ion);
3155 }
3156
generateMipmapsWithBlit(ContextVk * contextVk,GLuint maxLevel)3157 angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, GLuint maxLevel)
3158 {
3159 CommandBuffer *commandBuffer = nullptr;
3160 ANGLE_TRY(contextVk->onImageWrite(VK_IMAGE_ASPECT_COLOR_BIT, ImageLayout::TransferDst, this));
3161 ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&commandBuffer));
3162
3163 // We are able to use blitImage since the image format we are using supports it. This
3164 // is a faster way we can generate the mips.
3165 int32_t mipWidth = mExtents.width;
3166 int32_t mipHeight = mExtents.height;
3167 int32_t mipDepth = mExtents.depth;
3168
3169 // Manually manage the image memory barrier because it uses a lot more parameters than our
3170 // usual one.
3171 VkImageMemoryBarrier barrier = {};
3172 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
3173 barrier.image = mImage.getHandle();
3174 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3175 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3176 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
3177 barrier.subresourceRange.baseArrayLayer = 0;
3178 barrier.subresourceRange.layerCount = mLayerCount;
3179 barrier.subresourceRange.levelCount = 1;
3180
3181 for (uint32_t mipLevel = 1; mipLevel <= maxLevel; mipLevel++)
3182 {
3183 int32_t nextMipWidth = std::max<int32_t>(1, mipWidth >> 1);
3184 int32_t nextMipHeight = std::max<int32_t>(1, mipHeight >> 1);
3185 int32_t nextMipDepth = std::max<int32_t>(1, mipDepth >> 1);
3186
3187 barrier.subresourceRange.baseMipLevel = mipLevel - 1;
3188 barrier.oldLayout = getCurrentLayout();
3189 barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
3190 barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
3191 barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
3192
3193 // We can do it for all layers at once.
3194 commandBuffer->imageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
3195 barrier);
3196 VkImageBlit blit = {};
3197 blit.srcOffsets[0] = {0, 0, 0};
3198 blit.srcOffsets[1] = {mipWidth, mipHeight, mipDepth};
3199 blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
3200 blit.srcSubresource.mipLevel = mipLevel - 1;
3201 blit.srcSubresource.baseArrayLayer = 0;
3202 blit.srcSubresource.layerCount = mLayerCount;
3203 blit.dstOffsets[0] = {0, 0, 0};
3204 blit.dstOffsets[1] = {nextMipWidth, nextMipHeight, nextMipDepth};
3205 blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
3206 blit.dstSubresource.mipLevel = mipLevel;
3207 blit.dstSubresource.baseArrayLayer = 0;
3208 blit.dstSubresource.layerCount = mLayerCount;
3209
3210 mipWidth = nextMipWidth;
3211 mipHeight = nextMipHeight;
3212 mipDepth = nextMipDepth;
3213
3214 bool formatSupportsLinearFiltering = contextVk->getRenderer()->hasImageFormatFeatureBits(
3215 getFormat().vkImageFormat, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT);
3216
3217 commandBuffer->blitImage(
3218 mImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, mImage,
3219 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit,
3220 formatSupportsLinearFiltering ? VK_FILTER_LINEAR : VK_FILTER_NEAREST);
3221 }
3222
3223 // Transition the last mip level to the same layout as all the other ones, so we can declare
3224 // our whole image layout to be SRC_OPTIMAL.
3225 barrier.subresourceRange.baseMipLevel = maxLevel;
3226 barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
3227 barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
3228
3229 // We can do it for all layers at once.
3230 commandBuffer->imageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
3231 barrier);
3232 // This is just changing the internal state of the image helper so that the next call
3233 // to changeLayout will use this layout as the "oldLayout" argument.
3234 mCurrentLayout = ImageLayout::TransferSrc;
3235
3236 return angle::Result::Continue;
3237 }
3238
resolve(ImageHelper * dest,const VkImageResolve & region,CommandBuffer * commandBuffer)3239 void ImageHelper::resolve(ImageHelper *dest,
3240 const VkImageResolve ®ion,
3241 CommandBuffer *commandBuffer)
3242 {
3243 ASSERT(mCurrentLayout == ImageLayout::TransferSrc);
3244 commandBuffer->resolveImage(getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dest->getImage(),
3245 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
3246 }
3247
removeStagedUpdates(ContextVk * contextVk,uint32_t levelIndex,uint32_t layerIndex)3248 void ImageHelper::removeStagedUpdates(ContextVk *contextVk,
3249 uint32_t levelIndex,
3250 uint32_t layerIndex)
3251 {
3252 // Find any staged updates for this index and removes them from the pending list.
3253 for (size_t index = 0; index < mSubresourceUpdates.size();)
3254 {
3255 auto update = mSubresourceUpdates.begin() + index;
3256 if (update->isUpdateToLayerLevel(layerIndex, levelIndex))
3257 {
3258 update->release(contextVk->getRenderer());
3259 mSubresourceUpdates.erase(update);
3260 }
3261 else
3262 {
3263 index++;
3264 }
3265 }
3266 }
3267
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,const GLuint inputRowPitch,const GLuint inputDepthPitch,const GLuint inputSkipBytes)3268 angle::Result ImageHelper::stageSubresourceUpdateImpl(ContextVk *contextVk,
3269 const gl::ImageIndex &index,
3270 const gl::Extents &glExtents,
3271 const gl::Offset &offset,
3272 const gl::InternalFormat &formatInfo,
3273 const gl::PixelUnpackState &unpack,
3274 GLenum type,
3275 const uint8_t *pixels,
3276 const Format &vkFormat,
3277 const GLuint inputRowPitch,
3278 const GLuint inputDepthPitch,
3279 const GLuint inputSkipBytes)
3280 {
3281 const angle::Format &storageFormat = vkFormat.actualImageFormat();
3282
3283 size_t outputRowPitch;
3284 size_t outputDepthPitch;
3285 size_t stencilAllocationSize = 0;
3286 uint32_t bufferRowLength;
3287 uint32_t bufferImageHeight;
3288 size_t allocationSize;
3289
3290 LoadImageFunctionInfo loadFunctionInfo = vkFormat.textureLoadFunctions(type);
3291 LoadImageFunction stencilLoadFunction = nullptr;
3292
3293 if (storageFormat.isBlock)
3294 {
3295 const gl::InternalFormat &storageFormatInfo = vkFormat.getInternalFormatInfo(type);
3296 GLuint rowPitch;
3297 GLuint depthPitch;
3298 GLuint totalSize;
3299
3300 ANGLE_VK_CHECK_MATH(contextVk, storageFormatInfo.computeCompressedImageSize(
3301 gl::Extents(glExtents.width, 1, 1), &rowPitch));
3302 ANGLE_VK_CHECK_MATH(contextVk,
3303 storageFormatInfo.computeCompressedImageSize(
3304 gl::Extents(glExtents.width, glExtents.height, 1), &depthPitch));
3305
3306 ANGLE_VK_CHECK_MATH(contextVk,
3307 storageFormatInfo.computeCompressedImageSize(glExtents, &totalSize));
3308
3309 outputRowPitch = rowPitch;
3310 outputDepthPitch = depthPitch;
3311
3312 angle::CheckedNumeric<uint32_t> checkedRowLength =
3313 rx::CheckedRoundUp<uint32_t>(glExtents.width, storageFormatInfo.compressedBlockWidth);
3314 angle::CheckedNumeric<uint32_t> checkedImageHeight =
3315 rx::CheckedRoundUp<uint32_t>(glExtents.height, storageFormatInfo.compressedBlockHeight);
3316
3317 ANGLE_VK_CHECK_MATH(contextVk, checkedRowLength.IsValid());
3318 ANGLE_VK_CHECK_MATH(contextVk, checkedImageHeight.IsValid());
3319
3320 bufferRowLength = checkedRowLength.ValueOrDie();
3321 bufferImageHeight = checkedImageHeight.ValueOrDie();
3322 allocationSize = totalSize;
3323 }
3324 else
3325 {
3326 ASSERT(storageFormat.pixelBytes != 0);
3327
3328 if (storageFormat.id == angle::FormatID::D24_UNORM_S8_UINT)
3329 {
3330 stencilLoadFunction = angle::LoadX24S8ToS8;
3331 }
3332 if (storageFormat.id == angle::FormatID::D32_FLOAT_S8X24_UINT)
3333 {
3334 // If depth is D32FLOAT_S8, we must pack D32F tightly (no stencil) for CopyBufferToImage
3335 outputRowPitch = sizeof(float) * glExtents.width;
3336
3337 // The generic load functions don't handle tightly packing D32FS8 to D32F & S8 so call
3338 // special case load functions.
3339 switch (type)
3340 {
3341 case GL_UNSIGNED_INT:
3342 loadFunctionInfo.loadFunction = angle::LoadD32ToD32F;
3343 stencilLoadFunction = nullptr;
3344 break;
3345 case GL_DEPTH32F_STENCIL8:
3346 case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
3347 loadFunctionInfo.loadFunction = angle::LoadD32FS8X24ToD32F;
3348 stencilLoadFunction = angle::LoadX32S8ToS8;
3349 break;
3350 case GL_UNSIGNED_INT_24_8_OES:
3351 loadFunctionInfo.loadFunction = angle::LoadD24S8ToD32F;
3352 stencilLoadFunction = angle::LoadX24S8ToS8;
3353 break;
3354 default:
3355 UNREACHABLE();
3356 }
3357 }
3358 else
3359 {
3360 outputRowPitch = storageFormat.pixelBytes * glExtents.width;
3361 }
3362 outputDepthPitch = outputRowPitch * glExtents.height;
3363
3364 bufferRowLength = glExtents.width;
3365 bufferImageHeight = glExtents.height;
3366
3367 allocationSize = outputDepthPitch * glExtents.depth;
3368
3369 // Note: because the LoadImageFunctionInfo functions are limited to copying a single
3370 // component, we have to special case packed depth/stencil use and send the stencil as a
3371 // separate chunk.
3372 if (storageFormat.depthBits > 0 && storageFormat.stencilBits > 0 &&
3373 formatInfo.depthBits > 0 && formatInfo.stencilBits > 0)
3374 {
3375 // Note: Stencil is always one byte
3376 stencilAllocationSize = glExtents.width * glExtents.height * glExtents.depth;
3377 allocationSize += stencilAllocationSize;
3378 }
3379 }
3380
3381 VkBuffer bufferHandle = VK_NULL_HANDLE;
3382
3383 uint8_t *stagingPointer = nullptr;
3384 VkDeviceSize stagingOffset = 0;
3385 ANGLE_TRY(mStagingBuffer.allocate(contextVk, allocationSize, &stagingPointer, &bufferHandle,
3386 &stagingOffset, nullptr));
3387
3388 const uint8_t *source = pixels + static_cast<ptrdiff_t>(inputSkipBytes);
3389
3390 loadFunctionInfo.loadFunction(glExtents.width, glExtents.height, glExtents.depth, source,
3391 inputRowPitch, inputDepthPitch, stagingPointer, outputRowPitch,
3392 outputDepthPitch);
3393
3394 VkBufferImageCopy copy = {};
3395 VkImageAspectFlags aspectFlags = GetFormatAspectFlags(vkFormat.actualImageFormat());
3396
3397 copy.bufferOffset = stagingOffset;
3398 copy.bufferRowLength = bufferRowLength;
3399 copy.bufferImageHeight = bufferImageHeight;
3400
3401 copy.imageSubresource.mipLevel = index.getLevelIndex();
3402 copy.imageSubresource.layerCount = index.getLayerCount();
3403
3404 gl_vk::GetOffset(offset, ©.imageOffset);
3405 gl_vk::GetExtent(glExtents, ©.imageExtent);
3406
3407 if (gl::IsArrayTextureType(index.getType()))
3408 {
3409 copy.imageSubresource.baseArrayLayer = offset.z;
3410 copy.imageOffset.z = 0;
3411 copy.imageExtent.depth = 1;
3412 }
3413 else
3414 {
3415 copy.imageSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0;
3416 }
3417
3418 if (stencilAllocationSize > 0)
3419 {
3420 // Note: Stencil is always one byte
3421 ASSERT((aspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) != 0);
3422
3423 // Skip over depth data.
3424 stagingPointer += outputDepthPitch * glExtents.depth;
3425 stagingOffset += outputDepthPitch * glExtents.depth;
3426
3427 // recompute pitch for stencil data
3428 outputRowPitch = glExtents.width;
3429 outputDepthPitch = outputRowPitch * glExtents.height;
3430
3431 ASSERT(stencilLoadFunction != nullptr);
3432 stencilLoadFunction(glExtents.width, glExtents.height, glExtents.depth, source,
3433 inputRowPitch, inputDepthPitch, stagingPointer, outputRowPitch,
3434 outputDepthPitch);
3435
3436 VkBufferImageCopy stencilCopy = {};
3437
3438 stencilCopy.bufferOffset = stagingOffset;
3439 stencilCopy.bufferRowLength = bufferRowLength;
3440 stencilCopy.bufferImageHeight = bufferImageHeight;
3441 stencilCopy.imageSubresource.mipLevel = copy.imageSubresource.mipLevel;
3442 stencilCopy.imageSubresource.baseArrayLayer = copy.imageSubresource.baseArrayLayer;
3443 stencilCopy.imageSubresource.layerCount = copy.imageSubresource.layerCount;
3444 stencilCopy.imageOffset = copy.imageOffset;
3445 stencilCopy.imageExtent = copy.imageExtent;
3446 stencilCopy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
3447 appendSubresourceUpdate(SubresourceUpdate(mStagingBuffer.getCurrentBuffer(), stencilCopy));
3448
3449 aspectFlags &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
3450 }
3451
3452 if (IsMaskFlagSet(aspectFlags, static_cast<VkImageAspectFlags>(VK_IMAGE_ASPECT_STENCIL_BIT |
3453 VK_IMAGE_ASPECT_DEPTH_BIT)))
3454 {
3455 // We still have both depth and stencil aspect bits set. That means we have a destination
3456 // buffer that is packed depth stencil and that the application is only loading one aspect.
3457 // Figure out which aspect the user is touching and remove the unused aspect bit.
3458 if (formatInfo.stencilBits > 0)
3459 {
3460 aspectFlags &= ~VK_IMAGE_ASPECT_DEPTH_BIT;
3461 }
3462 else
3463 {
3464 aspectFlags &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
3465 }
3466 }
3467
3468 if (aspectFlags)
3469 {
3470 copy.imageSubresource.aspectMask = aspectFlags;
3471 appendSubresourceUpdate(SubresourceUpdate(mStagingBuffer.getCurrentBuffer(), copy));
3472 }
3473
3474 return angle::Result::Continue;
3475 }
3476
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)3477 angle::Result ImageHelper::CalculateBufferInfo(ContextVk *contextVk,
3478 const gl::Extents &glExtents,
3479 const gl::InternalFormat &formatInfo,
3480 const gl::PixelUnpackState &unpack,
3481 GLenum type,
3482 bool is3D,
3483 GLuint *inputRowPitch,
3484 GLuint *inputDepthPitch,
3485 GLuint *inputSkipBytes)
3486 {
3487 ANGLE_VK_CHECK_MATH(contextVk,
3488 formatInfo.computeRowPitch(type, glExtents.width, unpack.alignment,
3489 unpack.rowLength, inputRowPitch));
3490
3491 ANGLE_VK_CHECK_MATH(contextVk,
3492 formatInfo.computeDepthPitch(glExtents.height, unpack.imageHeight,
3493 *inputRowPitch, inputDepthPitch));
3494
3495 ANGLE_VK_CHECK_MATH(
3496 contextVk, formatInfo.computeSkipBytes(type, *inputRowPitch, *inputDepthPitch, unpack, is3D,
3497 inputSkipBytes));
3498
3499 return angle::Result::Continue;
3500 }
3501
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)3502 angle::Result ImageHelper::stageSubresourceUpdate(ContextVk *contextVk,
3503 const gl::ImageIndex &index,
3504 const gl::Extents &glExtents,
3505 const gl::Offset &offset,
3506 const gl::InternalFormat &formatInfo,
3507 const gl::PixelUnpackState &unpack,
3508 GLenum type,
3509 const uint8_t *pixels,
3510 const Format &vkFormat)
3511 {
3512 GLuint inputRowPitch = 0;
3513 GLuint inputDepthPitch = 0;
3514 GLuint inputSkipBytes = 0;
3515 ANGLE_TRY(CalculateBufferInfo(contextVk, glExtents, formatInfo, unpack, type, index.usesTex3D(),
3516 &inputRowPitch, &inputDepthPitch, &inputSkipBytes));
3517
3518 ANGLE_TRY(stageSubresourceUpdateImpl(contextVk, index, glExtents, offset, formatInfo, unpack,
3519 type, pixels, vkFormat, inputRowPitch, inputDepthPitch,
3520 inputSkipBytes));
3521
3522 return angle::Result::Continue;
3523 }
3524
stageSubresourceUpdateAndGetData(ContextVk * contextVk,size_t allocationSize,const gl::ImageIndex & imageIndex,const gl::Extents & glExtents,const gl::Offset & offset,uint8_t ** destData)3525 angle::Result ImageHelper::stageSubresourceUpdateAndGetData(ContextVk *contextVk,
3526 size_t allocationSize,
3527 const gl::ImageIndex &imageIndex,
3528 const gl::Extents &glExtents,
3529 const gl::Offset &offset,
3530 uint8_t **destData)
3531 {
3532 VkBuffer bufferHandle;
3533 VkDeviceSize stagingOffset = 0;
3534 ANGLE_TRY(mStagingBuffer.allocate(contextVk, allocationSize, destData, &bufferHandle,
3535 &stagingOffset, nullptr));
3536
3537 VkBufferImageCopy copy = {};
3538 copy.bufferOffset = stagingOffset;
3539 copy.bufferRowLength = glExtents.width;
3540 copy.bufferImageHeight = glExtents.height;
3541 copy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
3542 copy.imageSubresource.mipLevel = imageIndex.getLevelIndex();
3543 copy.imageSubresource.baseArrayLayer = imageIndex.hasLayer() ? imageIndex.getLayerIndex() : 0;
3544 copy.imageSubresource.layerCount = imageIndex.getLayerCount();
3545
3546 // Note: Only support color now
3547 ASSERT((mFormat == nullptr) || (getAspectFlags() == VK_IMAGE_ASPECT_COLOR_BIT));
3548
3549 gl_vk::GetOffset(offset, ©.imageOffset);
3550 gl_vk::GetExtent(glExtents, ©.imageExtent);
3551
3552 appendSubresourceUpdate(SubresourceUpdate(mStagingBuffer.getCurrentBuffer(), copy));
3553
3554 return angle::Result::Continue;
3555 }
3556
stageSubresourceUpdateFromBuffer(ContextVk * contextVk,size_t allocationSize,uint32_t mipLevel,uint32_t baseArrayLayer,uint32_t layerCount,uint32_t bufferRowLength,uint32_t bufferImageHeight,const VkExtent3D & extent,const VkOffset3D & offset,BufferHelper * bufferHelper,StagingBufferOffsetArray stagingOffsets)3557 angle::Result ImageHelper::stageSubresourceUpdateFromBuffer(ContextVk *contextVk,
3558 size_t allocationSize,
3559 uint32_t mipLevel,
3560 uint32_t baseArrayLayer,
3561 uint32_t layerCount,
3562 uint32_t bufferRowLength,
3563 uint32_t bufferImageHeight,
3564 const VkExtent3D &extent,
3565 const VkOffset3D &offset,
3566 BufferHelper *bufferHelper,
3567 StagingBufferOffsetArray stagingOffsets)
3568 {
3569 // This function stages an update from explicitly provided handle and offset
3570 // It is used when the texture base level has changed, and we need to propagate data
3571
3572 VkBufferImageCopy copy[2] = {};
3573 copy[0].bufferOffset = stagingOffsets[0];
3574 copy[0].bufferRowLength = bufferRowLength;
3575 copy[0].bufferImageHeight = bufferImageHeight;
3576 copy[0].imageSubresource.aspectMask = getAspectFlags();
3577 copy[0].imageSubresource.mipLevel = mipLevel;
3578 copy[0].imageSubresource.baseArrayLayer = baseArrayLayer;
3579 copy[0].imageSubresource.layerCount = layerCount;
3580 copy[0].imageOffset = offset;
3581 copy[0].imageExtent = extent;
3582
3583 if (isCombinedDepthStencilFormat())
3584 {
3585 // Force aspect to depth for first copy
3586 copy[0].imageSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
3587 // Copy stencil aspect separately
3588 copy[1].bufferOffset = stagingOffsets[1];
3589 copy[1].bufferRowLength = bufferRowLength;
3590 copy[1].bufferImageHeight = bufferImageHeight;
3591 copy[1].imageSubresource.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
3592 copy[1].imageSubresource.mipLevel = mipLevel;
3593 copy[1].imageSubresource.baseArrayLayer = baseArrayLayer;
3594 copy[1].imageSubresource.layerCount = layerCount;
3595 copy[1].imageOffset = offset;
3596 copy[1].imageExtent = extent;
3597 appendSubresourceUpdate(SubresourceUpdate(bufferHelper, copy[1]));
3598 }
3599
3600 appendSubresourceUpdate(SubresourceUpdate(bufferHelper, copy[0]));
3601
3602 return angle::Result::Continue;
3603 }
3604
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,FramebufferVk * framebufferVk)3605 angle::Result ImageHelper::stageSubresourceUpdateFromFramebuffer(
3606 const gl::Context *context,
3607 const gl::ImageIndex &index,
3608 const gl::Rectangle &sourceArea,
3609 const gl::Offset &dstOffset,
3610 const gl::Extents &dstExtent,
3611 const gl::InternalFormat &formatInfo,
3612 FramebufferVk *framebufferVk)
3613 {
3614 ContextVk *contextVk = GetImpl(context);
3615
3616 // If the extents and offset is outside the source image, we need to clip.
3617 gl::Rectangle clippedRectangle;
3618 const gl::Extents readExtents = framebufferVk->getReadImageExtents();
3619 if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, readExtents.width, readExtents.height),
3620 &clippedRectangle))
3621 {
3622 // Empty source area, nothing to do.
3623 return angle::Result::Continue;
3624 }
3625
3626 bool isViewportFlipEnabled = contextVk->isViewportFlipEnabledForDrawFBO();
3627 if (isViewportFlipEnabled)
3628 {
3629 clippedRectangle.y = readExtents.height - clippedRectangle.y - clippedRectangle.height;
3630 }
3631
3632 // 1- obtain a buffer handle to copy to
3633 RendererVk *renderer = contextVk->getRenderer();
3634
3635 const Format &vkFormat = renderer->getFormat(formatInfo.sizedInternalFormat);
3636 const angle::Format &storageFormat = vkFormat.actualImageFormat();
3637 LoadImageFunctionInfo loadFunction = vkFormat.textureLoadFunctions(formatInfo.type);
3638
3639 size_t outputRowPitch = storageFormat.pixelBytes * clippedRectangle.width;
3640 size_t outputDepthPitch = outputRowPitch * clippedRectangle.height;
3641
3642 VkBuffer bufferHandle = VK_NULL_HANDLE;
3643
3644 uint8_t *stagingPointer = nullptr;
3645 VkDeviceSize stagingOffset = 0;
3646
3647 // The destination is only one layer deep.
3648 size_t allocationSize = outputDepthPitch;
3649 ANGLE_TRY(mStagingBuffer.allocate(contextVk, allocationSize, &stagingPointer, &bufferHandle,
3650 &stagingOffset, nullptr));
3651
3652 const angle::Format ©Format =
3653 GetFormatFromFormatType(formatInfo.internalFormat, formatInfo.type);
3654 PackPixelsParams params(clippedRectangle, copyFormat, static_cast<GLuint>(outputRowPitch),
3655 isViewportFlipEnabled, nullptr, 0);
3656
3657 RenderTargetVk *readRenderTarget = framebufferVk->getColorReadRenderTarget();
3658
3659 // 2- copy the source image region to the pixel buffer using a cpu readback
3660 if (loadFunction.requiresConversion)
3661 {
3662 // When a conversion is required, we need to use the loadFunction to read from a temporary
3663 // buffer instead so its an even slower path.
3664 size_t bufferSize =
3665 storageFormat.pixelBytes * clippedRectangle.width * clippedRectangle.height;
3666 angle::MemoryBuffer *memoryBuffer = nullptr;
3667 ANGLE_VK_CHECK_ALLOC(contextVk, context->getScratchBuffer(bufferSize, &memoryBuffer));
3668
3669 // Read into the scratch buffer
3670 ANGLE_TRY(framebufferVk->readPixelsImpl(contextVk, clippedRectangle, params,
3671 VK_IMAGE_ASPECT_COLOR_BIT, readRenderTarget,
3672 memoryBuffer->data()));
3673
3674 // Load from scratch buffer to our pixel buffer
3675 loadFunction.loadFunction(clippedRectangle.width, clippedRectangle.height, 1,
3676 memoryBuffer->data(), outputRowPitch, 0, stagingPointer,
3677 outputRowPitch, 0);
3678 }
3679 else
3680 {
3681 // We read directly from the framebuffer into our pixel buffer.
3682 ANGLE_TRY(framebufferVk->readPixelsImpl(contextVk, clippedRectangle, params,
3683 VK_IMAGE_ASPECT_COLOR_BIT, readRenderTarget,
3684 stagingPointer));
3685 }
3686
3687 // 3- enqueue the destination image subresource update
3688 VkBufferImageCopy copyToImage = {};
3689 copyToImage.bufferOffset = static_cast<VkDeviceSize>(stagingOffset);
3690 copyToImage.bufferRowLength = 0; // Tightly packed data can be specified as 0.
3691 copyToImage.bufferImageHeight = clippedRectangle.height;
3692 copyToImage.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
3693 copyToImage.imageSubresource.mipLevel = index.getLevelIndex();
3694 copyToImage.imageSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0;
3695 copyToImage.imageSubresource.layerCount = index.getLayerCount();
3696 gl_vk::GetOffset(dstOffset, ©ToImage.imageOffset);
3697 gl_vk::GetExtent(dstExtent, ©ToImage.imageExtent);
3698
3699 // 3- enqueue the destination image subresource update
3700 appendSubresourceUpdate(SubresourceUpdate(mStagingBuffer.getCurrentBuffer(), copyToImage));
3701 return angle::Result::Continue;
3702 }
3703
stageSubresourceUpdateFromImage(ImageHelper * image,const gl::ImageIndex & index,const gl::Offset & destOffset,const gl::Extents & glExtents,const VkImageType imageType)3704 void ImageHelper::stageSubresourceUpdateFromImage(ImageHelper *image,
3705 const gl::ImageIndex &index,
3706 const gl::Offset &destOffset,
3707 const gl::Extents &glExtents,
3708 const VkImageType imageType)
3709 {
3710 VkImageCopy copyToImage = {};
3711 copyToImage.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
3712 copyToImage.srcSubresource.layerCount = index.getLayerCount();
3713 copyToImage.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
3714 copyToImage.dstSubresource.mipLevel = index.getLevelIndex();
3715
3716 if (imageType == VK_IMAGE_TYPE_3D)
3717 {
3718 // These values must be set explicitly to follow the Vulkan spec:
3719 // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VkImageCopy.html
3720 // If either of the calling command's srcImage or dstImage parameters are of VkImageType
3721 // VK_IMAGE_TYPE_3D, the baseArrayLayer and layerCount members of the corresponding
3722 // subresource must be 0 and 1, respectively
3723 copyToImage.dstSubresource.baseArrayLayer = 0;
3724 copyToImage.dstSubresource.layerCount = 1;
3725 // Preserve the assumption that destOffset.z == "dstSubresource.baseArrayLayer"
3726 ASSERT(destOffset.z == (index.hasLayer() ? index.getLayerIndex() : 0));
3727 }
3728 else
3729 {
3730 copyToImage.dstSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0;
3731 copyToImage.dstSubresource.layerCount = index.getLayerCount();
3732 }
3733
3734 gl_vk::GetOffset(destOffset, ©ToImage.dstOffset);
3735 gl_vk::GetExtent(glExtents, ©ToImage.extent);
3736
3737 appendSubresourceUpdate(SubresourceUpdate(image, copyToImage));
3738 }
3739
stageClear(const gl::ImageIndex & index,VkImageAspectFlags aspectFlags,const VkClearValue & clearValue)3740 void ImageHelper::stageClear(const gl::ImageIndex &index,
3741 VkImageAspectFlags aspectFlags,
3742 const VkClearValue &clearValue)
3743 {
3744 appendSubresourceUpdate(SubresourceUpdate(aspectFlags, clearValue, index));
3745 }
3746
stageRobustResourceClear(const gl::ImageIndex & index)3747 void ImageHelper::stageRobustResourceClear(const gl::ImageIndex &index)
3748 {
3749 const VkImageAspectFlags aspectFlags = getAspectFlags();
3750
3751 ASSERT(mFormat);
3752 VkClearValue clearValue = GetRobustResourceClearValue(*mFormat);
3753 appendSubresourceUpdate(SubresourceUpdate(aspectFlags, clearValue, index));
3754 }
3755
stageRobustResourceClearWithFormat(ContextVk * contextVk,const gl::ImageIndex & index,const gl::Extents & glExtents,const vk::Format & format)3756 angle::Result ImageHelper::stageRobustResourceClearWithFormat(ContextVk *contextVk,
3757 const gl::ImageIndex &index,
3758 const gl::Extents &glExtents,
3759 const vk::Format &format)
3760 {
3761 const angle::Format &imageFormat = format.actualImageFormat();
3762 const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(imageFormat);
3763
3764 // Robust clears must only be staged if we do not have any prior data for this subresource.
3765 ASSERT(!isUpdateStaged(index.getLevelIndex(), index.getLayerIndex()));
3766
3767 VkClearValue clearValue = GetRobustResourceClearValue(format);
3768
3769 if (imageFormat.isBlock)
3770 {
3771 // This only supports doing an initial clear to 0, not clearing to a specific encoded RGBA
3772 // value
3773 ASSERT((clearValue.color.int32[0] == 0) && (clearValue.color.int32[1] == 0) &&
3774 (clearValue.color.int32[2] == 0) && (clearValue.color.int32[3] == 0));
3775
3776 const gl::InternalFormat &formatInfo =
3777 gl::GetSizedInternalFormatInfo(imageFormat.glInternalFormat);
3778 GLuint totalSize;
3779 ANGLE_VK_CHECK_MATH(contextVk,
3780 formatInfo.computeCompressedImageSize(glExtents, &totalSize));
3781
3782 VkBuffer bufferHandle = VK_NULL_HANDLE;
3783 uint8_t *stagingPointer = nullptr;
3784 VkDeviceSize stagingOffset = 0;
3785 ANGLE_TRY(mStagingBuffer.allocate(contextVk, totalSize, &stagingPointer, &bufferHandle,
3786 &stagingOffset, nullptr));
3787 memset(stagingPointer, 0, totalSize);
3788
3789 VkBufferImageCopy copyRegion = {};
3790 copyRegion.imageExtent.width = glExtents.width;
3791 copyRegion.imageExtent.height = glExtents.height;
3792 copyRegion.imageExtent.depth = glExtents.depth;
3793 copyRegion.imageSubresource.aspectMask = aspectFlags;
3794 copyRegion.imageSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0;
3795 copyRegion.imageSubresource.layerCount = index.getLayerCount();
3796
3797 appendSubresourceUpdate(SubresourceUpdate(mStagingBuffer.getCurrentBuffer(), copyRegion));
3798 }
3799 else
3800 {
3801 appendSubresourceUpdate(SubresourceUpdate(aspectFlags, clearValue, index));
3802 }
3803
3804 return angle::Result::Continue;
3805 }
3806
stageClearIfEmulatedFormat(Context * context)3807 void ImageHelper::stageClearIfEmulatedFormat(Context *context)
3808 {
3809 // Skip staging extra clears if robust resource init is enabled.
3810 if (!mFormat->hasEmulatedImageChannels() || context->isRobustResourceInitEnabled())
3811 return;
3812
3813 VkClearValue clearValue;
3814 if (mFormat->intendedFormat().hasDepthOrStencilBits())
3815 {
3816 clearValue.depthStencil = kRobustInitDepthStencilValue;
3817 }
3818 else
3819 {
3820 clearValue.color = kEmulatedInitColorValue;
3821 }
3822
3823 const VkImageAspectFlags aspectFlags = getAspectFlags();
3824
3825 // If the image has an emulated channel and robust resource init is not enabled, always clear
3826 // it. These channels will be masked out in future writes, and shouldn't contain uninitialized
3827 // values.
3828 for (uint32_t level = 0; level < mLevelCount; ++level)
3829 {
3830 gl::ImageIndex index = gl::ImageIndex::Make2DArrayRange(level, 0, mLayerCount);
3831 prependSubresourceUpdate(SubresourceUpdate(aspectFlags, clearValue, index));
3832 }
3833 }
3834
allocateStagingMemory(ContextVk * contextVk,size_t sizeInBytes,uint8_t ** ptrOut,BufferHelper ** bufferOut,StagingBufferOffsetArray * offsetOut,bool * newBufferAllocatedOut)3835 angle::Result ImageHelper::allocateStagingMemory(ContextVk *contextVk,
3836 size_t sizeInBytes,
3837 uint8_t **ptrOut,
3838 BufferHelper **bufferOut,
3839 StagingBufferOffsetArray *offsetOut,
3840 bool *newBufferAllocatedOut)
3841 {
3842 VkBuffer handle;
3843 ANGLE_TRY(mStagingBuffer.allocate(contextVk, sizeInBytes, ptrOut, &handle, &(*offsetOut)[0],
3844 newBufferAllocatedOut));
3845 *bufferOut = mStagingBuffer.getCurrentBuffer();
3846 return angle::Result::Continue;
3847 }
3848
flushSingleSubresourceStagedUpdates(ContextVk * contextVk,uint32_t level,uint32_t layer,CommandBuffer * commandBuffer,ClearValuesArray * deferredClears,uint32_t deferredClearIndex)3849 angle::Result ImageHelper::flushSingleSubresourceStagedUpdates(ContextVk *contextVk,
3850 uint32_t level,
3851 uint32_t layer,
3852 CommandBuffer *commandBuffer,
3853 ClearValuesArray *deferredClears,
3854 uint32_t deferredClearIndex)
3855 {
3856 // Handle deferred clears. Search the updates list for a matching clear index.
3857 if (deferredClears)
3858 {
3859 Optional<size_t> foundClear;
3860
3861 for (size_t updateIndex = 0; updateIndex < mSubresourceUpdates.size(); ++updateIndex)
3862 {
3863 SubresourceUpdate &update = mSubresourceUpdates[updateIndex];
3864
3865 if (update.isUpdateToLayerLevel(layer, level))
3866 {
3867 // On any data update, exit out. We'll need to do a full upload.
3868 if (update.updateSource != UpdateSource::Clear ||
3869 (update.clear.layerCount != 1 &&
3870 !(update.clear.layerCount == VK_REMAINING_ARRAY_LAYERS && mLayerCount == 1)))
3871 {
3872 foundClear.reset();
3873 break;
3874 }
3875
3876 // Otherwise track the latest clear update index.
3877 foundClear = updateIndex;
3878 }
3879 }
3880
3881 // If we have a valid index we defer the clear using the clear reference.
3882 if (foundClear.valid())
3883 {
3884 size_t foundIndex = foundClear.value();
3885 const ClearUpdate &update = mSubresourceUpdates[foundIndex].clear;
3886
3887 // Note that this set command handles combined or separate depth/stencil clears.
3888 deferredClears->store(deferredClearIndex, update.aspectFlags, update.value);
3889
3890 // We process the updates again to erase any clears for this level.
3891 removeStagedUpdates(contextVk, level, layer);
3892 return angle::Result::Continue;
3893 }
3894
3895 // Otherwise we proceed with a normal update.
3896 }
3897
3898 return flushStagedUpdates(contextVk, level, level + 1, layer, layer + 1, commandBuffer);
3899 }
3900
flushStagedUpdates(ContextVk * contextVk,uint32_t levelStart,uint32_t levelEnd,uint32_t layerStart,uint32_t layerEnd,CommandBuffer * commandBuffer)3901 angle::Result ImageHelper::flushStagedUpdates(ContextVk *contextVk,
3902 uint32_t levelStart,
3903 uint32_t levelEnd,
3904 uint32_t layerStart,
3905 uint32_t layerEnd,
3906 CommandBuffer *commandBuffer)
3907 {
3908 if (mSubresourceUpdates.empty())
3909 {
3910 return angle::Result::Continue;
3911 }
3912
3913 ANGLE_TRY(mStagingBuffer.flush(contextVk));
3914
3915 std::vector<SubresourceUpdate> updatesToKeep;
3916 const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(mFormat->actualImageFormat());
3917
3918 // Upload levels and layers that don't conflict in parallel. The (level, layer) pair is hashed
3919 // to `(level * mLayerCount + layer) % 64` and used to track whether that subresource is
3920 // currently in transfer. If so, a barrier is inserted. If mLayerCount * mLevelCount > 64,
3921 // there will be a few unnecessary barriers.
3922 constexpr uint32_t kMaxParallelSubresourceUpload = 64;
3923 uint64_t subresourceUploadsInProgress = 0;
3924
3925 // Start in TransferDst.
3926 ANGLE_TRY(contextVk->onImageWrite(aspectFlags, ImageLayout::TransferDst, this));
3927
3928 for (SubresourceUpdate &update : mSubresourceUpdates)
3929 {
3930 ASSERT(update.updateSource == UpdateSource::Clear ||
3931 (update.updateSource == UpdateSource::Buffer &&
3932 update.buffer.bufferHelper != nullptr) ||
3933 (update.updateSource == UpdateSource::Image && update.image.image != nullptr &&
3934 update.image.image->valid()));
3935
3936 uint32_t updateMipLevel;
3937 uint32_t updateBaseLayer;
3938 uint32_t updateLayerCount;
3939 if (update.updateSource == UpdateSource::Clear)
3940 {
3941 updateMipLevel = update.clear.levelIndex;
3942 updateBaseLayer = update.clear.layerIndex;
3943 updateLayerCount = update.clear.layerCount;
3944 if (updateLayerCount == static_cast<uint32_t>(gl::ImageIndex::kEntireLevel))
3945 {
3946 updateLayerCount = mLayerCount;
3947 }
3948 }
3949 else
3950 {
3951 const VkImageSubresourceLayers &dstSubresource = update.dstSubresource();
3952 updateMipLevel = dstSubresource.mipLevel;
3953 updateBaseLayer = dstSubresource.baseArrayLayer;
3954 updateLayerCount = dstSubresource.layerCount;
3955 ASSERT(updateLayerCount != static_cast<uint32_t>(gl::ImageIndex::kEntireLevel));
3956 }
3957
3958 // If the update level is not within the requested range, skip the update.
3959 const bool isUpdateLevelOutsideRange =
3960 updateMipLevel < (levelStart + mBaseLevel) ||
3961 (updateMipLevel >= (levelEnd + mBaseLevel) || updateMipLevel > mMaxLevel);
3962
3963 // If the update layers don't intersect the requested layers, skip the update.
3964 const bool areUpdateLayersOutsideRange =
3965 updateBaseLayer + updateLayerCount <= layerStart || updateBaseLayer >= layerEnd;
3966
3967 if (isUpdateLevelOutsideRange || areUpdateLayersOutsideRange)
3968 {
3969 updatesToKeep.emplace_back(update);
3970 continue;
3971 }
3972
3973 if (mBaseLevel > 0)
3974 {
3975 // We need to shift the miplevel in the update to fall into the vkiamge
3976 updateMipLevel -= mBaseLevel;
3977 if (update.updateSource == UpdateSource::Clear)
3978 {
3979 update.clear.levelIndex -= mBaseLevel;
3980 }
3981 else if (update.updateSource == UpdateSource::Buffer)
3982 {
3983 update.buffer.copyRegion.imageSubresource.mipLevel -= mBaseLevel;
3984 }
3985 else if (update.updateSource == UpdateSource::Image)
3986 {
3987 update.image.copyRegion.dstSubresource.mipLevel -= mBaseLevel;
3988 }
3989 }
3990
3991 if (updateLayerCount >= kMaxParallelSubresourceUpload)
3992 {
3993 // If there are more subresources than bits we can track, always insert a barrier.
3994 changeLayout(aspectFlags, ImageLayout::TransferDst, commandBuffer);
3995 subresourceUploadsInProgress = std::numeric_limits<uint64_t>::max();
3996 }
3997 else
3998 {
3999 const uint64_t subresourceHashRange = angle::Bit<uint64_t>(updateLayerCount) - 1;
4000 const uint32_t subresourceHashOffset =
4001 (updateMipLevel * mLayerCount + updateBaseLayer) % kMaxParallelSubresourceUpload;
4002 const uint64_t subresourceHash =
4003 ANGLE_ROTL64(subresourceHashRange, subresourceHashOffset);
4004
4005 if ((subresourceUploadsInProgress & subresourceHash) != 0)
4006 {
4007 // If there's overlap in subresource upload, issue a barrier.
4008 changeLayout(aspectFlags, ImageLayout::TransferDst, commandBuffer);
4009 subresourceUploadsInProgress = 0;
4010 }
4011 subresourceUploadsInProgress |= subresourceHash;
4012 }
4013
4014 if (update.updateSource == UpdateSource::Clear)
4015 {
4016 ASSERT(updateMipLevel == update.clear.levelIndex);
4017 clear(update.clear.aspectFlags, update.clear.value, updateMipLevel, updateBaseLayer,
4018 updateLayerCount, commandBuffer);
4019 }
4020 else if (update.updateSource == UpdateSource::Buffer)
4021 {
4022 BufferUpdate &bufferUpdate = update.buffer;
4023
4024 BufferHelper *currentBuffer = bufferUpdate.bufferHelper;
4025 ASSERT(currentBuffer && currentBuffer->valid());
4026
4027 ANGLE_TRY(contextVk->onBufferTransferRead(currentBuffer));
4028
4029 commandBuffer->copyBufferToImage(currentBuffer->getBuffer().getHandle(), mImage,
4030 getCurrentLayout(), 1, &update.buffer.copyRegion);
4031 }
4032 else
4033 {
4034 ANGLE_TRY(
4035 contextVk->onImageRead(aspectFlags, ImageLayout::TransferSrc, update.image.image));
4036
4037 commandBuffer->copyImage(update.image.image->getImage(),
4038 update.image.image->getCurrentLayout(), mImage,
4039 getCurrentLayout(), 1, &update.image.copyRegion);
4040 }
4041
4042 update.release(contextVk->getRenderer());
4043 }
4044
4045 // Only remove the updates that were actually applied to the image.
4046 mSubresourceUpdates = std::move(updatesToKeep);
4047
4048 if (mSubresourceUpdates.empty())
4049 {
4050 mStagingBuffer.releaseInFlightBuffers(contextVk);
4051 }
4052
4053 return angle::Result::Continue;
4054 }
4055
flushAllStagedUpdates(ContextVk * contextVk)4056 angle::Result ImageHelper::flushAllStagedUpdates(ContextVk *contextVk)
4057 {
4058 // Clear the image.
4059 CommandBuffer *commandBuffer = nullptr;
4060 ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&commandBuffer));
4061 return flushStagedUpdates(contextVk, 0, mLevelCount, 0, mLayerCount, commandBuffer);
4062 }
4063
isUpdateStaged(uint32_t level,uint32_t layer)4064 bool ImageHelper::isUpdateStaged(uint32_t level, uint32_t layer)
4065 {
4066 // Check to see if any updates are staged for the given level and layer
4067
4068 if (mSubresourceUpdates.empty())
4069 {
4070 return false;
4071 }
4072
4073 for (SubresourceUpdate &update : mSubresourceUpdates)
4074 {
4075 uint32_t updateMipLevel;
4076 uint32_t updateBaseLayer;
4077 uint32_t updateLayerCount;
4078
4079 if (update.updateSource == UpdateSource::Clear)
4080 {
4081 updateMipLevel = update.clear.levelIndex;
4082 updateBaseLayer = update.clear.layerIndex;
4083 updateLayerCount = update.clear.layerCount;
4084 }
4085 else
4086 {
4087 const VkImageSubresourceLayers &dstSubresource = update.dstSubresource();
4088 updateMipLevel = dstSubresource.mipLevel;
4089 updateBaseLayer = dstSubresource.baseArrayLayer;
4090 updateLayerCount = dstSubresource.layerCount;
4091 }
4092
4093 if (updateMipLevel == level)
4094 {
4095 if (layer >= updateBaseLayer && layer < (updateBaseLayer + updateLayerCount))
4096 {
4097 // The level matches, and the layer is within the range
4098 return true;
4099 }
4100 }
4101 }
4102
4103 return false;
4104 }
4105
copyImageDataToBuffer(ContextVk * contextVk,size_t sourceLevel,uint32_t layerCount,uint32_t baseLayer,const gl::Box & sourceArea,BufferHelper ** bufferOut,size_t * bufferSize,StagingBufferOffsetArray * bufferOffsetsOut,uint8_t ** outDataPtr)4106 angle::Result ImageHelper::copyImageDataToBuffer(ContextVk *contextVk,
4107 size_t sourceLevel,
4108 uint32_t layerCount,
4109 uint32_t baseLayer,
4110 const gl::Box &sourceArea,
4111 BufferHelper **bufferOut,
4112 size_t *bufferSize,
4113 StagingBufferOffsetArray *bufferOffsetsOut,
4114 uint8_t **outDataPtr)
4115 {
4116 ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::copyImageDataToBuffer");
4117
4118 const angle::Format &imageFormat = mFormat->actualImageFormat();
4119
4120 // Two VK formats (one depth-only, one combined depth/stencil) use an extra byte for depth.
4121 // From https://www.khronos.org/registry/vulkan/specs/1.1/html/vkspec.html#VkBufferImageCopy:
4122 // data copied to or from the depth aspect of a VK_FORMAT_X8_D24_UNORM_PACK32 or
4123 // VK_FORMAT_D24_UNORM_S8_UINT format is packed with one 32-bit word per texel...
4124 // So make sure if we hit the depth/stencil format that we have 5 bytes per pixel (4 for depth
4125 // data, 1 for stencil). NOTE that depth-only VK_FORMAT_X8_D24_UNORM_PACK32 already has 4 bytes
4126 // per pixel which is sufficient to contain its depth aspect (no stencil aspect).
4127 uint32_t pixelBytes = imageFormat.pixelBytes;
4128 uint32_t depthBytesPerPixel = imageFormat.depthBits >> 3;
4129 if (mFormat->vkImageFormat == VK_FORMAT_D24_UNORM_S8_UINT)
4130 {
4131 pixelBytes = 5;
4132 depthBytesPerPixel = 4;
4133 }
4134
4135 *bufferSize = sourceArea.width * sourceArea.height * sourceArea.depth * pixelBytes * layerCount;
4136
4137 const VkImageAspectFlags aspectFlags = getAspectFlags();
4138
4139 // Allocate staging buffer data
4140 ANGLE_TRY(allocateStagingMemory(contextVk, *bufferSize, outDataPtr, bufferOut, bufferOffsetsOut,
4141 nullptr));
4142
4143 CommandBuffer *commandBuffer = nullptr;
4144 ANGLE_TRY(contextVk->onImageRead(aspectFlags, ImageLayout::TransferSrc, this));
4145 ANGLE_TRY(contextVk->onBufferTransferWrite(*bufferOut));
4146 ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&commandBuffer));
4147
4148 VkBufferImageCopy regions[2] = {};
4149 // Default to non-combined DS case
4150 regions[0].bufferOffset = (*bufferOffsetsOut)[0];
4151 regions[0].bufferRowLength = 0;
4152 regions[0].bufferImageHeight = 0;
4153 regions[0].imageExtent.width = sourceArea.width;
4154 regions[0].imageExtent.height = sourceArea.height;
4155 regions[0].imageExtent.depth = sourceArea.depth;
4156 regions[0].imageOffset.x = sourceArea.x;
4157 regions[0].imageOffset.y = sourceArea.y;
4158 regions[0].imageOffset.z = sourceArea.z;
4159 regions[0].imageSubresource.aspectMask = aspectFlags;
4160 regions[0].imageSubresource.baseArrayLayer = baseLayer;
4161 regions[0].imageSubresource.layerCount = layerCount;
4162 regions[0].imageSubresource.mipLevel = static_cast<uint32_t>(sourceLevel);
4163
4164 if (isCombinedDepthStencilFormat())
4165 {
4166 // For combined DS image we'll copy depth and stencil aspects separately
4167 // Depth aspect comes first in buffer and can use most settings from above
4168 regions[0].imageSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
4169
4170 // Get depth data size since stencil data immediately follows depth data in buffer
4171 const VkDeviceSize depthSize = depthBytesPerPixel * sourceArea.width * sourceArea.height *
4172 sourceArea.depth * layerCount;
4173
4174 // Double-check that we allocated enough buffer space (always 1 byte per stencil)
4175 ASSERT(*bufferSize >= (depthSize + (sourceArea.width * sourceArea.height *
4176 sourceArea.depth * layerCount)));
4177
4178 // Copy stencil data into buffer immediately following the depth data
4179 const VkDeviceSize stencilOffset = (*bufferOffsetsOut)[0] + depthSize;
4180 (*bufferOffsetsOut)[1] = stencilOffset;
4181 regions[1].bufferOffset = stencilOffset;
4182 regions[1].bufferRowLength = 0;
4183 regions[1].bufferImageHeight = 0;
4184 regions[1].imageExtent.width = sourceArea.width;
4185 regions[1].imageExtent.height = sourceArea.height;
4186 regions[1].imageExtent.depth = sourceArea.depth;
4187 regions[1].imageOffset.x = sourceArea.x;
4188 regions[1].imageOffset.y = sourceArea.y;
4189 regions[1].imageOffset.z = sourceArea.z;
4190 regions[1].imageSubresource.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
4191 regions[1].imageSubresource.baseArrayLayer = baseLayer;
4192 regions[1].imageSubresource.layerCount = layerCount;
4193 regions[1].imageSubresource.mipLevel = static_cast<uint32_t>(sourceLevel);
4194 commandBuffer->copyImageToBuffer(mImage, getCurrentLayout(),
4195 (*bufferOut)->getBuffer().getHandle(), 1, ®ions[1]);
4196 }
4197
4198 commandBuffer->copyImageToBuffer(mImage, getCurrentLayout(),
4199 (*bufferOut)->getBuffer().getHandle(), 1, regions);
4200
4201 return angle::Result::Continue;
4202 }
4203
4204 // 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)4205 angle::Result ImageHelper::GetReadPixelsParams(ContextVk *contextVk,
4206 const gl::PixelPackState &packState,
4207 gl::Buffer *packBuffer,
4208 GLenum format,
4209 GLenum type,
4210 const gl::Rectangle &area,
4211 const gl::Rectangle &clippedArea,
4212 PackPixelsParams *paramsOut,
4213 GLuint *skipBytesOut)
4214 {
4215 const gl::InternalFormat &sizedFormatInfo = gl::GetInternalFormatInfo(format, type);
4216
4217 GLuint outputPitch = 0;
4218 ANGLE_VK_CHECK_MATH(contextVk,
4219 sizedFormatInfo.computeRowPitch(type, area.width, packState.alignment,
4220 packState.rowLength, &outputPitch));
4221 ANGLE_VK_CHECK_MATH(contextVk, sizedFormatInfo.computeSkipBytes(type, outputPitch, 0, packState,
4222 false, skipBytesOut));
4223
4224 *skipBytesOut += (clippedArea.x - area.x) * sizedFormatInfo.pixelBytes +
4225 (clippedArea.y - area.y) * outputPitch;
4226
4227 const angle::Format &angleFormat = GetFormatFromFormatType(format, type);
4228
4229 *paramsOut = PackPixelsParams(clippedArea, angleFormat, outputPitch, packState.reverseRowOrder,
4230 packBuffer, 0);
4231 return angle::Result::Continue;
4232 }
4233
readPixelsForGetImage(ContextVk * contextVk,const gl::PixelPackState & packState,gl::Buffer * packBuffer,uint32_t level,uint32_t layer,GLenum format,GLenum type,void * pixels)4234 angle::Result ImageHelper::readPixelsForGetImage(ContextVk *contextVk,
4235 const gl::PixelPackState &packState,
4236 gl::Buffer *packBuffer,
4237 uint32_t level,
4238 uint32_t layer,
4239 GLenum format,
4240 GLenum type,
4241 void *pixels)
4242 {
4243 const angle::Format &angleFormat = GetFormatFromFormatType(format, type);
4244
4245 VkImageAspectFlagBits aspectFlags = {};
4246 if (angleFormat.redBits > 0 || angleFormat.blueBits > 0 || angleFormat.greenBits > 0 ||
4247 angleFormat.alphaBits > 0)
4248 {
4249 aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT;
4250 }
4251 else
4252 {
4253 if (angleFormat.depthBits > 0)
4254 {
4255 if (angleFormat.stencilBits != 0)
4256 {
4257 // TODO (anglebug.com/4688) Support combined depth stencil for GetTexImage
4258 WARN() << "Unable to pull combined depth/stencil for GetTexImage";
4259 return angle::Result::Continue;
4260 }
4261 aspectFlags = VK_IMAGE_ASPECT_DEPTH_BIT;
4262 }
4263 if (angleFormat.stencilBits > 0)
4264 {
4265 aspectFlags = VK_IMAGE_ASPECT_STENCIL_BIT;
4266 }
4267 }
4268
4269 ASSERT(aspectFlags != 0);
4270
4271 PackPixelsParams params;
4272 GLuint outputSkipBytes = 0;
4273
4274 uint32_t width = std::max(1u, mExtents.width >> level);
4275 uint32_t height = std::max(1u, mExtents.height >> level);
4276 uint32_t depth = std::max(1u, mExtents.depth >> level);
4277 gl::Rectangle area(0, 0, width, height);
4278
4279 ANGLE_TRY(GetReadPixelsParams(contextVk, packState, packBuffer, format, type, area, area,
4280 ¶ms, &outputSkipBytes));
4281
4282 // Use a temporary staging buffer. Could be optimized.
4283 vk::RendererScoped<vk::DynamicBuffer> stagingBuffer(contextVk->getRenderer());
4284 stagingBuffer.get().init(contextVk->getRenderer(), VK_BUFFER_USAGE_TRANSFER_DST_BIT, 1,
4285 kStagingBufferSize, true);
4286
4287 if (mExtents.depth > 1)
4288 {
4289 // Depth > 1 means this is a 3D texture and we need to copy all layers
4290 for (layer = 0; layer < depth; layer++)
4291 {
4292 ANGLE_TRY(readPixels(contextVk, area, params, aspectFlags, level, layer,
4293 static_cast<uint8_t *>(pixels) + outputSkipBytes,
4294 &stagingBuffer.get()));
4295
4296 outputSkipBytes += width * height * gl::GetInternalFormatInfo(format, type).pixelBytes;
4297 }
4298 }
4299 else
4300 {
4301 ANGLE_TRY(readPixels(contextVk, area, params, aspectFlags, level, layer,
4302 static_cast<uint8_t *>(pixels) + outputSkipBytes,
4303 &stagingBuffer.get()));
4304 }
4305
4306 return angle::Result::Continue;
4307 }
4308
readPixels(ContextVk * contextVk,const gl::Rectangle & area,const PackPixelsParams & packPixelsParams,VkImageAspectFlagBits copyAspectFlags,uint32_t level,uint32_t layer,void * pixels,DynamicBuffer * stagingBuffer)4309 angle::Result ImageHelper::readPixels(ContextVk *contextVk,
4310 const gl::Rectangle &area,
4311 const PackPixelsParams &packPixelsParams,
4312 VkImageAspectFlagBits copyAspectFlags,
4313 uint32_t level,
4314 uint32_t layer,
4315 void *pixels,
4316 DynamicBuffer *stagingBuffer)
4317 {
4318 ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::readPixels");
4319
4320 RendererVk *renderer = contextVk->getRenderer();
4321
4322 // If the source image is multisampled, we need to resolve it into a temporary image before
4323 // performing a readback.
4324 bool isMultisampled = mSamples > 1;
4325 RendererScoped<ImageHelper> resolvedImage(contextVk->getRenderer());
4326
4327 ImageHelper *src = this;
4328
4329 ASSERT(!isUpdateStaged(level, layer));
4330
4331 if (isMultisampled)
4332 {
4333 ANGLE_TRY(resolvedImage.get().init2DStaging(
4334 contextVk, renderer->getMemoryProperties(), gl::Extents(area.width, area.height, 1),
4335 *mFormat, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, 1));
4336 resolvedImage.get().retain(&contextVk->getResourceUseList());
4337 }
4338
4339 VkImageAspectFlags layoutChangeAspectFlags = src->getAspectFlags();
4340
4341 // Note that although we're reading from the image, we need to update the layout below.
4342 CommandBuffer *commandBuffer;
4343 if (isMultisampled)
4344 {
4345 ANGLE_TRY(contextVk->onImageWrite(layoutChangeAspectFlags, ImageLayout::TransferDst,
4346 &resolvedImage.get()));
4347 }
4348 ANGLE_TRY(contextVk->onImageRead(layoutChangeAspectFlags, ImageLayout::TransferSrc, this));
4349 ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&commandBuffer));
4350
4351 const angle::Format *readFormat = &mFormat->actualImageFormat();
4352
4353 if (copyAspectFlags != VK_IMAGE_ASPECT_COLOR_BIT)
4354 {
4355 readFormat = &GetDepthStencilImageToBufferFormat(*readFormat, copyAspectFlags);
4356 }
4357
4358 VkOffset3D srcOffset = {area.x, area.y, 0};
4359
4360 VkImageSubresourceLayers srcSubresource = {};
4361 srcSubresource.aspectMask = copyAspectFlags;
4362 srcSubresource.mipLevel = level;
4363 srcSubresource.baseArrayLayer = layer;
4364 srcSubresource.layerCount = 1;
4365
4366 VkExtent3D srcExtent = {static_cast<uint32_t>(area.width), static_cast<uint32_t>(area.height),
4367 1};
4368
4369 if (mExtents.depth > 1)
4370 {
4371 // Depth > 1 means this is a 3D texture and we need special handling
4372 srcOffset.z = layer;
4373 srcSubresource.baseArrayLayer = 0;
4374 }
4375
4376 if (isMultisampled)
4377 {
4378 // Note: resolve only works on color images (not depth/stencil).
4379 //
4380 // TODO: Currently, depth/stencil blit can perform a depth/stencil readback, but that code
4381 // path will be optimized away. http://anglebug.com/3200
4382 ASSERT(copyAspectFlags == VK_IMAGE_ASPECT_COLOR_BIT);
4383
4384 VkImageResolve resolveRegion = {};
4385 resolveRegion.srcSubresource = srcSubresource;
4386 resolveRegion.srcOffset = srcOffset;
4387 resolveRegion.dstSubresource.aspectMask = copyAspectFlags;
4388 resolveRegion.dstSubresource.mipLevel = 0;
4389 resolveRegion.dstSubresource.baseArrayLayer = 0;
4390 resolveRegion.dstSubresource.layerCount = 1;
4391 resolveRegion.dstOffset = {};
4392 resolveRegion.extent = srcExtent;
4393
4394 resolve(&resolvedImage.get(), resolveRegion, commandBuffer);
4395
4396 ANGLE_TRY(contextVk->onImageRead(layoutChangeAspectFlags, ImageLayout::TransferSrc,
4397 &resolvedImage.get()));
4398
4399 // Make the resolved image the target of buffer copy.
4400 src = &resolvedImage.get();
4401 level = 0;
4402 layer = 0;
4403 srcOffset = {0, 0, 0};
4404 srcSubresource.baseArrayLayer = 0;
4405 srcSubresource.layerCount = 1;
4406 srcSubresource.mipLevel = 0;
4407 }
4408
4409 VkBuffer bufferHandle = VK_NULL_HANDLE;
4410 uint8_t *readPixelBuffer = nullptr;
4411 VkDeviceSize stagingOffset = 0;
4412 size_t allocationSize = readFormat->pixelBytes * area.width * area.height;
4413
4414 ANGLE_TRY(stagingBuffer->allocate(contextVk, allocationSize, &readPixelBuffer, &bufferHandle,
4415 &stagingOffset, nullptr));
4416
4417 VkBufferImageCopy region = {};
4418 region.bufferImageHeight = srcExtent.height;
4419 region.bufferOffset = stagingOffset;
4420 region.bufferRowLength = srcExtent.width;
4421 region.imageExtent = srcExtent;
4422 region.imageOffset = srcOffset;
4423 region.imageSubresource = srcSubresource;
4424
4425 commandBuffer->copyImageToBuffer(src->getImage(), src->getCurrentLayout(), bufferHandle, 1,
4426 ®ion);
4427
4428 // Triggers a full finish.
4429 // TODO(jmadill): Don't block on asynchronous readback.
4430 ANGLE_TRY(contextVk->finishImpl());
4431
4432 // The buffer we copied to needs to be invalidated before we read from it because its not been
4433 // created with the host coherent bit.
4434 ANGLE_TRY(stagingBuffer->invalidate(contextVk));
4435
4436 if (packPixelsParams.packBuffer)
4437 {
4438 // Must map the PBO in order to read its contents (and then unmap it later)
4439 BufferVk *packBufferVk = GetImpl(packPixelsParams.packBuffer);
4440 void *mapPtr = nullptr;
4441 ANGLE_TRY(packBufferVk->mapImpl(contextVk, &mapPtr));
4442 uint8_t *dest = static_cast<uint8_t *>(mapPtr) + reinterpret_cast<ptrdiff_t>(pixels);
4443 PackPixels(packPixelsParams, *readFormat, area.width * readFormat->pixelBytes,
4444 readPixelBuffer, static_cast<uint8_t *>(dest));
4445 ANGLE_TRY(packBufferVk->unmapImpl(contextVk));
4446 }
4447 else
4448 {
4449 PackPixels(packPixelsParams, *readFormat, area.width * readFormat->pixelBytes,
4450 readPixelBuffer, static_cast<uint8_t *>(pixels));
4451 }
4452
4453 return angle::Result::Continue;
4454 }
4455
4456 // ImageHelper::SubresourceUpdate implementation
SubresourceUpdate()4457 ImageHelper::SubresourceUpdate::SubresourceUpdate() : updateSource(UpdateSource::Buffer), buffer{}
4458 {}
4459
SubresourceUpdate(BufferHelper * bufferHelperIn,const VkBufferImageCopy & copyRegionIn)4460 ImageHelper::SubresourceUpdate::SubresourceUpdate(BufferHelper *bufferHelperIn,
4461 const VkBufferImageCopy ©RegionIn)
4462 : updateSource(UpdateSource::Buffer), buffer{bufferHelperIn, copyRegionIn}
4463 {}
4464
SubresourceUpdate(ImageHelper * imageIn,const VkImageCopy & copyRegionIn)4465 ImageHelper::SubresourceUpdate::SubresourceUpdate(ImageHelper *imageIn,
4466 const VkImageCopy ©RegionIn)
4467 : updateSource(UpdateSource::Image), image{imageIn, copyRegionIn}
4468 {}
4469
SubresourceUpdate(VkImageAspectFlags aspectFlags,const VkClearValue & clearValue,const gl::ImageIndex & imageIndex)4470 ImageHelper::SubresourceUpdate::SubresourceUpdate(VkImageAspectFlags aspectFlags,
4471 const VkClearValue &clearValue,
4472 const gl::ImageIndex &imageIndex)
4473 : updateSource(UpdateSource::Clear)
4474 {
4475 clear.aspectFlags = aspectFlags;
4476 clear.value = clearValue;
4477 clear.levelIndex = imageIndex.getLevelIndex();
4478 clear.layerIndex = imageIndex.hasLayer() ? imageIndex.getLayerIndex() : 0;
4479 clear.layerCount =
4480 imageIndex.hasLayer() ? imageIndex.getLayerCount() : VK_REMAINING_ARRAY_LAYERS;
4481 }
4482
SubresourceUpdate(const SubresourceUpdate & other)4483 ImageHelper::SubresourceUpdate::SubresourceUpdate(const SubresourceUpdate &other)
4484 : updateSource(other.updateSource)
4485 {
4486 if (updateSource == UpdateSource::Clear)
4487 {
4488 clear = other.clear;
4489 }
4490 else if (updateSource == UpdateSource::Buffer)
4491 {
4492 buffer = other.buffer;
4493 }
4494 else
4495 {
4496 image = other.image;
4497 }
4498 }
4499
release(RendererVk * renderer)4500 void ImageHelper::SubresourceUpdate::release(RendererVk *renderer)
4501 {
4502 if (updateSource == UpdateSource::Image)
4503 {
4504 image.image->releaseImage(renderer);
4505 image.image->releaseStagingBuffer(renderer);
4506 SafeDelete(image.image);
4507 }
4508 }
4509
isUpdateToLayerLevel(uint32_t layerIndex,uint32_t levelIndex) const4510 bool ImageHelper::SubresourceUpdate::isUpdateToLayerLevel(uint32_t layerIndex,
4511 uint32_t levelIndex) const
4512 {
4513 if (updateSource == UpdateSource::Clear)
4514 {
4515 return clear.levelIndex == levelIndex && clear.layerIndex == layerIndex;
4516 }
4517
4518 const VkImageSubresourceLayers &dst = dstSubresource();
4519 return dst.baseArrayLayer == layerIndex && dst.mipLevel == levelIndex;
4520 }
4521
appendSubresourceUpdate(SubresourceUpdate && update)4522 void ImageHelper::appendSubresourceUpdate(SubresourceUpdate &&update)
4523 {
4524 mSubresourceUpdates.emplace_back(std::move(update));
4525 onStateChange(angle::SubjectMessage::SubjectChanged);
4526 }
4527
prependSubresourceUpdate(SubresourceUpdate && update)4528 void ImageHelper::prependSubresourceUpdate(SubresourceUpdate &&update)
4529 {
4530 mSubresourceUpdates.insert(mSubresourceUpdates.begin(), std::move(update));
4531 onStateChange(angle::SubjectMessage::SubjectChanged);
4532 }
4533
4534 // FramebufferHelper implementation.
4535 FramebufferHelper::FramebufferHelper() = default;
4536
4537 FramebufferHelper::~FramebufferHelper() = default;
4538
FramebufferHelper(FramebufferHelper && other)4539 FramebufferHelper::FramebufferHelper(FramebufferHelper &&other)
4540 {
4541 mFramebuffer = std::move(other.mFramebuffer);
4542 }
4543
operator =(FramebufferHelper && other)4544 FramebufferHelper &FramebufferHelper::operator=(FramebufferHelper &&other)
4545 {
4546 std::swap(mFramebuffer, other.mFramebuffer);
4547 return *this;
4548 }
4549
init(ContextVk * contextVk,const VkFramebufferCreateInfo & createInfo)4550 angle::Result FramebufferHelper::init(ContextVk *contextVk,
4551 const VkFramebufferCreateInfo &createInfo)
4552 {
4553 ANGLE_VK_TRY(contextVk, mFramebuffer.init(contextVk->getDevice(), createInfo));
4554 return angle::Result::Continue;
4555 }
4556
release(ContextVk * contextVk)4557 void FramebufferHelper::release(ContextVk *contextVk)
4558 {
4559 contextVk->addGarbage(&mFramebuffer);
4560 }
4561
4562 // ImageViewHelper implementation.
ImageViewHelper()4563 ImageViewHelper::ImageViewHelper() : mLinearColorspace(true)
4564 {
4565 mUse.init();
4566 }
4567
ImageViewHelper(ImageViewHelper && other)4568 ImageViewHelper::ImageViewHelper(ImageViewHelper &&other)
4569 {
4570 std::swap(mLinearReadImageView, other.mLinearReadImageView);
4571 std::swap(mNonLinearReadImageView, other.mNonLinearReadImageView);
4572 std::swap(mLinearFetchImageView, other.mLinearFetchImageView);
4573 std::swap(mNonLinearFetchImageView, other.mNonLinearFetchImageView);
4574 std::swap(mLinearColorspace, other.mLinearColorspace);
4575
4576 std::swap(mStencilReadImageView, other.mStencilReadImageView);
4577 std::swap(mLevelDrawImageViews, other.mLevelDrawImageViews);
4578 std::swap(mLayerLevelDrawImageViews, other.mLayerLevelDrawImageViews);
4579 }
4580
~ImageViewHelper()4581 ImageViewHelper::~ImageViewHelper()
4582 {
4583 mUse.release();
4584 }
4585
release(RendererVk * renderer)4586 void ImageViewHelper::release(RendererVk *renderer)
4587 {
4588 std::vector<GarbageObject> garbage;
4589
4590 if (mLinearReadImageView.valid())
4591 {
4592 garbage.emplace_back(GetGarbage(&mLinearReadImageView));
4593 }
4594 if (mNonLinearReadImageView.valid())
4595 {
4596 garbage.emplace_back(GetGarbage(&mNonLinearReadImageView));
4597 }
4598 if (mLinearFetchImageView.valid())
4599 {
4600 garbage.emplace_back(GetGarbage(&mLinearFetchImageView));
4601 }
4602 if (mNonLinearFetchImageView.valid())
4603 {
4604 garbage.emplace_back(GetGarbage(&mNonLinearFetchImageView));
4605 }
4606 if (mStencilReadImageView.valid())
4607 {
4608 garbage.emplace_back(GetGarbage(&mStencilReadImageView));
4609 }
4610
4611 for (ImageView &imageView : mLevelDrawImageViews)
4612 {
4613 if (imageView.valid())
4614 {
4615 garbage.emplace_back(GetGarbage(&imageView));
4616 }
4617 }
4618 mLevelDrawImageViews.clear();
4619
4620 for (ImageViewVector &layerViews : mLayerLevelDrawImageViews)
4621 {
4622 for (ImageView &imageView : layerViews)
4623 {
4624 if (imageView.valid())
4625 {
4626 garbage.emplace_back(GetGarbage(&imageView));
4627 }
4628 }
4629 }
4630 mLayerLevelDrawImageViews.clear();
4631
4632 if (!garbage.empty())
4633 {
4634 renderer->collectGarbage(std::move(mUse), std::move(garbage));
4635
4636 // Ensure the resource use is always valid.
4637 mUse.init();
4638 }
4639 }
4640
destroy(VkDevice device)4641 void ImageViewHelper::destroy(VkDevice device)
4642 {
4643 mLinearReadImageView.destroy(device);
4644 mNonLinearReadImageView.destroy(device);
4645 mLinearFetchImageView.destroy(device);
4646 mNonLinearFetchImageView.destroy(device);
4647 mStencilReadImageView.destroy(device);
4648
4649 for (ImageView &imageView : mLevelDrawImageViews)
4650 {
4651 imageView.destroy(device);
4652 }
4653 mLevelDrawImageViews.clear();
4654
4655 for (ImageViewVector &layerViews : mLayerLevelDrawImageViews)
4656 {
4657 for (ImageView &imageView : layerViews)
4658 {
4659 imageView.destroy(device);
4660 }
4661 }
4662 mLayerLevelDrawImageViews.clear();
4663 }
4664
initReadViews(ContextVk * contextVk,gl::TextureType viewType,const ImageHelper & image,const Format & format,const gl::SwizzleState & swizzleState,uint32_t baseLevel,uint32_t levelCount,uint32_t baseLayer,uint32_t layerCount)4665 angle::Result ImageViewHelper::initReadViews(ContextVk *contextVk,
4666 gl::TextureType viewType,
4667 const ImageHelper &image,
4668 const Format &format,
4669 const gl::SwizzleState &swizzleState,
4670 uint32_t baseLevel,
4671 uint32_t levelCount,
4672 uint32_t baseLayer,
4673 uint32_t layerCount)
4674 {
4675 const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(format.intendedFormat());
4676 mLinearColorspace = IsLinearFormat(format.vkImageFormat);
4677
4678 if (HasBothDepthAndStencilAspects(aspectFlags))
4679 {
4680 ANGLE_TRY(image.initLayerImageView(contextVk, viewType, VK_IMAGE_ASPECT_DEPTH_BIT,
4681 swizzleState, &getReadImageView(), baseLevel, levelCount,
4682 baseLayer, layerCount));
4683 ANGLE_TRY(image.initLayerImageView(contextVk, viewType, VK_IMAGE_ASPECT_STENCIL_BIT,
4684 swizzleState, &mStencilReadImageView, baseLevel,
4685 levelCount, baseLayer, layerCount));
4686 }
4687 else
4688 {
4689 ANGLE_TRY(image.initLayerImageView(contextVk, viewType, aspectFlags, swizzleState,
4690 &getReadImageView(), baseLevel, levelCount, baseLayer,
4691 layerCount));
4692 }
4693
4694 if (viewType == gl::TextureType::CubeMap || viewType == gl::TextureType::_2DArray ||
4695 viewType == gl::TextureType::_2DMultisampleArray)
4696 {
4697 gl::TextureType arrayType = Get2DTextureType(layerCount, image.getSamples());
4698
4699 // TODO(http://anglebug.com/4004): SwizzleState incorrect for CopyTextureCHROMIUM.
4700 ANGLE_TRY(image.initLayerImageView(contextVk, arrayType, aspectFlags, swizzleState,
4701 &getFetchImageView(), baseLevel, levelCount, baseLayer,
4702 layerCount));
4703 }
4704
4705 return angle::Result::Continue;
4706 }
4707
initSRGBReadViews(ContextVk * contextVk,gl::TextureType viewType,const ImageHelper & image,const Format & format,const gl::SwizzleState & swizzleState,uint32_t baseLevel,uint32_t levelCount,uint32_t baseLayer,uint32_t layerCount)4708 angle::Result ImageViewHelper::initSRGBReadViews(ContextVk *contextVk,
4709 gl::TextureType viewType,
4710 const ImageHelper &image,
4711 const Format &format,
4712 const gl::SwizzleState &swizzleState,
4713 uint32_t baseLevel,
4714 uint32_t levelCount,
4715 uint32_t baseLayer,
4716 uint32_t layerCount)
4717 {
4718 VkFormat nonLinearOverrideFormat = ConvertToNonLinear(image.getFormat().vkImageFormat);
4719 VkFormat linearOverrideFormat = ConvertToLinear(image.getFormat().vkImageFormat);
4720 VkFormat linearFormat =
4721 (linearOverrideFormat != VK_FORMAT_UNDEFINED) ? linearOverrideFormat : format.vkImageFormat;
4722 ASSERT(linearFormat != VK_FORMAT_UNDEFINED);
4723
4724 const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(format.intendedFormat());
4725
4726 if (!mLinearReadImageView.valid())
4727 {
4728 ANGLE_TRY(image.initLayerImageViewImpl(contextVk, viewType, aspectFlags, swizzleState,
4729 &mLinearReadImageView, baseLevel, levelCount,
4730 baseLayer, layerCount, linearFormat));
4731 }
4732 if (nonLinearOverrideFormat != VK_FORMAT_UNDEFINED && !mNonLinearReadImageView.valid())
4733 {
4734 ANGLE_TRY(image.initLayerImageViewImpl(contextVk, viewType, aspectFlags, swizzleState,
4735 &mNonLinearReadImageView, baseLevel, levelCount,
4736 baseLayer, layerCount, nonLinearOverrideFormat));
4737 }
4738
4739 if (viewType == gl::TextureType::CubeMap || viewType == gl::TextureType::_2DArray ||
4740 viewType == gl::TextureType::_2DMultisampleArray)
4741 {
4742 gl::TextureType arrayType = Get2DTextureType(layerCount, image.getSamples());
4743
4744 // TODO(http://anglebug.com/4004): SwizzleState incorrect for CopyTextureCHROMIUM.
4745 if (!mLinearFetchImageView.valid())
4746 {
4747
4748 ANGLE_TRY(image.initLayerImageViewImpl(contextVk, arrayType, aspectFlags, swizzleState,
4749 &mLinearFetchImageView, baseLevel, levelCount,
4750 baseLayer, layerCount, linearFormat));
4751 }
4752 if (nonLinearOverrideFormat != VK_FORMAT_UNDEFINED && !mNonLinearFetchImageView.valid())
4753 {
4754 ANGLE_TRY(image.initLayerImageViewImpl(contextVk, viewType, aspectFlags, swizzleState,
4755 &mNonLinearFetchImageView, baseLevel, levelCount,
4756 baseLayer, layerCount, nonLinearOverrideFormat));
4757 }
4758 }
4759
4760 return angle::Result::Continue;
4761 }
4762
getLevelDrawImageView(ContextVk * contextVk,gl::TextureType viewType,const ImageHelper & image,uint32_t level,uint32_t layer,const ImageView ** imageViewOut)4763 angle::Result ImageViewHelper::getLevelDrawImageView(ContextVk *contextVk,
4764 gl::TextureType viewType,
4765 const ImageHelper &image,
4766 uint32_t level,
4767 uint32_t layer,
4768 const ImageView **imageViewOut)
4769 {
4770 retain(&contextVk->getResourceUseList());
4771
4772 ImageView *imageView = GetLevelImageView(&mLevelDrawImageViews, level, image.getLevelCount());
4773
4774 *imageViewOut = imageView;
4775 if (imageView->valid())
4776 {
4777 return angle::Result::Continue;
4778 }
4779
4780 // Create the view. Note that storage images are not affected by swizzle parameters.
4781 return image.initLayerImageView(contextVk, viewType, image.getAspectFlags(), gl::SwizzleState(),
4782 imageView, level, 1, layer, image.getLayerCount());
4783 }
4784
getLevelLayerDrawImageView(ContextVk * contextVk,const ImageHelper & image,uint32_t level,uint32_t layer,const ImageView ** imageViewOut)4785 angle::Result ImageViewHelper::getLevelLayerDrawImageView(ContextVk *contextVk,
4786 const ImageHelper &image,
4787 uint32_t level,
4788 uint32_t layer,
4789 const ImageView **imageViewOut)
4790 {
4791 ASSERT(image.valid());
4792 ASSERT(!image.getFormat().actualImageFormat().isBlock);
4793
4794 retain(&contextVk->getResourceUseList());
4795
4796 uint32_t layerCount = GetImageLayerCountForView(image);
4797
4798 // Lazily allocate the storage for image views
4799 if (mLayerLevelDrawImageViews.empty())
4800 {
4801 mLayerLevelDrawImageViews.resize(layerCount);
4802 }
4803 ASSERT(mLayerLevelDrawImageViews.size() > layer);
4804
4805 ImageView *imageView =
4806 GetLevelImageView(&mLayerLevelDrawImageViews[layer], level, image.getLevelCount());
4807 *imageViewOut = imageView;
4808
4809 if (imageView->valid())
4810 {
4811 return angle::Result::Continue;
4812 }
4813
4814 // Lazily allocate the image view itself.
4815 // Note that these views are specifically made to be used as color attachments, and therefore
4816 // don't have swizzle.
4817 gl::TextureType viewType = Get2DTextureType(1, image.getSamples());
4818 return image.initLayerImageView(contextVk, viewType, image.getAspectFlags(), gl::SwizzleState(),
4819 imageView, level, 1, layer, 1);
4820 }
4821
4822 // SamplerHelper implementation.
SamplerHelper()4823 SamplerHelper::SamplerHelper()
4824 {
4825 mUse.init();
4826 }
4827
~SamplerHelper()4828 SamplerHelper::~SamplerHelper()
4829 {
4830 mUse.release();
4831 }
4832
release(RendererVk * renderer)4833 void SamplerHelper::release(RendererVk *renderer)
4834 {
4835 renderer->collectGarbageAndReinit(&mUse, &mSampler);
4836 }
4837
init(Context * context,const VkSamplerCreateInfo & createInfo)4838 angle::Result SamplerHelper::init(Context *context, const VkSamplerCreateInfo &createInfo)
4839 {
4840 RendererVk *renderer = context->getRenderer();
4841 ANGLE_VK_TRY(context, mSampler.init(renderer->getDevice(), createInfo));
4842 renderer->getActiveHandleCounts().onAllocate(HandleType::Sampler);
4843 return angle::Result::Continue;
4844 }
4845
4846 // DispatchHelper implementation.
4847 DispatchHelper::DispatchHelper() = default;
4848
4849 DispatchHelper::~DispatchHelper() = default;
4850
4851 // ShaderProgramHelper implementation.
4852 ShaderProgramHelper::ShaderProgramHelper() = default;
4853
4854 ShaderProgramHelper::~ShaderProgramHelper() = default;
4855
valid(const gl::ShaderType shaderType) const4856 bool ShaderProgramHelper::valid(const gl::ShaderType shaderType) const
4857 {
4858 return mShaders[shaderType].valid();
4859 }
4860
destroy(VkDevice device)4861 void ShaderProgramHelper::destroy(VkDevice device)
4862 {
4863 mGraphicsPipelines.destroy(device);
4864 mComputePipeline.destroy(device);
4865 for (BindingPointer<ShaderAndSerial> &shader : mShaders)
4866 {
4867 shader.reset();
4868 }
4869 }
4870
release(ContextVk * contextVk)4871 void ShaderProgramHelper::release(ContextVk *contextVk)
4872 {
4873 mGraphicsPipelines.release(contextVk);
4874 contextVk->addGarbage(&mComputePipeline.get());
4875 for (BindingPointer<ShaderAndSerial> &shader : mShaders)
4876 {
4877 shader.reset();
4878 }
4879 }
4880
setShader(gl::ShaderType shaderType,RefCounted<ShaderAndSerial> * shader)4881 void ShaderProgramHelper::setShader(gl::ShaderType shaderType, RefCounted<ShaderAndSerial> *shader)
4882 {
4883 mShaders[shaderType].set(shader);
4884 }
4885
enableSpecializationConstant(sh::vk::SpecializationConstantId id)4886 void ShaderProgramHelper::enableSpecializationConstant(sh::vk::SpecializationConstantId id)
4887 {
4888 ASSERT(id < sh::vk::SpecializationConstantId::EnumCount);
4889
4890 mSpecializationConstants.set(id);
4891 }
4892
getComputePipeline(Context * context,const PipelineLayout & pipelineLayout,PipelineAndSerial ** pipelineOut)4893 angle::Result ShaderProgramHelper::getComputePipeline(Context *context,
4894 const PipelineLayout &pipelineLayout,
4895 PipelineAndSerial **pipelineOut)
4896 {
4897 if (mComputePipeline.valid())
4898 {
4899 *pipelineOut = &mComputePipeline;
4900 return angle::Result::Continue;
4901 }
4902
4903 RendererVk *renderer = context->getRenderer();
4904
4905 VkPipelineShaderStageCreateInfo shaderStage = {};
4906 VkComputePipelineCreateInfo createInfo = {};
4907
4908 shaderStage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
4909 shaderStage.flags = 0;
4910 shaderStage.stage = VK_SHADER_STAGE_COMPUTE_BIT;
4911 shaderStage.module = mShaders[gl::ShaderType::Compute].get().get().getHandle();
4912 shaderStage.pName = "main";
4913 shaderStage.pSpecializationInfo = nullptr;
4914
4915 createInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
4916 createInfo.flags = 0;
4917 createInfo.stage = shaderStage;
4918 createInfo.layout = pipelineLayout.getHandle();
4919 createInfo.basePipelineHandle = VK_NULL_HANDLE;
4920 createInfo.basePipelineIndex = 0;
4921
4922 PipelineCache *pipelineCache = nullptr;
4923 ANGLE_TRY(renderer->getPipelineCache(&pipelineCache));
4924 ANGLE_VK_TRY(context, mComputePipeline.get().initCompute(context->getDevice(), createInfo,
4925 *pipelineCache));
4926
4927 *pipelineOut = &mComputePipeline;
4928 return angle::Result::Continue;
4929 }
4930
4931 // ActiveHandleCounter implementation.
ActiveHandleCounter()4932 ActiveHandleCounter::ActiveHandleCounter() : mActiveCounts{}, mAllocatedCounts{} {}
4933
4934 ActiveHandleCounter::~ActiveHandleCounter() = default;
4935
4936 } // namespace vk
4937 } // namespace rx
4938