Skip to content

Commit 2574272

Browse files
committed
[62.CAD] Texture LRUCache
1 parent d38f5fa commit 2574272

File tree

3 files changed

+94
-47
lines changed

3 files changed

+94
-47
lines changed

62_CAD/DrawResourcesFiller.cpp

Lines changed: 66 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
#include "DrawResourcesFiller.h"
22

3-
DrawResourcesFiller::DrawResourcesFiller(smart_refctd_ptr<IUtilities>&& utils, IQueue* copyQueue)
4-
{
5-
m_utilities = utils;
6-
m_copyQueue = copyQueue;
7-
}
3+
DrawResourcesFiller::DrawResourcesFiller() :
4+
textureLRUCache(1024u)
5+
{}
6+
7+
DrawResourcesFiller::DrawResourcesFiller(smart_refctd_ptr<IUtilities>&& utils, IQueue* copyQueue) :
8+
textureLRUCache(1024u),
9+
m_utilities(utils),
10+
m_copyQueue(copyQueue)
11+
{}
812

913
// function is called when buffer is filled and we should submit draws and clear the buffers and continue filling
1014

@@ -118,6 +122,10 @@ void DrawResourcesFiller::allocateStylesBuffer(ILogicalDevice* logicalDevice, ui
118122

119123
void DrawResourcesFiller::allocateMSDFTextures(ILogicalDevice* logicalDevice, uint32_t maxMSDFs)
120124
{
125+
// TODO[Erfan]: Fix resize TextureLRUCache
126+
// assert(maxMSDFs == textureLRUCache.capacity);
127+
// textureLRUCache = TextureLRUCache(maxMSDFs);
128+
121129
asset::E_FORMAT msdfFormat = asset::EF_R8G8B8A8_UNORM; // @Lucas change the format to what MSDFs use
122130
constexpr asset::VkExtent3D MSDFsExtent = { 32u, 32u, 1u }; // 32x32 images, TODO: maybe make this a paramerter
123131
assert(maxMSDFs <= logicalDevice->getPhysicalDevice()->getLimits().maxImageArrayLayers);
@@ -221,7 +229,7 @@ void DrawResourcesFiller::drawHatch(
221229
const Hatch& hatch,
222230
const float32_t4& foregroundColor,
223231
const float32_t4& backgroundColor,
224-
const uint32_t msdfTextureIdx,
232+
const texture_hash msdfTexture,
225233
SIntendedSubmitInfo& intendedNextSubmit)
226234
{
227235
// TODO[Optimization Idea]: don't draw hatch twice if both colors are visible: instead do the msdf inside the alpha resolve by detecting mainObj being a hatch
@@ -237,12 +245,23 @@ void DrawResourcesFiller::drawHatch(
237245
void DrawResourcesFiller::drawHatch(
238246
const Hatch& hatch,
239247
const float32_t4& color,
240-
const uint32_t msdfTextureIdx,
248+
const texture_hash msdfTexture,
241249
SIntendedSubmitInfo& intendedNextSubmit)
242250
{
251+
uint32_t textureIdx = InvalidTextureIdx;
252+
if (msdfTexture != InvalidTextureHash)
253+
{
254+
TextureReference* tRef = textureLRUCache.get(msdfTexture);
255+
if (tRef)
256+
{
257+
textureIdx = tRef->alloc_idx;
258+
tRef->lastUsedSemaphoreValue = intendedNextSubmit.getScratchSemaphoreNextWait().value; // update this because the texture will get used on the next submit
259+
}
260+
}
261+
243262
LineStyleInfo lineStyle = {};
244263
lineStyle.color = color;
245-
lineStyle.screenSpaceLineWidth = nbl::hlsl::bit_cast<float, uint32_t>(msdfTextureIdx);
264+
lineStyle.screenSpaceLineWidth = nbl::hlsl::bit_cast<float, uint32_t>(textureIdx);
246265
// @Lucas we use LineStyle struct for hatches too but we aliased a member with textureId, So you need to do asuint(lineStyle.screenSpaceLineWidth) to get you the index into msdfTextureArray
247266

248267
const uint32_t styleIdx = addLineStyle_SubmitIfNeeded(lineStyle, intendedNextSubmit);
@@ -264,38 +283,50 @@ void DrawResourcesFiller::drawHatch(
264283

265284
void DrawResourcesFiller::drawHatch(const Hatch& hatch, const float32_t4& color, SIntendedSubmitInfo& intendedNextSubmit)
266285
{
267-
drawHatch(hatch, color, InvalidTextureIdx, intendedNextSubmit);
286+
drawHatch(hatch, color, InvalidTextureHash, intendedNextSubmit);
268287
}
269288

270-
uint32_t DrawResourcesFiller::addMSDFTexture(ICPUBuffer const* srcBuffer, const asset::IImage::SBufferCopy& region, texture_hash hash)
289+
void DrawResourcesFiller::addMSDFTexture(ICPUBuffer const* srcBuffer, const asset::IImage::SBufferCopy& region, texture_hash hash, SIntendedSubmitInfo& intendedNextSubmit)
271290
{
272-
uint32_t ret = InvalidTextureIdx;
291+
// TextureReferences hold the semaValue related to the "scratch semaphore" in IntendedSubmitInfo
292+
// Every single submit increases this value by 1
293+
// The reason for hiolding on to the lastUsedSema is deferred dealloc, which we call in the case of eviction, making sure we get rid of the entry inside the allocator only when the texture is done being used
294+
uint64_t nextSemaValue = intendedNextSubmit.getScratchSemaphoreNextWait().value;
295+
const auto* signalSema = intendedNextSubmit.getScratchSemaphoreNextWait().semaphore;
273296

274-
// @Lucas TODO: Here should rely the main logic for allocating an index from our allocator and evicting based on LRU Cache if we failed
275-
/*
276-
* look into `textureIdToIndexMap` if we already have the `texture_hash` in the texture array slices (skip if hash is InvalidTextureHash)
277-
* If we found a match we return that index;
278-
* Else:
279-
* LRUIndexAllocator try allocate
280-
* Failure to Alloc Index (Auto-Submission logic):
281-
1. evict something from LRU cache + remove entry from lookup unordered_map ->
282-
2. dealloc with deferred (based on next submit signal val) ->
283-
3. resetGeometryCounters(); (because geometries using previous glyphs are done rendering and should be invalidated)
284-
4. ret = try alloc again (+ assert it should succeed because we evicted and dealloced)
285-
* Success to Alloc Index: ret = index; add entry to lookup unordered_map
286-
*/
287-
288-
// asuming allocator gave us 0 as index
289-
ret = 0u;
290-
291-
// We queue copy and finalize all on `finalizeTextureCopies` function called before draw calls to make sure it's in mem
292-
textureCopies.push_back({
293-
.srcBuffer = srcBuffer,
294-
.region = region,
295-
.index = ret,
296-
});
297+
auto evictionCallback = [&](const TextureReference& evicted)
298+
{
299+
// @Lucas TODO:
300+
301+
// Dealloc:
302+
//allocator.multi_deallocate(1u,&evicted.alloc_idx,{signalSema,evicted.lastUsedSemaphoreValue});
303+
304+
// Overflow Handling:
305+
//finalizeAllCopiesToGPU(intendedNextSubmit);
306+
//submitDraws(intendedNextSubmit);
307+
//resetGeometryCounters();
308+
//resetMainObjectCounters();
309+
};
310+
311+
// We pass nextSemaValue instead of constructing a new TextureReference and passing it into `insert` that's because we might get a cache hit and only update the value of the nextSema
312+
TextureReference* inserted = textureLRUCache.insert(hash, nextSemaValue, evictionCallback);
313+
314+
// if inserted->alloc_idx was not InvalidTextureIdx then it means we had a cache hit and updated the value of our sema, in which case we don't queue anything for upload, and return the idx
315+
if (inserted->alloc_idx == InvalidTextureIdx)
316+
{
317+
// New insertion == cache miss happened and insertion was successfull
318+
// allocator.multi_allocate(1u,&inserted->alloc_idx);
319+
inserted->alloc_idx = 0u; // temp
320+
321+
// We queue copy and finalize all on `finalizeTextureCopies` function called before draw calls to make sure it's in mem
322+
textureCopies.push_back({
323+
.srcBuffer = srcBuffer,
324+
.region = region,
325+
.index = inserted->alloc_idx,
326+
});
327+
}
297328

298-
return ret;
329+
assert(inserted->alloc_idx != InvalidTextureIdx);
299330
}
300331

301332
void DrawResourcesFiller::finalizeAllCopiesToGPU(SIntendedSubmitInfo& intendedNextSubmit)

62_CAD/DrawResourcesFiller.h

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ struct DrawResourcesFiller
3535

3636
typedef uint32_t index_buffer_type;
3737

38-
DrawResourcesFiller() {}
38+
DrawResourcesFiller();
3939

4040
DrawResourcesFiller(smart_refctd_ptr<IUtilities>&& utils, IQueue* copyQueue);
4141

@@ -55,6 +55,12 @@ struct DrawResourcesFiller
5555
void allocateStylesBuffer(ILogicalDevice* logicalDevice, uint32_t lineStylesCount);
5656

5757
void allocateMSDFTextures(ILogicalDevice* logicalDevice, uint32_t maxMSDFs);
58+
59+
using texture_hash = uint64_t;
60+
static constexpr uint64_t InvalidTextureHash = std::numeric_limits<uint64_t>::max();
61+
62+
// ! return index to be used later in hatch fill style or text glyph object
63+
void addMSDFTexture(ICPUBuffer const* srcBuffer, const asset::IImage::SBufferCopy& region, texture_hash hash, SIntendedSubmitInfo& intendedNextSubmit);
5864

5965
//! this function fills buffers required for drawing a polyline and submits a draw through provided callback when there is not enough memory.
6066
void drawPolyline(const CPolylineBase& polyline, const LineStyleInfo& lineStyleInfo, SIntendedSubmitInfo& intendedNextSubmit);
@@ -66,14 +72,14 @@ struct DrawResourcesFiller
6672
const Hatch& hatch,
6773
const float32_t4& foregroundColor,
6874
const float32_t4& backgroundColor,
69-
const uint32_t msdfTextureIdx,
75+
const texture_hash msdfTexture,
7076
SIntendedSubmitInfo& intendedNextSubmit);
7177

7278
// ! Hatch with MSDF Pattern
7379
void drawHatch(
7480
const Hatch& hatch,
7581
const float32_t4& color,
76-
const uint32_t msdfTextureIdx,
82+
const texture_hash msdfTexture,
7783
SIntendedSubmitInfo& intendedNextSubmit);
7884

7985
// ! Solid Fill Hacth
@@ -82,12 +88,6 @@ struct DrawResourcesFiller
8288
const float32_t4& color,
8389
SIntendedSubmitInfo& intendedNextSubmit);
8490

85-
using texture_hash = uint64_t;
86-
static constexpr uint64_t InvalidTextureHash = std::numeric_limits<uint64_t>::max();
87-
88-
// ! return index to be used later in hatch fill style or text glyph object
89-
uint32_t addMSDFTexture(ICPUBuffer const* srcBuffer, const asset::IImage::SBufferCopy& region, texture_hash hash = InvalidTextureHash);
90-
9191
void finalizeAllCopiesToGPU(SIntendedSubmitInfo& intendedNextSubmit);
9292

9393
inline uint32_t getLineStyleCount() const { return currentLineStylesCount; }
@@ -249,8 +249,23 @@ struct DrawResourcesFiller
249249

250250
std::stack<ClipProjectionData> clipProjections; // stack of clip projectios stored so we can resubmit them if geometry buffer got reset.
251251
std::deque<uint64_t> clipProjectionAddresses; // stack of clip projection gpu addresses in geometry buffer. to keep track of them in push/pops
252+
253+
struct TextureReference
254+
{
255+
uint32_t alloc_idx;
256+
uint64_t lastUsedSemaphoreValue;
257+
258+
TextureReference(uint32_t alloc_idx, uint64_t semaphoreVal) : alloc_idx(alloc_idx), lastUsedSemaphoreValue(semaphoreVal) {}
259+
TextureReference(uint64_t semaphoreVal) : TextureReference(InvalidTextureIdx, semaphoreVal) {}
260+
TextureReference() : TextureReference(InvalidTextureIdx, ~0ull) {}
261+
262+
// In LRU Cache `insert` function, in case of cache hit, we need to assign semaphore value to TextureReference without changing `alloc_idx`
263+
inline TextureReference& operator=(uint64_t semamphoreVal) { lastUsedSemaphoreValue = semamphoreVal; return *this; }
264+
};
265+
266+
using TextureLRUCache = core::LRUCache<texture_hash, TextureReference>;
252267

253-
smart_refctd_ptr<IGPUImageView> msdfTextureArray;
254-
std::vector<TextureCopy> textureCopies;
255-
std::unordered_map<texture_hash, uint32_t/*index*/> textureIdToIndexMap;
268+
smart_refctd_ptr<IGPUImageView> msdfTextureArray; // view to the resource holding all the msdfs in it's layers
269+
std::vector<TextureCopy> textureCopies; // queued up texture copies, @Lucas change to deque if possible
270+
TextureLRUCache textureLRUCache; // LRU Cache to evict Least Recently Used in case of overflow
256271
};

62_CAD/main.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ using namespace video;
2525

2626
#include "nbl/video/surface/CSurfaceVulkan.h"
2727
#include "nbl/ext/FullScreenTriangle/FullScreenTriangle.h"
28+
#include "nbl/core/containers/LRUCache.h"
2829

2930
static constexpr bool DebugMode = false;
3031
static constexpr bool DebugRotatingViewProj = false;

0 commit comments

Comments
 (0)