1fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/*
2fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Copyright 2012 Google Inc.
3fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *
4fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Use of this source code is governed by a BSD-style license that can be
5fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * found in the LICENSE file.
6fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */
7fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
8fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "GrTextureStripAtlas.h"
9fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "GrContext.h"
10fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "GrContextPriv.h"
11fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "GrProxyProvider.h"
12fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "GrSurfaceContext.h"
13fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkGr.h"
14fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkPixelRef.h"
15fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkTSearch.h"
16fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
17fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifdef SK_DEBUG
18fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    #define VALIDATE this->validate()
19fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#else
20fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    #define VALIDATE
21fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
22fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
23fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotclass GrTextureStripAtlas::Hash : public SkTDynamicHash<GrTextureStripAtlas::AtlasEntry,
24fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                        GrTextureStripAtlas::Desc> {};
25fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
26fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotint32_t GrTextureStripAtlas::gCacheCount = 0;
27fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
28fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotGrTextureStripAtlas::Hash* GrTextureStripAtlas::gAtlasCache = nullptr;
29fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
30fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotGrTextureStripAtlas::Hash* GrTextureStripAtlas::GetCache() {
31fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
32fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (nullptr == gAtlasCache) {
33fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        gAtlasCache = new Hash;
34fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
35fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
36fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return gAtlasCache;
37fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
38fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
39fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Remove the specified atlas from the cache
40fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrTextureStripAtlas::CleanUp(const GrContext*, void* info) {
41fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(info);
42fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
43fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    AtlasEntry* entry = static_cast<AtlasEntry*>(info);
44fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
45fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // remove the cache entry
46fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    GetCache()->remove(entry->fDesc);
47fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
48fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // remove the actual entry
49fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    delete entry;
50fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
51fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (0 == GetCache()->count()) {
52fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        delete gAtlasCache;
53fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        gAtlasCache = nullptr;
54fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
55fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
56fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
57fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotGrTextureStripAtlas* GrTextureStripAtlas::GetAtlas(const GrTextureStripAtlas::Desc& desc) {
58fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    AtlasEntry* entry = GetCache()->find(desc);
59fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (nullptr == entry) {
60fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        entry = new AtlasEntry;
61fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
62fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        entry->fAtlas = new GrTextureStripAtlas(desc);
63fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        entry->fDesc = desc;
64fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
65fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        desc.fContext->addCleanUp(CleanUp, entry);
66fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
67fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        GetCache()->add(entry);
68fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
69fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
70fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return entry->fAtlas;
71fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
72fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
73fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotGrTextureStripAtlas::GrTextureStripAtlas(GrTextureStripAtlas::Desc desc)
74fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    : fCacheKey(sk_atomic_inc(&gCacheCount))
75fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    , fLockedRows(0)
76fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    , fDesc(desc)
77fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    , fNumRows(desc.fHeight / desc.fRowHeight)
78fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    , fRows(new AtlasRow[fNumRows])
79fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    , fLRUFront(nullptr)
80fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    , fLRUBack(nullptr) {
81fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(fNumRows * fDesc.fRowHeight == fDesc.fHeight);
82fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->initLRU();
83fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fNormalizedYHeight = SK_Scalar1 / fDesc.fHeight;
84fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    VALIDATE;
85fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
86fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
87fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotGrTextureStripAtlas::~GrTextureStripAtlas() { delete[] fRows; }
88fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
89fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrTextureStripAtlas::lockRow(int row) {
90fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // This should only be called on a row that is already locked.
91fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(fRows[row].fLocks);
92fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fRows[row].fLocks++;
93fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    ++fLockedRows;
94fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
95fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
96fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotint GrTextureStripAtlas::lockRow(const SkBitmap& bitmap) {
97fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    VALIDATE;
98fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (0 == fLockedRows) {
99fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->lockTexture();
100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!fTexContext) {
101fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return -1;
102fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
103fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
104fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
105fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int key = bitmap.getGenerationID();
106fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int rowNumber = -1;
107fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int index = this->searchByKey(key);
108fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
109fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (index >= 0) {
110fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // We already have the data in a row, so we can just return that row
111fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        AtlasRow* row = fKeyTable[index];
112fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (0 == row->fLocks) {
113fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->removeFromLRU(row);
114fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
115fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ++row->fLocks;
116fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ++fLockedRows;
117fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
118fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // Since all the rows are always stored in a contiguous array, we can save the memory
119fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // required for storing row numbers and just compute it with some pointer arithmetic
120fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        rowNumber = static_cast<int>(row - fRows);
121fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
122fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // ~index is the index where we will insert the new key to keep things sorted
123fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        index = ~index;
124fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
125fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // We don't have this data cached, so pick the least recently used row to copy into
126fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        AtlasRow* row = this->getLRU();
127fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
128fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ++fLockedRows;
129fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
130fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (nullptr == row) {
131fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // force a flush, which should unlock all the rows; then try again
132fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fDesc.fContext->contextPriv().flush(nullptr); // tighten this up?
133fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            row = this->getLRU();
134fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (nullptr == row) {
135fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                --fLockedRows;
136fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                return -1;
137fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
138fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
139fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
140fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->removeFromLRU(row);
141fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
142fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        uint32_t oldKey = row->fKey;
143fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
144fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // If we are writing into a row that already held bitmap data, we need to remove the
145fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // reference to that genID which is stored in our sorted table of key values.
146fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (oldKey != kEmptyAtlasRowKey) {
147fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
148fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // Find the entry in the list; if it's before the index where we plan on adding the new
149fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // entry, we decrement since it will shift elements ahead of it back by one.
150fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            int oldIndex = this->searchByKey(oldKey);
151fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (oldIndex < index) {
152fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                --index;
153fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
154fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
155fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fKeyTable.remove(oldIndex);
156fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
157fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
158fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        row->fKey = key;
159fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        row->fLocks = 1;
160fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fKeyTable.insert(index, 1, &row);
161fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        rowNumber = static_cast<int>(row - fRows);
162fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
163fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(bitmap.width() == fDesc.fWidth);
164fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(bitmap.height() == fDesc.fRowHeight);
165fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
166fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // Pass in the kDontFlush flag, since we know we're writing to a part of this texture
167fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // that is not currently in use
168fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fTexContext->writePixels(bitmap.info(), bitmap.getPixels(), bitmap.rowBytes(),
169fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                 0, rowNumber * fDesc.fRowHeight,
170fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                 GrContextPriv::kDontFlush_PixelOpsFlag);
171fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
172fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
173fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(rowNumber >= 0);
174fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    VALIDATE;
175fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return rowNumber;
176fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
177fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
178fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotsk_sp<GrTextureProxy> GrTextureStripAtlas::asTextureProxyRef() const {
179fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return fTexContext->asTextureProxyRef();
180fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
181fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
182fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrTextureStripAtlas::unlockRow(int row) {
183fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    VALIDATE;
184fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    --fRows[row].fLocks;
185fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    --fLockedRows;
186fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(fRows[row].fLocks >= 0 && fLockedRows >= 0);
187fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (0 == fRows[row].fLocks) {
188fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->appendLRU(fRows + row);
189fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
190fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (0 == fLockedRows) {
191fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->unlockTexture();
192fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
193fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    VALIDATE;
194fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
195fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
196fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotGrTextureStripAtlas::AtlasRow* GrTextureStripAtlas::getLRU() {
197fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // Front is least-recently-used
198fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    AtlasRow* row = fLRUFront;
199fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return row;
200fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
201fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
202fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrTextureStripAtlas::lockTexture() {
203fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
204fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
205fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    GrUniqueKey key;
206fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    GrUniqueKey::Builder builder(&key, kDomain, 1);
207fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    builder[0] = static_cast<uint32_t>(fCacheKey);
208fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    builder.finish();
209fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
210fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    GrProxyProvider* proxyProvider = fDesc.fContext->contextPriv().proxyProvider();
211fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
212fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    sk_sp<GrTextureProxy> proxy = proxyProvider->findOrCreateProxyByUniqueKey(
213fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                                key, kTopLeft_GrSurfaceOrigin);
214fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!proxy) {
215fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        GrSurfaceDesc texDesc;
216fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        texDesc.fOrigin = kTopLeft_GrSurfaceOrigin;
217fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        texDesc.fWidth  = fDesc.fWidth;
218fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        texDesc.fHeight = fDesc.fHeight;
219fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        texDesc.fConfig = fDesc.fConfig;
220fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
221fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        proxy = proxyProvider->createProxy(texDesc, SkBackingFit::kExact, SkBudgeted::kYes,
222fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                           GrResourceProvider::kNoPendingIO_Flag);
223fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!proxy) {
224fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return;
225fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
226fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
227fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(proxy->origin() == kTopLeft_GrSurfaceOrigin);
228fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        proxyProvider->assignUniqueKeyToProxy(key, proxy.get());
229fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // This is a new texture, so all of our cache info is now invalid
230fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->initLRU();
231fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fKeyTable.rewind();
232fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
233fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(proxy);
234fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fTexContext = fDesc.fContext->contextPriv().makeWrappedSurfaceContext(std::move(proxy));
235fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
236fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
237fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrTextureStripAtlas::unlockTexture() {
238fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(fTexContext && 0 == fLockedRows);
239fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fTexContext.reset();
240fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
241fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
242fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrTextureStripAtlas::initLRU() {
243fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fLRUFront = nullptr;
244fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fLRUBack = nullptr;
245fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // Initially all the rows are in the LRU list
246fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int i = 0; i < fNumRows; ++i) {
247fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fRows[i].fKey = kEmptyAtlasRowKey;
248fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fRows[i].fNext = nullptr;
249fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fRows[i].fPrev = nullptr;
250fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->appendLRU(fRows + i);
251fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
252fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(nullptr == fLRUFront || nullptr == fLRUFront->fPrev);
253fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(nullptr == fLRUBack || nullptr == fLRUBack->fNext);
254fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
255fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
256fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrTextureStripAtlas::appendLRU(AtlasRow* row) {
257fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(nullptr == row->fPrev && nullptr == row->fNext);
258fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (nullptr == fLRUFront && nullptr == fLRUBack) {
259fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fLRUFront = row;
260fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fLRUBack = row;
261fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
262fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        row->fPrev = fLRUBack;
263fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fLRUBack->fNext = row;
264fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fLRUBack = row;
265fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
266fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
267fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
268fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrTextureStripAtlas::removeFromLRU(AtlasRow* row) {
269fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(row);
270fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (row->fNext && row->fPrev) {
271fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        row->fPrev->fNext = row->fNext;
272fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        row->fNext->fPrev = row->fPrev;
273fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
274fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (nullptr == row->fNext) {
275fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(row == fLRUBack);
276fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fLRUBack = row->fPrev;
277fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (fLRUBack) {
278fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                fLRUBack->fNext = nullptr;
279fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
280fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
281fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (nullptr == row->fPrev) {
282fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(row == fLRUFront);
283fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fLRUFront = row->fNext;
284fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (fLRUFront) {
285fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                fLRUFront->fPrev = nullptr;
286fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
287fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
288fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
289fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    row->fNext = nullptr;
290fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    row->fPrev = nullptr;
291fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
292fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
293fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotint GrTextureStripAtlas::searchByKey(uint32_t key) {
294fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    AtlasRow target;
295fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    target.fKey = key;
296fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return SkTSearch<const AtlasRow,
297fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                     GrTextureStripAtlas::KeyLess>((const AtlasRow**)fKeyTable.begin(),
298fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                   fKeyTable.count(),
299fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                   &target,
300fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                   sizeof(AtlasRow*));
301fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
302fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
303fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifdef SK_DEBUG
304fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrTextureStripAtlas::validate() {
305fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
306fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // Our key table should be sorted
307fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    uint32_t prev = 1 > fKeyTable.count() ? 0 : fKeyTable[0]->fKey;
308fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int i = 1; i < fKeyTable.count(); ++i) {
309fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(prev < fKeyTable[i]->fKey);
310fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(fKeyTable[i]->fKey != kEmptyAtlasRowKey);
311fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        prev = fKeyTable[i]->fKey;
312fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
313fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
314fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int lruCount = 0;
315fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // Validate LRU pointers, and count LRU entries
316fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(nullptr == fLRUFront || nullptr == fLRUFront->fPrev);
317fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(nullptr == fLRUBack  || nullptr == fLRUBack->fNext);
318fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (AtlasRow* r = fLRUFront; r != nullptr; r = r->fNext) {
319fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (nullptr == r->fNext) {
320fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(r == fLRUBack);
321fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        } else {
322fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(r->fNext->fPrev == r);
323fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
324fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ++lruCount;
325fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
326fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
327fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int rowLocks = 0;
328fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int freeRows = 0;
329fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
330fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int i = 0; i < fNumRows; ++i) {
331fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        rowLocks += fRows[i].fLocks;
332fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (0 == fRows[i].fLocks) {
333fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            ++freeRows;
334fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            bool inLRU = false;
335fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // Step through the LRU and make sure it's present
336fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            for (AtlasRow* r = fLRUFront; r != nullptr; r = r->fNext) {
337fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (r == &fRows[i]) {
338fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    inLRU = true;
339fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    break;
340fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
341fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
342fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(inLRU);
343fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        } else {
344fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // If we are locked, we should have a key
345fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(kEmptyAtlasRowKey != fRows[i].fKey);
346fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
347fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
348fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // If we have a key != kEmptyAtlasRowKey, it should be in the key table
349fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(fRows[i].fKey == kEmptyAtlasRowKey || this->searchByKey(fRows[i].fKey) >= 0);
350fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
351fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
352fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // Our count of locks should equal the sum of row locks, unless we ran out of rows and flushed,
353fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // in which case we'll have one more lock than recorded in the rows (to represent the pending
354fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // lock of a row; which ensures we don't unlock the texture prematurely).
355fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(rowLocks == fLockedRows || rowLocks + 1 == fLockedRows);
356fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
357fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // We should have one lru entry for each free row
358fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(freeRows == lruCount);
359fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
360fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // If we have locked rows, we should have a locked texture, otherwise
361fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // it should be unlocked
362fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fLockedRows == 0) {
363fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(!fTexContext);
364fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
365fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(fTexContext);
366fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
367fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
368fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
369