Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / gpu / GrAtlas.cpp
1
2 /*
3  * Copyright 2010 Google Inc.
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8
9 #include "GrAtlas.h"
10 #include "GrContext.h"
11 #include "GrGpu.h"
12 #include "GrRectanizer.h"
13
14 ///////////////////////////////////////////////////////////////////////////////
15
16 // for testing
17 #define FONT_CACHE_STATS 0
18 #if FONT_CACHE_STATS
19 static int g_UploadCount = 0;
20 #endif
21
22 GrPlot::GrPlot() : fDrawToken(NULL, 0)
23                  , fTexture(NULL)
24                  , fRects(NULL)
25                  , fAtlasMgr(NULL)
26                  , fBytesPerPixel(1)
27 {
28     fOffset.set(0, 0);
29 }
30
31 GrPlot::~GrPlot() {
32     delete fRects;
33 }
34
35 void GrPlot::init(GrAtlasMgr* mgr, int offX, int offY, int width, int height, size_t bpp) {
36     fRects = GrRectanizer::Factory(width, height);
37     fAtlasMgr = mgr;
38     fOffset.set(offX * width, offY * height);
39     fBytesPerPixel = bpp;
40 }
41
42 static inline void adjust_for_offset(GrIPoint16* loc, const GrIPoint16& offset) {
43     loc->fX += offset.fX;
44     loc->fY += offset.fY;
45 }
46
47 bool GrPlot::addSubImage(int width, int height, const void* image,
48                           GrIPoint16* loc) {
49     if (!fRects->addRect(width, height, loc)) {
50         return false;
51     }
52
53     SkAutoSMalloc<1024> storage;
54     adjust_for_offset(loc, fOffset);
55     GrContext* context = fTexture->getContext();
56     // We pass the flag that does not force a flush. We assume our caller is
57     // smart and hasn't referenced the part of the texture we're about to update
58     // since the last flush.
59     context->writeTexturePixels(fTexture,
60                                 loc->fX, loc->fY, width, height,
61                                 fTexture->config(), image, 0,
62                                 GrContext::kDontFlush_PixelOpsFlag);
63
64 #if FONT_CACHE_STATS
65     ++g_UploadCount;
66 #endif
67
68     return true;
69 }
70
71 void GrPlot::resetRects() {
72     SkASSERT(NULL != fRects);
73     fRects->reset();
74 }
75
76 ///////////////////////////////////////////////////////////////////////////////
77
78 GrAtlasMgr::GrAtlasMgr(GrGpu* gpu, GrPixelConfig config,
79                        const SkISize& backingTextureSize,
80                        int numPlotsX, int numPlotsY) {
81     fGpu = SkRef(gpu);
82     fPixelConfig = config;
83     fBackingTextureSize = backingTextureSize;
84     fNumPlotsX = numPlotsX;
85     fNumPlotsY = numPlotsY;
86     fTexture = NULL;
87
88     int plotWidth = fBackingTextureSize.width() / fNumPlotsX;
89     int plotHeight = fBackingTextureSize.height() / fNumPlotsY;
90
91     SkASSERT(plotWidth * fNumPlotsX == fBackingTextureSize.width());
92     SkASSERT(plotHeight * fNumPlotsY == fBackingTextureSize.height());
93
94     // set up allocated plots
95     size_t bpp = GrBytesPerPixel(fPixelConfig);
96     fPlotArray = SkNEW_ARRAY(GrPlot, (fNumPlotsX*fNumPlotsY));
97
98     GrPlot* currPlot = fPlotArray;
99     for (int y = numPlotsY-1; y >= 0; --y) {
100         for (int x = numPlotsX-1; x >= 0; --x) {
101             currPlot->init(this, x, y, plotWidth, plotHeight, bpp);
102
103             // build LRU list
104             fPlotList.addToHead(currPlot);
105             ++currPlot;
106         }
107     }
108 }
109
110 GrAtlasMgr::~GrAtlasMgr() {
111     SkSafeUnref(fTexture);
112     SkDELETE_ARRAY(fPlotArray);
113
114     fGpu->unref();
115 #if FONT_CACHE_STATS
116       GrPrintf("Num uploads: %d\n", g_UploadCount);
117 #endif
118 }
119
120 void GrAtlasMgr::moveToHead(GrPlot* plot) {
121     if (fPlotList.head() == plot) {
122         return;
123     }
124
125     fPlotList.remove(plot);
126     fPlotList.addToHead(plot);
127 };
128
129 GrPlot* GrAtlasMgr::addToAtlas(GrAtlas* atlas,
130                                int width, int height, const void* image,
131                                GrIPoint16* loc) {
132     // iterate through entire plot list for this atlas, see if we can find a hole
133     // last one was most recently added and probably most empty
134     for (int i = atlas->fPlots.count()-1; i >= 0; --i) {
135         GrPlot* plot = atlas->fPlots[i];
136         if (plot->addSubImage(width, height, image, loc)) {
137             this->moveToHead(plot);
138             return plot;
139         }
140     }
141
142     // before we get a new plot, make sure we have a backing texture
143     if (NULL == fTexture) {
144         // TODO: Update this to use the cache rather than directly creating a texture.
145         GrTextureDesc desc;
146         desc.fFlags = kDynamicUpdate_GrTextureFlagBit;
147         desc.fWidth = fBackingTextureSize.width();
148         desc.fHeight = fBackingTextureSize.height();
149         desc.fConfig = fPixelConfig;
150
151         fTexture = fGpu->createTexture(desc, NULL, 0);
152         if (NULL == fTexture) {
153             return NULL;
154         }
155     }
156
157     // now look through all allocated plots for one we can share, in MRU order
158     GrPlotList::Iter plotIter;
159     plotIter.init(fPlotList, GrPlotList::Iter::kHead_IterStart);
160     GrPlot* plot;
161     while (NULL != (plot = plotIter.get())) {
162         // make sure texture is set for quick lookup
163         plot->fTexture = fTexture;
164         if (plot->addSubImage(width, height, image, loc)) {
165             this->moveToHead(plot);
166             // new plot for atlas, put at end of array
167             *(atlas->fPlots.append()) = plot;
168             return plot;
169         }
170         plotIter.next();
171     }
172
173     // If the above fails, then the current plot list has no room
174     return NULL;
175 }
176
177 bool GrAtlasMgr::removePlot(GrAtlas* atlas, const GrPlot* plot) {
178     // iterate through plot list for this atlas
179     int count = atlas->fPlots.count();
180     for (int i = 0; i < count; ++i) {
181         if (plot == atlas->fPlots[i]) {
182             atlas->fPlots.remove(i);
183             return true;
184         }
185     }
186
187     return false;
188 }
189
190 // get a plot that's not being used by the current draw
191 GrPlot* GrAtlasMgr::getUnusedPlot() {
192     GrPlotList::Iter plotIter;
193     plotIter.init(fPlotList, GrPlotList::Iter::kTail_IterStart);
194     GrPlot* plot;
195     while (NULL != (plot = plotIter.get())) {
196         if (plot->drawToken().isIssued()) {
197             return plot;
198         }
199         plotIter.prev();
200     }
201
202     return NULL;
203 }