1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/gpu/effects/GrTextureStripAtlas.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,194 @@ 1.4 +/* 1.5 + * Copyright 2012 Google Inc. 1.6 + * 1.7 + * Use of this source code is governed by a BSD-style license that can be 1.8 + * found in the LICENSE file. 1.9 + */ 1.10 + 1.11 +#ifndef GrTextureStripAtlas_DEFINED 1.12 +#define GrTextureStripAtlas_DEFINED 1.13 + 1.14 +#include "GrBinHashKey.h" 1.15 +#include "GrTHashTable.h" 1.16 +#include "SkBitmap.h" 1.17 +#include "SkGr.h" 1.18 +#include "SkTDArray.h" 1.19 +#include "SkTypes.h" 1.20 + 1.21 +/** 1.22 + * Maintains a single large texture whose rows store many textures of a small fixed height, 1.23 + * stored in rows across the x-axis such that we can safely wrap/repeat them horizontally. 1.24 + */ 1.25 +class GrTextureStripAtlas { 1.26 +public: 1.27 + /** 1.28 + * Descriptor struct which we'll use as a hash table key 1.29 + **/ 1.30 + struct Desc { 1.31 + Desc() { memset(this, 0, sizeof(*this)); } 1.32 + uint16_t fWidth, fHeight, fRowHeight; 1.33 + GrPixelConfig fConfig; 1.34 + GrContext* fContext; 1.35 + const uint32_t* asKey() const { return reinterpret_cast<const uint32_t*>(this); } 1.36 + }; 1.37 + 1.38 + /** 1.39 + * Try to find an atlas with the required parameters, creates a new one if necessary 1.40 + */ 1.41 + static GrTextureStripAtlas* GetAtlas(const Desc& desc); 1.42 + 1.43 + ~GrTextureStripAtlas(); 1.44 + 1.45 + /** 1.46 + * Add a texture to the atlas 1.47 + * @param data Bitmap data to copy into the row 1.48 + * @return The row index we inserted into, or -1 if we failed to find an open row. The caller 1.49 + * is responsible for calling unlockRow() with this row index when it's done with it. 1.50 + */ 1.51 + int lockRow(const SkBitmap& data); 1.52 + void unlockRow(int row); 1.53 + 1.54 + /** 1.55 + * These functions help turn an integer row index in [0, 1, 2, ... numRows] into a scalar y 1.56 + * texture coordinate in [0, 1] that we can use in a shader. 1.57 + * 1.58 + * If a regular texture access without using the atlas looks like: 1.59 + * 1.60 + * texture2D(sampler, vec2(x, y)) 1.61 + * 1.62 + * Then when using the atlas we'd replace it with: 1.63 + * 1.64 + * texture2D(sampler, vec2(x, yOffset + y * scaleFactor)) 1.65 + * 1.66 + * Where yOffset, returned by getYOffset(), is the offset to the start of the row within the 1.67 + * atlas and scaleFactor, returned by getVerticalScaleFactor(), is the y-scale of the row, 1.68 + * relative to the height of the overall atlas texture. 1.69 + */ 1.70 + SkScalar getYOffset(int row) const { return SkIntToScalar(row) / fNumRows; } 1.71 + SkScalar getVerticalScaleFactor() const { return SkIntToScalar(fDesc.fRowHeight) / fDesc.fHeight; } 1.72 + 1.73 + GrContext* getContext() const { return fDesc.fContext; } 1.74 + GrTexture* getTexture() const { return fTexture; } 1.75 + 1.76 +private: 1.77 + 1.78 + // Key to indicate an atlas row without any meaningful data stored in it 1.79 + const static uint32_t kEmptyAtlasRowKey = 0xffffffff; 1.80 + 1.81 + /** 1.82 + * The state of a single row in our cache, next/prev pointers allow these to be chained 1.83 + * together to represent LRU status 1.84 + */ 1.85 + struct AtlasRow : public SkNoncopyable { 1.86 + AtlasRow() : fKey(kEmptyAtlasRowKey), fLocks(0), fNext(NULL), fPrev(NULL) { } 1.87 + // GenerationID of the bitmap that is represented by this row, 0xffffffff means "empty" 1.88 + uint32_t fKey; 1.89 + // How many times this has been locked (0 == unlocked) 1.90 + int32_t fLocks; 1.91 + // We maintain an LRU linked list between unlocked nodes with these pointers 1.92 + AtlasRow* fNext; 1.93 + AtlasRow* fPrev; 1.94 + }; 1.95 + 1.96 + /** 1.97 + * We'll only allow construction via the static GrTextureStripAtlas::GetAtlas 1.98 + */ 1.99 + GrTextureStripAtlas(Desc desc); 1.100 + 1.101 + void lockTexture(); 1.102 + void unlockTexture(); 1.103 + 1.104 + /** 1.105 + * Initialize our LRU list (if one already exists, clear it and start anew) 1.106 + */ 1.107 + void initLRU(); 1.108 + 1.109 + /** 1.110 + * Grabs the least recently used free row out of the LRU list, returns NULL if no rows are free. 1.111 + */ 1.112 + AtlasRow* getLRU(); 1.113 + 1.114 + void appendLRU(AtlasRow* row); 1.115 + void removeFromLRU(AtlasRow* row); 1.116 + 1.117 + /** 1.118 + * Searches the key table for a key and returns the index if found; if not found, it returns 1.119 + * the bitwise not of the index at which we could insert the key to maintain a sorted list. 1.120 + **/ 1.121 + int searchByKey(uint32_t key); 1.122 + 1.123 + /** 1.124 + * Compare two atlas rows by key, so we can sort/search by key 1.125 + */ 1.126 + static bool KeyLess(const AtlasRow& lhs, const AtlasRow& rhs) { 1.127 + return lhs.fKey < rhs.fKey; 1.128 + } 1.129 + 1.130 +#ifdef SK_DEBUG 1.131 + void validate(); 1.132 +#endif 1.133 + 1.134 + /** 1.135 + * Clean up callback registered with GrContext. Allows this class to 1.136 + * free up any allocated AtlasEntry and GrTextureStripAtlas objects 1.137 + */ 1.138 + static void CleanUp(const GrContext* context, void* info); 1.139 + 1.140 + // Hash table entry for atlases 1.141 + class AtlasEntry; 1.142 + class AtlasHashKey : public GrBinHashKey<sizeof(GrTextureStripAtlas::Desc)> { 1.143 + public: 1.144 + static bool Equals(const AtlasEntry& entry, const AtlasHashKey& key); 1.145 + static bool LessThan(const AtlasEntry& entry, const AtlasHashKey& key); 1.146 + }; 1.147 + class AtlasEntry : public ::SkNoncopyable { 1.148 + public: 1.149 + AtlasEntry() : fAtlas(NULL) {} 1.150 + ~AtlasEntry() { SkDELETE(fAtlas); } 1.151 + AtlasHashKey fKey; 1.152 + GrTextureStripAtlas* fAtlas; 1.153 + }; 1.154 + 1.155 + static GrTHashTable<AtlasEntry, AtlasHashKey, 8>* gAtlasCache; 1.156 + 1.157 + static GrTHashTable<AtlasEntry, AtlasHashKey, 8>* GetCache(); 1.158 + 1.159 + // We increment gCacheCount for each atlas 1.160 + static int32_t gCacheCount; 1.161 + 1.162 + // A unique ID for this texture (formed with: gCacheCount++), so we can be sure that if we 1.163 + // get a texture back from the texture cache, that it's the same one we last used. 1.164 + const int32_t fCacheKey; 1.165 + 1.166 + // Total locks on all rows (when this reaches zero, we can unlock our texture) 1.167 + int32_t fLockedRows; 1.168 + 1.169 + const Desc fDesc; 1.170 + const uint16_t fNumRows; 1.171 + GrTexture* fTexture; 1.172 + 1.173 + // Array of AtlasRows which store the state of all our rows. Stored in a contiguous array, in 1.174 + // order that they appear in our texture, this means we can subtract this pointer from a row 1.175 + // pointer to get its index in the texture, and can save storing a row number in AtlasRow. 1.176 + AtlasRow* fRows; 1.177 + 1.178 + // Head and tail for linked list of least-recently-used rows (front = least recently used). 1.179 + // Note that when a texture is locked, it gets removed from this list until it is unlocked. 1.180 + AtlasRow* fLRUFront; 1.181 + AtlasRow* fLRUBack; 1.182 + 1.183 + // A list of pointers to AtlasRows that currently contain cached images, sorted by key 1.184 + SkTDArray<AtlasRow*> fKeyTable; 1.185 +}; 1.186 + 1.187 +inline bool GrTextureStripAtlas::AtlasHashKey::Equals(const AtlasEntry& entry, 1.188 + const AtlasHashKey& key) { 1.189 + return entry.fKey == key; 1.190 +} 1.191 + 1.192 +inline bool GrTextureStripAtlas::AtlasHashKey::LessThan(const AtlasEntry& entry, 1.193 + const AtlasHashKey& key) { 1.194 + return entry.fKey < key; 1.195 +} 1.196 + 1.197 +#endif