3 * Copyright 2010 Google Inc.
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
10 #include "GrContext.h"
12 #include "GrRectanizer.h"
14 ///////////////////////////////////////////////////////////////////////////////
17 #define FONT_CACHE_STATS 0
19 static int g_UploadCount = 0;
22 GrPlot::GrPlot() : fDrawToken(NULL, 0)
35 void GrPlot::init(GrAtlasMgr* mgr, int offX, int offY, int width, int height, size_t bpp) {
36 fRects = GrRectanizer::Factory(width, height);
38 fOffset.set(offX * width, offY * height);
42 static inline void adjust_for_offset(GrIPoint16* loc, const GrIPoint16& offset) {
47 bool GrPlot::addSubImage(int width, int height, const void* image,
49 if (!fRects->addRect(width, height, loc)) {
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);
71 void GrPlot::resetRects() {
72 SkASSERT(NULL != fRects);
76 ///////////////////////////////////////////////////////////////////////////////
78 GrAtlasMgr::GrAtlasMgr(GrGpu* gpu, GrPixelConfig config,
79 const SkISize& backingTextureSize,
80 int numPlotsX, int numPlotsY) {
82 fPixelConfig = config;
83 fBackingTextureSize = backingTextureSize;
84 fNumPlotsX = numPlotsX;
85 fNumPlotsY = numPlotsY;
88 int plotWidth = fBackingTextureSize.width() / fNumPlotsX;
89 int plotHeight = fBackingTextureSize.height() / fNumPlotsY;
91 SkASSERT(plotWidth * fNumPlotsX == fBackingTextureSize.width());
92 SkASSERT(plotHeight * fNumPlotsY == fBackingTextureSize.height());
94 // set up allocated plots
95 size_t bpp = GrBytesPerPixel(fPixelConfig);
96 fPlotArray = SkNEW_ARRAY(GrPlot, (fNumPlotsX*fNumPlotsY));
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);
104 fPlotList.addToHead(currPlot);
110 GrAtlasMgr::~GrAtlasMgr() {
111 SkSafeUnref(fTexture);
112 SkDELETE_ARRAY(fPlotArray);
116 GrPrintf("Num uploads: %d\n", g_UploadCount);
120 void GrAtlasMgr::moveToHead(GrPlot* plot) {
121 if (fPlotList.head() == plot) {
125 fPlotList.remove(plot);
126 fPlotList.addToHead(plot);
129 GrPlot* GrAtlasMgr::addToAtlas(GrAtlas* atlas,
130 int width, int height, const void* image,
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);
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.
146 desc.fFlags = kDynamicUpdate_GrTextureFlagBit;
147 desc.fWidth = fBackingTextureSize.width();
148 desc.fHeight = fBackingTextureSize.height();
149 desc.fConfig = fPixelConfig;
151 fTexture = fGpu->createTexture(desc, NULL, 0);
152 if (NULL == fTexture) {
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);
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;
173 // If the above fails, then the current plot list has no room
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);
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);
195 while (NULL != (plot = plotIter.get())) {
196 if (plot->drawToken().isIssued()) {