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