/*
 * Copyright 2018 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#ifndef GrCCPathCache_DEFINED
#define GrCCPathCache_DEFINED

#include "GrShape.h"
#include "SkExchange.h"
#include "SkTHash.h"
#include "SkTInternalLList.h"
#include "ccpr/GrCCAtlas.h"
#include "ccpr/GrCCPathProcessor.h"

class GrCCPathCacheEntry;
class GrShape;

/**
 * This class implements an LRU cache that maps from GrShape to GrCCPathCacheEntry objects. Shapes
 * are only given one entry in the cache, so any time they are accessed with a different matrix, the
 * old entry gets evicted.
 */
class GrCCPathCache {
public:
    GrCCPathCache(uint32_t contextUniqueID);
    ~GrCCPathCache();

    class Key : public SkPathRef::GenIDChangeListener {
    public:
        static sk_sp<Key> Make(uint32_t pathCacheUniqueID, int dataCountU32,
                               const void* data = nullptr);

        uint32_t pathCacheUniqueID() const { return fPathCacheUniqueID; }

        int dataSizeInBytes() const { return fDataSizeInBytes; }
        const uint32_t* data() const;

        void resetDataCountU32(int dataCountU32) {
            SkASSERT(dataCountU32 <= fDataReserveCountU32);
            fDataSizeInBytes = dataCountU32 * sizeof(uint32_t);
        }
        uint32_t* data();

        bool operator==(const Key& that) const {
            return fDataSizeInBytes == that.fDataSizeInBytes &&
                   !memcmp(this->data(), that.data(), fDataSizeInBytes);
        }

        // Called when our corresponding path is modified or deleted. Not threadsafe.
        void onChange() override;

    private:
        Key(uint32_t pathCacheUniqueID, int dataCountU32)
                : fPathCacheUniqueID(pathCacheUniqueID)
                , fDataSizeInBytes(dataCountU32 * sizeof(uint32_t))
                SkDEBUGCODE(, fDataReserveCountU32(dataCountU32)) {
            SkASSERT(SK_InvalidUniqueID != fPathCacheUniqueID);
        }

        const uint32_t fPathCacheUniqueID;
        int fDataSizeInBytes;
        SkDEBUGCODE(const int fDataReserveCountU32);
        // The GrShape's unstyled key is stored as a variable-length footer to this class. GetKey
        // provides access to it.
    };

    // Stores the components of a transformation that affect a path mask (i.e. everything but
    // integer translation). During construction, any integer portions of the matrix's translate are
    // shaved off and returned to the caller. The caller is responsible for those integer shifts.
    struct MaskTransform {
        MaskTransform(const SkMatrix& m, SkIVector* shift);
        float fMatrix2x2[4];
#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
        // Except on AOSP, cache hits must have matching subpixel portions of their view matrix.
        // On AOSP we follow after HWUI and ignore the subpixel translate.
        float fSubpixelTranslate[2];
#endif
    };

    // Represents a ref on a GrCCPathCacheEntry that should only be used during the current flush.
    class OnFlushEntryRef : SkNoncopyable {
    public:
        static OnFlushEntryRef OnFlushRef(GrCCPathCacheEntry*);
        OnFlushEntryRef() = default;
        OnFlushEntryRef(OnFlushEntryRef&& ref) : fEntry(skstd::exchange(ref.fEntry, nullptr)) {}
        ~OnFlushEntryRef();

        GrCCPathCacheEntry* get() const { return fEntry; }
        GrCCPathCacheEntry* operator->() const { return fEntry; }
        GrCCPathCacheEntry& operator*() const { return *fEntry; }
        explicit operator bool() const { return fEntry; }
        void operator=(OnFlushEntryRef&& ref) { fEntry = skstd::exchange(ref.fEntry, nullptr); }

    private:
        OnFlushEntryRef(GrCCPathCacheEntry* entry) : fEntry(entry) {}
        GrCCPathCacheEntry* fEntry = nullptr;
    };

    enum class CreateIfAbsent : bool {
        kNo = false,
        kYes = true
    };

    // Finds an entry in the cache. Shapes are only given one entry, so any time they are accessed
    // with a different MaskTransform, the old entry gets evicted.
    OnFlushEntryRef find(GrOnFlushResourceProvider*, const GrShape&, const MaskTransform&,
                         CreateIfAbsent = CreateIfAbsent::kNo);

    void doPreFlushProcessing();

    void purgeEntriesOlderThan(GrProxyProvider*, const GrStdSteadyClock::time_point& purgeTime);

    // As we evict entries from our local path cache, we accumulate a list of invalidated atlas
    // textures. This call purges the invalidated atlas textures from the mainline GrResourceCache.
    // This call is available with two different "provider" objects, to accomodate whatever might
    // be available at the callsite.
    void purgeInvalidatedAtlasTextures(GrOnFlushResourceProvider*);
    void purgeInvalidatedAtlasTextures(GrProxyProvider*);

private:
    // This is a special ref ptr for GrCCPathCacheEntry, used by the hash table. It provides static
    // methods for SkTHash, and can only be moved. This guarantees the hash table holds exactly one
    // reference for each entry. Also, when a HashNode goes out of scope, that means it is exiting
    // the hash table. We take that opportunity to remove it from the LRU list and do some cleanup.
    class HashNode : SkNoncopyable {
    public:
        static const Key& GetKey(const HashNode&);
        inline static uint32_t Hash(const Key& key) {
            return GrResourceKeyHash(key.data(), key.dataSizeInBytes());
        }

        HashNode() = default;
        HashNode(GrCCPathCache*, sk_sp<Key>, const MaskTransform&, const GrShape&);
        HashNode(HashNode&& node)
                : fPathCache(node.fPathCache), fEntry(std::move(node.fEntry)) {
            SkASSERT(!node.fEntry);
        }

        ~HashNode();

        void operator=(HashNode&& node);

        GrCCPathCacheEntry* entry() const { return fEntry.get(); }

    private:
        GrCCPathCache* fPathCache = nullptr;
        sk_sp<GrCCPathCacheEntry> fEntry;
    };

    GrStdSteadyClock::time_point quickPerFlushTimestamp() {
        // time_point::min() means it's time to update fPerFlushTimestamp with a newer clock read.
        if (GrStdSteadyClock::time_point::min() == fPerFlushTimestamp) {
            fPerFlushTimestamp = GrStdSteadyClock::now();
        }
        return fPerFlushTimestamp;
    }

    void evict(const GrCCPathCache::Key&, GrCCPathCacheEntry* = nullptr);

    // Evicts all the cache entries whose keys have been queued up in fInvalidatedKeysInbox via
    // SkPath listeners.
    void evictInvalidatedCacheKeys();

    const uint32_t fContextUniqueID;

    SkTHashTable<HashNode, const Key&> fHashTable;
    SkTInternalLList<GrCCPathCacheEntry> fLRU;
    SkMessageBus<sk_sp<Key>>::Inbox fInvalidatedKeysInbox;
    sk_sp<Key> fScratchKey;  // Reused for creating a temporary key in the find() method.

    // We only read the clock once per flush, and cache it in this variable. This prevents us from
    // excessive clock reads for cache timestamps that might degrade performance.
    GrStdSteadyClock::time_point fPerFlushTimestamp = GrStdSteadyClock::time_point::min();

    // As we evict entries from our local path cache, we accumulate lists of invalidated atlas
    // textures in these two members. We hold these until we purge them from the GrResourceCache
    // (e.g. via purgeInvalidatedAtlasTextures().)
    SkSTArray<4, sk_sp<GrTextureProxy>> fInvalidatedProxies;
    SkSTArray<4, GrUniqueKey> fInvalidatedProxyUniqueKeys;

    friend class GrCCCachedAtlas;  // To append to fInvalidatedProxies, fInvalidatedProxyUniqueKeys.

public:
    const SkTHashTable<HashNode, const Key&>& testingOnly_getHashTable() const;
    const SkTInternalLList<GrCCPathCacheEntry>& testingOnly_getLRU() const;
};

/**
 * This class stores all the data necessary to draw a specific path + matrix combination from their
 * corresponding cached atlas.
 */
class GrCCPathCacheEntry : public GrNonAtomicRef<GrCCPathCacheEntry> {
public:
    SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrCCPathCacheEntry);

    ~GrCCPathCacheEntry() {
        SkASSERT(0 == fOnFlushRefCnt);
        SkASSERT(!fCachedAtlas);  // Should have called GrCCPathCache::evict().
    }

    const GrCCPathCache::Key& cacheKey() const { SkASSERT(fCacheKey); return *fCacheKey; }

    // The number of times this specific entry (path + matrix combination) has been pulled from
    // the path cache. As long as the caller does exactly one lookup per draw, this translates to
    // the number of times the path has been drawn with a compatible matrix.
    //
    // If the entry did not previously exist and was created during
    // GrCCPathCache::find(.., CreateIfAbsent::kYes), its hit count will be 1.
    int hitCount() const { return fHitCount; }

    const GrCCCachedAtlas* cachedAtlas() const { return fCachedAtlas.get(); }

    const SkIRect& devIBounds() const { return fDevIBounds; }
    int width() const { return fDevIBounds.width(); }
    int height() const { return fDevIBounds.height(); }

    enum class ReleaseAtlasResult : bool {
        kNone,
        kDidInvalidateFromCache
    };

    // Called once our path has been rendered into the mainline CCPR (fp16, coverage count) atlas.
    // The caller will stash this atlas texture away after drawing, and during the next flush,
    // recover it and attempt to copy any paths that got reused into permanent 8-bit atlases.
    void setCoverageCountAtlas(GrOnFlushResourceProvider*, GrCCAtlas*, const SkIVector& atlasOffset,
                               const SkRect& devBounds, const SkRect& devBounds45,
                               const SkIRect& devIBounds, const SkIVector& maskShift);

    // Called once our path mask has been copied into a permanent, 8-bit atlas. This method points
    // the entry at the new atlas and updates the GrCCCCachedAtlas data.
    ReleaseAtlasResult upgradeToLiteralCoverageAtlas(GrCCPathCache*, GrOnFlushResourceProvider*,
                                                     GrCCAtlas*, const SkIVector& newAtlasOffset);

private:
    using MaskTransform = GrCCPathCache::MaskTransform;

    GrCCPathCacheEntry(sk_sp<GrCCPathCache::Key> cacheKey, const MaskTransform& maskTransform)
            : fCacheKey(std::move(cacheKey)), fMaskTransform(maskTransform) {
    }

    // Resets this entry back to not having an atlas, and purges its previous atlas texture from the
    // resource cache if needed.
    ReleaseAtlasResult releaseCachedAtlas(GrCCPathCache*);

    sk_sp<GrCCPathCache::Key> fCacheKey;
    GrStdSteadyClock::time_point fTimestamp;
    int fHitCount = 0;

    sk_sp<GrCCCachedAtlas> fCachedAtlas;
    SkIVector fAtlasOffset;

    MaskTransform fMaskTransform;
    SkRect fDevBounds;
    SkRect fDevBounds45;
    SkIRect fDevIBounds;

    int fOnFlushRefCnt = 0;

    friend class GrCCPathCache;
    friend void GrCCPathProcessor::Instance::set(const GrCCPathCacheEntry&, const SkIVector&,
                                                 GrColor, DoEvenOddFill);  // To access data.

public:
    int testingOnly_peekOnFlushRefCnt() const;
};

/**
 * Encapsulates the data for an atlas whose texture is stored in the mainline GrResourceCache. Many
 * instances of GrCCPathCacheEntry will reference the same GrCCCachedAtlas.
 *
 * We use this object to track the percentage of the original atlas pixels that could still ever
 * potentially be reused (i.e., those which still represent an extant path). When the percentage
 * of useful pixels drops below 50%, we purge the entire texture from the resource cache.
 *
 * This object also holds a ref on the atlas's actual texture proxy during flush. When
 * fOnFlushRefCnt decrements back down to zero, we release fOnFlushProxy and reset it back to null.
 */
class GrCCCachedAtlas : public GrNonAtomicRef<GrCCCachedAtlas> {
public:
    using ReleaseAtlasResult = GrCCPathCacheEntry::ReleaseAtlasResult;

    GrCCCachedAtlas(GrCCAtlas::CoverageType type, const GrUniqueKey& textureKey,
                    sk_sp<GrTextureProxy> onFlushProxy)
            : fCoverageType(type)
            , fTextureKey(textureKey)
            , fOnFlushProxy(std::move(onFlushProxy)) {}

    ~GrCCCachedAtlas() {
        SkASSERT(!fOnFlushProxy);
        SkASSERT(!fOnFlushRefCnt);
    }

    GrCCAtlas::CoverageType coverageType() const  { return fCoverageType; }
    const GrUniqueKey& textureKey() const { return fTextureKey; }

    GrTextureProxy* getOnFlushProxy() const { return fOnFlushProxy.get(); }

    void setOnFlushProxy(sk_sp<GrTextureProxy> proxy) {
        SkASSERT(!fOnFlushProxy);
        fOnFlushProxy = std::move(proxy);
    }

    void addPathPixels(int numPixels) { fNumPathPixels += numPixels; }
    ReleaseAtlasResult invalidatePathPixels(GrCCPathCache*, int numPixels);

    int peekOnFlushRefCnt() const { return fOnFlushRefCnt; }
    void incrOnFlushRefCnt(int count = 1) const {
        SkASSERT(count > 0);
        SkASSERT(fOnFlushProxy);
        fOnFlushRefCnt += count;
    }
    void decrOnFlushRefCnt(int count = 1) const;

private:
    const GrCCAtlas::CoverageType fCoverageType;
    const GrUniqueKey fTextureKey;

    int fNumPathPixels = 0;
    int fNumInvalidatedPathPixels = 0;
    bool fIsInvalidatedFromResourceCache = false;

    mutable sk_sp<GrTextureProxy> fOnFlushProxy;
    mutable int fOnFlushRefCnt = 0;

public:
    int testingOnly_peekOnFlushRefCnt() const;
};


inline GrCCPathCache::HashNode::HashNode(GrCCPathCache* pathCache, sk_sp<Key> key,
                                         const MaskTransform& m, const GrShape& shape)
        : fPathCache(pathCache)
        , fEntry(new GrCCPathCacheEntry(key, m)) {
    SkASSERT(shape.hasUnstyledKey());
    shape.addGenIDChangeListener(std::move(key));
}

inline const GrCCPathCache::Key& GrCCPathCache::HashNode::GetKey(
        const GrCCPathCache::HashNode& node) {
    return *node.entry()->fCacheKey;
}

inline GrCCPathCache::HashNode::~HashNode() {
    SkASSERT(!fEntry || !fEntry->fCachedAtlas);  // Should have called GrCCPathCache::evict().
}

inline void GrCCPathCache::HashNode::operator=(HashNode&& node) {
    SkASSERT(!fEntry || !fEntry->fCachedAtlas);  // Should have called GrCCPathCache::evict().
    fEntry = skstd::exchange(node.fEntry, nullptr);
}

inline void GrCCPathProcessor::Instance::set(const GrCCPathCacheEntry& entry,
                                             const SkIVector& shift, GrColor color,
                                             DoEvenOddFill doEvenOddFill) {
    float dx = (float)shift.fX, dy = (float)shift.fY;
    this->set(entry.fDevBounds.makeOffset(dx, dy), MakeOffset45(entry.fDevBounds45, dx, dy),
              entry.fAtlasOffset - shift, color, doEvenOddFill);
}

#endif
