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 #ifndef LIBANGLE_RENDERER_VULKAN_VK_HELPERS_H_ 10 #define LIBANGLE_RENDERER_VULKAN_VK_HELPERS_H_ 11 12 #include "libANGLE/renderer/vulkan/CommandGraph.h" 13 #include "libANGLE/renderer/vulkan/vk_utils.h" 14 15 namespace gl 16 { 17 class ImageIndex; 18 } // namespace gl 19 20 namespace rx 21 { 22 namespace vk 23 { 24 constexpr VkBufferUsageFlags kVertexBufferUsageFlags = 25 VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; 26 constexpr VkBufferUsageFlags kIndexBufferUsageFlags = 27 VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; 28 constexpr size_t kVertexBufferAlignment = 4; 29 constexpr size_t kIndexBufferAlignment = 4; 30 31 constexpr VkBufferUsageFlags kStagingBufferFlags = 32 VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; 33 constexpr size_t kStagingBufferSize = 1024 * 16; 34 35 struct TextureUnit final 36 { 37 TextureVk *texture; 38 SamplerVk *sampler; 39 }; 40 41 // A dynamic buffer is conceptually an infinitely long buffer. Each time you write to the buffer, 42 // you will always write to a previously unused portion. After a series of writes, you must flush 43 // the buffer data to the device. Buffer lifetime currently assumes that each new allocation will 44 // last as long or longer than each prior allocation. 45 // 46 // Dynamic buffers are used to implement a variety of data streaming operations in Vulkan, such 47 // as for immediate vertex array and element array data, uniform updates, and other dynamic data. 48 // 49 // Internally dynamic buffers keep a collection of VkBuffers. When we write past the end of a 50 // currently active VkBuffer we keep it until it is no longer in use. We then mark it available 51 // for future allocations in a free list. 52 class BufferHelper; 53 class DynamicBuffer : angle::NonCopyable 54 { 55 public: 56 DynamicBuffer(); 57 DynamicBuffer(DynamicBuffer &&other); 58 ~DynamicBuffer(); 59 60 // Init is called after the buffer creation so that the alignment can be specified later. 61 void init(RendererVk *renderer, 62 VkBufferUsageFlags usage, 63 size_t alignment, 64 size_t initialSize, 65 bool hostVisible); 66 67 // This call will allocate a new region at the end of the buffer. It internally may trigger 68 // a new buffer to be created (which is returned in the optional parameter 69 // `newBufferAllocatedOut`). The new region will be in the returned buffer at given offset. If 70 // a memory pointer is given, the buffer will be automatically map()ed. 71 angle::Result allocate(ContextVk *contextVk, 72 size_t sizeInBytes, 73 uint8_t **ptrOut, 74 VkBuffer *bufferOut, 75 VkDeviceSize *offsetOut, 76 bool *newBufferAllocatedOut); 77 78 // After a sequence of writes, call flush to ensure the data is visible to the device. 79 angle::Result flush(ContextVk *contextVk); 80 81 // After a sequence of writes, call invalidate to ensure the data is visible to the host. 82 angle::Result invalidate(ContextVk *contextVk); 83 84 // This releases resources when they might currently be in use. 85 void release(ContextVk *contextVk); 86 void release(DisplayVk *display, std::vector<GarbageObjectBase> *garbageQueue); 87 88 // This releases all the buffers that have been allocated since this was last called. 89 void releaseInFlightBuffers(ContextVk *contextVk); 90 91 // This frees resources immediately. 92 void destroy(VkDevice device); 93 getCurrentBuffer()94 BufferHelper *getCurrentBuffer() { return mBuffer; } 95 getAlignment()96 size_t getAlignment() { return mAlignment; } 97 void updateAlignment(RendererVk *renderer, size_t alignment); 98 99 // For testing only! 100 void setMinimumSizeForTesting(size_t minSize); 101 102 private: 103 void reset(); 104 angle::Result allocateNewBuffer(ContextVk *contextVk); 105 void releaseBufferListToContext(ContextVk *contextVk, std::vector<BufferHelper *> *buffers); 106 void releaseBufferListToDisplay(DisplayVk *display, 107 std::vector<GarbageObjectBase> *garbageQueue, 108 std::vector<BufferHelper *> *buffers); 109 void destroyBufferList(VkDevice device, std::vector<BufferHelper *> *buffers); 110 111 VkBufferUsageFlags mUsage; 112 bool mHostVisible; 113 size_t mInitialSize; 114 BufferHelper *mBuffer; 115 uint32_t mNextAllocationOffset; 116 uint32_t mLastFlushOrInvalidateOffset; 117 size_t mSize; 118 size_t mAlignment; 119 120 std::vector<BufferHelper *> mInFlightBuffers; 121 std::vector<BufferHelper *> mBufferFreeList; 122 }; 123 124 // Uses DescriptorPool to allocate descriptor sets as needed. If a descriptor pool becomes full, we 125 // allocate new pools internally as needed. RendererVk takes care of the lifetime of the discarded 126 // pools. Note that we used a fixed layout for descriptor pools in ANGLE. Uniform buffers must 127 // use set zero and combined Image Samplers must use set 1. We conservatively count each new set 128 // using the maximum number of descriptor sets and buffers with each allocation. Currently: 2 129 // (Vertex/Fragment) uniform buffers and 64 (MAX_ACTIVE_TEXTURES) image/samplers. 130 131 // Shared handle to a descriptor pool. Each helper is allocated from the dynamic descriptor pool. 132 // Can be used to share descriptor pools between multiple ProgramVks and the ContextVk. 133 class DescriptorPoolHelper 134 { 135 public: 136 DescriptorPoolHelper(); 137 ~DescriptorPoolHelper(); 138 valid()139 bool valid() { return mDescriptorPool.valid(); } 140 141 bool hasCapacity(uint32_t descriptorSetCount) const; 142 angle::Result init(Context *context, 143 const std::vector<VkDescriptorPoolSize> &poolSizes, 144 uint32_t maxSets); 145 void destroy(VkDevice device); 146 void release(ContextVk *contextVk); 147 148 angle::Result allocateSets(ContextVk *contextVk, 149 const VkDescriptorSetLayout *descriptorSetLayout, 150 uint32_t descriptorSetCount, 151 VkDescriptorSet *descriptorSetsOut); 152 updateSerial(Serial serial)153 void updateSerial(Serial serial) { mMostRecentSerial = serial; } 154 getSerial()155 Serial getSerial() const { return mMostRecentSerial; } 156 157 private: 158 uint32_t mFreeDescriptorSets; 159 DescriptorPool mDescriptorPool; 160 Serial mMostRecentSerial; 161 }; 162 163 using RefCountedDescriptorPoolHelper = RefCounted<DescriptorPoolHelper>; 164 using RefCountedDescriptorPoolBinding = BindingPointer<DescriptorPoolHelper>; 165 166 class DynamicDescriptorPool final : angle::NonCopyable 167 { 168 public: 169 DynamicDescriptorPool(); 170 ~DynamicDescriptorPool(); 171 172 // The DynamicDescriptorPool only handles one pool size at this time. 173 // Note that setSizes[i].descriptorCount is expected to be the number of descriptors in 174 // an individual set. The pool size will be calculated accordingly. 175 angle::Result init(ContextVk *contextVk, 176 const VkDescriptorPoolSize *setSizes, 177 uint32_t setSizeCount); 178 void destroy(VkDevice device); 179 void release(ContextVk *contextVk); 180 181 // We use the descriptor type to help count the number of free sets. 182 // By convention, sets are indexed according to the constants in vk_cache_utils.h. allocateSets(ContextVk * contextVk,const VkDescriptorSetLayout * descriptorSetLayout,uint32_t descriptorSetCount,RefCountedDescriptorPoolBinding * bindingOut,VkDescriptorSet * descriptorSetsOut)183 ANGLE_INLINE angle::Result allocateSets(ContextVk *contextVk, 184 const VkDescriptorSetLayout *descriptorSetLayout, 185 uint32_t descriptorSetCount, 186 RefCountedDescriptorPoolBinding *bindingOut, 187 VkDescriptorSet *descriptorSetsOut) 188 { 189 bool ignoreNewPoolAllocated; 190 return allocateSetsAndGetInfo(contextVk, descriptorSetLayout, descriptorSetCount, 191 bindingOut, descriptorSetsOut, &ignoreNewPoolAllocated); 192 } 193 194 // We use the descriptor type to help count the number of free sets. 195 // By convention, sets are indexed according to the constants in vk_cache_utils.h. 196 angle::Result allocateSetsAndGetInfo(ContextVk *contextVk, 197 const VkDescriptorSetLayout *descriptorSetLayout, 198 uint32_t descriptorSetCount, 199 RefCountedDescriptorPoolBinding *bindingOut, 200 VkDescriptorSet *descriptorSetsOut, 201 bool *newPoolAllocatedOut); 202 203 // For testing only! 204 void setMaxSetsPerPoolForTesting(uint32_t maxSetsPerPool); 205 206 private: 207 angle::Result allocateNewPool(ContextVk *contextVk); 208 209 uint32_t mMaxSetsPerPool; 210 size_t mCurrentPoolIndex; 211 std::vector<RefCountedDescriptorPoolHelper *> mDescriptorPools; 212 std::vector<VkDescriptorPoolSize> mPoolSizes; 213 }; 214 215 template <typename Pool> 216 class DynamicallyGrowingPool : angle::NonCopyable 217 { 218 public: 219 DynamicallyGrowingPool(); 220 virtual ~DynamicallyGrowingPool(); 221 isValid()222 bool isValid() { return mPoolSize > 0; } 223 224 protected: 225 angle::Result initEntryPool(Context *contextVk, uint32_t poolSize); 226 void destroyEntryPool(); 227 228 // Checks to see if any pool is already free, in which case it sets it as current pool and 229 // returns true. 230 bool findFreeEntryPool(ContextVk *contextVk); 231 232 // Allocates a new entry and initializes it with the given pool. 233 angle::Result allocateNewEntryPool(ContextVk *contextVk, Pool &&pool); 234 235 // Called by the implementation whenever an entry is freed. 236 void onEntryFreed(ContextVk *contextVk, size_t poolIndex); 237 238 // The pool size, to know when a pool is completely freed. 239 uint32_t mPoolSize; 240 241 std::vector<Pool> mPools; 242 243 struct PoolStats 244 { 245 // A count corresponding to each pool indicating how many of its allocated entries 246 // have been freed. Once that value reaches mPoolSize for each pool, that pool is considered 247 // free and reusable. While keeping a bitset would allow allocation of each index, the 248 // slight runtime overhead of finding free indices is not worth the slight memory overhead 249 // of creating new pools when unnecessary. 250 uint32_t freedCount; 251 // The serial of the renderer is stored on each object free to make sure no 252 // new allocations are made from the pool until it's not in use. 253 Serial serial; 254 }; 255 std::vector<PoolStats> mPoolStats; 256 257 // Index into mPools indicating pool we are currently allocating from. 258 size_t mCurrentPool; 259 // Index inside mPools[mCurrentPool] indicating which index can be allocated next. 260 uint32_t mCurrentFreeEntry; 261 }; 262 263 // DynamicQueryPool allocates indices out of QueryPool as needed. Once a QueryPool is exhausted, 264 // another is created. The query pools live permanently, but are recycled as indices get freed. 265 266 // These are arbitrary default sizes for query pools. 267 constexpr uint32_t kDefaultOcclusionQueryPoolSize = 64; 268 constexpr uint32_t kDefaultTimestampQueryPoolSize = 64; 269 270 class QueryHelper; 271 272 class DynamicQueryPool final : public DynamicallyGrowingPool<QueryPool> 273 { 274 public: 275 DynamicQueryPool(); 276 ~DynamicQueryPool() override; 277 278 angle::Result init(ContextVk *contextVk, VkQueryType type, uint32_t poolSize); 279 void destroy(VkDevice device); 280 281 angle::Result allocateQuery(ContextVk *contextVk, QueryHelper *queryOut); 282 void freeQuery(ContextVk *contextVk, QueryHelper *query); 283 284 // Special allocator that doesn't work with QueryHelper, which is a CommandGraphResource. 285 // Currently only used with RendererVk::GpuEventQuery. 286 angle::Result allocateQuery(ContextVk *contextVk, size_t *poolIndex, uint32_t *queryIndex); 287 void freeQuery(ContextVk *contextVk, size_t poolIndex, uint32_t queryIndex); 288 getQueryPool(size_t index)289 const QueryPool *getQueryPool(size_t index) const { return &mPools[index]; } 290 291 private: 292 angle::Result allocateNewPool(ContextVk *contextVk); 293 294 // Information required to create new query pools 295 VkQueryType mQueryType; 296 }; 297 298 // Queries in vulkan are identified by the query pool and an index for a query within that pool. 299 // Unlike other pools, such as descriptor pools where an allocation returns an independent object 300 // from the pool, the query allocations are not done through a Vulkan function and are only an 301 // integer index. 302 // 303 // Furthermore, to support arbitrarily large number of queries, DynamicQueryPool creates query pools 304 // of a fixed size as needed and allocates indices within those pools. 305 // 306 // The QueryHelper class below keeps the pool and index pair together. 307 class QueryHelper final 308 { 309 public: 310 QueryHelper(); 311 ~QueryHelper(); 312 313 void init(const DynamicQueryPool *dynamicQueryPool, 314 const size_t queryPoolIndex, 315 uint32_t query); 316 void deinit(); 317 getQueryPool()318 const QueryPool *getQueryPool() const 319 { 320 return mDynamicQueryPool ? mDynamicQueryPool->getQueryPool(mQueryPoolIndex) : nullptr; 321 } getQuery()322 uint32_t getQuery() const { return mQuery; } 323 324 // Used only by DynamicQueryPool. getQueryPoolIndex()325 size_t getQueryPoolIndex() const { return mQueryPoolIndex; } 326 327 void beginQuery(ContextVk *contextVk); 328 void endQuery(ContextVk *contextVk); 329 void writeTimestamp(ContextVk *contextVk); 330 getStoredQueueSerial()331 Serial getStoredQueueSerial() { return mMostRecentSerial; } 332 bool hasPendingWork(ContextVk *contextVk); 333 334 private: 335 const DynamicQueryPool *mDynamicQueryPool; 336 size_t mQueryPoolIndex; 337 uint32_t mQuery; 338 Serial mMostRecentSerial; 339 }; 340 341 // DynamicSemaphorePool allocates semaphores as needed. It uses a std::vector 342 // as a pool to allocate many semaphores at once. The pools live permanently, 343 // but are recycled as semaphores get freed. 344 345 // These are arbitrary default sizes for semaphore pools. 346 constexpr uint32_t kDefaultSemaphorePoolSize = 64; 347 348 class SemaphoreHelper; 349 350 class DynamicSemaphorePool final : public DynamicallyGrowingPool<std::vector<Semaphore>> 351 { 352 public: 353 DynamicSemaphorePool(); 354 ~DynamicSemaphorePool() override; 355 356 angle::Result init(ContextVk *contextVk, uint32_t poolSize); 357 void destroy(VkDevice device); 358 isValid()359 bool isValid() { return mPoolSize > 0; } 360 361 // autoFree can be used to allocate a semaphore that's expected to be freed at the end of the 362 // frame. This renders freeSemaphore unnecessary and saves an eventual search. 363 angle::Result allocateSemaphore(ContextVk *contextVk, SemaphoreHelper *semaphoreOut); 364 void freeSemaphore(ContextVk *contextVk, SemaphoreHelper *semaphore); 365 366 private: 367 angle::Result allocateNewPool(ContextVk *contextVk); 368 }; 369 370 // Semaphores that are allocated from the semaphore pool are encapsulated in a helper object, 371 // keeping track of where in the pool they are allocated from. 372 class SemaphoreHelper final : angle::NonCopyable 373 { 374 public: 375 SemaphoreHelper(); 376 ~SemaphoreHelper(); 377 378 SemaphoreHelper(SemaphoreHelper &&other); 379 SemaphoreHelper &operator=(SemaphoreHelper &&other); 380 381 void init(const size_t semaphorePoolIndex, const Semaphore *semaphore); 382 void deinit(); 383 getSemaphore()384 const Semaphore *getSemaphore() const { return mSemaphore; } 385 386 // Used only by DynamicSemaphorePool. getSemaphorePoolIndex()387 size_t getSemaphorePoolIndex() const { return mSemaphorePoolIndex; } 388 389 private: 390 size_t mSemaphorePoolIndex; 391 const Semaphore *mSemaphore; 392 }; 393 394 // This class' responsibility is to create index buffers needed to support line loops in Vulkan. 395 // In the setup phase of drawing, the createIndexBuffer method should be called with the 396 // current draw call parameters. If an element array buffer is bound for an indexed draw, use 397 // createIndexBufferFromElementArrayBuffer. 398 // 399 // If the user wants to draw a loop between [v1, v2, v3], we will create an indexed buffer with 400 // these indexes: [0, 1, 2, 3, 0] to emulate the loop. 401 class LineLoopHelper final : angle::NonCopyable 402 { 403 public: 404 LineLoopHelper(RendererVk *renderer); 405 ~LineLoopHelper(); 406 407 angle::Result getIndexBufferForDrawArrays(ContextVk *contextVk, 408 uint32_t clampedVertexCount, 409 GLint firstVertex, 410 vk::BufferHelper **bufferOut, 411 VkDeviceSize *offsetOut); 412 413 angle::Result getIndexBufferForElementArrayBuffer(ContextVk *contextVk, 414 BufferVk *elementArrayBufferVk, 415 gl::DrawElementsType glIndexType, 416 int indexCount, 417 intptr_t elementArrayOffset, 418 vk::BufferHelper **bufferOut, 419 VkDeviceSize *bufferOffsetOut, 420 uint32_t *indexCountOut); 421 422 angle::Result streamIndices(ContextVk *contextVk, 423 gl::DrawElementsType glIndexType, 424 GLsizei indexCount, 425 const uint8_t *srcPtr, 426 vk::BufferHelper **bufferOut, 427 VkDeviceSize *bufferOffsetOut, 428 uint32_t *indexCountOut); 429 430 void release(ContextVk *contextVk); 431 void destroy(VkDevice device); 432 433 static void Draw(uint32_t count, vk::CommandBuffer *commandBuffer); 434 435 private: 436 DynamicBuffer mDynamicIndexBuffer; 437 }; 438 439 class FramebufferHelper; 440 441 class BufferHelper final : public CommandGraphResource 442 { 443 public: 444 BufferHelper(); 445 ~BufferHelper() override; 446 447 angle::Result init(ContextVk *contextVk, 448 const VkBufferCreateInfo &createInfo, 449 VkMemoryPropertyFlags memoryPropertyFlags); 450 void destroy(VkDevice device); 451 452 void release(ContextVk *contextVk); 453 void release(DisplayVk *display, std::vector<GarbageObjectBase> *garbageQueue); 454 valid()455 bool valid() const { return mBuffer.valid(); } getBuffer()456 const Buffer &getBuffer() const { return mBuffer; } getDeviceMemory()457 const DeviceMemory &getDeviceMemory() const { return mDeviceMemory; } getSize()458 VkDeviceSize getSize() const { return mSize; } 459 460 // Helpers for setting the graph dependencies *and* setting the appropriate barrier. These are 461 // made for dependencies to non-buffer resources, as only one of two resources participating in 462 // the dependency would require a memory barrier. Note that onWrite takes read access flags 463 // too, as output buffers could be read as well. onRead(CommandGraphResource * reader,VkAccessFlags readAccessType)464 void onRead(CommandGraphResource *reader, VkAccessFlags readAccessType) 465 { 466 addReadDependency(reader); 467 onReadAccess(reader, readAccessType); 468 } onWrite(ContextVk * contextVk,CommandGraphResource * writer,VkAccessFlags readAccessType,VkAccessFlags writeAccessType)469 void onWrite(ContextVk *contextVk, 470 CommandGraphResource *writer, 471 VkAccessFlags readAccessType, 472 VkAccessFlags writeAccessType) 473 { 474 addWriteDependency(writer); 475 onWriteAccess(contextVk, readAccessType, writeAccessType); 476 } 477 // Helper for setting a graph dependency between two buffers. This is a specialized function as 478 // both buffers may incur a memory barrier. Using |onRead| followed by |onWrite| between the 479 // buffers is impossible as it would result in a command graph loop. onReadByBuffer(ContextVk * contextVk,BufferHelper * reader,VkAccessFlags readAccessType,VkAccessFlags writeAccessType)480 void onReadByBuffer(ContextVk *contextVk, 481 BufferHelper *reader, 482 VkAccessFlags readAccessType, 483 VkAccessFlags writeAccessType) 484 { 485 addReadDependency(reader); 486 onReadAccess(reader, readAccessType); 487 reader->onWriteAccess(contextVk, 0, writeAccessType); 488 } 489 // Helper for setting a barrier when different parts of the same buffer is being read from and 490 // written to. onSelfReadWrite(ContextVk * contextVk,VkAccessFlags readAccessType,VkAccessFlags writeAccessType)491 void onSelfReadWrite(ContextVk *contextVk, 492 VkAccessFlags readAccessType, 493 VkAccessFlags writeAccessType) 494 { 495 if (mCurrentReadAccess || mCurrentWriteAccess) 496 { 497 finishCurrentCommands(contextVk); 498 } 499 onWriteAccess(contextVk, readAccessType, writeAccessType); 500 } 501 // Set write access mask when the buffer is modified externally, e.g. by host. There is no 502 // graph resource to create a dependency to. onExternalWrite(VkAccessFlags writeAccessType)503 void onExternalWrite(VkAccessFlags writeAccessType) { mCurrentWriteAccess |= writeAccessType; } 504 505 // Also implicitly sets up the correct barriers. 506 angle::Result copyFromBuffer(ContextVk *contextVk, 507 const Buffer &buffer, 508 VkAccessFlags bufferAccessType, 509 const VkBufferCopy ©Region); 510 511 // Note: currently only one view is allowed. If needs be, multiple views can be created 512 // based on format. 513 angle::Result initBufferView(ContextVk *contextVk, const Format &format); 514 getBufferView()515 const BufferView &getBufferView() const 516 { 517 ASSERT(mBufferView.valid()); 518 return mBufferView; 519 } 520 getViewFormat()521 const Format &getViewFormat() const 522 { 523 ASSERT(mViewFormat); 524 return *mViewFormat; 525 } 526 map(ContextVk * contextVk,uint8_t ** ptrOut)527 angle::Result map(ContextVk *contextVk, uint8_t **ptrOut) 528 { 529 if (!mMappedMemory) 530 { 531 ANGLE_TRY(mapImpl(contextVk)); 532 } 533 *ptrOut = mMappedMemory; 534 return angle::Result::Continue; 535 } 536 void unmap(VkDevice device); 537 538 // After a sequence of writes, call flush to ensure the data is visible to the device. 539 angle::Result flush(ContextVk *contextVk, size_t offset, size_t size); 540 541 // After a sequence of writes, call invalidate to ensure the data is visible to the host. 542 angle::Result invalidate(ContextVk *contextVk, size_t offset, size_t size); 543 544 private: 545 angle::Result mapImpl(ContextVk *contextVk); needsOnReadBarrier(VkAccessFlags readAccessType,VkAccessFlags * barrierSrcOut,VkAccessFlags * barrierDstOut)546 bool needsOnReadBarrier(VkAccessFlags readAccessType, 547 VkAccessFlags *barrierSrcOut, 548 VkAccessFlags *barrierDstOut) 549 { 550 bool needsBarrier = 551 mCurrentWriteAccess != 0 && (mCurrentReadAccess & readAccessType) != readAccessType; 552 553 *barrierSrcOut = mCurrentWriteAccess; 554 *barrierDstOut = readAccessType; 555 556 mCurrentReadAccess |= readAccessType; 557 return needsBarrier; 558 } onReadAccess(CommandGraphResource * reader,VkAccessFlags readAccessType)559 void onReadAccess(CommandGraphResource *reader, VkAccessFlags readAccessType) 560 { 561 VkAccessFlags barrierSrc, barrierDst; 562 if (needsOnReadBarrier(readAccessType, &barrierSrc, &barrierDst)) 563 { 564 reader->addGlobalMemoryBarrier(barrierSrc, barrierDst, 565 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); 566 } 567 } 568 bool needsOnWriteBarrier(VkAccessFlags readAccessType, 569 VkAccessFlags writeAccessType, 570 VkAccessFlags *barrierSrcOut, 571 VkAccessFlags *barrierDstOut); 572 void onWriteAccess(ContextVk *contextVk, 573 VkAccessFlags readAccessType, 574 VkAccessFlags writeAccessType); 575 576 // Vulkan objects. 577 Buffer mBuffer; 578 BufferView mBufferView; 579 DeviceMemory mDeviceMemory; 580 581 // Cached properties. 582 VkMemoryPropertyFlags mMemoryPropertyFlags; 583 VkDeviceSize mSize; 584 uint8_t *mMappedMemory; 585 const Format *mViewFormat; 586 587 // For memory barriers. 588 VkFlags mCurrentWriteAccess; 589 VkFlags mCurrentReadAccess; 590 }; 591 592 // Imagine an image going through a few layout transitions: 593 // 594 // srcStage 1 dstStage 2 srcStage 2 dstStage 3 595 // Layout 1 ------Transition 1-----> Layout 2 ------Transition 2------> Layout 3 596 // srcAccess 1 dstAccess 2 srcAccess 2 dstAccess 3 597 // \_________________ ___________________/ 598 // \/ 599 // A transition 600 // 601 // Every transition requires 6 pieces of information: from/to layouts, src/dst stage masks and 602 // src/dst access masks. At the moment we decide to transition the image to Layout 2 (i.e. 603 // Transition 1), we need to have Layout 1, srcStage 1 and srcAccess 1 stored as history of the 604 // image. To perform the transition, we need to know Layout 2, dstStage 2 and dstAccess 2. 605 // Additionally, we need to know srcStage 2 and srcAccess 2 to retain them for the next transition. 606 // 607 // That is, with the history kept, on every new transition we need 5 pieces of new information: 608 // layout/dstStage/dstAccess to transition into the layout, and srcStage/srcAccess for the future 609 // transition out from it. Given the small number of possible combinations of these values, an 610 // enum is used were each value encapsulates these 5 pieces of information: 611 // 612 // +--------------------------------+ 613 // srcStage 1 | dstStage 2 srcStage 2 | dstStage 3 614 // Layout 1 ------Transition 1-----> Layout 2 ------Transition 2------> Layout 3 615 // srcAccess 1 |dstAccess 2 srcAccess 2| dstAccess 3 616 // +--------------- ---------------+ 617 // \/ 618 // One enum value 619 // 620 // Note that, while generally dstStage for the to-transition and srcStage for the from-transition 621 // are the same, they may occasionally be BOTTOM_OF_PIPE and TOP_OF_PIPE respectively. 622 enum class ImageLayout 623 { 624 Undefined = 0, 625 ExternalPreInitialized = 1, 626 TransferSrc = 2, 627 TransferDst = 3, 628 ComputeShaderReadOnly = 4, 629 ComputeShaderWrite = 5, 630 AllGraphicsShadersReadOnly = 6, 631 ColorAttachment = 7, 632 DepthStencilAttachment = 8, 633 Present = 9, 634 635 InvalidEnum = 10, 636 EnumCount = 10, 637 }; 638 639 class ImageHelper final : public CommandGraphResource 640 { 641 public: 642 ImageHelper(); 643 ImageHelper(ImageHelper &&other); 644 ~ImageHelper() override; 645 646 void initStagingBuffer(RendererVk *renderer, 647 const vk::Format &format, 648 VkBufferUsageFlags usageFlags, 649 size_t initialSize); 650 651 angle::Result init(Context *context, 652 gl::TextureType textureType, 653 const VkExtent3D &extents, 654 const Format &format, 655 GLint samples, 656 VkImageUsageFlags usage, 657 uint32_t mipLevels, 658 uint32_t layerCount); 659 angle::Result initExternal(Context *context, 660 gl::TextureType textureType, 661 const VkExtent3D &extents, 662 const Format &format, 663 GLint samples, 664 VkImageUsageFlags usage, 665 ImageLayout initialLayout, 666 const void *externalImageCreateInfo, 667 uint32_t mipLevels, 668 uint32_t layerCount); 669 angle::Result initMemory(Context *context, 670 const MemoryProperties &memoryProperties, 671 VkMemoryPropertyFlags flags); 672 angle::Result initExternalMemory(Context *context, 673 const MemoryProperties &memoryProperties, 674 const VkMemoryRequirements &memoryRequirements, 675 const void *extraAllocationInfo, 676 uint32_t currentQueueFamilyIndex, 677 VkMemoryPropertyFlags flags); 678 angle::Result initLayerImageView(Context *context, 679 gl::TextureType textureType, 680 VkImageAspectFlags aspectMask, 681 const gl::SwizzleState &swizzleMap, 682 ImageView *imageViewOut, 683 uint32_t baseMipLevel, 684 uint32_t levelCount, 685 uint32_t baseArrayLayer, 686 uint32_t layerCount); 687 angle::Result initImageView(Context *context, 688 gl::TextureType textureType, 689 VkImageAspectFlags aspectMask, 690 const gl::SwizzleState &swizzleMap, 691 ImageView *imageViewOut, 692 uint32_t baseMipLevel, 693 uint32_t levelCount); 694 // Create a 2D[Array] for staging purposes. Used by: 695 // 696 // - TextureVk::copySubImageImplWithDraw 697 // - FramebufferVk::readPixelsImpl 698 // 699 angle::Result init2DStaging(Context *context, 700 const MemoryProperties &memoryProperties, 701 const gl::Extents &glExtents, 702 const Format &format, 703 VkImageUsageFlags usage, 704 uint32_t layerCount); 705 706 void releaseImage(ContextVk *contextVk); 707 void releaseImage(DisplayVk *display, std::vector<GarbageObjectBase> *garbageQueue); 708 709 void releaseStagingBuffer(ContextVk *contextVk); 710 void releaseStagingBuffer(DisplayVk *display, std::vector<GarbageObjectBase> *garbageQueue); 711 valid()712 bool valid() const { return mImage.valid(); } 713 714 VkImageAspectFlags getAspectFlags() const; 715 void destroy(VkDevice device); 716 void dumpResources(Serial serial, std::vector<GarbageObject> *garbageQueue); 717 718 void init2DWeakReference(VkImage handle, 719 const gl::Extents &glExtents, 720 const Format &format, 721 GLint samples); 722 void resetImageWeakReference(); 723 getImage()724 const Image &getImage() const { return mImage; } getDeviceMemory()725 const DeviceMemory &getDeviceMemory() const { return mDeviceMemory; } 726 getExtents()727 const VkExtent3D &getExtents() const { return mExtents; } getLayerCount()728 uint32_t getLayerCount() const { return mLayerCount; } getLevelCount()729 uint32_t getLevelCount() const { return mLevelCount; } getFormat()730 const Format &getFormat() const { return *mFormat; } getSamples()731 GLint getSamples() const { return mSamples; } 732 733 VkImageLayout getCurrentLayout() const; 734 735 // Helper function to calculate the extents of a render target created for a certain mip of the 736 // image. 737 gl::Extents getLevelExtents2D(uint32_t level) const; 738 739 // Clear either color or depth/stencil based on image format. 740 void clear(const VkClearValue &value, 741 uint32_t mipLevel, 742 uint32_t baseArrayLayer, 743 uint32_t layerCount, 744 vk::CommandBuffer *commandBuffer); 745 746 gl::Extents getSize(const gl::ImageIndex &index) const; 747 748 static void Copy(ImageHelper *srcImage, 749 ImageHelper *dstImage, 750 const gl::Offset &srcOffset, 751 const gl::Offset &dstOffset, 752 const gl::Extents ©Size, 753 const VkImageSubresourceLayers &srcSubresources, 754 const VkImageSubresourceLayers &dstSubresources, 755 vk::CommandBuffer *commandBuffer); 756 757 angle::Result generateMipmapsWithBlit(ContextVk *contextVk, GLuint maxLevel); 758 759 // Resolve this image into a destination image. This image should be in the TransferSrc layout. 760 // The destination image is automatically transitioned into TransferDst. 761 void resolve(ImageHelper *dest, const VkImageResolve ®ion, vk::CommandBuffer *commandBuffer); 762 763 // Data staging 764 void removeStagedUpdates(ContextVk *contextVk, const gl::ImageIndex &index); 765 766 angle::Result stageSubresourceUpdate(ContextVk *contextVk, 767 const gl::ImageIndex &index, 768 const gl::Extents &glExtents, 769 const gl::Offset &offset, 770 const gl::InternalFormat &formatInfo, 771 const gl::PixelUnpackState &unpack, 772 GLenum type, 773 const uint8_t *pixels, 774 const vk::Format &vkFormat); 775 776 angle::Result stageSubresourceUpdateAndGetData(ContextVk *contextVk, 777 size_t allocationSize, 778 const gl::ImageIndex &imageIndex, 779 const gl::Extents &glExtents, 780 const gl::Offset &offset, 781 uint8_t **destData); 782 783 angle::Result stageSubresourceUpdateFromFramebuffer(const gl::Context *context, 784 const gl::ImageIndex &index, 785 const gl::Rectangle &sourceArea, 786 const gl::Offset &dstOffset, 787 const gl::Extents &dstExtent, 788 const gl::InternalFormat &formatInfo, 789 FramebufferVk *framebufferVk); 790 791 void stageSubresourceUpdateFromImage(vk::ImageHelper *image, 792 const gl::ImageIndex &index, 793 const gl::Offset &destOffset, 794 const gl::Extents &glExtents, 795 const VkImageType imageType); 796 797 // Stage a clear operation to a clear value based on WebGL requirements. 798 void stageSubresourceRobustClear(const gl::ImageIndex &index, const angle::Format &format); 799 800 // Stage a clear operation to a clear value that initializes emulated channels to the desired 801 // values. 802 void stageSubresourceEmulatedClear(const gl::ImageIndex &index, const angle::Format &format); 803 804 // If the image has emulated channels, we clear them once so as not to leave garbage on those 805 // channels. 806 void stageClearIfEmulatedFormat(const gl::ImageIndex &index, const Format &format); 807 808 // This will use the underlying dynamic buffer to allocate some memory to be used as a src or 809 // dst. 810 angle::Result allocateStagingMemory(ContextVk *contextVk, 811 size_t sizeInBytes, 812 uint8_t **ptrOut, 813 VkBuffer *handleOut, 814 VkDeviceSize *offsetOut, 815 bool *newBufferAllocatedOut); 816 817 // Flushes staged updates to a range of levels and layers from start to (but not including) end. 818 // Due to the nature of updates (done wholly to a VkImageSubresourceLayers), some unsolicited 819 // layers may also be updated. 820 angle::Result flushStagedUpdates(ContextVk *contextVk, 821 uint32_t levelStart, 822 uint32_t levelEnd, 823 uint32_t layerStart, 824 uint32_t layerEnd, 825 vk::CommandBuffer *commandBuffer); 826 // Creates a command buffer and flushes all staged updates. This is used for one-time 827 // initialization of resources that we don't expect to accumulate further staged updates, such 828 // as with renderbuffers or surface images. 829 angle::Result flushAllStagedUpdates(ContextVk *contextVk); 830 hasStagedUpdates()831 bool hasStagedUpdates() const { return !mSubresourceUpdates.empty(); } 832 833 // changeLayout automatically skips the layout change if it's unnecessary. This function can be 834 // used to prevent creating a command graph node and subsequently a command buffer for the sole 835 // purpose of performing a transition (which may then not be issued). 836 bool isLayoutChangeNecessary(ImageLayout newLayout) const; 837 838 void changeLayout(VkImageAspectFlags aspectMask, 839 ImageLayout newLayout, 840 vk::CommandBuffer *commandBuffer); 841 isQueueChangeNeccesary(uint32_t newQueueFamilyIndex)842 bool isQueueChangeNeccesary(uint32_t newQueueFamilyIndex) const 843 { 844 return mCurrentQueueFamilyIndex != newQueueFamilyIndex; 845 } 846 847 void changeLayoutAndQueue(VkImageAspectFlags aspectMask, 848 ImageLayout newLayout, 849 uint32_t newQueueFamilyIndex, 850 vk::CommandBuffer *commandBuffer); 851 852 private: 853 void forceChangeLayoutAndQueue(VkImageAspectFlags aspectMask, 854 ImageLayout newLayout, 855 uint32_t newQueueFamilyIndex, 856 vk::CommandBuffer *commandBuffer); 857 858 void stageSubresourceClear(const gl::ImageIndex &index, 859 const angle::Format &format, 860 const VkClearColorValue &colorValue, 861 const VkClearDepthStencilValue &depthStencilValue); 862 863 void clearColor(const VkClearColorValue &color, 864 uint32_t baseMipLevel, 865 uint32_t levelCount, 866 uint32_t baseArrayLayer, 867 uint32_t layerCount, 868 vk::CommandBuffer *commandBuffer); 869 870 void clearDepthStencil(VkImageAspectFlags imageAspectFlags, 871 VkImageAspectFlags clearAspectFlags, 872 const VkClearDepthStencilValue &depthStencil, 873 uint32_t baseMipLevel, 874 uint32_t levelCount, 875 uint32_t baseArrayLayer, 876 uint32_t layerCount, 877 vk::CommandBuffer *commandBuffer); 878 879 struct SubresourceUpdate 880 { 881 SubresourceUpdate(); 882 SubresourceUpdate(VkBuffer bufferHandle, const VkBufferImageCopy ©Region); 883 SubresourceUpdate(vk::ImageHelper *image, const VkImageCopy ©Region); 884 SubresourceUpdate(const VkClearValue &clearValue, const gl::ImageIndex &imageIndex); 885 SubresourceUpdate(const SubresourceUpdate &other); 886 887 void release(ContextVk *contextVk); 888 void release(DisplayVk *display, std::vector<GarbageObjectBase> *garbageQueue); 889 dstSubresourceSubresourceUpdate890 const VkImageSubresourceLayers &dstSubresource() const 891 { 892 ASSERT(updateSource == UpdateSource::Buffer || updateSource == UpdateSource::Image); 893 return updateSource == UpdateSource::Buffer ? buffer.copyRegion.imageSubresource 894 : image.copyRegion.dstSubresource; 895 } 896 bool isUpdateToLayerLevel(uint32_t layerIndex, uint32_t levelIndex) const; 897 898 enum class UpdateSource 899 { 900 Clear, 901 Buffer, 902 Image, 903 }; 904 struct ClearUpdate 905 { 906 VkClearValue value; 907 uint32_t levelIndex; 908 uint32_t layerIndex; 909 uint32_t layerCount; 910 }; 911 struct BufferUpdate 912 { 913 VkBuffer bufferHandle; 914 VkBufferImageCopy copyRegion; 915 }; 916 struct ImageUpdate 917 { 918 vk::ImageHelper *image; 919 VkImageCopy copyRegion; 920 }; 921 922 UpdateSource updateSource; 923 union 924 { 925 ClearUpdate clear; 926 BufferUpdate buffer; 927 ImageUpdate image; 928 }; 929 }; 930 931 // Vulkan objects. 932 Image mImage; 933 DeviceMemory mDeviceMemory; 934 935 // Image properties. 936 VkExtent3D mExtents; 937 const Format *mFormat; 938 GLint mSamples; 939 940 // Current state. 941 ImageLayout mCurrentLayout; 942 uint32_t mCurrentQueueFamilyIndex; 943 944 // Cached properties. 945 uint32_t mLayerCount; 946 uint32_t mLevelCount; 947 948 // Staging buffer 949 vk::DynamicBuffer mStagingBuffer; 950 std::vector<SubresourceUpdate> mSubresourceUpdates; 951 }; 952 953 class FramebufferHelper : public CommandGraphResource 954 { 955 public: 956 FramebufferHelper(); 957 ~FramebufferHelper() override; 958 959 angle::Result init(ContextVk *contextVk, const VkFramebufferCreateInfo &createInfo); 960 void release(ContextVk *contextVk); 961 valid()962 bool valid() { return mFramebuffer.valid(); } 963 getFramebuffer()964 const Framebuffer &getFramebuffer() const 965 { 966 ASSERT(mFramebuffer.valid()); 967 return mFramebuffer; 968 } 969 getFramebuffer()970 Framebuffer &getFramebuffer() 971 { 972 ASSERT(mFramebuffer.valid()); 973 return mFramebuffer; 974 } 975 976 private: 977 // Vulkan object. 978 Framebuffer mFramebuffer; 979 }; 980 981 // A special command graph resource to hold resource dependencies for dispatch calls. It's the 982 // equivalent of FramebufferHelper, though it doesn't contain a Vulkan object. 983 class DispatchHelper : public CommandGraphResource 984 { 985 public: 986 DispatchHelper(); 987 ~DispatchHelper() override; 988 }; 989 990 class ShaderProgramHelper : angle::NonCopyable 991 { 992 public: 993 ShaderProgramHelper(); 994 ~ShaderProgramHelper(); 995 996 bool valid() const; 997 void destroy(VkDevice device); 998 void release(ContextVk *contextVk); 999 isGraphicsProgram()1000 bool isGraphicsProgram() const 1001 { 1002 ASSERT(mShaders[gl::ShaderType::Vertex].valid() != 1003 mShaders[gl::ShaderType::Compute].valid()); 1004 return mShaders[gl::ShaderType::Vertex].valid(); 1005 } 1006 getShader(gl::ShaderType shaderType)1007 vk::ShaderAndSerial &getShader(gl::ShaderType shaderType) { return mShaders[shaderType].get(); } 1008 1009 void setShader(gl::ShaderType shaderType, RefCounted<ShaderAndSerial> *shader); 1010 1011 // For getting a vk::Pipeline and from the pipeline cache. getGraphicsPipeline(Context * context,RenderPassCache * renderPassCache,const PipelineCache & pipelineCache,Serial currentQueueSerial,const PipelineLayout & pipelineLayout,const GraphicsPipelineDesc & pipelineDesc,const gl::AttributesMask & activeAttribLocationsMask,const gl::ComponentTypeMask & programAttribsTypeMask,const vk::GraphicsPipelineDesc ** descPtrOut,PipelineHelper ** pipelineOut)1012 ANGLE_INLINE angle::Result getGraphicsPipeline( 1013 Context *context, 1014 RenderPassCache *renderPassCache, 1015 const PipelineCache &pipelineCache, 1016 Serial currentQueueSerial, 1017 const PipelineLayout &pipelineLayout, 1018 const GraphicsPipelineDesc &pipelineDesc, 1019 const gl::AttributesMask &activeAttribLocationsMask, 1020 const gl::ComponentTypeMask &programAttribsTypeMask, 1021 const vk::GraphicsPipelineDesc **descPtrOut, 1022 PipelineHelper **pipelineOut) 1023 { 1024 // Pull in a compatible RenderPass. 1025 vk::RenderPass *compatibleRenderPass = nullptr; 1026 ANGLE_TRY(renderPassCache->getCompatibleRenderPass( 1027 context, currentQueueSerial, pipelineDesc.getRenderPassDesc(), &compatibleRenderPass)); 1028 1029 ShaderModule *vertexShader = &mShaders[gl::ShaderType::Vertex].get().get(); 1030 ShaderModule *fragmentShader = mShaders[gl::ShaderType::Fragment].valid() 1031 ? &mShaders[gl::ShaderType::Fragment].get().get() 1032 : nullptr; 1033 1034 return mGraphicsPipelines.getPipeline(context, pipelineCache, *compatibleRenderPass, 1035 pipelineLayout, activeAttribLocationsMask, 1036 programAttribsTypeMask, vertexShader, fragmentShader, 1037 pipelineDesc, descPtrOut, pipelineOut); 1038 } 1039 1040 angle::Result getComputePipeline(Context *context, 1041 const PipelineLayout &pipelineLayout, 1042 PipelineAndSerial **pipelineOut); 1043 1044 private: 1045 gl::ShaderMap<BindingPointer<ShaderAndSerial>> mShaders; 1046 GraphicsPipelineCache mGraphicsPipelines; 1047 1048 // We should probably use PipelineHelper here so we can remove PipelineAndSerial. 1049 PipelineAndSerial mComputePipeline; 1050 }; 1051 } // namespace vk 1052 } // namespace rx 1053 1054 #endif // LIBANGLE_RENDERER_VULKAN_VK_HELPERS_H_ 1055