Loading...
Searching...
No Matches
Gfx::AssetTable Class Reference

Cross-RenderList content-hash dedup for decoded asset bytes. More...

Detailed Description

Cross-RenderList content-hash dedup for decoded asset bytes.

Lives on GfxContext, shared across all RenderLists in the session. Keyed by content_hash (64-bit stable hash of the source bytes — the canonical primitive is ossia::hash_bytes from ossia/detail/hash.hpp, which dispatches to rapidhash; parsers and the preprocessor produce content_hash values through that helper).

Purpose: one decode per asset across the whole session. When two glTF files reference the same baseColor.jpg, we decode it once and reuse. Per-RenderList GpuResourceRegistries upload from the cached QImage independently: one decode, N uploads.

Not the GPU-resource owner — GpuResourceRegistry does that per QRhi. AssetTable only holds CPU-side bytes + format metadata during the window between decode and eviction.

Lifecycle

Three states per entry:

  • hot (refcount > 0): actively held by at least one consumer. Never evicted.
  • cool (refcount == 0, still referenced in the LRU list): eviction candidate. acquire() resurrects it at zero cost.
  • evicted: dropped from the map. Next acquire() misses; the caller re-decodes and restage()s.

Transitions:

  • stage() inserts a refcount==0 entry directly into the cold LRU pool (or no-op if already present), so a stage that is never acquired remains trimmable rather than leaking.
  • acquire() bumps refcount and (if the entry is cold) splices it out of the LRU list.
  • release() decrements; at 0 the entry moves to the LRU head.
  • trim(max_bytes) pops from the LRU tail until under budget.
  • maybeAutoTrim() called periodically: reads a supplied utilization ratio and trims when above a threshold.

Byte accounting is approximate — sizeInBytes(DecodedAsset) hits QImage::sizeInBytes and the raw bytes vector size. Good enough for budget bookkeeping without a full allocator hook.

Thread safety

All public methods take m_mutex. Fine for the access pattern (parser worker threads stage, render threads acquire/release, GUI tick trims) — the mutex is held for microseconds at a time.

Classes

struct  DecodedAsset
 

Public Member Functions

 AssetTable (const AssetTable &)=delete
 
AssetTableoperator= (const AssetTable &)=delete
 
void stage (uint64_t content_hash, QImage image)
 
void stage (uint64_t content_hash, std::shared_ptr< const std::vector< uint8_t > > bytes, std::string mime_type={})
 
std::shared_ptr< const DecodedAssetacquire (uint64_t content_hash)
 
std::shared_ptr< const DecodedAssetpeek (uint64_t content_hash) const
 
void release (uint64_t content_hash)
 
std::size_t trim (std::size_t max_bytes_budget)
 
void maybeAutoTrim (float utilization, float high_watermark=0.80f, float target=0.60f)
 
std::size_t size () const noexcept
 Debug / inspector.
 
std::size_t totalBytes () const noexcept
 Approx total bytes held in cold pool + hot pool.
 
std::size_t coldCount () const noexcept
 Number of cold entries eligible for eviction.
 

Member Function Documentation

◆ acquire()

std::shared_ptr< const AssetTable::DecodedAsset > Gfx::AssetTable::acquire ( uint64_t  content_hash)

Return a shared pointer to the decoded asset, bumping its refcount. Null when not staged. O(1) average.

◆ maybeAutoTrim()

void Gfx::AssetTable::maybeAutoTrim ( float  utilization,
float  high_watermark = 0.80f,
float  target = 0.60f 
)

Called on a cadence (e.g. from the Gfx thread idle tick) to pressure-trim when the supplied utilization ratio exceeds high_watermark. Cost: O(n) in the LRU list when a trim fires; constant otherwise.

utilization in [0, 1]. Compute externally from QRhiStats::usedBytes / (usedBytes + unusedBytes), or from a hard OS-level memory query. high_watermark default 0.80. target default 0.60.

◆ peek()

std::shared_ptr< const AssetTable::DecodedAsset > Gfx::AssetTable::peek ( uint64_t  content_hash) const

Read-through without refcount bump. The returned shared_ptr keeps the DecodedAsset alive on the caller's side even if the AssetTable evicts the entry — but does NOT prevent eviction. Suitable for the "upload once to GPU, then done" path where the consumer doesn't care if the CPU-side bytes live on.

◆ release()

void Gfx::AssetTable::release ( uint64_t  content_hash)

Decrement refcount. At 0 the entry moves to the LRU head and is eligible for eviction on the next trim.

◆ stage()

void Gfx::AssetTable::stage ( uint64_t  content_hash,
QImage  image 
)

Publish a decoded asset under its content hash. Idempotent — a second stage() with the same hash is a no-op (hash contract: same hash = same bytes).

◆ trim()

std::size_t Gfx::AssetTable::trim ( std::size_t  max_bytes_budget)

Force eviction until the cold-pool byte total is below max_bytes. Called explicitly by UI ("unload unused") or implicitly by maybeAutoTrim.

Returns
bytes evicted.

The documentation for this class was generated from the following files: