blob: c2fcf46f687b5656a71f0c02ca6cf82ca4e2a727 [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
robertphillips@google.com8b169312013-10-15 17:47:36 +000063static inline uint8_t* zero_fill(uint8_t* ptr, size_t count) {
64 sk_bzero(ptr, count);
65 return ptr + count;
reed@google.com98539c62011-03-15 15:40:16 +000066}
67
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +000068bool GrPlot::addSubImage(int width, int height, const void* image,
reed@google.comac10a2d2010-12-22 21:39:39 +000069 GrIPoint16* loc) {
commit-bot@chromium.orgf9529242014-02-14 18:41:47 +000070 if (!fRects->addRect(width, height, loc)) {
reed@google.comac10a2d2010-12-22 21:39:39 +000071 return false;
72 }
73
bsalomon@google.com3582bf92011-06-30 21:32:31 +000074 SkAutoSMalloc<1024> storage;
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +000075 adjust_for_offset(loc, fOffset);
bsalomon@google.com6f379512011-11-16 20:36:03 +000076 GrContext* context = fTexture->getContext();
bsalomon@google.com0342a852012-08-20 19:22:38 +000077 // We pass the flag that does not force a flush. We assume our caller is
78 // smart and hasn't referenced the part of the texture we're about to update
79 // since the last flush.
80 context->writeTexturePixels(fTexture,
commit-bot@chromium.orgf9529242014-02-14 18:41:47 +000081 loc->fX, loc->fY, width, height,
bsalomon@google.com0342a852012-08-20 19:22:38 +000082 fTexture->config(), image, 0,
83 GrContext::kDontFlush_PixelOpsFlag);
reed@google.comac10a2d2010-12-22 21:39:39 +000084
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +000085#if FONT_CACHE_STATS
86 ++g_UploadCount;
87#endif
88
reed@google.comac10a2d2010-12-22 21:39:39 +000089 return true;
90}
91
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +000092void GrPlot::resetRects() {
93 SkASSERT(NULL != fRects);
94 fRects->reset();
95}
96
reed@google.comac10a2d2010-12-22 21:39:39 +000097///////////////////////////////////////////////////////////////////////////////
98
commit-bot@chromium.org95294412013-09-26 15:28:40 +000099GrAtlasMgr::GrAtlasMgr(GrGpu* gpu, GrPixelConfig config) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000100 fGpu = gpu;
commit-bot@chromium.org95294412013-09-26 15:28:40 +0000101 fPixelConfig = config;
reed@google.comac10a2d2010-12-22 21:39:39 +0000102 gpu->ref();
commit-bot@chromium.org3fddf0e2013-09-26 12:57:19 +0000103 fTexture = NULL;
skia.committer@gmail.com50df4d02013-09-28 07:01:33 +0000104
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000105 // set up allocated plots
robertphillips@google.com8b169312013-10-15 17:47:36 +0000106 size_t bpp = GrBytesPerPixel(fPixelConfig);
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000107 fPlotArray = SkNEW_ARRAY(GrPlot, (GR_PLOT_WIDTH*GR_PLOT_HEIGHT));
108
109 GrPlot* currPlot = fPlotArray;
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000110 for (int y = GR_PLOT_HEIGHT-1; y >= 0; --y) {
111 for (int x = GR_PLOT_WIDTH-1; x >= 0; --x) {
112 currPlot->fAtlasMgr = this;
113 currPlot->fOffset.set(x, y);
114 currPlot->fBytesPerPixel = bpp;
skia.committer@gmail.com50df4d02013-09-28 07:01:33 +0000115
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000116 // build LRU list
117 fPlotList.addToHead(currPlot);
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000118 ++currPlot;
119 }
120 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000121}
122
123GrAtlasMgr::~GrAtlasMgr() {
commit-bot@chromium.org3fddf0e2013-09-26 12:57:19 +0000124 SkSafeUnref(fTexture);
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000125 SkDELETE_ARRAY(fPlotArray);
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +0000126
reed@google.comac10a2d2010-12-22 21:39:39 +0000127 fGpu->unref();
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +0000128#if FONT_CACHE_STATS
129 GrPrintf("Num uploads: %d\n", g_UploadCount);
130#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000131}
132
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000133void GrAtlasMgr::moveToHead(GrPlot* plot) {
134 if (fPlotList.head() == plot) {
135 return;
136 }
137
138 fPlotList.remove(plot);
139 fPlotList.addToHead(plot);
140};
141
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000142GrPlot* GrAtlasMgr::addToAtlas(GrAtlas* atlas,
143 int width, int height, const void* image,
144 GrIPoint16* loc) {
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000145 // iterate through entire plot list for this atlas, see if we can find a hole
146 // last one was most recently added and probably most empty
147 for (int i = atlas->fPlots.count()-1; i >= 0; --i) {
148 GrPlot* plot = atlas->fPlots[i];
149 if (plot->addSubImage(width, height, image, loc)) {
150 this->moveToHead(plot);
151 return plot;
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +0000152 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000153 }
154
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000155 // before we get a new plot, make sure we have a backing texture
commit-bot@chromium.org3fddf0e2013-09-26 12:57:19 +0000156 if (NULL == fTexture) {
bsalomon@google.com95ed55a2013-01-24 14:46:47 +0000157 // TODO: Update this to use the cache rather than directly creating a texture.
robertphillips@google.com75b3c962012-06-07 12:08:45 +0000158 GrTextureDesc desc;
159 desc.fFlags = kDynamicUpdate_GrTextureFlagBit;
160 desc.fWidth = GR_ATLAS_TEXTURE_WIDTH;
161 desc.fHeight = GR_ATLAS_TEXTURE_HEIGHT;
commit-bot@chromium.org95294412013-09-26 15:28:40 +0000162 desc.fConfig = fPixelConfig;
robertphillips@google.com75b3c962012-06-07 12:08:45 +0000163
commit-bot@chromium.org3fddf0e2013-09-26 12:57:19 +0000164 fTexture = fGpu->createTexture(desc, NULL, 0);
165 if (NULL == fTexture) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000166 return NULL;
167 }
168 }
skia.committer@gmail.com50df4d02013-09-28 07:01:33 +0000169
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000170 // now look through all allocated plots for one we can share, in MRU order
171 GrPlotList::Iter plotIter;
172 plotIter.init(fPlotList, GrPlotList::Iter::kHead_IterStart);
173 GrPlot* plot;
174 while (NULL != (plot = plotIter.get())) {
175 // make sure texture is set for quick lookup
176 plot->fTexture = fTexture;
177 if (plot->addSubImage(width, height, image, loc)) {
178 this->moveToHead(plot);
179 // new plot for atlas, put at end of array
180 *(atlas->fPlots.append()) = plot;
181 return plot;
182 }
183 plotIter.next();
reed@google.comac10a2d2010-12-22 21:39:39 +0000184 }
185
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000186 // If the above fails, then the current plot list has no room
187 return NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +0000188}
189
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000190bool GrAtlasMgr::removePlot(GrAtlas* atlas, const GrPlot* plot) {
191 // iterate through plot list for this atlas
192 int count = atlas->fPlots.count();
193 for (int i = 0; i < count; ++i) {
194 if (plot == atlas->fPlots[i]) {
195 atlas->fPlots.remove(i);
196 return true;
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000197 }
198 }
skia.committer@gmail.com50df4d02013-09-28 07:01:33 +0000199
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000200 return false;
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000201}
202
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000203// get a plot that's not being used by the current draw
204GrPlot* GrAtlasMgr::getUnusedPlot() {
205 GrPlotList::Iter plotIter;
206 plotIter.init(fPlotList, GrPlotList::Iter::kTail_IterStart);
207 GrPlot* plot;
208 while (NULL != (plot = plotIter.get())) {
209 if (plot->drawToken().isIssued()) {
210 return plot;
211 }
212 plotIter.prev();
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000213 }
skia.committer@gmail.com50df4d02013-09-28 07:01:33 +0000214
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000215 return NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +0000216}
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +0000217
218SkISize GrAtlas::getSize() const {
219 return SkISize::Make(GR_ATLAS_TEXTURE_WIDTH, GR_ATLAS_TEXTURE_HEIGHT);
220}