bool GrFontCache::freeUnusedPlot(GrTextStrike* preserveStrike, const GrGlyph* glyph) { SkASSERT(preserveStrike); int index = mask_format_to_atlas_index(glyph->fMaskFormat); GrAtlas* atlas = fAtlases[index]; GrPlot* plot = atlas->getUnusedPlot(); if (NULL == plot) { return false; } plot->resetRects(); GrTextStrike* strike = fHead; while (strike) { GrTextStrike* strikeToPurge = strike; strike = strikeToPurge->fNext; strikeToPurge->removePlot(plot); // clear out any empty strikes (except this one) if (strikeToPurge != preserveStrike && strikeToPurge->fPlotUsage.isEmpty()) { this->purgeStrike(strikeToPurge); } } #if FONT_CACHE_STATS ++g_PurgeCount; #endif return true; }
bool GrFontCache::freeUnusedPlot(GrTextStrike* preserveStrike) { SkASSERT(preserveStrike); GrAtlas* atlas = preserveStrike->fAtlas; GrPlot* plot = atlas->getUnusedPlot(); if (NULL == plot) { return false; } plot->resetRects(); GrTextStrike* strike = fHead; GrMaskFormat maskFormat = preserveStrike->fMaskFormat; while (strike) { if (maskFormat != strike->fMaskFormat) { strike = strike->fNext; continue; } GrTextStrike* strikeToPurge = strike; strike = strikeToPurge->fNext; strikeToPurge->removePlot(plot); // clear out any empty strikes (except this one) if (strikeToPurge != preserveStrike && strikeToPurge->fPlotUsage.isEmpty()) { this->purgeStrike(strikeToPurge); } } #if FONT_CACHE_STATS ++g_PurgeCount; #endif return true; }
// get a plot that's not being used by the current draw GrPlot* GrAtlasMgr::getUnusedPlot() { GrPlotList::Iter plotIter; plotIter.init(fPlotList, GrPlotList::Iter::kTail_IterStart); GrPlot* plot; while (NULL != (plot = plotIter.get())) { if (plot->drawToken().isIssued()) { return plot; } plotIter.prev(); } return NULL; }
GrPlot* GrAtlas::addToAtlas(ClientPlotUsage* usage, int width, int height, const void* image, SkIPoint16* loc) { // iterate through entire plot list for this atlas, see if we can find a hole // last one was most recently added and probably most empty for (int i = usage->fPlots.count()-1; i >= 0; --i) { GrPlot* plot = usage->fPlots[i]; // client may have plots from more than one atlas, must check for ours before adding if (this == plot->fAtlas && plot->addSubImage(width, height, image, loc)) { this->makeMRU(plot); return plot; } } // before we get a new plot, make sure we have a backing texture if (NULL == fTexture) { // TODO: Update this to use the cache rather than directly creating a texture. GrSurfaceDesc desc; desc.fFlags = fFlags; desc.fWidth = fBackingTextureSize.width(); desc.fHeight = fBackingTextureSize.height(); desc.fConfig = fPixelConfig; fTexture = fGpu->createTexture(desc, true, NULL, 0); if (NULL == fTexture) { return NULL; } } // now look through all allocated plots for one we can share, in MRU order GrPlotList::Iter plotIter; plotIter.init(fPlotList, GrPlotList::Iter::kHead_IterStart); GrPlot* plot; while ((plot = plotIter.get())) { // make sure texture is set for quick lookup plot->fTexture = fTexture; if (plot->addSubImage(width, height, image, loc)) { this->makeMRU(plot); // new plot for atlas, put at end of array SkASSERT(!usage->fPlots.contains(plot)); *(usage->fPlots.append()) = plot; return plot; } plotIter.next(); } // If the above fails, then the current plot list has no room return NULL; }
GrPlot* GrAtlasMgr::addToAtlas(GrAtlas* atlas, int width, int height, const void* image, GrIPoint16* loc) { // iterate through entire plot list for this atlas, see if we can find a hole // last one was most recently added and probably most empty for (int i = atlas->fPlots.count()-1; i >= 0; --i) { GrPlot* plot = atlas->fPlots[i]; if (plot->addSubImage(width, height, image, loc)) { this->moveToHead(plot); return plot; } } // before we get a new plot, make sure we have a backing texture if (NULL == fTexture) { // TODO: Update this to use the cache rather than directly creating a texture. GrTextureDesc desc; desc.fFlags = kDynamicUpdate_GrTextureFlagBit; desc.fWidth = GR_ATLAS_TEXTURE_WIDTH; desc.fHeight = GR_ATLAS_TEXTURE_HEIGHT; desc.fConfig = fPixelConfig; fTexture = fGpu->createTexture(desc, NULL, 0); if (NULL == fTexture) { return NULL; } } // now look through all allocated plots for one we can share, in MRU order GrPlotList::Iter plotIter; plotIter.init(fPlotList, GrPlotList::Iter::kHead_IterStart); GrPlot* plot; while (NULL != (plot = plotIter.get())) { // make sure texture is set for quick lookup plot->fTexture = fTexture; if (plot->addSubImage(width, height, image, loc)) { this->moveToHead(plot); // new plot for atlas, put at end of array *(atlas->fPlots.append()) = plot; return plot; } plotIter.next(); } // If the above fails, then the current plot list has no room return NULL; }
GrAtlas::GrAtlas(GrGpu* gpu, GrPixelConfig config, GrSurfaceFlags flags, const SkISize& backingTextureSize, int numPlotsX, int numPlotsY, bool batchUploads) { fGpu = SkRef(gpu); fPixelConfig = config; fFlags = flags; fBackingTextureSize = backingTextureSize; fNumPlotsX = numPlotsX; fNumPlotsY = numPlotsY; fBatchUploads = batchUploads; fTexture = NULL; int textureWidth = fBackingTextureSize.width(); int textureHeight = fBackingTextureSize.height(); int plotWidth = textureWidth / fNumPlotsX; int plotHeight = textureHeight / fNumPlotsY; SkASSERT(plotWidth * fNumPlotsX == textureWidth); SkASSERT(plotHeight * fNumPlotsY == textureHeight); // We currently do not support compressed atlases... SkASSERT(!GrPixelConfigIsCompressed(config)); // set up allocated plots size_t bpp = GrBytesPerPixel(fPixelConfig); fPlotArray = new GrPlot[(fNumPlotsX * fNumPlotsY)]; GrPlot* currPlot = fPlotArray; for (int y = numPlotsY-1; y >= 0; --y) { for (int x = numPlotsX-1; x >= 0; --x) { currPlot->init(this, y*numPlotsX+x, x, y, plotWidth, plotHeight, bpp, batchUploads); // build LRU list fPlotList.addToHead(currPlot); ++currPlot; } } }