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 "common/MemoryBuffer.h" 13 #include "libANGLE/renderer/vulkan/ResourceVk.h" 14 #include "libANGLE/renderer/vulkan/vk_cache_utils.h" 15 16 namespace gl 17 { 18 class ImageIndex; 19 } // namespace gl 20 21 namespace rx 22 { 23 namespace vk 24 { 25 constexpr VkBufferUsageFlags kVertexBufferUsageFlags = 26 VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; 27 constexpr VkBufferUsageFlags kIndexBufferUsageFlags = 28 VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; 29 constexpr VkBufferUsageFlags kIndirectBufferUsageFlags = 30 VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; 31 constexpr size_t kVertexBufferAlignment = 4; 32 constexpr size_t kIndexBufferAlignment = 4; 33 constexpr size_t kIndirectBufferAlignment = 4; 34 35 constexpr VkBufferUsageFlags kStagingBufferFlags = 36 VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; 37 constexpr size_t kStagingBufferSize = 1024 * 16; 38 39 using StagingBufferOffsetArray = std::array<VkDeviceSize, 2>; 40 41 struct TextureUnit final 42 { 43 TextureVk *texture; 44 SamplerVk *sampler; 45 }; 46 47 // A dynamic buffer is conceptually an infinitely long buffer. Each time you write to the buffer, 48 // you will always write to a previously unused portion. After a series of writes, you must flush 49 // the buffer data to the device. Buffer lifetime currently assumes that each new allocation will 50 // last as long or longer than each prior allocation. 51 // 52 // Dynamic buffers are used to implement a variety of data streaming operations in Vulkan, such 53 // as for immediate vertex array and element array data, uniform updates, and other dynamic data. 54 // 55 // Internally dynamic buffers keep a collection of VkBuffers. When we write past the end of a 56 // currently active VkBuffer we keep it until it is no longer in use. We then mark it available 57 // for future allocations in a free list. 58 class BufferHelper; 59 class DynamicBuffer : angle::NonCopyable 60 { 61 public: 62 DynamicBuffer(); 63 DynamicBuffer(DynamicBuffer &&other); 64 ~DynamicBuffer(); 65 66 // Init is called after the buffer creation so that the alignment can be specified later. 67 void init(RendererVk *renderer, 68 VkBufferUsageFlags usage, 69 size_t alignment, 70 size_t initialSize, 71 bool hostVisible); 72 73 // This call will allocate a new region at the end of the buffer. It internally may trigger 74 // a new buffer to be created (which is returned in the optional parameter 75 // `newBufferAllocatedOut`). The new region will be in the returned buffer at given offset. If 76 // a memory pointer is given, the buffer will be automatically map()ed. 77 angle::Result allocate(ContextVk *contextVk, 78 size_t sizeInBytes, 79 uint8_t **ptrOut, 80 VkBuffer *bufferOut, 81 VkDeviceSize *offsetOut, 82 bool *newBufferAllocatedOut); 83 84 // After a sequence of writes, call flush to ensure the data is visible to the device. 85 angle::Result flush(ContextVk *contextVk); 86 87 // After a sequence of writes, call invalidate to ensure the data is visible to the host. 88 angle::Result invalidate(ContextVk *contextVk); 89 90 // This releases resources when they might currently be in use. 91 void release(RendererVk *renderer); 92 93 // This releases all the buffers that have been allocated since this was last called. 94 void releaseInFlightBuffers(ContextVk *contextVk); 95 96 // This frees resources immediately. 97 void destroy(RendererVk *renderer); 98 getCurrentBuffer()99 BufferHelper *getCurrentBuffer() { return mBuffer; } 100 101 void updateAlignment(RendererVk *renderer, size_t alignment); 102 103 // For testing only! 104 void setMinimumSizeForTesting(size_t minSize); 105 106 private: 107 void reset(); 108 angle::Result allocateNewBuffer(ContextVk *contextVk); 109 void releaseBufferListToRenderer(RendererVk *renderer, std::vector<BufferHelper *> *buffers); 110 void destroyBufferList(RendererVk *renderer, std::vector<BufferHelper *> *buffers); 111 112 VkBufferUsageFlags mUsage; 113 bool mHostVisible; 114 size_t mInitialSize; 115 BufferHelper *mBuffer; 116 uint32_t mNextAllocationOffset; 117 uint32_t mLastFlushOrInvalidateOffset; 118 size_t mSize; 119 size_t mAlignment; 120 121 std::vector<BufferHelper *> mInFlightBuffers; 122 std::vector<BufferHelper *> mBufferFreeList; 123 }; 124 125 // Based off of the DynamicBuffer class, DynamicShadowBuffer provides 126 // a similar conceptually infinitely long buffer that will only be written 127 // to and read by the CPU. This can be used to provide CPU cached copies of 128 // GPU-read only buffers. The value add here is that when an app requests 129 // CPU access to a buffer we can fullfil such a request in O(1) time since 130 // we don't need to wait for GPU to be done with in-flight commands. 131 // 132 // The hidden cost here is that any operation that updates a buffer, either 133 // through a buffer sub data update or a buffer-to-buffer copy will have an 134 // additional overhead of having to update its CPU only buffer 135 class DynamicShadowBuffer : public angle::NonCopyable 136 { 137 public: 138 DynamicShadowBuffer(); 139 DynamicShadowBuffer(DynamicShadowBuffer &&other); 140 ~DynamicShadowBuffer(); 141 142 // Initialize the DynamicShadowBuffer. 143 void init(size_t initialSize); 144 145 // Returns whether this DynamicShadowBuffer is active valid()146 ANGLE_INLINE bool valid() { return (mSize != 0); } 147 148 // This call will actually allocate a new CPU only memory from the heap. 149 // The size can be different than the one specified during `init`. 150 angle::Result allocate(size_t sizeInBytes); 151 updateData(const uint8_t * data,size_t size,size_t offset)152 ANGLE_INLINE void updateData(const uint8_t *data, size_t size, size_t offset) 153 { 154 ASSERT(!mBuffer.empty()); 155 // Memcopy data into the buffer 156 memcpy((mBuffer.data() + offset), data, size); 157 } 158 159 // Map the CPU only buffer and return the pointer. We map the entire buffer for now. map(size_t offset,void ** mapPtr)160 ANGLE_INLINE void map(size_t offset, void **mapPtr) 161 { 162 ASSERT(mapPtr); 163 ASSERT(!mBuffer.empty()); 164 *mapPtr = mBuffer.data() + offset; 165 } 166 167 // Unmap the CPU only buffer, NOOP for now unmap()168 ANGLE_INLINE void unmap() {} 169 170 // This releases resources when they might currently be in use. 171 void release(); 172 173 // This frees resources immediately. 174 void destroy(VkDevice device); 175 getCurrentBuffer()176 ANGLE_INLINE uint8_t *getCurrentBuffer() 177 { 178 ASSERT(!mBuffer.empty()); 179 return mBuffer.data(); 180 } 181 getCurrentBuffer()182 ANGLE_INLINE const uint8_t *getCurrentBuffer() const 183 { 184 ASSERT(!mBuffer.empty()); 185 return mBuffer.data(); 186 } 187 188 private: 189 void reset(); 190 191 size_t mInitialSize; 192 size_t mSize; 193 angle::MemoryBuffer mBuffer; 194 }; 195 196 // Uses DescriptorPool to allocate descriptor sets as needed. If a descriptor pool becomes full, we 197 // allocate new pools internally as needed. RendererVk takes care of the lifetime of the discarded 198 // pools. Note that we used a fixed layout for descriptor pools in ANGLE. Uniform buffers must 199 // use set zero and combined Image Samplers must use set 1. We conservatively count each new set 200 // using the maximum number of descriptor sets and buffers with each allocation. Currently: 2 201 // (Vertex/Fragment) uniform buffers and 64 (MAX_ACTIVE_TEXTURES) image/samplers. 202 203 // Shared handle to a descriptor pool. Each helper is allocated from the dynamic descriptor pool. 204 // Can be used to share descriptor pools between multiple ProgramVks and the ContextVk. 205 class DescriptorPoolHelper 206 { 207 public: 208 DescriptorPoolHelper(); 209 ~DescriptorPoolHelper(); 210 valid()211 bool valid() { return mDescriptorPool.valid(); } 212 213 bool hasCapacity(uint32_t descriptorSetCount) const; 214 angle::Result init(Context *context, 215 const std::vector<VkDescriptorPoolSize> &poolSizes, 216 uint32_t maxSets); 217 void destroy(VkDevice device); 218 void release(ContextVk *contextVk); 219 220 angle::Result allocateSets(ContextVk *contextVk, 221 const VkDescriptorSetLayout *descriptorSetLayout, 222 uint32_t descriptorSetCount, 223 VkDescriptorSet *descriptorSetsOut); 224 updateSerial(Serial serial)225 void updateSerial(Serial serial) { mMostRecentSerial = serial; } 226 getSerial()227 Serial getSerial() const { return mMostRecentSerial; } 228 229 private: 230 uint32_t mFreeDescriptorSets; 231 DescriptorPool mDescriptorPool; 232 Serial mMostRecentSerial; 233 }; 234 235 using RefCountedDescriptorPoolHelper = RefCounted<DescriptorPoolHelper>; 236 using RefCountedDescriptorPoolBinding = BindingPointer<DescriptorPoolHelper>; 237 238 class DynamicDescriptorPool final : angle::NonCopyable 239 { 240 public: 241 DynamicDescriptorPool(); 242 ~DynamicDescriptorPool(); 243 244 // The DynamicDescriptorPool only handles one pool size at this time. 245 // Note that setSizes[i].descriptorCount is expected to be the number of descriptors in 246 // an individual set. The pool size will be calculated accordingly. 247 angle::Result init(ContextVk *contextVk, 248 const VkDescriptorPoolSize *setSizes, 249 uint32_t setSizeCount); 250 void destroy(VkDevice device); 251 void release(ContextVk *contextVk); 252 253 // We use the descriptor type to help count the number of free sets. 254 // 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)255 ANGLE_INLINE angle::Result allocateSets(ContextVk *contextVk, 256 const VkDescriptorSetLayout *descriptorSetLayout, 257 uint32_t descriptorSetCount, 258 RefCountedDescriptorPoolBinding *bindingOut, 259 VkDescriptorSet *descriptorSetsOut) 260 { 261 bool ignoreNewPoolAllocated; 262 return allocateSetsAndGetInfo(contextVk, descriptorSetLayout, descriptorSetCount, 263 bindingOut, descriptorSetsOut, &ignoreNewPoolAllocated); 264 } 265 266 // We use the descriptor type to help count the number of free sets. 267 // By convention, sets are indexed according to the constants in vk_cache_utils.h. 268 angle::Result allocateSetsAndGetInfo(ContextVk *contextVk, 269 const VkDescriptorSetLayout *descriptorSetLayout, 270 uint32_t descriptorSetCount, 271 RefCountedDescriptorPoolBinding *bindingOut, 272 VkDescriptorSet *descriptorSetsOut, 273 bool *newPoolAllocatedOut); 274 275 // For testing only! 276 void setMaxSetsPerPoolForTesting(uint32_t maxSetsPerPool); 277 278 private: 279 angle::Result allocateNewPool(ContextVk *contextVk); 280 281 uint32_t mMaxSetsPerPool; 282 size_t mCurrentPoolIndex; 283 std::vector<RefCountedDescriptorPoolHelper *> mDescriptorPools; 284 std::vector<VkDescriptorPoolSize> mPoolSizes; 285 }; 286 287 template <typename Pool> 288 class DynamicallyGrowingPool : angle::NonCopyable 289 { 290 public: 291 DynamicallyGrowingPool(); 292 virtual ~DynamicallyGrowingPool(); 293 isValid()294 bool isValid() { return mPoolSize > 0; } 295 296 protected: 297 angle::Result initEntryPool(Context *contextVk, uint32_t poolSize); 298 void destroyEntryPool(); 299 300 // Checks to see if any pool is already free, in which case it sets it as current pool and 301 // returns true. 302 bool findFreeEntryPool(ContextVk *contextVk); 303 304 // Allocates a new entry and initializes it with the given pool. 305 angle::Result allocateNewEntryPool(ContextVk *contextVk, Pool &&pool); 306 307 // Called by the implementation whenever an entry is freed. 308 void onEntryFreed(ContextVk *contextVk, size_t poolIndex); 309 310 // The pool size, to know when a pool is completely freed. 311 uint32_t mPoolSize; 312 313 std::vector<Pool> mPools; 314 315 struct PoolStats 316 { 317 // A count corresponding to each pool indicating how many of its allocated entries 318 // have been freed. Once that value reaches mPoolSize for each pool, that pool is considered 319 // free and reusable. While keeping a bitset would allow allocation of each index, the 320 // slight runtime overhead of finding free indices is not worth the slight memory overhead 321 // of creating new pools when unnecessary. 322 uint32_t freedCount; 323 // The serial of the renderer is stored on each object free to make sure no 324 // new allocations are made from the pool until it's not in use. 325 Serial serial; 326 }; 327 std::vector<PoolStats> mPoolStats; 328 329 // Index into mPools indicating pool we are currently allocating from. 330 size_t mCurrentPool; 331 // Index inside mPools[mCurrentPool] indicating which index can be allocated next. 332 uint32_t mCurrentFreeEntry; 333 }; 334 335 // DynamicQueryPool allocates indices out of QueryPool as needed. Once a QueryPool is exhausted, 336 // another is created. The query pools live permanently, but are recycled as indices get freed. 337 338 // These are arbitrary default sizes for query pools. 339 constexpr uint32_t kDefaultOcclusionQueryPoolSize = 64; 340 constexpr uint32_t kDefaultTimestampQueryPoolSize = 64; 341 342 class QueryHelper; 343 344 class DynamicQueryPool final : public DynamicallyGrowingPool<QueryPool> 345 { 346 public: 347 DynamicQueryPool(); 348 ~DynamicQueryPool() override; 349 350 angle::Result init(ContextVk *contextVk, VkQueryType type, uint32_t poolSize); 351 void destroy(VkDevice device); 352 353 angle::Result allocateQuery(ContextVk *contextVk, QueryHelper *queryOut); 354 void freeQuery(ContextVk *contextVk, QueryHelper *query); 355 getQueryPool(size_t index)356 const QueryPool &getQueryPool(size_t index) const { return mPools[index]; } 357 358 private: 359 angle::Result allocateNewPool(ContextVk *contextVk); 360 361 // Information required to create new query pools 362 VkQueryType mQueryType; 363 }; 364 365 // Queries in vulkan are identified by the query pool and an index for a query within that pool. 366 // Unlike other pools, such as descriptor pools where an allocation returns an independent object 367 // from the pool, the query allocations are not done through a Vulkan function and are only an 368 // integer index. 369 // 370 // Furthermore, to support arbitrarily large number of queries, DynamicQueryPool creates query pools 371 // of a fixed size as needed and allocates indices within those pools. 372 // 373 // The QueryHelper class below keeps the pool and index pair together. 374 class QueryHelper final 375 { 376 public: 377 QueryHelper(); 378 ~QueryHelper(); 379 380 void init(const DynamicQueryPool *dynamicQueryPool, 381 const size_t queryPoolIndex, 382 uint32_t query); 383 void deinit(); 384 valid()385 bool valid() const { return mDynamicQueryPool != nullptr; } 386 387 angle::Result beginQuery(ContextVk *contextVk); 388 angle::Result endQuery(ContextVk *contextVk); 389 390 // for occlusion query 391 void beginOcclusionQuery(ContextVk *contextVk, 392 PrimaryCommandBuffer *primaryCommands, 393 CommandBuffer *renderPassCommandBuffer); 394 void endOcclusionQuery(ContextVk *contextVk, CommandBuffer *renderPassCommandBuffer); 395 396 angle::Result flushAndWriteTimestamp(ContextVk *contextVk); 397 void writeTimestamp(ContextVk *contextVk, PrimaryCommandBuffer *primary); 398 getStoredQueueSerial()399 Serial getStoredQueueSerial() { return mMostRecentSerial; } 400 bool hasPendingWork(ContextVk *contextVk); 401 402 angle::Result getUint64ResultNonBlocking(ContextVk *contextVk, 403 uint64_t *resultOut, 404 bool *availableOut); 405 angle::Result getUint64Result(ContextVk *contextVk, uint64_t *resultOut); 406 407 private: 408 friend class DynamicQueryPool; getQueryPool()409 const QueryPool &getQueryPool() const 410 { 411 ASSERT(valid()); 412 return mDynamicQueryPool->getQueryPool(mQueryPoolIndex); 413 } 414 415 const DynamicQueryPool *mDynamicQueryPool; 416 size_t mQueryPoolIndex; 417 uint32_t mQuery; 418 Serial mMostRecentSerial; 419 }; 420 421 // DynamicSemaphorePool allocates semaphores as needed. It uses a std::vector 422 // as a pool to allocate many semaphores at once. The pools live permanently, 423 // but are recycled as semaphores get freed. 424 425 // These are arbitrary default sizes for semaphore pools. 426 constexpr uint32_t kDefaultSemaphorePoolSize = 64; 427 428 class SemaphoreHelper; 429 430 class DynamicSemaphorePool final : public DynamicallyGrowingPool<std::vector<Semaphore>> 431 { 432 public: 433 DynamicSemaphorePool(); 434 ~DynamicSemaphorePool() override; 435 436 angle::Result init(ContextVk *contextVk, uint32_t poolSize); 437 void destroy(VkDevice device); 438 isValid()439 bool isValid() { return mPoolSize > 0; } 440 441 // autoFree can be used to allocate a semaphore that's expected to be freed at the end of the 442 // frame. This renders freeSemaphore unnecessary and saves an eventual search. 443 angle::Result allocateSemaphore(ContextVk *contextVk, SemaphoreHelper *semaphoreOut); 444 void freeSemaphore(ContextVk *contextVk, SemaphoreHelper *semaphore); 445 446 private: 447 angle::Result allocateNewPool(ContextVk *contextVk); 448 }; 449 450 // Semaphores that are allocated from the semaphore pool are encapsulated in a helper object, 451 // keeping track of where in the pool they are allocated from. 452 class SemaphoreHelper final : angle::NonCopyable 453 { 454 public: 455 SemaphoreHelper(); 456 ~SemaphoreHelper(); 457 458 SemaphoreHelper(SemaphoreHelper &&other); 459 SemaphoreHelper &operator=(SemaphoreHelper &&other); 460 461 void init(const size_t semaphorePoolIndex, const Semaphore *semaphore); 462 void deinit(); 463 getSemaphore()464 const Semaphore *getSemaphore() const { return mSemaphore; } 465 466 // Used only by DynamicSemaphorePool. getSemaphorePoolIndex()467 size_t getSemaphorePoolIndex() const { return mSemaphorePoolIndex; } 468 469 private: 470 size_t mSemaphorePoolIndex; 471 const Semaphore *mSemaphore; 472 }; 473 474 // This class' responsibility is to create index buffers needed to support line loops in Vulkan. 475 // In the setup phase of drawing, the createIndexBuffer method should be called with the 476 // current draw call parameters. If an element array buffer is bound for an indexed draw, use 477 // createIndexBufferFromElementArrayBuffer. 478 // 479 // If the user wants to draw a loop between [v1, v2, v3], we will create an indexed buffer with 480 // these indexes: [0, 1, 2, 3, 0] to emulate the loop. 481 class LineLoopHelper final : angle::NonCopyable 482 { 483 public: 484 LineLoopHelper(RendererVk *renderer); 485 ~LineLoopHelper(); 486 487 angle::Result getIndexBufferForDrawArrays(ContextVk *contextVk, 488 uint32_t clampedVertexCount, 489 GLint firstVertex, 490 BufferHelper **bufferOut, 491 VkDeviceSize *offsetOut); 492 493 angle::Result getIndexBufferForElementArrayBuffer(ContextVk *contextVk, 494 BufferVk *elementArrayBufferVk, 495 gl::DrawElementsType glIndexType, 496 int indexCount, 497 intptr_t elementArrayOffset, 498 BufferHelper **bufferOut, 499 VkDeviceSize *bufferOffsetOut, 500 uint32_t *indexCountOut); 501 502 angle::Result streamIndices(ContextVk *contextVk, 503 gl::DrawElementsType glIndexType, 504 GLsizei indexCount, 505 const uint8_t *srcPtr, 506 BufferHelper **bufferOut, 507 VkDeviceSize *bufferOffsetOut, 508 uint32_t *indexCountOut); 509 510 angle::Result streamIndicesIndirect(ContextVk *contextVk, 511 gl::DrawElementsType glIndexType, 512 BufferHelper *indexBuffer, 513 BufferHelper *indirectBuffer, 514 VkDeviceSize indirectBufferOffset, 515 BufferHelper **indexBufferOut, 516 VkDeviceSize *indexBufferOffsetOut, 517 BufferHelper **indirectBufferOut, 518 VkDeviceSize *indirectBufferOffsetOut); 519 520 angle::Result streamArrayIndirect(ContextVk *contextVk, 521 size_t vertexCount, 522 BufferHelper *arrayIndirectBuffer, 523 VkDeviceSize arrayIndirectBufferOffset, 524 BufferHelper **indexBufferOut, 525 VkDeviceSize *indexBufferOffsetOut, 526 BufferHelper **indexIndirectBufferOut, 527 VkDeviceSize *indexIndirectBufferOffsetOut); 528 529 void release(ContextVk *contextVk); 530 void destroy(RendererVk *renderer); 531 532 static void Draw(uint32_t count, uint32_t baseVertex, CommandBuffer *commandBuffer); 533 534 private: 535 DynamicBuffer mDynamicIndexBuffer; 536 DynamicBuffer mDynamicIndirectBuffer; 537 }; 538 539 class FramebufferHelper; 540 541 class BufferHelper final : public Resource 542 { 543 public: 544 BufferHelper(); 545 ~BufferHelper() override; 546 547 angle::Result init(ContextVk *contextVk, 548 const VkBufferCreateInfo &createInfo, 549 VkMemoryPropertyFlags memoryPropertyFlags); 550 void destroy(RendererVk *renderer); 551 552 void release(RendererVk *renderer); 553 valid()554 bool valid() const { return mBuffer.valid(); } getBuffer()555 const Buffer &getBuffer() const { return mBuffer; } getSize()556 VkDeviceSize getSize() const { return mSize; } isHostVisible()557 bool isHostVisible() const 558 { 559 return (mMemoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0; 560 } 561 562 // Set write access mask when the buffer is modified externally, e.g. by host. There is no 563 // graph resource to create a dependency to. onExternalWrite(VkAccessFlags writeAccessType)564 void onExternalWrite(VkAccessFlags writeAccessType) { mCurrentWriteAccess |= writeAccessType; } 565 566 // Also implicitly sets up the correct barriers. 567 angle::Result copyFromBuffer(ContextVk *contextVk, 568 BufferHelper *srcBuffer, 569 VkAccessFlags bufferAccessType, 570 const VkBufferCopy ©Region); 571 572 // Note: currently only one view is allowed. If needs be, multiple views can be created 573 // based on format. 574 angle::Result initBufferView(ContextVk *contextVk, const Format &format); 575 getBufferView()576 const BufferView &getBufferView() const 577 { 578 ASSERT(mBufferView.valid()); 579 return mBufferView; 580 } 581 getViewFormat()582 const Format &getViewFormat() const 583 { 584 ASSERT(mViewFormat); 585 return *mViewFormat; 586 } 587 map(ContextVk * contextVk,uint8_t ** ptrOut)588 angle::Result map(ContextVk *contextVk, uint8_t **ptrOut) 589 { 590 if (!mMappedMemory) 591 { 592 ANGLE_TRY(mapImpl(contextVk)); 593 } 594 *ptrOut = mMappedMemory; 595 return angle::Result::Continue; 596 } 597 mapWithOffset(ContextVk * contextVk,uint8_t ** ptrOut,size_t offset)598 angle::Result mapWithOffset(ContextVk *contextVk, uint8_t **ptrOut, size_t offset) 599 { 600 uint8_t *mapBufPointer; 601 ANGLE_TRY(map(contextVk, &mapBufPointer)); 602 *ptrOut = mapBufPointer + offset; 603 return angle::Result::Continue; 604 } 605 606 void unmap(RendererVk *renderer); 607 608 // After a sequence of writes, call flush to ensure the data is visible to the device. 609 angle::Result flush(RendererVk *renderer, VkDeviceSize offset, VkDeviceSize size); 610 611 // After a sequence of writes, call invalidate to ensure the data is visible to the host. 612 angle::Result invalidate(RendererVk *renderer, VkDeviceSize offset, VkDeviceSize size); 613 614 void changeQueue(uint32_t newQueueFamilyIndex, CommandBuffer *commandBuffer); 615 616 // Currently always returns false. Should be smarter about accumulation. 617 bool canAccumulateRead(ContextVk *contextVk, VkAccessFlags readAccessType); 618 bool canAccumulateWrite(ContextVk *contextVk, VkAccessFlags writeAccessType); 619 620 void updateReadBarrier(VkAccessFlags readAccessType, 621 VkAccessFlags *barrierSrcOut, 622 VkAccessFlags *barrierDstOut); 623 624 void updateWriteBarrier(VkAccessFlags writeAccessType, 625 VkAccessFlags *barrierSrcOut, 626 VkAccessFlags *barrierDstOut); 627 628 private: 629 angle::Result mapImpl(ContextVk *contextVk); needsOnReadBarrier(VkAccessFlags readAccessType,VkAccessFlags * barrierSrcOut,VkAccessFlags * barrierDstOut)630 bool needsOnReadBarrier(VkAccessFlags readAccessType, 631 VkAccessFlags *barrierSrcOut, 632 VkAccessFlags *barrierDstOut) 633 { 634 bool needsBarrier = 635 mCurrentWriteAccess != 0 && (mCurrentReadAccess & readAccessType) != readAccessType; 636 637 *barrierSrcOut = mCurrentWriteAccess; 638 *barrierDstOut = readAccessType; 639 640 mCurrentReadAccess |= readAccessType; 641 return needsBarrier; 642 } 643 bool needsOnWriteBarrier(VkAccessFlags writeAccessType, 644 VkAccessFlags *barrierSrcOut, 645 VkAccessFlags *barrierDstOut); 646 647 angle::Result initializeNonZeroMemory(Context *context, VkDeviceSize size); 648 649 // Vulkan objects. 650 Buffer mBuffer; 651 BufferView mBufferView; 652 Allocation mAllocation; 653 654 // Cached properties. 655 VkMemoryPropertyFlags mMemoryPropertyFlags; 656 VkDeviceSize mSize; 657 uint8_t *mMappedMemory; 658 const Format *mViewFormat; 659 uint32_t mCurrentQueueFamilyIndex; 660 661 // For memory barriers. 662 VkFlags mCurrentWriteAccess; 663 VkFlags mCurrentReadAccess; 664 }; 665 666 // Imagine an image going through a few layout transitions: 667 // 668 // srcStage 1 dstStage 2 srcStage 2 dstStage 3 669 // Layout 1 ------Transition 1-----> Layout 2 ------Transition 2------> Layout 3 670 // srcAccess 1 dstAccess 2 srcAccess 2 dstAccess 3 671 // \_________________ ___________________/ 672 // \/ 673 // A transition 674 // 675 // Every transition requires 6 pieces of information: from/to layouts, src/dst stage masks and 676 // src/dst access masks. At the moment we decide to transition the image to Layout 2 (i.e. 677 // Transition 1), we need to have Layout 1, srcStage 1 and srcAccess 1 stored as history of the 678 // image. To perform the transition, we need to know Layout 2, dstStage 2 and dstAccess 2. 679 // Additionally, we need to know srcStage 2 and srcAccess 2 to retain them for the next transition. 680 // 681 // That is, with the history kept, on every new transition we need 5 pieces of new information: 682 // layout/dstStage/dstAccess to transition into the layout, and srcStage/srcAccess for the future 683 // transition out from it. Given the small number of possible combinations of these values, an 684 // enum is used were each value encapsulates these 5 pieces of information: 685 // 686 // +--------------------------------+ 687 // srcStage 1 | dstStage 2 srcStage 2 | dstStage 3 688 // Layout 1 ------Transition 1-----> Layout 2 ------Transition 2------> Layout 3 689 // srcAccess 1 |dstAccess 2 srcAccess 2| dstAccess 3 690 // +--------------- ---------------+ 691 // \/ 692 // One enum value 693 // 694 // Note that, while generally dstStage for the to-transition and srcStage for the from-transition 695 // are the same, they may occasionally be BOTTOM_OF_PIPE and TOP_OF_PIPE respectively. 696 enum class ImageLayout 697 { 698 Undefined = 0, 699 ExternalPreInitialized = 1, 700 ExternalShadersReadOnly = 2, 701 ExternalShadersWrite = 3, 702 TransferSrc = 4, 703 TransferDst = 5, 704 VertexShaderReadOnly = 6, 705 VertexShaderWrite = 7, 706 GeometryShaderReadOnly = 8, 707 GeometryShaderWrite = 9, 708 FragmentShaderReadOnly = 10, 709 FragmentShaderWrite = 11, 710 ComputeShaderReadOnly = 12, 711 ComputeShaderWrite = 13, 712 AllGraphicsShadersReadOnly = 14, 713 AllGraphicsShadersReadWrite = 15, 714 ColorAttachment = 16, 715 DepthStencilAttachment = 17, 716 Present = 18, 717 718 InvalidEnum = 19, 719 EnumCount = 19, 720 }; 721 722 VkImageLayout ConvertImageLayoutToVkImageLayout(ImageLayout imageLayout); 723 724 class ImageHelper final : public Resource, public angle::Subject 725 { 726 public: 727 ImageHelper(); 728 ImageHelper(ImageHelper &&other); 729 ~ImageHelper() override; 730 731 void initStagingBuffer(RendererVk *renderer, 732 const Format &format, 733 VkBufferUsageFlags usageFlags, 734 size_t initialSize); 735 736 angle::Result init(Context *context, 737 gl::TextureType textureType, 738 const VkExtent3D &extents, 739 const Format &format, 740 GLint samples, 741 VkImageUsageFlags usage, 742 uint32_t baseLevel, 743 uint32_t maxLevel, 744 uint32_t mipLevels, 745 uint32_t layerCount); 746 angle::Result initExternal(Context *context, 747 gl::TextureType textureType, 748 const VkExtent3D &extents, 749 const Format &format, 750 GLint samples, 751 VkImageUsageFlags usage, 752 ImageLayout initialLayout, 753 const void *externalImageCreateInfo, 754 uint32_t baseLevel, 755 uint32_t maxLevel, 756 uint32_t mipLevels, 757 uint32_t layerCount); 758 angle::Result initMemory(Context *context, 759 const MemoryProperties &memoryProperties, 760 VkMemoryPropertyFlags flags); 761 angle::Result initExternalMemory(Context *context, 762 const MemoryProperties &memoryProperties, 763 const VkMemoryRequirements &memoryRequirements, 764 const void *extraAllocationInfo, 765 uint32_t currentQueueFamilyIndex, 766 VkMemoryPropertyFlags flags); 767 angle::Result initLayerImageView(Context *context, 768 gl::TextureType textureType, 769 VkImageAspectFlags aspectMask, 770 const gl::SwizzleState &swizzleMap, 771 ImageView *imageViewOut, 772 uint32_t baseMipLevel, 773 uint32_t levelCount, 774 uint32_t baseArrayLayer, 775 uint32_t layerCount) const; 776 angle::Result initImageView(Context *context, 777 gl::TextureType textureType, 778 VkImageAspectFlags aspectMask, 779 const gl::SwizzleState &swizzleMap, 780 ImageView *imageViewOut, 781 uint32_t baseMipLevel, 782 uint32_t levelCount); 783 // Create a 2D[Array] for staging purposes. Used by: 784 // 785 // - TextureVk::copySubImageImplWithDraw 786 // - FramebufferVk::readPixelsImpl 787 // 788 angle::Result init2DStaging(Context *context, 789 const MemoryProperties &memoryProperties, 790 const gl::Extents &glExtents, 791 const Format &format, 792 VkImageUsageFlags usage, 793 uint32_t layerCount); 794 795 void releaseImage(RendererVk *rendererVk); 796 void releaseStagingBuffer(RendererVk *renderer); 797 valid()798 bool valid() const { return mImage.valid(); } 799 800 VkImageAspectFlags getAspectFlags() const; 801 // True if image contains both depth & stencil aspects 802 bool isCombinedDepthStencilFormat() const; 803 void destroy(RendererVk *renderer); release(RendererVk * renderer)804 void release(RendererVk *renderer) { destroy(renderer); } 805 806 void init2DWeakReference(Context *context, 807 VkImage handle, 808 const gl::Extents &glExtents, 809 const Format &format, 810 GLint samples); 811 void resetImageWeakReference(); 812 getImage()813 const Image &getImage() const { return mImage; } getDeviceMemory()814 const DeviceMemory &getDeviceMemory() const { return mDeviceMemory; } 815 getType()816 VkImageType getType() const { return mImageType; } getExtents()817 const VkExtent3D &getExtents() const { return mExtents; } getLayerCount()818 uint32_t getLayerCount() const { return mLayerCount; } getLevelCount()819 uint32_t getLevelCount() const { return mLevelCount; } getFormat()820 const Format &getFormat() const { return *mFormat; } getSamples()821 GLint getSamples() const { return mSamples; } 822 setCurrentImageLayout(ImageLayout newLayout)823 void setCurrentImageLayout(ImageLayout newLayout) { mCurrentLayout = newLayout; } getCurrentImageLayout()824 ImageLayout getCurrentImageLayout() const { return mCurrentLayout; } 825 VkImageLayout getCurrentLayout() const; 826 827 // Helper function to calculate the extents of a render target created for a certain mip of the 828 // image. 829 gl::Extents getLevelExtents2D(uint32_t level) const; 830 831 // Clear either color or depth/stencil based on image format. 832 void clear(VkImageAspectFlags aspectFlags, 833 const VkClearValue &value, 834 uint32_t mipLevel, 835 uint32_t baseArrayLayer, 836 uint32_t layerCount, 837 CommandBuffer *commandBuffer); 838 839 gl::Extents getSize(const gl::ImageIndex &index) const; 840 841 // Return unique Serial for underlying image, first assigning it if it hasn't been set yet 842 Serial getAssignSerial(ContextVk *contextVk); resetSerial()843 void resetSerial() { mSerial = rx::kZeroSerial; } 844 845 static void Copy(ImageHelper *srcImage, 846 ImageHelper *dstImage, 847 const gl::Offset &srcOffset, 848 const gl::Offset &dstOffset, 849 const gl::Extents ©Size, 850 const VkImageSubresourceLayers &srcSubresources, 851 const VkImageSubresourceLayers &dstSubresources, 852 CommandBuffer *commandBuffer); 853 854 angle::Result generateMipmapsWithBlit(ContextVk *contextVk, GLuint maxLevel); 855 856 // Resolve this image into a destination image. This image should be in the TransferSrc layout. 857 // The destination image is automatically transitioned into TransferDst. 858 void resolve(ImageHelper *dest, const VkImageResolve ®ion, CommandBuffer *commandBuffer); 859 860 // Data staging 861 void removeStagedUpdates(ContextVk *contextVk, const gl::ImageIndex &index); 862 863 angle::Result stageSubresourceUpdateImpl(ContextVk *contextVk, 864 const gl::ImageIndex &index, 865 const gl::Extents &glExtents, 866 const gl::Offset &offset, 867 const gl::InternalFormat &formatInfo, 868 const gl::PixelUnpackState &unpack, 869 GLenum type, 870 const uint8_t *pixels, 871 const Format &vkFormat, 872 const GLuint inputRowPitch, 873 const GLuint inputDepthPitch, 874 const GLuint inputSkipBytes); 875 876 angle::Result stageSubresourceUpdate(ContextVk *contextVk, 877 const gl::ImageIndex &index, 878 const gl::Extents &glExtents, 879 const gl::Offset &offset, 880 const gl::InternalFormat &formatInfo, 881 const gl::PixelUnpackState &unpack, 882 GLenum type, 883 const uint8_t *pixels, 884 const Format &vkFormat); 885 886 angle::Result stageSubresourceUpdateAndGetData(ContextVk *contextVk, 887 size_t allocationSize, 888 const gl::ImageIndex &imageIndex, 889 const gl::Extents &glExtents, 890 const gl::Offset &offset, 891 uint8_t **destData); 892 893 angle::Result stageSubresourceUpdateFromBuffer(ContextVk *contextVk, 894 size_t allocationSize, 895 uint32_t mipLevel, 896 uint32_t baseArrayLayer, 897 uint32_t layerCount, 898 const VkExtent3D &extent, 899 const VkOffset3D &offset, 900 BufferHelper *stagingBuffer, 901 StagingBufferOffsetArray stagingOffsets); 902 903 angle::Result stageSubresourceUpdateFromFramebuffer(const gl::Context *context, 904 const gl::ImageIndex &index, 905 const gl::Rectangle &sourceArea, 906 const gl::Offset &dstOffset, 907 const gl::Extents &dstExtent, 908 const gl::InternalFormat &formatInfo, 909 FramebufferVk *framebufferVk); 910 911 void stageSubresourceUpdateFromImage(ImageHelper *image, 912 const gl::ImageIndex &index, 913 const gl::Offset &destOffset, 914 const gl::Extents &glExtents, 915 const VkImageType imageType); 916 917 // Stage a clear based on robust resource init. 918 void stageRobustResourceClear(const gl::ImageIndex &index, const vk::Format &format); 919 void stageSubresourceClear(const gl::ImageIndex &index); 920 921 // This will use the underlying dynamic buffer to allocate some memory to be used as a src or 922 // dst. 923 angle::Result allocateStagingMemory(ContextVk *contextVk, 924 size_t sizeInBytes, 925 uint8_t **ptrOut, 926 BufferHelper **bufferOut, 927 StagingBufferOffsetArray *offsetOut, 928 bool *newBufferAllocatedOut); 929 930 // Flushes staged updates to a range of levels and layers from start to (but not including) end. 931 // Due to the nature of updates (done wholly to a VkImageSubresourceLayers), some unsolicited 932 // layers may also be updated. 933 angle::Result flushStagedUpdates(ContextVk *contextVk, 934 uint32_t levelStart, 935 uint32_t levelEnd, 936 uint32_t layerStart, 937 uint32_t layerEnd, 938 CommandBuffer *commandBuffer); 939 // Creates a command buffer and flushes all staged updates. This is used for one-time 940 // initialization of resources that we don't expect to accumulate further staged updates, such 941 // as with renderbuffers or surface images. 942 angle::Result flushAllStagedUpdates(ContextVk *contextVk); 943 944 bool isUpdateStaged(uint32_t level, uint32_t layer); hasStagedUpdates()945 bool hasStagedUpdates() const { return !mSubresourceUpdates.empty(); } 946 947 // changeLayout automatically skips the layout change if it's unnecessary. This function can be 948 // used to prevent creating a command graph node and subsequently a command buffer for the sole 949 // purpose of performing a transition (which may then not be issued). 950 bool isLayoutChangeNecessary(ImageLayout newLayout) const; 951 952 template <typename CommandBufferT> changeLayout(VkImageAspectFlags aspectMask,ImageLayout newLayout,CommandBufferT * commandBuffer)953 void changeLayout(VkImageAspectFlags aspectMask, 954 ImageLayout newLayout, 955 CommandBufferT *commandBuffer) 956 { 957 if (!isLayoutChangeNecessary(newLayout)) 958 { 959 return; 960 } 961 962 forceChangeLayoutAndQueue(aspectMask, newLayout, mCurrentQueueFamilyIndex, commandBuffer); 963 } 964 isQueueChangeNeccesary(uint32_t newQueueFamilyIndex)965 bool isQueueChangeNeccesary(uint32_t newQueueFamilyIndex) const 966 { 967 return mCurrentQueueFamilyIndex != newQueueFamilyIndex; 968 } 969 970 void changeLayoutAndQueue(VkImageAspectFlags aspectMask, 971 ImageLayout newLayout, 972 uint32_t newQueueFamilyIndex, 973 CommandBuffer *commandBuffer); 974 975 // If the image is used externally to GL, its layout could be different from ANGLE's internal 976 // state. This function is used to inform ImageHelper of an external layout change. 977 void onExternalLayoutChange(ImageLayout newLayout); 978 979 uint32_t getBaseLevel(); 980 void setBaseAndMaxLevels(uint32_t baseLevel, uint32_t maxLevel); 981 982 angle::Result copyImageDataToBuffer(ContextVk *contextVk, 983 size_t sourceLevel, 984 uint32_t layerCount, 985 uint32_t baseLayer, 986 const gl::Box &sourceArea, 987 BufferHelper **bufferOut, 988 size_t *bufferSize, 989 StagingBufferOffsetArray *bufferOffsetsOut, 990 uint8_t **outDataPtr); 991 992 static angle::Result GetReadPixelsParams(ContextVk *contextVk, 993 const gl::PixelPackState &packState, 994 gl::Buffer *packBuffer, 995 GLenum format, 996 GLenum type, 997 const gl::Rectangle &area, 998 const gl::Rectangle &clippedArea, 999 PackPixelsParams *paramsOut, 1000 GLuint *skipBytesOut); 1001 1002 angle::Result readPixelsForGetImage(ContextVk *contextVk, 1003 const gl::PixelPackState &packState, 1004 gl::Buffer *packBuffer, 1005 uint32_t level, 1006 uint32_t layer, 1007 GLenum format, 1008 GLenum type, 1009 void *pixels); 1010 1011 angle::Result readPixels(ContextVk *contextVk, 1012 const gl::Rectangle &area, 1013 const PackPixelsParams &packPixelsParams, 1014 VkImageAspectFlagBits copyAspectFlags, 1015 uint32_t level, 1016 uint32_t layer, 1017 void *pixels, 1018 DynamicBuffer *stagingBuffer); 1019 1020 angle::Result CalculateBufferInfo(ContextVk *contextVk, 1021 const gl::Extents &glExtents, 1022 const gl::InternalFormat &formatInfo, 1023 const gl::PixelUnpackState &unpack, 1024 GLenum type, 1025 bool is3D, 1026 GLuint *inputRowPitch, 1027 GLuint *inputDepthPitch, 1028 GLuint *inputSkipBytes); 1029 1030 private: 1031 enum class UpdateSource 1032 { 1033 Clear, 1034 Buffer, 1035 Image, 1036 }; 1037 struct ClearUpdate 1038 { 1039 VkImageAspectFlags aspectFlags; 1040 VkClearValue value; 1041 uint32_t levelIndex; 1042 uint32_t layerIndex; 1043 uint32_t layerCount; 1044 }; 1045 struct BufferUpdate 1046 { 1047 BufferHelper *bufferHelper; 1048 VkBufferImageCopy copyRegion; 1049 }; 1050 struct ImageUpdate 1051 { 1052 ImageHelper *image; 1053 VkImageCopy copyRegion; 1054 }; 1055 1056 struct SubresourceUpdate 1057 { 1058 SubresourceUpdate(); 1059 SubresourceUpdate(BufferHelper *bufferHelperIn, const VkBufferImageCopy ©Region); 1060 SubresourceUpdate(ImageHelper *image, const VkImageCopy ©Region); 1061 SubresourceUpdate(VkImageAspectFlags aspectFlags, 1062 const VkClearValue &clearValue, 1063 const gl::ImageIndex &imageIndex); 1064 SubresourceUpdate(const SubresourceUpdate &other); 1065 1066 void release(RendererVk *renderer); 1067 dstSubresourceSubresourceUpdate1068 const VkImageSubresourceLayers &dstSubresource() const 1069 { 1070 ASSERT(updateSource == UpdateSource::Buffer || updateSource == UpdateSource::Image); 1071 return updateSource == UpdateSource::Buffer ? buffer.copyRegion.imageSubresource 1072 : image.copyRegion.dstSubresource; 1073 } 1074 bool isUpdateToLayerLevel(uint32_t layerIndex, uint32_t levelIndex) const; 1075 1076 UpdateSource updateSource; 1077 union 1078 { 1079 ClearUpdate clear; 1080 BufferUpdate buffer; 1081 ImageUpdate image; 1082 }; 1083 }; 1084 1085 // Generalized to accept both "primary" and "secondary" command buffers. 1086 template <typename CommandBufferT> 1087 void forceChangeLayoutAndQueue(VkImageAspectFlags aspectMask, 1088 ImageLayout newLayout, 1089 uint32_t newQueueFamilyIndex, 1090 CommandBufferT *commandBuffer); 1091 1092 // If the image has emulated channels, we clear them once so as not to leave garbage on those 1093 // channels. 1094 void stageClearIfEmulatedFormat(Context *context); 1095 1096 void clearColor(const VkClearColorValue &color, 1097 uint32_t baseMipLevel, 1098 uint32_t levelCount, 1099 uint32_t baseArrayLayer, 1100 uint32_t layerCount, 1101 CommandBuffer *commandBuffer); 1102 1103 void clearDepthStencil(VkImageAspectFlags clearAspectFlags, 1104 const VkClearDepthStencilValue &depthStencil, 1105 uint32_t baseMipLevel, 1106 uint32_t levelCount, 1107 uint32_t baseArrayLayer, 1108 uint32_t layerCount, 1109 CommandBuffer *commandBuffer); 1110 1111 angle::Result initializeNonZeroMemory(Context *context, VkDeviceSize size); 1112 1113 void appendSubresourceUpdate(SubresourceUpdate &&update); 1114 void prependSubresourceUpdate(SubresourceUpdate &&update); 1115 void resetCachedProperties(); 1116 1117 // Vulkan objects. 1118 Image mImage; 1119 DeviceMemory mDeviceMemory; 1120 1121 // Image properties. 1122 VkImageType mImageType; 1123 VkExtent3D mExtents; 1124 const Format *mFormat; 1125 GLint mSamples; 1126 Serial mSerial; 1127 1128 // Current state. 1129 ImageLayout mCurrentLayout; 1130 uint32_t mCurrentQueueFamilyIndex; 1131 1132 // Cached properties. 1133 uint32_t mBaseLevel; 1134 uint32_t mMaxLevel; 1135 uint32_t mLayerCount; 1136 uint32_t mLevelCount; 1137 1138 // Staging buffer 1139 DynamicBuffer mStagingBuffer; 1140 std::vector<SubresourceUpdate> mSubresourceUpdates; 1141 }; 1142 1143 // A vector of image views, such as one per level or one per layer. 1144 using ImageViewVector = std::vector<ImageView>; 1145 1146 // A vector of vector of image views. Primary index is layer, secondary index is level. 1147 using LayerLevelImageViewVector = std::vector<ImageViewVector>; 1148 1149 class ImageViewHelper : angle::NonCopyable 1150 { 1151 public: 1152 ImageViewHelper(); 1153 ImageViewHelper(ImageViewHelper &&other); 1154 ~ImageViewHelper(); 1155 1156 void release(RendererVk *renderer); 1157 void destroy(VkDevice device); 1158 getReadImageView()1159 const ImageView &getReadImageView() const { return mReadImageView; } getFetchImageView()1160 const ImageView &getFetchImageView() const { return mFetchImageView; } getStencilReadImageView()1161 const ImageView &getStencilReadImageView() const { return mStencilReadImageView; } 1162 1163 // Used when initialized RenderTargets. hasStencilReadImageView()1164 bool hasStencilReadImageView() const { return mStencilReadImageView.valid(); } 1165 hasFetchImageView()1166 bool hasFetchImageView() const { return mFetchImageView.valid(); } 1167 1168 // Store reference to usage in graph. retain(ResourceUseList * resourceUseList)1169 void retain(ResourceUseList *resourceUseList) const { resourceUseList->add(mUse); } 1170 1171 // Creates views with multiple layers and levels. 1172 angle::Result initReadViews(ContextVk *contextVk, 1173 gl::TextureType viewType, 1174 const ImageHelper &image, 1175 const Format &format, 1176 const gl::SwizzleState &swizzleState, 1177 uint32_t baseLevel, 1178 uint32_t levelCount, 1179 uint32_t baseLayer, 1180 uint32_t layerCount); 1181 1182 // Creates a view with all layers of the level. 1183 angle::Result getLevelDrawImageView(ContextVk *contextVk, 1184 gl::TextureType viewType, 1185 const ImageHelper &image, 1186 uint32_t level, 1187 uint32_t layer, 1188 const ImageView **imageViewOut); 1189 1190 // Creates a view with a single layer of the level. 1191 angle::Result getLevelLayerDrawImageView(ContextVk *contextVk, 1192 const ImageHelper &image, 1193 uint32_t level, 1194 uint32_t layer, 1195 const ImageView **imageViewOut); 1196 1197 private: 1198 // Lifetime. 1199 SharedResourceUse mUse; 1200 1201 // Read views. 1202 ImageView mReadImageView; 1203 ImageView mFetchImageView; 1204 ImageView mStencilReadImageView; 1205 1206 // Draw views. 1207 ImageViewVector mLevelDrawImageViews; 1208 LayerLevelImageViewVector mLayerLevelDrawImageViews; 1209 }; 1210 1211 // The SamplerHelper allows a Sampler to be coupled with a resource lifetime. 1212 class SamplerHelper final : angle::NonCopyable 1213 { 1214 public: 1215 SamplerHelper(); 1216 ~SamplerHelper(); 1217 1218 void release(RendererVk *renderer); 1219 valid()1220 bool valid() const { return mSampler.valid(); } get()1221 Sampler &get() { return mSampler; } get()1222 const Sampler &get() const { return mSampler; } 1223 retain(ResourceUseList * resourceUseList)1224 void retain(ResourceUseList *resourceUseList) { resourceUseList->add(mUse); } 1225 1226 private: 1227 SharedResourceUse mUse; 1228 Sampler mSampler; 1229 }; 1230 1231 class FramebufferHelper : public Resource 1232 { 1233 public: 1234 FramebufferHelper(); 1235 ~FramebufferHelper() override; 1236 1237 FramebufferHelper(FramebufferHelper &&other); 1238 FramebufferHelper &operator=(FramebufferHelper &&other); 1239 1240 angle::Result init(ContextVk *contextVk, const VkFramebufferCreateInfo &createInfo); 1241 void release(ContextVk *contextVk); 1242 valid()1243 bool valid() { return mFramebuffer.valid(); } 1244 getFramebuffer()1245 const Framebuffer &getFramebuffer() const 1246 { 1247 ASSERT(mFramebuffer.valid()); 1248 return mFramebuffer; 1249 } 1250 getFramebuffer()1251 Framebuffer &getFramebuffer() 1252 { 1253 ASSERT(mFramebuffer.valid()); 1254 return mFramebuffer; 1255 } 1256 1257 private: 1258 // Vulkan object. 1259 Framebuffer mFramebuffer; 1260 }; 1261 1262 // A special command graph resource to hold resource dependencies for dispatch calls. It's the 1263 // equivalent of FramebufferHelper, though it doesn't contain a Vulkan object. 1264 class DispatchHelper : public Resource 1265 { 1266 public: 1267 DispatchHelper(); 1268 ~DispatchHelper() override; 1269 }; 1270 1271 class ShaderProgramHelper : angle::NonCopyable 1272 { 1273 public: 1274 ShaderProgramHelper(); 1275 ~ShaderProgramHelper(); 1276 1277 bool valid(const gl::ShaderType shaderType) const; 1278 void destroy(VkDevice device); 1279 void release(ContextVk *contextVk); 1280 isGraphicsProgram()1281 bool isGraphicsProgram() const 1282 { 1283 ASSERT((mShaders[gl::ShaderType::Vertex].valid() || 1284 mShaders[gl::ShaderType::Fragment].valid()) != 1285 mShaders[gl::ShaderType::Compute].valid()); 1286 return !mShaders[gl::ShaderType::Compute].valid(); 1287 } 1288 getShader(gl::ShaderType shaderType)1289 ShaderAndSerial &getShader(gl::ShaderType shaderType) { return mShaders[shaderType].get(); } 1290 1291 void setShader(gl::ShaderType shaderType, RefCounted<ShaderAndSerial> *shader); 1292 void enableSpecializationConstant(sh::vk::SpecializationConstantId id); 1293 1294 // For getting a Pipeline and from the pipeline cache. getGraphicsPipeline(ContextVk * contextVk,RenderPassCache * renderPassCache,const PipelineCache & pipelineCache,Serial currentQueueSerial,const PipelineLayout & pipelineLayout,const GraphicsPipelineDesc & pipelineDesc,const gl::AttributesMask & activeAttribLocationsMask,const gl::ComponentTypeMask & programAttribsTypeMask,const GraphicsPipelineDesc ** descPtrOut,PipelineHelper ** pipelineOut)1295 ANGLE_INLINE angle::Result getGraphicsPipeline( 1296 ContextVk *contextVk, 1297 RenderPassCache *renderPassCache, 1298 const PipelineCache &pipelineCache, 1299 Serial currentQueueSerial, 1300 const PipelineLayout &pipelineLayout, 1301 const GraphicsPipelineDesc &pipelineDesc, 1302 const gl::AttributesMask &activeAttribLocationsMask, 1303 const gl::ComponentTypeMask &programAttribsTypeMask, 1304 const GraphicsPipelineDesc **descPtrOut, 1305 PipelineHelper **pipelineOut) 1306 { 1307 // Pull in a compatible RenderPass. 1308 RenderPass *compatibleRenderPass = nullptr; 1309 ANGLE_TRY(renderPassCache->getCompatibleRenderPass(contextVk, currentQueueSerial, 1310 pipelineDesc.getRenderPassDesc(), 1311 &compatibleRenderPass)); 1312 1313 ShaderModule *vertexShader = &mShaders[gl::ShaderType::Vertex].get().get(); 1314 ShaderModule *fragmentShader = mShaders[gl::ShaderType::Fragment].valid() 1315 ? &mShaders[gl::ShaderType::Fragment].get().get() 1316 : nullptr; 1317 ShaderModule *geometryShader = mShaders[gl::ShaderType::Geometry].valid() 1318 ? &mShaders[gl::ShaderType::Geometry].get().get() 1319 : nullptr; 1320 1321 return mGraphicsPipelines.getPipeline( 1322 contextVk, pipelineCache, *compatibleRenderPass, pipelineLayout, 1323 activeAttribLocationsMask, programAttribsTypeMask, vertexShader, fragmentShader, 1324 geometryShader, mSpecializationConstants, pipelineDesc, descPtrOut, pipelineOut); 1325 } 1326 1327 angle::Result getComputePipeline(Context *context, 1328 const PipelineLayout &pipelineLayout, 1329 PipelineAndSerial **pipelineOut); 1330 1331 private: 1332 gl::ShaderMap<BindingPointer<ShaderAndSerial>> mShaders; 1333 GraphicsPipelineCache mGraphicsPipelines; 1334 1335 // We should probably use PipelineHelper here so we can remove PipelineAndSerial. 1336 PipelineAndSerial mComputePipeline; 1337 1338 // Specialization constants, currently only used by the graphics queue. 1339 vk::SpecializationConstantBitSet mSpecializationConstants; 1340 }; 1341 } // namespace vk 1342 } // namespace rx 1343 1344 #endif // LIBANGLE_RENDERER_VULKAN_VK_HELPERS_H_ 1345