1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/gpu/GrAtlas.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,215 @@ 1.4 + 1.5 +/* 1.6 + * Copyright 2010 Google Inc. 1.7 + * 1.8 + * Use of this source code is governed by a BSD-style license that can be 1.9 + * found in the LICENSE file. 1.10 + */ 1.11 + 1.12 +#include "GrAtlas.h" 1.13 +#include "GrContext.h" 1.14 +#include "GrGpu.h" 1.15 +#include "GrRectanizer.h" 1.16 + 1.17 +#if 0 1.18 +#define GR_PLOT_WIDTH 8 1.19 +#define GR_PLOT_HEIGHT 4 1.20 +#define GR_ATLAS_WIDTH 256 1.21 +#define GR_ATLAS_HEIGHT 256 1.22 + 1.23 +#define GR_ATLAS_TEXTURE_WIDTH (GR_PLOT_WIDTH * GR_ATLAS_WIDTH) 1.24 +#define GR_ATLAS_TEXTURE_HEIGHT (GR_PLOT_HEIGHT * GR_ATLAS_HEIGHT) 1.25 + 1.26 +#else 1.27 + 1.28 +#define GR_ATLAS_TEXTURE_WIDTH 1024 1.29 +#define GR_ATLAS_TEXTURE_HEIGHT 2048 1.30 + 1.31 +#define GR_ATLAS_WIDTH 256 1.32 +#define GR_ATLAS_HEIGHT 256 1.33 + 1.34 +#define GR_PLOT_WIDTH (GR_ATLAS_TEXTURE_WIDTH / GR_ATLAS_WIDTH) 1.35 +#define GR_PLOT_HEIGHT (GR_ATLAS_TEXTURE_HEIGHT / GR_ATLAS_HEIGHT) 1.36 + 1.37 +#endif 1.38 + 1.39 +/////////////////////////////////////////////////////////////////////////////// 1.40 + 1.41 +// for testing 1.42 +#define FONT_CACHE_STATS 0 1.43 +#if FONT_CACHE_STATS 1.44 +static int g_UploadCount = 0; 1.45 +#endif 1.46 + 1.47 +GrPlot::GrPlot() : fDrawToken(NULL, 0) 1.48 + , fTexture(NULL) 1.49 + , fAtlasMgr(NULL) 1.50 + , fBytesPerPixel(1) 1.51 +{ 1.52 + fRects = GrRectanizer::Factory(GR_ATLAS_WIDTH, 1.53 + GR_ATLAS_HEIGHT); 1.54 + fOffset.set(0, 0); 1.55 +} 1.56 + 1.57 +GrPlot::~GrPlot() { 1.58 + delete fRects; 1.59 +} 1.60 + 1.61 +static inline void adjust_for_offset(GrIPoint16* loc, const GrIPoint16& offset) { 1.62 + loc->fX += offset.fX * GR_ATLAS_WIDTH; 1.63 + loc->fY += offset.fY * GR_ATLAS_HEIGHT; 1.64 +} 1.65 + 1.66 +bool GrPlot::addSubImage(int width, int height, const void* image, 1.67 + GrIPoint16* loc) { 1.68 + if (!fRects->addRect(width, height, loc)) { 1.69 + return false; 1.70 + } 1.71 + 1.72 + SkAutoSMalloc<1024> storage; 1.73 + adjust_for_offset(loc, fOffset); 1.74 + GrContext* context = fTexture->getContext(); 1.75 + // We pass the flag that does not force a flush. We assume our caller is 1.76 + // smart and hasn't referenced the part of the texture we're about to update 1.77 + // since the last flush. 1.78 + context->writeTexturePixels(fTexture, 1.79 + loc->fX, loc->fY, width, height, 1.80 + fTexture->config(), image, 0, 1.81 + GrContext::kDontFlush_PixelOpsFlag); 1.82 + 1.83 +#if FONT_CACHE_STATS 1.84 + ++g_UploadCount; 1.85 +#endif 1.86 + 1.87 + return true; 1.88 +} 1.89 + 1.90 +void GrPlot::resetRects() { 1.91 + SkASSERT(NULL != fRects); 1.92 + fRects->reset(); 1.93 +} 1.94 + 1.95 +/////////////////////////////////////////////////////////////////////////////// 1.96 + 1.97 +GrAtlasMgr::GrAtlasMgr(GrGpu* gpu, GrPixelConfig config) { 1.98 + fGpu = gpu; 1.99 + fPixelConfig = config; 1.100 + gpu->ref(); 1.101 + fTexture = NULL; 1.102 + 1.103 + // set up allocated plots 1.104 + size_t bpp = GrBytesPerPixel(fPixelConfig); 1.105 + fPlotArray = SkNEW_ARRAY(GrPlot, (GR_PLOT_WIDTH*GR_PLOT_HEIGHT)); 1.106 + 1.107 + GrPlot* currPlot = fPlotArray; 1.108 + for (int y = GR_PLOT_HEIGHT-1; y >= 0; --y) { 1.109 + for (int x = GR_PLOT_WIDTH-1; x >= 0; --x) { 1.110 + currPlot->fAtlasMgr = this; 1.111 + currPlot->fOffset.set(x, y); 1.112 + currPlot->fBytesPerPixel = bpp; 1.113 + 1.114 + // build LRU list 1.115 + fPlotList.addToHead(currPlot); 1.116 + ++currPlot; 1.117 + } 1.118 + } 1.119 +} 1.120 + 1.121 +GrAtlasMgr::~GrAtlasMgr() { 1.122 + SkSafeUnref(fTexture); 1.123 + SkDELETE_ARRAY(fPlotArray); 1.124 + 1.125 + fGpu->unref(); 1.126 +#if FONT_CACHE_STATS 1.127 + GrPrintf("Num uploads: %d\n", g_UploadCount); 1.128 +#endif 1.129 +} 1.130 + 1.131 +void GrAtlasMgr::moveToHead(GrPlot* plot) { 1.132 + if (fPlotList.head() == plot) { 1.133 + return; 1.134 + } 1.135 + 1.136 + fPlotList.remove(plot); 1.137 + fPlotList.addToHead(plot); 1.138 +}; 1.139 + 1.140 +GrPlot* GrAtlasMgr::addToAtlas(GrAtlas* atlas, 1.141 + int width, int height, const void* image, 1.142 + GrIPoint16* loc) { 1.143 + // iterate through entire plot list for this atlas, see if we can find a hole 1.144 + // last one was most recently added and probably most empty 1.145 + for (int i = atlas->fPlots.count()-1; i >= 0; --i) { 1.146 + GrPlot* plot = atlas->fPlots[i]; 1.147 + if (plot->addSubImage(width, height, image, loc)) { 1.148 + this->moveToHead(plot); 1.149 + return plot; 1.150 + } 1.151 + } 1.152 + 1.153 + // before we get a new plot, make sure we have a backing texture 1.154 + if (NULL == fTexture) { 1.155 + // TODO: Update this to use the cache rather than directly creating a texture. 1.156 + GrTextureDesc desc; 1.157 + desc.fFlags = kDynamicUpdate_GrTextureFlagBit; 1.158 + desc.fWidth = GR_ATLAS_TEXTURE_WIDTH; 1.159 + desc.fHeight = GR_ATLAS_TEXTURE_HEIGHT; 1.160 + desc.fConfig = fPixelConfig; 1.161 + 1.162 + fTexture = fGpu->createTexture(desc, NULL, 0); 1.163 + if (NULL == fTexture) { 1.164 + return NULL; 1.165 + } 1.166 + } 1.167 + 1.168 + // now look through all allocated plots for one we can share, in MRU order 1.169 + GrPlotList::Iter plotIter; 1.170 + plotIter.init(fPlotList, GrPlotList::Iter::kHead_IterStart); 1.171 + GrPlot* plot; 1.172 + while (NULL != (plot = plotIter.get())) { 1.173 + // make sure texture is set for quick lookup 1.174 + plot->fTexture = fTexture; 1.175 + if (plot->addSubImage(width, height, image, loc)) { 1.176 + this->moveToHead(plot); 1.177 + // new plot for atlas, put at end of array 1.178 + *(atlas->fPlots.append()) = plot; 1.179 + return plot; 1.180 + } 1.181 + plotIter.next(); 1.182 + } 1.183 + 1.184 + // If the above fails, then the current plot list has no room 1.185 + return NULL; 1.186 +} 1.187 + 1.188 +bool GrAtlasMgr::removePlot(GrAtlas* atlas, const GrPlot* plot) { 1.189 + // iterate through plot list for this atlas 1.190 + int count = atlas->fPlots.count(); 1.191 + for (int i = 0; i < count; ++i) { 1.192 + if (plot == atlas->fPlots[i]) { 1.193 + atlas->fPlots.remove(i); 1.194 + return true; 1.195 + } 1.196 + } 1.197 + 1.198 + return false; 1.199 +} 1.200 + 1.201 +// get a plot that's not being used by the current draw 1.202 +GrPlot* GrAtlasMgr::getUnusedPlot() { 1.203 + GrPlotList::Iter plotIter; 1.204 + plotIter.init(fPlotList, GrPlotList::Iter::kTail_IterStart); 1.205 + GrPlot* plot; 1.206 + while (NULL != (plot = plotIter.get())) { 1.207 + if (plot->drawToken().isIssued()) { 1.208 + return plot; 1.209 + } 1.210 + plotIter.prev(); 1.211 + } 1.212 + 1.213 + return NULL; 1.214 +} 1.215 + 1.216 +SkISize GrAtlas::getSize() const { 1.217 + return SkISize::Make(GR_ATLAS_TEXTURE_WIDTH, GR_ATLAS_TEXTURE_HEIGHT); 1.218 +}