blob: f035155b6b76a2d2dd21dc2cf69106b7a78cfd32 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
reed@google.comac10a2d2010-12-22 21:39:39 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * 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.
reed@google.comac10a2d2010-12-22 21:39:39 +00007 */
8
reed@google.comac10a2d2010-12-22 21:39:39 +00009#include "GrAtlas.h"
bsalomon@google.com6f379512011-11-16 20:36:03 +000010#include "GrContext.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000011#include "GrGpu.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000012#include "GrRectanizer.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000013
reed@google.comac10a2d2010-12-22 21:39:39 +000014///////////////////////////////////////////////////////////////////////////////
15
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +000016// for testing
17#define FONT_CACHE_STATS 0
18#if FONT_CACHE_STATS
19static int g_UploadCount = 0;
20#endif
21
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +000022GrPlot::GrPlot() : fDrawToken(NULL, 0)
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +000023 , fTexture(NULL)
commit-bot@chromium.org53e1e4d2014-04-01 16:25:11 +000024 , fRects(NULL)
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +000025 , fAtlasMgr(NULL)
26 , fBytesPerPixel(1)
27{
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +000028 fOffset.set(0, 0);
reed@google.comac10a2d2010-12-22 21:39:39 +000029}
30
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +000031GrPlot::~GrPlot() {
reed@google.comac10a2d2010-12-22 21:39:39 +000032 delete fRects;
reed@google.comac10a2d2010-12-22 21:39:39 +000033}
34
commit-bot@chromium.org53e1e4d2014-04-01 16:25:11 +000035void 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
robertphillips@google.com8b169312013-10-15 17:47:36 +000042static inline void adjust_for_offset(GrIPoint16* loc, const GrIPoint16& offset) {
commit-bot@chromium.org53e1e4d2014-04-01 16:25:11 +000043 loc->fX += offset.fX;
44 loc->fY += offset.fY;
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +000045}
46
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +000047bool GrPlot::addSubImage(int width, int height, const void* image,
reed@google.comac10a2d2010-12-22 21:39:39 +000048 GrIPoint16* loc) {
commit-bot@chromium.orgf9529242014-02-14 18:41:47 +000049 if (!fRects->addRect(width, height, loc)) {
reed@google.comac10a2d2010-12-22 21:39:39 +000050 return false;
51 }
52
bsalomon@google.com3582bf92011-06-30 21:32:31 +000053 SkAutoSMalloc<1024> storage;
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +000054 adjust_for_offset(loc, fOffset);
bsalomon@google.com6f379512011-11-16 20:36:03 +000055 GrContext* context = fTexture->getContext();
bsalomon@google.com0342a852012-08-20 19:22:38 +000056 // 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,
commit-bot@chromium.orgf9529242014-02-14 18:41:47 +000060 loc->fX, loc->fY, width, height,
bsalomon@google.com0342a852012-08-20 19:22:38 +000061 fTexture->config(), image, 0,
62 GrContext::kDontFlush_PixelOpsFlag);
reed@google.comac10a2d2010-12-22 21:39:39 +000063
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +000064#if FONT_CACHE_STATS
65 ++g_UploadCount;
66#endif
67
reed@google.comac10a2d2010-12-22 21:39:39 +000068 return true;
69}
70
skia.committer@gmail.comade9a342014-03-04 03:02:32 +000071void GrPlot::resetRects() {
72 SkASSERT(NULL != fRects);
73 fRects->reset();
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +000074}
75
reed@google.comac10a2d2010-12-22 21:39:39 +000076///////////////////////////////////////////////////////////////////////////////
77
commit-bot@chromium.org53e1e4d2014-04-01 16:25:11 +000078GrAtlasMgr::GrAtlasMgr(GrGpu* gpu, GrPixelConfig config,
79 const SkISize& backingTextureSize,
80 int numPlotsX, int numPlotsY) {
81 fGpu = SkRef(gpu);
commit-bot@chromium.org95294412013-09-26 15:28:40 +000082 fPixelConfig = config;
commit-bot@chromium.org53e1e4d2014-04-01 16:25:11 +000083 fBackingTextureSize = backingTextureSize;
84 fNumPlotsX = numPlotsX;
85 fNumPlotsY = numPlotsY;
commit-bot@chromium.org3fddf0e2013-09-26 12:57:19 +000086 fTexture = NULL;
skia.committer@gmail.com50df4d02013-09-28 07:01:33 +000087
commit-bot@chromium.org53e1e4d2014-04-01 16:25:11 +000088 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
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +000094 // set up allocated plots
robertphillips@google.com8b169312013-10-15 17:47:36 +000095 size_t bpp = GrBytesPerPixel(fPixelConfig);
commit-bot@chromium.org53e1e4d2014-04-01 16:25:11 +000096 fPlotArray = SkNEW_ARRAY(GrPlot, (fNumPlotsX*fNumPlotsY));
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +000097
98 GrPlot* currPlot = fPlotArray;
commit-bot@chromium.org53e1e4d2014-04-01 16:25:11 +000099 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);
skia.committer@gmail.com50df4d02013-09-28 07:01:33 +0000102
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000103 // build LRU list
104 fPlotList.addToHead(currPlot);
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000105 ++currPlot;
106 }
107 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000108}
109
110GrAtlasMgr::~GrAtlasMgr() {
commit-bot@chromium.org3fddf0e2013-09-26 12:57:19 +0000111 SkSafeUnref(fTexture);
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000112 SkDELETE_ARRAY(fPlotArray);
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +0000113
reed@google.comac10a2d2010-12-22 21:39:39 +0000114 fGpu->unref();
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +0000115#if FONT_CACHE_STATS
116 GrPrintf("Num uploads: %d\n", g_UploadCount);
117#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000118}
119
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000120void GrAtlasMgr::moveToHead(GrPlot* plot) {
121 if (fPlotList.head() == plot) {
122 return;
123 }
skia.committer@gmail.comade9a342014-03-04 03:02:32 +0000124
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000125 fPlotList.remove(plot);
126 fPlotList.addToHead(plot);
127};
128
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000129GrPlot* GrAtlasMgr::addToAtlas(GrAtlas* atlas,
130 int width, int height, const void* image,
131 GrIPoint16* loc) {
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000132 // 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;
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +0000139 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000140 }
141
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000142 // before we get a new plot, make sure we have a backing texture
commit-bot@chromium.org3fddf0e2013-09-26 12:57:19 +0000143 if (NULL == fTexture) {
bsalomon@google.com95ed55a2013-01-24 14:46:47 +0000144 // TODO: Update this to use the cache rather than directly creating a texture.
robertphillips@google.com75b3c962012-06-07 12:08:45 +0000145 GrTextureDesc desc;
146 desc.fFlags = kDynamicUpdate_GrTextureFlagBit;
commit-bot@chromium.org53e1e4d2014-04-01 16:25:11 +0000147 desc.fWidth = fBackingTextureSize.width();
148 desc.fHeight = fBackingTextureSize.height();
commit-bot@chromium.org95294412013-09-26 15:28:40 +0000149 desc.fConfig = fPixelConfig;
robertphillips@google.com75b3c962012-06-07 12:08:45 +0000150
commit-bot@chromium.org3fddf0e2013-09-26 12:57:19 +0000151 fTexture = fGpu->createTexture(desc, NULL, 0);
152 if (NULL == fTexture) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000153 return NULL;
154 }
155 }
skia.committer@gmail.com50df4d02013-09-28 07:01:33 +0000156
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000157 // 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();
reed@google.comac10a2d2010-12-22 21:39:39 +0000171 }
172
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000173 // If the above fails, then the current plot list has no room
174 return NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +0000175}
176
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000177bool 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;
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000184 }
185 }
skia.committer@gmail.com50df4d02013-09-28 07:01:33 +0000186
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000187 return false;
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000188}
189
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000190// get a plot that's not being used by the current draw
191GrPlot* 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();
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000200 }
skia.committer@gmail.com50df4d02013-09-28 07:01:33 +0000201
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000202 return NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +0000203}