blob: a67438bbe7192ef6c77999979d410ec80f26d2f9 [file] [log] [blame]
rileya@google.com2e2aedc2012-08-13 20:28:48 +00001/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef GrTextureStripAtlas_DEFINED
9#define GrTextureStripAtlas_DEFINED
10
commit-bot@chromium.orga0b40282013-09-18 13:00:55 +000011#include "SkBitmap.h"
mtklein4e976072016-08-08 09:06:27 -070012#include "SkOpts.h"
rileya@google.com2e2aedc2012-08-13 20:28:48 +000013#include "SkGr.h"
14#include "SkTDArray.h"
robertphillips3d533ac2014-07-20 09:40:00 -070015#include "SkTDynamicHash.h"
commit-bot@chromium.orga0b40282013-09-18 13:00:55 +000016#include "SkTypes.h"
rileya@google.com2e2aedc2012-08-13 20:28:48 +000017
Robert Phillips30f9bc62017-02-22 15:28:38 -050018class GrSurfaceContext;
19class GrTextureProxy;
20
rileya@google.com2e2aedc2012-08-13 20:28:48 +000021/**
rmistry@google.comfbfcd562012-08-23 18:09:54 +000022 * Maintains a single large texture whose rows store many textures of a small fixed height,
rileya@google.com2e2aedc2012-08-13 20:28:48 +000023 * stored in rows across the x-axis such that we can safely wrap/repeat them horizontally.
24 */
25class GrTextureStripAtlas {
26public:
rileya@google.com2e2aedc2012-08-13 20:28:48 +000027 /**
28 * Descriptor struct which we'll use as a hash table key
29 **/
30 struct Desc {
joshualitt690fc752015-07-13 12:49:13 -070031 Desc() { sk_bzero(this, sizeof(*this)); }
rileya@google.com2e2aedc2012-08-13 20:28:48 +000032 GrContext* fContext;
joshualitt690fc752015-07-13 12:49:13 -070033 GrPixelConfig fConfig;
34 uint16_t fWidth, fHeight, fRowHeight;
35 uint16_t fUnusedPadding;
36 bool operator==(const Desc& other) const {
37 return 0 == memcmp(this, &other, sizeof(Desc));
38 }
rileya@google.com2e2aedc2012-08-13 20:28:48 +000039 };
40
41 /**
42 * Try to find an atlas with the required parameters, creates a new one if necessary
43 */
44 static GrTextureStripAtlas* GetAtlas(const Desc& desc);
45
46 ~GrTextureStripAtlas();
47
48 /**
49 * Add a texture to the atlas
50 * @param data Bitmap data to copy into the row
51 * @return The row index we inserted into, or -1 if we failed to find an open row. The caller
52 * is responsible for calling unlockRow() with this row index when it's done with it.
53 */
54 int lockRow(const SkBitmap& data);
Brian Salomon0e05a822017-07-25 09:43:22 -040055 /**
56 * This is intended to be used when cloning a processor that already holds a lock. It is
57 * assumed that the row already has at least one lock.
58 */
59 void lockRow(int row);
rileya@google.com2e2aedc2012-08-13 20:28:48 +000060 void unlockRow(int row);
61
rmistry@google.comfbfcd562012-08-23 18:09:54 +000062 /**
63 * These functions help turn an integer row index in [0, 1, 2, ... numRows] into a scalar y
rileya@google.com2e2aedc2012-08-13 20:28:48 +000064 * texture coordinate in [0, 1] that we can use in a shader.
65 *
rmistry@google.comfbfcd562012-08-23 18:09:54 +000066 * If a regular texture access without using the atlas looks like:
rileya@google.com2e2aedc2012-08-13 20:28:48 +000067 *
Ethan Nicholas5af9ea32017-07-28 15:19:46 -040068 * texture2D(sampler, float2(x, y))
rileya@google.com2e2aedc2012-08-13 20:28:48 +000069 *
rmistry@google.comfbfcd562012-08-23 18:09:54 +000070 * Then when using the atlas we'd replace it with:
rileya@google.com2e2aedc2012-08-13 20:28:48 +000071 *
Ethan Nicholas5af9ea32017-07-28 15:19:46 -040072 * texture2D(sampler, float2(x, yOffset + y * scaleFactor))
rileya@google.com2e2aedc2012-08-13 20:28:48 +000073 *
74 * Where yOffset, returned by getYOffset(), is the offset to the start of the row within the
bsalomonc6327a82014-10-27 12:53:08 -070075 * atlas and scaleFactor, returned by getNormalizedTexelHeight, is the normalized height of
76 * one texel row.
rileya@google.com2e2aedc2012-08-13 20:28:48 +000077 */
bsalomon@google.com81712882012-11-01 17:12:34 +000078 SkScalar getYOffset(int row) const { return SkIntToScalar(row) / fNumRows; }
bsalomonc6327a82014-10-27 12:53:08 -070079 SkScalar getNormalizedTexelHeight() const { return fNormalizedYHeight; }
rileya@google.com2e2aedc2012-08-13 20:28:48 +000080
81 GrContext* getContext() const { return fDesc.fContext; }
Robert Phillips30f9bc62017-02-22 15:28:38 -050082
83 sk_sp<GrTextureProxy> asTextureProxyRef() const;
rileya@google.com2e2aedc2012-08-13 20:28:48 +000084
85private:
86
87 // Key to indicate an atlas row without any meaningful data stored in it
88 const static uint32_t kEmptyAtlasRowKey = 0xffffffff;
89
rmistry@google.comfbfcd562012-08-23 18:09:54 +000090 /**
rileya@google.com2e2aedc2012-08-13 20:28:48 +000091 * The state of a single row in our cache, next/prev pointers allow these to be chained
92 * together to represent LRU status
93 */
commit-bot@chromium.orge3beb6b2014-04-07 19:34:38 +000094 struct AtlasRow : SkNoncopyable {
halcanary96fcdcc2015-08-27 07:41:13 -070095 AtlasRow() : fKey(kEmptyAtlasRowKey), fLocks(0), fNext(nullptr), fPrev(nullptr) { }
rileya@google.com2e2aedc2012-08-13 20:28:48 +000096 // GenerationID of the bitmap that is represented by this row, 0xffffffff means "empty"
rmistry@google.comfbfcd562012-08-23 18:09:54 +000097 uint32_t fKey;
rileya@google.com2e2aedc2012-08-13 20:28:48 +000098 // How many times this has been locked (0 == unlocked)
rmistry@google.comfbfcd562012-08-23 18:09:54 +000099 int32_t fLocks;
rileya@google.com2e2aedc2012-08-13 20:28:48 +0000100 // We maintain an LRU linked list between unlocked nodes with these pointers
101 AtlasRow* fNext;
102 AtlasRow* fPrev;
103 };
104
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000105 /**
rileya@google.com2e2aedc2012-08-13 20:28:48 +0000106 * We'll only allow construction via the static GrTextureStripAtlas::GetAtlas
107 */
108 GrTextureStripAtlas(Desc desc);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000109
rileya@google.com2e2aedc2012-08-13 20:28:48 +0000110 void lockTexture();
111 void unlockTexture();
112
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000113 /**
rileya@google.com2e2aedc2012-08-13 20:28:48 +0000114 * Initialize our LRU list (if one already exists, clear it and start anew)
115 */
116 void initLRU();
117
118 /**
halcanary96fcdcc2015-08-27 07:41:13 -0700119 * Grabs the least recently used free row out of the LRU list, returns nullptr if no rows are free.
rileya@google.com2e2aedc2012-08-13 20:28:48 +0000120 */
121 AtlasRow* getLRU();
122
123 void appendLRU(AtlasRow* row);
124 void removeFromLRU(AtlasRow* row);
125
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000126 /**
127 * Searches the key table for a key and returns the index if found; if not found, it returns
rileya@google.com2e2aedc2012-08-13 20:28:48 +0000128 * the bitwise not of the index at which we could insert the key to maintain a sorted list.
129 **/
130 int searchByKey(uint32_t key);
131
132 /**
133 * Compare two atlas rows by key, so we can sort/search by key
134 */
bsalomon@google.com20f7f172013-05-17 19:05:03 +0000135 static bool KeyLess(const AtlasRow& lhs, const AtlasRow& rhs) {
136 return lhs.fKey < rhs.fKey;
rileya@google.com2e2aedc2012-08-13 20:28:48 +0000137 }
138
139#ifdef SK_DEBUG
140 void validate();
141#endif
142
robertphillips@google.comcdb426d2012-09-24 19:33:59 +0000143 /**
144 * Clean up callback registered with GrContext. Allows this class to
145 * free up any allocated AtlasEntry and GrTextureStripAtlas objects
146 */
147 static void CleanUp(const GrContext* context, void* info);
148
149 // Hash table entry for atlases
commit-bot@chromium.orga0b40282013-09-18 13:00:55 +0000150 class AtlasEntry : public ::SkNoncopyable {
robertphillips@google.comcdb426d2012-09-24 19:33:59 +0000151 public:
robertphillips3d533ac2014-07-20 09:40:00 -0700152 // for SkTDynamicHash
joshualitt690fc752015-07-13 12:49:13 -0700153 static const Desc& GetKey(const AtlasEntry& entry) { return entry.fDesc; }
mtklein4e976072016-08-08 09:06:27 -0700154 static uint32_t Hash(const Desc& desc) { return SkOpts::hash(&desc, sizeof(Desc)); }
robertphillips3d533ac2014-07-20 09:40:00 -0700155
156 // AtlasEntry proper
halcanary96fcdcc2015-08-27 07:41:13 -0700157 AtlasEntry() : fAtlas(nullptr) {}
halcanary385fe4d2015-08-26 13:07:48 -0700158 ~AtlasEntry() { delete fAtlas; }
joshualitt690fc752015-07-13 12:49:13 -0700159 Desc fDesc;
robertphillips@google.comcdb426d2012-09-24 19:33:59 +0000160 GrTextureStripAtlas* fAtlas;
161 };
162
robertphillips3d533ac2014-07-20 09:40:00 -0700163 class Hash;
164 static Hash* gAtlasCache;
robertphillips@google.comcdb426d2012-09-24 19:33:59 +0000165
robertphillips3d533ac2014-07-20 09:40:00 -0700166 static Hash* GetCache();
robertphillips@google.comcdb426d2012-09-24 19:33:59 +0000167
rileya@google.comf61c7462012-08-13 21:03:39 +0000168 // We increment gCacheCount for each atlas
rileya@google.com2e2aedc2012-08-13 20:28:48 +0000169 static int32_t gCacheCount;
rileya@google.com2e2aedc2012-08-13 20:28:48 +0000170
rileya@google.comf61c7462012-08-13 21:03:39 +0000171 // A unique ID for this texture (formed with: gCacheCount++), so we can be sure that if we
172 // get a texture back from the texture cache, that it's the same one we last used.
bsalomon@google.com0797c2c2012-12-20 15:13:01 +0000173 const int32_t fCacheKey;
rileya@google.com2e2aedc2012-08-13 20:28:48 +0000174
175 // Total locks on all rows (when this reaches zero, we can unlock our texture)
176 int32_t fLockedRows;
177
178 const Desc fDesc;
179 const uint16_t fNumRows;
Robert Phillips30f9bc62017-02-22 15:28:38 -0500180 sk_sp<GrSurfaceContext> fTexContext;
rileya@google.com2e2aedc2012-08-13 20:28:48 +0000181
bsalomonc6327a82014-10-27 12:53:08 -0700182 SkScalar fNormalizedYHeight;
183
rileya@google.com2e2aedc2012-08-13 20:28:48 +0000184 // Array of AtlasRows which store the state of all our rows. Stored in a contiguous array, in
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000185 // order that they appear in our texture, this means we can subtract this pointer from a row
rileya@google.com2e2aedc2012-08-13 20:28:48 +0000186 // pointer to get its index in the texture, and can save storing a row number in AtlasRow.
187 AtlasRow* fRows;
188
189 // Head and tail for linked list of least-recently-used rows (front = least recently used).
190 // Note that when a texture is locked, it gets removed from this list until it is unlocked.
191 AtlasRow* fLRUFront;
192 AtlasRow* fLRUBack;
193
194 // A list of pointers to AtlasRows that currently contain cached images, sorted by key
195 SkTDArray<AtlasRow*> fKeyTable;
196};
197
198#endif