blob: e17171f8018f9cc277493ea317917f6551d97dbf [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
14#if 0
15#define GR_PLOT_WIDTH 8
16#define GR_PLOT_HEIGHT 4
17#define GR_ATLAS_WIDTH 256
18#define GR_ATLAS_HEIGHT 256
19
20#define GR_ATLAS_TEXTURE_WIDTH (GR_PLOT_WIDTH * GR_ATLAS_WIDTH)
21#define GR_ATLAS_TEXTURE_HEIGHT (GR_PLOT_HEIGHT * GR_ATLAS_HEIGHT)
22
23#else
24
25#define GR_ATLAS_TEXTURE_WIDTH 1024
26#define GR_ATLAS_TEXTURE_HEIGHT 2048
27
commit-bot@chromium.org09846a02013-10-02 17:37:59 +000028#define GR_ATLAS_WIDTH 256
29#define GR_ATLAS_HEIGHT 256
reed@google.comac10a2d2010-12-22 21:39:39 +000030
31#define GR_PLOT_WIDTH (GR_ATLAS_TEXTURE_WIDTH / GR_ATLAS_WIDTH)
32#define GR_PLOT_HEIGHT (GR_ATLAS_TEXTURE_HEIGHT / GR_ATLAS_HEIGHT)
33
34#endif
35
36///////////////////////////////////////////////////////////////////////////////
37
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +000038// for testing
39#define FONT_CACHE_STATS 0
40#if FONT_CACHE_STATS
41static int g_UploadCount = 0;
42#endif
43
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +000044GrPlot::GrPlot() : fDrawToken(NULL, 0)
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +000045 , fTexture(NULL)
46 , fAtlasMgr(NULL)
47 , fBytesPerPixel(1)
48{
commit-bot@chromium.orgf9529242014-02-14 18:41:47 +000049 fRects = GrRectanizer::Factory(GR_ATLAS_WIDTH,
50 GR_ATLAS_HEIGHT);
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +000051 fOffset.set(0, 0);
reed@google.comac10a2d2010-12-22 21:39:39 +000052}
53
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +000054GrPlot::~GrPlot() {
reed@google.comac10a2d2010-12-22 21:39:39 +000055 delete fRects;
reed@google.comac10a2d2010-12-22 21:39:39 +000056}
57
robertphillips@google.com8b169312013-10-15 17:47:36 +000058static inline void adjust_for_offset(GrIPoint16* loc, const GrIPoint16& offset) {
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +000059 loc->fX += offset.fX * GR_ATLAS_WIDTH;
60 loc->fY += offset.fY * GR_ATLAS_HEIGHT;
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +000061}
62
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +000063bool GrPlot::addSubImage(int width, int height, const void* image,
reed@google.comac10a2d2010-12-22 21:39:39 +000064 GrIPoint16* loc) {
commit-bot@chromium.orgf9529242014-02-14 18:41:47 +000065 if (!fRects->addRect(width, height, loc)) {
reed@google.comac10a2d2010-12-22 21:39:39 +000066 return false;
67 }
68
bsalomon@google.com3582bf92011-06-30 21:32:31 +000069 SkAutoSMalloc<1024> storage;
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +000070 adjust_for_offset(loc, fOffset);
bsalomon@google.com6f379512011-11-16 20:36:03 +000071 GrContext* context = fTexture->getContext();
bsalomon@google.com0342a852012-08-20 19:22:38 +000072 // We pass the flag that does not force a flush. We assume our caller is
73 // smart and hasn't referenced the part of the texture we're about to update
74 // since the last flush.
75 context->writeTexturePixels(fTexture,
commit-bot@chromium.orgf9529242014-02-14 18:41:47 +000076 loc->fX, loc->fY, width, height,
bsalomon@google.com0342a852012-08-20 19:22:38 +000077 fTexture->config(), image, 0,
78 GrContext::kDontFlush_PixelOpsFlag);
reed@google.comac10a2d2010-12-22 21:39:39 +000079
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +000080#if FONT_CACHE_STATS
81 ++g_UploadCount;
82#endif
83
reed@google.comac10a2d2010-12-22 21:39:39 +000084 return true;
85}
86
skia.committer@gmail.comade9a342014-03-04 03:02:32 +000087void GrPlot::resetRects() {
88 SkASSERT(NULL != fRects);
89 fRects->reset();
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +000090}
91
reed@google.comac10a2d2010-12-22 21:39:39 +000092///////////////////////////////////////////////////////////////////////////////
93
commit-bot@chromium.org95294412013-09-26 15:28:40 +000094GrAtlasMgr::GrAtlasMgr(GrGpu* gpu, GrPixelConfig config) {
reed@google.comac10a2d2010-12-22 21:39:39 +000095 fGpu = gpu;
commit-bot@chromium.org95294412013-09-26 15:28:40 +000096 fPixelConfig = config;
reed@google.comac10a2d2010-12-22 21:39:39 +000097 gpu->ref();
commit-bot@chromium.org3fddf0e2013-09-26 12:57:19 +000098 fTexture = NULL;
skia.committer@gmail.com50df4d02013-09-28 07:01:33 +000099
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000100 // set up allocated plots
robertphillips@google.com8b169312013-10-15 17:47:36 +0000101 size_t bpp = GrBytesPerPixel(fPixelConfig);
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000102 fPlotArray = SkNEW_ARRAY(GrPlot, (GR_PLOT_WIDTH*GR_PLOT_HEIGHT));
103
104 GrPlot* currPlot = fPlotArray;
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000105 for (int y = GR_PLOT_HEIGHT-1; y >= 0; --y) {
106 for (int x = GR_PLOT_WIDTH-1; x >= 0; --x) {
107 currPlot->fAtlasMgr = this;
108 currPlot->fOffset.set(x, y);
109 currPlot->fBytesPerPixel = bpp;
skia.committer@gmail.com50df4d02013-09-28 07:01:33 +0000110
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000111 // build LRU list
112 fPlotList.addToHead(currPlot);
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000113 ++currPlot;
114 }
115 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000116}
117
118GrAtlasMgr::~GrAtlasMgr() {
commit-bot@chromium.org3fddf0e2013-09-26 12:57:19 +0000119 SkSafeUnref(fTexture);
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000120 SkDELETE_ARRAY(fPlotArray);
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +0000121
reed@google.comac10a2d2010-12-22 21:39:39 +0000122 fGpu->unref();
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +0000123#if FONT_CACHE_STATS
124 GrPrintf("Num uploads: %d\n", g_UploadCount);
125#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000126}
127
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000128void GrAtlasMgr::moveToHead(GrPlot* plot) {
129 if (fPlotList.head() == plot) {
130 return;
131 }
skia.committer@gmail.comade9a342014-03-04 03:02:32 +0000132
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000133 fPlotList.remove(plot);
134 fPlotList.addToHead(plot);
135};
136
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000137GrPlot* GrAtlasMgr::addToAtlas(GrAtlas* atlas,
138 int width, int height, const void* image,
139 GrIPoint16* loc) {
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000140 // iterate through entire plot list for this atlas, see if we can find a hole
141 // last one was most recently added and probably most empty
142 for (int i = atlas->fPlots.count()-1; i >= 0; --i) {
143 GrPlot* plot = atlas->fPlots[i];
144 if (plot->addSubImage(width, height, image, loc)) {
145 this->moveToHead(plot);
146 return plot;
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +0000147 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000148 }
149
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000150 // before we get a new plot, make sure we have a backing texture
commit-bot@chromium.org3fddf0e2013-09-26 12:57:19 +0000151 if (NULL == fTexture) {
bsalomon@google.com95ed55a2013-01-24 14:46:47 +0000152 // TODO: Update this to use the cache rather than directly creating a texture.
robertphillips@google.com75b3c962012-06-07 12:08:45 +0000153 GrTextureDesc desc;
154 desc.fFlags = kDynamicUpdate_GrTextureFlagBit;
155 desc.fWidth = GR_ATLAS_TEXTURE_WIDTH;
156 desc.fHeight = GR_ATLAS_TEXTURE_HEIGHT;
commit-bot@chromium.org95294412013-09-26 15:28:40 +0000157 desc.fConfig = fPixelConfig;
robertphillips@google.com75b3c962012-06-07 12:08:45 +0000158
commit-bot@chromium.org3fddf0e2013-09-26 12:57:19 +0000159 fTexture = fGpu->createTexture(desc, NULL, 0);
160 if (NULL == fTexture) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000161 return NULL;
162 }
163 }
skia.committer@gmail.com50df4d02013-09-28 07:01:33 +0000164
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000165 // now look through all allocated plots for one we can share, in MRU order
166 GrPlotList::Iter plotIter;
167 plotIter.init(fPlotList, GrPlotList::Iter::kHead_IterStart);
168 GrPlot* plot;
169 while (NULL != (plot = plotIter.get())) {
170 // make sure texture is set for quick lookup
171 plot->fTexture = fTexture;
172 if (plot->addSubImage(width, height, image, loc)) {
173 this->moveToHead(plot);
174 // new plot for atlas, put at end of array
175 *(atlas->fPlots.append()) = plot;
176 return plot;
177 }
178 plotIter.next();
reed@google.comac10a2d2010-12-22 21:39:39 +0000179 }
180
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000181 // If the above fails, then the current plot list has no room
182 return NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +0000183}
184
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000185bool GrAtlasMgr::removePlot(GrAtlas* atlas, const GrPlot* plot) {
186 // iterate through plot list for this atlas
187 int count = atlas->fPlots.count();
188 for (int i = 0; i < count; ++i) {
189 if (plot == atlas->fPlots[i]) {
190 atlas->fPlots.remove(i);
191 return true;
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000192 }
193 }
skia.committer@gmail.com50df4d02013-09-28 07:01:33 +0000194
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000195 return false;
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000196}
197
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000198// get a plot that's not being used by the current draw
199GrPlot* GrAtlasMgr::getUnusedPlot() {
200 GrPlotList::Iter plotIter;
201 plotIter.init(fPlotList, GrPlotList::Iter::kTail_IterStart);
202 GrPlot* plot;
203 while (NULL != (plot = plotIter.get())) {
204 if (plot->drawToken().isIssued()) {
205 return plot;
206 }
207 plotIter.prev();
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000208 }
skia.committer@gmail.com50df4d02013-09-28 07:01:33 +0000209
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000210 return NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +0000211}