57 enum class Arena : uint8_t
86 static constexpr uint32_t kInvalidIndex = 0xFFFFFFFFu;
88 Arena arena{Arena::RawCamera};
89 uint32_t slot_index{kInvalidIndex};
91 uint32_t generation{};
93 bool valid()
const noexcept {
return slot_index != kInvalidIndex; }
115 void init(QRhi& rhi, QRhiResourceUpdateBatch& batch);
145 void seedDefaults(QRhiResourceUpdateBatch& batch);
154 void uploadDefaultMaterial(QRhiResourceUpdateBatch& batch);
195 Slot allocate(Arena arena, uint32_t size);
200 void free(Slot& slot);
208 QRhiBuffer* buffer(Arena arena)
const noexcept;
213 uint32_t slotOffset(
const Slot& slot)
const noexcept;
220 uint32_t arenaSlotStride(Arena arena)
const noexcept;
225 uint32_t arenaSlotCount(Arena arena)
const noexcept;
236 QRhiResourceUpdateBatch& res,
const Slot& slot,
const void* data,
237 uint32_t size)
noexcept;
251 ossia::gpu_slot_ref r;
252 r.arena = (uint32_t)slot.arena;
253 r.offset = slotOffset(slot);
255 r.internal_index = slot.slot_index;
256 r.generation = slot.generation;
274 bool isLiveIn(
const ossia::gpu_slot_ref& r, Arena expected)
const noexcept
276 return r.arena == (uint32_t)expected && isLive(r);
286 bool isLive(
const ossia::gpu_slot_ref& r)
const noexcept
288 if(r.arena >= (uint32_t)Arena::Count_ || r.size == 0)
290 const auto& a = m_arenas[r.arena];
291 if(r.internal_index >= a.slot_generations.size())
293 return a.slot_generations[r.internal_index] == r.generation;
307 enum class TextureChannel : uint8_t
320 static constexpr int kTextureLayerSize = 1024;
323 static constexpr int kMaxDynamicSlots = 8;
335 static constexpr int kMaxBuckets = 8;
354 QRhiTexture* array{};
355 QRhiTexture::Format format{QRhiTexture::RGBA8};
365 QRhiTexture::Flags flags{};
369 QRhiSampler* sampler{};
374 ossia::flat_map<const ossia::texture_source*, int> layerMap;
378 std::vector<std::shared_ptr<const ossia::texture_source>> layerSources;
383 std::vector<char> layerCoverage;
385 bool mipsDirty{
false};
390 std::vector<Bucket> buckets;
396 uint64_t generation{0};
402 uint64_t rebuilds{0};
403 uint64_t layerUploads{0};
408 ossia::flat_map<const void*, std::vector<const ossia::texture_source*>> claims;
418 ossia::flat_map<quint64, int> dynamicSlotMap;
419 std::vector<QRhiTexture*> dynamicTextures;
422 std::vector<quint64> dynamicTextureIds;
423 std::vector<uint64_t> dynamicSlotLastUse;
424 uint64_t dynamicSlotCounter{0};
429 uint64_t dynamicSweepCheckpoint{0};
433 QRhiTexture* primaryArray() const noexcept
435 return buckets.empty() ? nullptr : buckets[0].array;
437 int primaryLayers() const noexcept
439 return buckets.empty() ? 0 : buckets[0].layers;
446 Bucket& ensurePrimary(QRhiTexture::Format fmt, QSize sz,
447 QRhiTexture::Flags flags = {})
450 buckets.emplace_back();
451 auto& b = buckets[0];
462 std::pair<int, Bucket*>
463 findOrCreateBucket(QRhiTexture::Format fmt, QSize sz, QRhiTexture::Flags flags)
465 for(std::size_t i = 0; i < buckets.size(); ++i)
467 if(buckets[i].format == fmt && buckets[i].pixelSize == sz
468 && buckets[i].flags == flags)
469 return {(int)i, &buckets[i]};
471 if((
int)buckets.size() >= kMaxBuckets)
472 return {-1,
nullptr};
473 buckets.emplace_back();
474 auto& b = buckets.back();
478 return {(int)buckets.size() - 1, &b};
497 } primitiveCloudUploads;
504 return m_texturePool;
506 const TextureChannelState& textureChannel(TextureChannel)
const noexcept
508 return m_texturePool;
513 const TextureChannelState& texturePool() const noexcept {
return m_texturePool; }
518 static constexpr const char* kSharedArrayName =
"materialArray";
519 static constexpr const char* kSharedDynName =
"materialDyn";
529 static const char* textureChannelArrayName(TextureChannel ch)
noexcept;
537 static const char* textureChannelDynBaseName(TextureChannel ch)
noexcept;
544 static QRhiTexture::Flags textureChannelFlags(TextureChannel ch)
noexcept;
558 int resolveDynamicSlot(TextureChannel channel,
void* native_handle)
noexcept;
588 enum class MeshStream : uint8_t
604 static constexpr uint32_t kMeshStride[(std::size_t)MeshStream::Count_]
605 = {16, 16, 8, 16, 16, 8, 4};
611 static constexpr uint32_t kMeshCapBytes[(std::size_t)MeshStream::Count_]
613 128u * 1024u * 1024u,
614 128u * 1024u * 1024u,
616 128u * 1024u * 1024u,
617 128u * 1024u * 1024u,
639 uint64_t stable_id{};
640 OffsetAllocator::Allocation vertex_slot{};
641 OffsetAllocator::Allocation index_slot{};
642 uint32_t vertex_count{};
643 uint32_t index_count{};
644 uint32_t last_seen_frame{};
645 bool freshly_allocated{};
658 uint32_t vertex_count,
659 uint32_t index_count,
660 uint32_t current_frame)
noexcept;
663 void markMeshSlabSeen(uint64_t stable_id, uint32_t current_frame)
noexcept;
667 void sweepMeshSlabs(uint32_t current_frame, uint32_t grace = 2) noexcept;
675 void sweepStaleDynamicTextureSlots() noexcept;
680 void forgetDynamicTexture(const QRhiTexture* tex) noexcept;
687 void drainExpiredPendingReleases(
688 uint32_t current_frame, uint32_t grace = 2) noexcept;
695 void releaseMeshSlab(uint64_t stable_id, uint32_t current_frame) noexcept;
699 uint32_t meshSlabOffsetBytes(
700 const
MeshSlab& slab, MeshStream stream) const noexcept;
704 QRhiBuffer* meshStreamBuffer(MeshStream s) const noexcept;
709 void uploadMeshStream(
710 QRhiResourceUpdateBatch& res, const
MeshSlab& slab,
711 MeshStream s, const
void* data, uint32_t size) noexcept;
726 ++m_registry->m_meshUploadBatchDepth;
730 if(m_registry && --m_registry->m_meshUploadBatchDepth == 0)
731 m_registry->flushMeshUploads();
733 MeshUploadBatch(
const MeshUploadBatch&) =
delete;
734 MeshUploadBatch& operator=(
const MeshUploadBatch&) =
delete;
737 GpuResourceRegistry* m_registry{};
741 uint32_t meshStreamUsedBytes(MeshStream s)
const noexcept;
742 uint32_t meshStreamFreeBytes(MeshStream s)
const noexcept;
747 QRhiBuffer* buffer{};
748 uint32_t slot_stride{0};
750 uint32_t slot_count{0};
751 QRhiBuffer::UsageFlags usage{};
752 QRhiBuffer::Type type{QRhiBuffer::Dynamic};
756 std::vector<uint32_t> free_slots;
762 std::vector<uint32_t> slot_generations;
765 std::array<ArenaState, (std::size_t)Arena::Count_> m_arenas{};
768 TextureChannelState m_texturePool{};
774 struct MeshStreamState
776 QRhiBuffer* buffer{};
777 uint32_t capacity_bytes{};
778 QRhiBuffer::UsageFlags usage{};
780 std::array<MeshStreamState, (std::size_t)MeshStream::Count_> m_meshStreams{};
784 struct PendingMeshUpload
786 QRhiResourceUpdateBatch* batch{};
788 std::vector<std::byte> bytes;
790 std::array<PendingMeshUpload, (std::size_t)MeshStream::Count_> m_pendingMeshUploads{};
791 int m_meshUploadBatchDepth{};
792 void flushMeshUpload(MeshStream s)
noexcept;
793 void flushMeshUploads() noexcept;
799 std::unique_ptr<OffsetAllocator::Allocator> m_vertexAllocator;
800 std::unique_ptr<OffsetAllocator::Allocator> m_indexAllocator;
801 uint32_t m_vertexSlotsCapacity{};
802 uint32_t m_indexSlotsCapacity{};
803 uint32_t m_vertexSlotsUsed{};
804 uint32_t m_indexSlotsUsed{};
806 ossia::hash_map<uint64_t, MeshSlab> m_meshSlabs;
812 struct PendingRelease
814 uint64_t stable_id{};
815 uint32_t released_frame{};
816 OffsetAllocator::Allocation vertex_slot{};
817 OffsetAllocator::Allocation index_slot{};
819 std::vector<PendingRelease> m_pendingReleases;
826 bool m_defaults_seeded{
false};
Channel texture state with multi-bucket support.
Definition GpuResourceRegistry.hpp:351