blob: e4a30eeb1ca52b2566ff6ad4415396b6dd7af88a [file] [log] [blame]
/*
* Copyright 2024 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef skgpu_graphite_ClipAtlasManager_DEFINED
#define skgpu_graphite_ClipAtlasManager_DEFINED
#include "include/core/SkRect.h"
#include "include/core/SkRefCnt.h"
#include "include/private/base/SkTDArray.h"
#include "src/base/SkTInternalLList.h"
#include "src/core/SkTHash.h"
#include "src/gpu/AtlasTypes.h"
#include "src/gpu/ResourceKey.h"
#include "src/gpu/graphite/ClipStack.h"
#include "src/gpu/graphite/DrawAtlas.h"
#include <cstddef>
#include <cstdint>
#include <memory>
#include <string_view>
struct SkIPoint;
namespace skgpu::graphite {
class Caps;
class DrawContext;
class Recorder;
class TextureProxy;
//////////////////////////////////////////////////////////////////////////////////////////////////
/** The ClipAtlasManager manages the lifetime of and access to rasterized clip masks.
*/
class ClipAtlasManager {
public:
ClipAtlasManager(Recorder* recorder);
~ClipAtlasManager() = default;
sk_sp<TextureProxy> findOrCreateEntry(uint32_t stackRecordID,
const ClipStack::ElementList*,
SkIRect maskDeviceBounds,
SkIPoint* outPos);
bool recordUploads(DrawContext* dc);
void compact();
void freeGpuResources();
void evictAtlases();
private:
// Wrapper class to manage DrawAtlas and associated caching operations
class DrawAtlasMgr : public AtlasGenerationCounter, public PlotEvictionCallback {
public:
DrawAtlasMgr(size_t width, size_t height,
size_t plotWidth, size_t plotHeight,
DrawAtlas::UseStorageTextures useStorageTextures,
std::string_view label, const Caps*);
sk_sp<TextureProxy> findOrCreateEntry(Recorder* recorder,
const skgpu::UniqueKey&,
const ClipStack::ElementList*,
SkIRect maskDeviceBounds,
SkIRect keyBounds,
SkIPoint* outPos);
// Adds to DrawAtlas but not the cache
sk_sp<TextureProxy> addToAtlas(Recorder* recorder,
const ClipStack::ElementList*,
SkIRect maskDeviceBounds,
SkIPoint* outPos,
AtlasLocator* locator);
bool recordUploads(DrawContext*, Recorder*);
void evict(PlotLocator) override;
void compact(Recorder*);
void freeGpuResources(Recorder*);
void evictAll();
private:
std::unique_ptr<DrawAtlas> fDrawAtlas;
// Tracks whether a combined clip mask is already in the DrawAtlas and its location
struct MaskHashEntry {
SkIRect fBounds;
AtlasLocator fLocator;
MaskHashEntry* fNext = nullptr;
};
struct UniqueKeyHash {
uint32_t operator()(const skgpu::UniqueKey& key) const { return key.hash(); }
};
using MaskCache = skia_private::THashMap<skgpu::UniqueKey, MaskHashEntry, UniqueKeyHash>;
MaskCache fMaskCache;
int fHashEntryCount = 0;
// List of stored keys per Plot, used to invalidate cache entries.
// When a Plot is invalidated via evict(), we'll get its index and Page index from the
// PlotLocator, index into the fKeyLists array to get the MaskKeyList for that Plot,
// then iterate through the list and remove entries matching those keys from the MaskCache.
struct MaskKeyEntry {
skgpu::UniqueKey fKey;
SkIRect fBounds;
SK_DECLARE_INTERNAL_LLIST_INTERFACE(MaskKeyEntry);
};
using MaskKeyList = SkTInternalLList<MaskKeyEntry>;
SkTDArray<MaskKeyList> fKeyLists;
int fListEntryCount = 0;
};
Recorder* fRecorder;
// We have two atlas managers, one for clips that can be keyed via the path keys,
// and a smaller one for those that can only be keyed by the SaveRecord ID. We keep
// them separate because the SaveRecord keyed clips will be far more transient, i.e.,
// once the SaveRecord is popped they'll never be used again.
DrawAtlasMgr fPathKeyAtlasMgr;
DrawAtlasMgr fSaveRecordKeyAtlasMgr;
};
} // namespace skgpu::graphite
#endif // skgpu_graphite_ClipAtlasManager_DEFINED