blob: c1b3d7bb406a953e24edd399c31231579a2d7178 [file] [log] [blame]
Robert Phillipsc4039ea2018-03-01 11:36:45 -05001/*
2 * Copyright 2018 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "GrAtlasManager.h"
9
Robert Phillipsc4039ea2018-03-01 11:36:45 -050010#include "GrGlyph.h"
11#include "GrGlyphCache.h"
Robert Phillipsc4039ea2018-03-01 11:36:45 -050012
Robert Phillips5a66efb2018-03-07 15:13:18 -050013GrAtlasManager::GrAtlasManager(GrProxyProvider* proxyProvider, GrGlyphCache* glyphCache,
Herb Derbya2bc1ca2018-09-07 15:27:57 -040014 size_t maxTextureBytes,
Robert Phillips5a66efb2018-03-07 15:13:18 -050015 GrDrawOpAtlas::AllowMultitexturing allowMultitexturing)
Herb Derbya2bc1ca2018-09-07 15:27:57 -040016 : fAllowMultitexturing{allowMultitexturing}
17 , fGlyphSizeLimit{SkGlyphCacheCommon::kSkSideTooBigForAtlas}
18 , fProxyProvider{proxyProvider}
19 , fCaps{fProxyProvider->refCaps()}
20 , fGlyphCache{glyphCache}
21 , fAtlasConfigs{fCaps->maxTextureSize(), maxTextureBytes} { }
Robert Phillipsc4039ea2018-03-01 11:36:45 -050022
Herb Derbya2bc1ca2018-09-07 15:27:57 -040023GrAtlasManager::~GrAtlasManager() = default;
Robert Phillipsc4039ea2018-03-01 11:36:45 -050024
Brian Osman2b23c4b2018-06-01 12:25:08 -040025static GrPixelConfig mask_format_to_pixel_config(GrMaskFormat format) {
Robert Phillipsc4039ea2018-03-01 11:36:45 -050026 switch (format) {
27 case kA8_GrMaskFormat:
28 return kAlpha_8_GrPixelConfig;
29 case kA565_GrMaskFormat:
30 return kRGB_565_GrPixelConfig;
31 case kARGB_GrMaskFormat:
Brian Osman2b23c4b2018-06-01 12:25:08 -040032 return kRGBA_8888_GrPixelConfig;
Robert Phillipsc4039ea2018-03-01 11:36:45 -050033 default:
34 SkDEBUGFAIL("unsupported GrMaskFormat");
35 return kAlpha_8_GrPixelConfig;
36 }
37}
38
Robert Phillipsc4039ea2018-03-01 11:36:45 -050039void GrAtlasManager::freeAll() {
40 for (int i = 0; i < kMaskFormatCount; ++i) {
41 fAtlases[i] = nullptr;
42 }
43}
44
45bool GrAtlasManager::hasGlyph(GrGlyph* glyph) {
46 SkASSERT(glyph);
47 return this->getAtlas(glyph->fMaskFormat)->hasID(glyph->fID);
48}
49
50// add to texture atlas that matches this format
Robert Phillipsd2e9f762018-03-07 11:54:37 -050051GrDrawOpAtlas::ErrorCode GrAtlasManager::addToAtlas(
52 GrResourceProvider* resourceProvider,
Robert Phillipsc4039ea2018-03-01 11:36:45 -050053 GrGlyphCache* glyphCache,
Robert Phillipscaf1ebb2018-03-01 14:28:44 -050054 GrTextStrike* strike, GrDrawOpAtlas::AtlasID* id,
Robert Phillipsc4039ea2018-03-01 11:36:45 -050055 GrDeferredUploadTarget* target, GrMaskFormat format,
56 int width, int height, const void* image, SkIPoint16* loc) {
57 glyphCache->setStrikeToPreserve(strike);
58 return this->getAtlas(format)->addToAtlas(resourceProvider, id, target, width, height,
Robert Phillipsd2e9f762018-03-07 11:54:37 -050059 image, loc);
Robert Phillipsc4039ea2018-03-01 11:36:45 -050060}
61
62void GrAtlasManager::addGlyphToBulkAndSetUseToken(GrDrawOpAtlas::BulkUseTokenUpdater* updater,
63 GrGlyph* glyph,
64 GrDeferredUploadToken token) {
65 SkASSERT(glyph);
66 updater->add(glyph->fID);
67 this->getAtlas(glyph->fMaskFormat)->setLastUseToken(glyph->fID, token);
68}
69
70#ifdef SK_DEBUG
71#include "GrContextPriv.h"
72#include "GrSurfaceProxy.h"
73#include "GrSurfaceContext.h"
74#include "GrTextureProxy.h"
75
76#include "SkBitmap.h"
77#include "SkImageEncoder.h"
78#include "SkStream.h"
79#include <stdio.h>
80
81/**
82 * Write the contents of the surface proxy to a PNG. Returns true if successful.
83 * @param filename Full path to desired file
84 */
85static bool save_pixels(GrContext* context, GrSurfaceProxy* sProxy, const char* filename) {
86 if (!sProxy) {
87 return false;
88 }
89
90 SkImageInfo ii = SkImageInfo::Make(sProxy->width(), sProxy->height(),
91 kRGBA_8888_SkColorType, kPremul_SkAlphaType);
92 SkBitmap bm;
93 if (!bm.tryAllocPixels(ii)) {
94 return false;
95 }
96
97 sk_sp<GrSurfaceContext> sContext(context->contextPriv().makeWrappedSurfaceContext(
98 sk_ref_sp(sProxy)));
99 if (!sContext || !sContext->asTextureProxy()) {
100 return false;
101 }
102
103 bool result = sContext->readPixels(ii, bm.getPixels(), bm.rowBytes(), 0, 0);
104 if (!result) {
105 SkDebugf("------ failed to read pixels for %s\n", filename);
106 return false;
107 }
108
109 // remove any previous version of this file
110 remove(filename);
111
112 SkFILEWStream file(filename);
113 if (!file.isValid()) {
114 SkDebugf("------ failed to create file: %s\n", filename);
115 remove(filename); // remove any partial file
116 return false;
117 }
118
119 if (!SkEncodeImage(&file, bm, SkEncodedImageFormat::kPNG, 100)) {
120 SkDebugf("------ failed to encode %s\n", filename);
121 remove(filename); // remove any partial file
122 return false;
123 }
124
125 return true;
126}
127
128void GrAtlasManager::dump(GrContext* context) const {
129 static int gDumpCount = 0;
130 for (int i = 0; i < kMaskFormatCount; ++i) {
131 if (fAtlases[i]) {
132 const sk_sp<GrTextureProxy>* proxies = fAtlases[i]->getProxies();
133 for (uint32_t pageIdx = 0; pageIdx < fAtlases[i]->numActivePages(); ++pageIdx) {
134 SkASSERT(proxies[pageIdx]);
135 SkString filename;
136#ifdef SK_BUILD_FOR_ANDROID
137 filename.printf("/sdcard/fontcache_%d%d%d.png", gDumpCount, i, pageIdx);
138#else
139 filename.printf("fontcache_%d%d%d.png", gDumpCount, i, pageIdx);
140#endif
141
142 save_pixels(context, proxies[pageIdx].get(), filename.c_str());
143 }
144 }
145 }
146 ++gDumpCount;
147}
148#endif
149
Herb Derbya2bc1ca2018-09-07 15:27:57 -0400150void GrAtlasManager::setAtlasSizesToMinimum_ForTesting() {
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500151 // Delete any old atlases.
152 // This should be safe to do as long as we are not in the middle of a flush.
153 for (int i = 0; i < kMaskFormatCount; i++) {
154 fAtlases[i] = nullptr;
155 }
Herb Derbya2bc1ca2018-09-07 15:27:57 -0400156
157 // Set all the atlas sizes to 1x1 plot each.
158 new (&fAtlasConfigs) GrDrawOpAtlasConfig{};
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500159}
160
161bool GrAtlasManager::initAtlas(GrMaskFormat format) {
162 int index = MaskFormatToAtlasIndex(format);
Herb Derbya2bc1ca2018-09-07 15:27:57 -0400163 if (fAtlases[index] == nullptr) {
Brian Osman2b23c4b2018-06-01 12:25:08 -0400164 GrPixelConfig config = mask_format_to_pixel_config(format);
Herb Derbya2bc1ca2018-09-07 15:27:57 -0400165 SkISize atlasDimensions = fAtlasConfigs.atlasDimensions(format);
166 SkISize numPlots = fAtlasConfigs.numPlots(format);
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500167
Herb Derbya2bc1ca2018-09-07 15:27:57 -0400168 fAtlases[index] = GrDrawOpAtlas::Make(
169 fProxyProvider, config, atlasDimensions.width(), atlasDimensions.height(),
170 numPlots.width(), numPlots.height(), fAllowMultitexturing,
171 &GrGlyphCache::HandleEviction, fGlyphCache);
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500172 if (!fAtlases[index]) {
173 return false;
174 }
175 }
176 return true;
177}