blob: 3eb74f074b0277d373df1977400faa2c6b5e87e9 [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"
jvanverth8e80d172014-06-19 12:01:10 -070013#include "GrTracing.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000014
reed@google.comac10a2d2010-12-22 21:39:39 +000015///////////////////////////////////////////////////////////////////////////////
16
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +000017// for testing
18#define FONT_CACHE_STATS 0
19#if FONT_CACHE_STATS
20static int g_UploadCount = 0;
21#endif
22
robertphillips17dabfc2014-07-16 13:26:24 -070023GrPlot::GrPlot()
joshualitt8debd892015-05-19 15:05:24 -070024 : fID(-1)
halcanary96fcdcc2015-08-27 07:41:13 -070025 , fTexture(nullptr)
26 , fRects(nullptr)
27 , fAtlas(nullptr)
robertphillips17dabfc2014-07-16 13:26:24 -070028 , fBytesPerPixel(1)
29 , fDirty(false)
30 , fBatchUploads(false)
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +000031{
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +000032 fOffset.set(0, 0);
reed@google.comac10a2d2010-12-22 21:39:39 +000033}
34
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +000035GrPlot::~GrPlot() {
halcanary385fe4d2015-08-26 13:07:48 -070036 delete[] fPlotData;
halcanary96fcdcc2015-08-27 07:41:13 -070037 fPlotData = nullptr;
reed@google.comac10a2d2010-12-22 21:39:39 +000038 delete fRects;
reed@google.comac10a2d2010-12-22 21:39:39 +000039}
40
robertphillips17dabfc2014-07-16 13:26:24 -070041void GrPlot::init(GrAtlas* atlas, int id, int offX, int offY, int width, int height, size_t bpp,
commit-bot@chromium.org7801faa2014-05-14 15:14:51 +000042 bool batchUploads) {
robertphillips17dabfc2014-07-16 13:26:24 -070043 fID = id;
commit-bot@chromium.org53e1e4d2014-04-01 16:25:11 +000044 fRects = GrRectanizer::Factory(width, height);
robertphillips1d86ee82014-06-24 15:08:49 -070045 fAtlas = atlas;
commit-bot@chromium.org53e1e4d2014-04-01 16:25:11 +000046 fOffset.set(offX * width, offY * height);
47 fBytesPerPixel = bpp;
halcanary96fcdcc2015-08-27 07:41:13 -070048 fPlotData = nullptr;
commit-bot@chromium.org7801faa2014-05-14 15:14:51 +000049 fDirtyRect.setEmpty();
50 fDirty = false;
51 fBatchUploads = batchUploads;
commit-bot@chromium.org53e1e4d2014-04-01 16:25:11 +000052}
53
robertphillipsd5373412014-06-02 10:20:14 -070054static inline void adjust_for_offset(SkIPoint16* loc, const SkIPoint16& offset) {
commit-bot@chromium.org53e1e4d2014-04-01 16:25:11 +000055 loc->fX += offset.fX;
56 loc->fY += offset.fY;
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +000057}
58
robertphillips952841b2014-06-30 08:26:50 -070059bool GrPlot::addSubImage(int width, int height, const void* image, SkIPoint16* loc) {
commit-bot@chromium.org7801faa2014-05-14 15:14:51 +000060 float percentFull = fRects->percentFull();
commit-bot@chromium.orgf9529242014-02-14 18:41:47 +000061 if (!fRects->addRect(width, height, loc)) {
reed@google.comac10a2d2010-12-22 21:39:39 +000062 return false;
63 }
64
commit-bot@chromium.org7801faa2014-05-14 15:14:51 +000065 // if batching uploads, create backing memory on first use
66 // once the plot is nearly full we will revert to uploading each subimage individually
67 int plotWidth = fRects->width();
68 int plotHeight = fRects->height();
halcanary96fcdcc2015-08-27 07:41:13 -070069 if (fBatchUploads && nullptr == fPlotData && 0.0f == percentFull) {
halcanary385fe4d2015-08-26 13:07:48 -070070 fPlotData = new unsigned char[fBytesPerPixel * plotWidth * plotHeight];
commit-bot@chromium.org7801faa2014-05-14 15:14:51 +000071 memset(fPlotData, 0, fBytesPerPixel*plotWidth*plotHeight);
72 }
73
74 // if we have backing memory, copy to the memory and set for future upload
bsalomon49f085d2014-09-05 13:34:00 -070075 if (fPlotData) {
commit-bot@chromium.org7801faa2014-05-14 15:14:51 +000076 const unsigned char* imagePtr = (const unsigned char*) image;
77 // point ourselves at the right starting spot
78 unsigned char* dataPtr = fPlotData;
79 dataPtr += fBytesPerPixel*plotWidth*loc->fY;
80 dataPtr += fBytesPerPixel*loc->fX;
81 // copy into the data buffer
82 for (int i = 0; i < height; ++i) {
83 memcpy(dataPtr, imagePtr, fBytesPerPixel*width);
84 dataPtr += fBytesPerPixel*plotWidth;
85 imagePtr += fBytesPerPixel*width;
86 }
87
88 fDirtyRect.join(loc->fX, loc->fY, loc->fX + width, loc->fY + height);
89 adjust_for_offset(loc, fOffset);
90 fDirty = true;
91 // otherwise, just upload the image directly
bsalomon49f085d2014-09-05 13:34:00 -070092 } else if (image) {
commit-bot@chromium.org7801faa2014-05-14 15:14:51 +000093 adjust_for_offset(loc, fOffset);
jvanverth8e80d172014-06-19 12:01:10 -070094 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("skia.gpu"), "GrPlot::uploadToTexture");
bsalomon81beccc2014-10-13 12:32:55 -070095 fTexture->writePixels(loc->fX, loc->fY, width, height, fTexture->config(), image, 0,
96 GrContext::kDontFlush_PixelOpsFlag);
robertphillips952841b2014-06-30 08:26:50 -070097 } else {
98 adjust_for_offset(loc, fOffset);
commit-bot@chromium.org7801faa2014-05-14 15:14:51 +000099 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000100
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +0000101#if FONT_CACHE_STATS
102 ++g_UploadCount;
103#endif
104
reed@google.comac10a2d2010-12-22 21:39:39 +0000105 return true;
106}
107
skia.committer@gmail.comade9a342014-03-04 03:02:32 +0000108void GrPlot::resetRects() {
bsalomon49f085d2014-09-05 13:34:00 -0700109 SkASSERT(fRects);
skia.committer@gmail.comade9a342014-03-04 03:02:32 +0000110 fRects->reset();
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000111}
112
reed@google.comac10a2d2010-12-22 21:39:39 +0000113///////////////////////////////////////////////////////////////////////////////
114
bsalomonf2703d82014-10-28 14:33:06 -0700115GrAtlas::GrAtlas(GrGpu* gpu, GrPixelConfig config, GrSurfaceFlags flags,
robertphillips1d86ee82014-06-24 15:08:49 -0700116 const SkISize& backingTextureSize,
117 int numPlotsX, int numPlotsY, bool batchUploads) {
commit-bot@chromium.org53e1e4d2014-04-01 16:25:11 +0000118 fGpu = SkRef(gpu);
commit-bot@chromium.org95294412013-09-26 15:28:40 +0000119 fPixelConfig = config;
robertphillips952841b2014-06-30 08:26:50 -0700120 fFlags = flags;
commit-bot@chromium.org53e1e4d2014-04-01 16:25:11 +0000121 fBackingTextureSize = backingTextureSize;
122 fNumPlotsX = numPlotsX;
123 fNumPlotsY = numPlotsY;
commit-bot@chromium.org7801faa2014-05-14 15:14:51 +0000124 fBatchUploads = batchUploads;
halcanary96fcdcc2015-08-27 07:41:13 -0700125 fTexture = nullptr;
skia.committer@gmail.com50df4d02013-09-28 07:01:33 +0000126
commit-bot@chromium.org7801faa2014-05-14 15:14:51 +0000127 int textureWidth = fBackingTextureSize.width();
128 int textureHeight = fBackingTextureSize.height();
commit-bot@chromium.org53e1e4d2014-04-01 16:25:11 +0000129
commit-bot@chromium.org7801faa2014-05-14 15:14:51 +0000130 int plotWidth = textureWidth / fNumPlotsX;
131 int plotHeight = textureHeight / fNumPlotsY;
132
133 SkASSERT(plotWidth * fNumPlotsX == textureWidth);
134 SkASSERT(plotHeight * fNumPlotsY == textureHeight);
commit-bot@chromium.org53e1e4d2014-04-01 16:25:11 +0000135
commit-bot@chromium.org6e7ddaa2014-05-30 13:55:58 +0000136 // We currently do not support compressed atlases...
137 SkASSERT(!GrPixelConfigIsCompressed(config));
138
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000139 // set up allocated plots
robertphillips@google.com8b169312013-10-15 17:47:36 +0000140 size_t bpp = GrBytesPerPixel(fPixelConfig);
halcanary385fe4d2015-08-26 13:07:48 -0700141 fPlotArray = new GrPlot[(fNumPlotsX * fNumPlotsY)];
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000142
143 GrPlot* currPlot = fPlotArray;
commit-bot@chromium.org53e1e4d2014-04-01 16:25:11 +0000144 for (int y = numPlotsY-1; y >= 0; --y) {
145 for (int x = numPlotsX-1; x >= 0; --x) {
robertphillips17dabfc2014-07-16 13:26:24 -0700146 currPlot->init(this, y*numPlotsX+x, x, y, plotWidth, plotHeight, bpp, batchUploads);
skia.committer@gmail.com50df4d02013-09-28 07:01:33 +0000147
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000148 // build LRU list
149 fPlotList.addToHead(currPlot);
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000150 ++currPlot;
151 }
152 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000153}
154
robertphillips1d86ee82014-06-24 15:08:49 -0700155GrAtlas::~GrAtlas() {
commit-bot@chromium.org3fddf0e2013-09-26 12:57:19 +0000156 SkSafeUnref(fTexture);
halcanary385fe4d2015-08-26 13:07:48 -0700157 delete[] fPlotArray;
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +0000158
reed@google.comac10a2d2010-12-22 21:39:39 +0000159 fGpu->unref();
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +0000160#if FONT_CACHE_STATS
tfarina38406c82014-10-31 07:11:12 -0700161 SkDebugf("Num uploads: %d\n", g_UploadCount);
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +0000162#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000163}
164
robertphillips1d86ee82014-06-24 15:08:49 -0700165void GrAtlas::makeMRU(GrPlot* plot) {
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000166 if (fPlotList.head() == plot) {
167 return;
168 }
skia.committer@gmail.comade9a342014-03-04 03:02:32 +0000169
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000170 fPlotList.remove(plot);
171 fPlotList.addToHead(plot);
172};
173
robertphillips1d86ee82014-06-24 15:08:49 -0700174GrPlot* GrAtlas::addToAtlas(ClientPlotUsage* usage,
175 int width, int height, const void* image,
176 SkIPoint16* loc) {
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000177 // iterate through entire plot list for this atlas, see if we can find a hole
178 // last one was most recently added and probably most empty
robertphillips1d86ee82014-06-24 15:08:49 -0700179 for (int i = usage->fPlots.count()-1; i >= 0; --i) {
180 GrPlot* plot = usage->fPlots[i];
jvanverth294c3262014-10-10 11:36:12 -0700181 // client may have plots from more than one atlas, must check for ours before adding
182 if (this == plot->fAtlas && plot->addSubImage(width, height, image, loc)) {
robertphillips1d86ee82014-06-24 15:08:49 -0700183 this->makeMRU(plot);
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000184 return plot;
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +0000185 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000186 }
187
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000188 // before we get a new plot, make sure we have a backing texture
halcanary96fcdcc2015-08-27 07:41:13 -0700189 if (nullptr == fTexture) {
bsalomon@google.com95ed55a2013-01-24 14:46:47 +0000190 // TODO: Update this to use the cache rather than directly creating a texture.
bsalomonf2703d82014-10-28 14:33:06 -0700191 GrSurfaceDesc desc;
192 desc.fFlags = fFlags;
commit-bot@chromium.org53e1e4d2014-04-01 16:25:11 +0000193 desc.fWidth = fBackingTextureSize.width();
194 desc.fHeight = fBackingTextureSize.height();
commit-bot@chromium.org95294412013-09-26 15:28:40 +0000195 desc.fConfig = fPixelConfig;
robertphillips@google.com75b3c962012-06-07 12:08:45 +0000196
halcanary96fcdcc2015-08-27 07:41:13 -0700197 fTexture = fGpu->createTexture(desc, true, nullptr, 0);
198 if (nullptr == fTexture) {
199 return nullptr;
reed@google.comac10a2d2010-12-22 21:39:39 +0000200 }
201 }
skia.committer@gmail.com50df4d02013-09-28 07:01:33 +0000202
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000203 // now look through all allocated plots for one we can share, in MRU order
204 GrPlotList::Iter plotIter;
205 plotIter.init(fPlotList, GrPlotList::Iter::kHead_IterStart);
206 GrPlot* plot;
bsalomon49f085d2014-09-05 13:34:00 -0700207 while ((plot = plotIter.get())) {
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000208 // make sure texture is set for quick lookup
209 plot->fTexture = fTexture;
210 if (plot->addSubImage(width, height, image, loc)) {
robertphillips1d86ee82014-06-24 15:08:49 -0700211 this->makeMRU(plot);
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000212 // new plot for atlas, put at end of array
robertphillips1d86ee82014-06-24 15:08:49 -0700213 SkASSERT(!usage->fPlots.contains(plot));
214 *(usage->fPlots.append()) = plot;
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000215 return plot;
216 }
217 plotIter.next();
reed@google.comac10a2d2010-12-22 21:39:39 +0000218 }
219
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000220 // If the above fails, then the current plot list has no room
halcanary96fcdcc2015-08-27 07:41:13 -0700221 return nullptr;
reed@google.comac10a2d2010-12-22 21:39:39 +0000222}
223
robertphillipsc4f30b12014-07-13 10:09:42 -0700224void GrAtlas::RemovePlot(ClientPlotUsage* usage, const GrPlot* plot) {
robertphillips1d86ee82014-06-24 15:08:49 -0700225 int index = usage->fPlots.find(const_cast<GrPlot*>(plot));
226 if (index >= 0) {
227 usage->fPlots.remove(index);
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000228 }
commit-bot@chromium.org7d330eb2013-09-27 19:39:38 +0000229}