1 | /* |
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 "src/gpu/text/GrAtlasManager.h" |
9 | |
10 | #include "src/gpu/GrGlyph.h" |
11 | #include "src/gpu/GrImageInfo.h" |
12 | #include "src/gpu/text/GrStrikeCache.h" |
13 | |
14 | GrAtlasManager::GrAtlasManager(GrProxyProvider* proxyProvider, |
15 | size_t maxTextureBytes, |
16 | GrDrawOpAtlas::AllowMultitexturing allowMultitexturing) |
17 | : fAllowMultitexturing{allowMultitexturing} |
18 | , fProxyProvider{proxyProvider} |
19 | , fCaps{fProxyProvider->refCaps()} |
20 | , fAtlasConfig{fCaps->maxTextureSize(), maxTextureBytes} { } |
21 | |
22 | GrAtlasManager::~GrAtlasManager() = default; |
23 | |
24 | void GrAtlasManager::freeAll() { |
25 | for (int i = 0; i < kMaskFormatCount; ++i) { |
26 | fAtlases[i] = nullptr; |
27 | } |
28 | } |
29 | |
30 | bool GrAtlasManager::hasGlyph(GrMaskFormat format, GrGlyph* glyph) { |
31 | SkASSERT(glyph); |
32 | return this->getAtlas(format)->hasID(glyph->fAtlasLocator); |
33 | } |
34 | |
35 | // add to texture atlas that matches this format |
36 | GrDrawOpAtlas::ErrorCode GrAtlasManager::addToAtlas(GrResourceProvider* resourceProvider, |
37 | GrDeferredUploadTarget* target, |
38 | GrMaskFormat format, |
39 | int width, int height, const void* image, |
40 | GrDrawOpAtlas::AtlasLocator* atlasLocator) { |
41 | return this->getAtlas(format)->addToAtlas( |
42 | resourceProvider, target, width, height, image, atlasLocator); |
43 | } |
44 | |
45 | void GrAtlasManager::addGlyphToBulkAndSetUseToken(GrDrawOpAtlas::BulkUseTokenUpdater* updater, |
46 | GrMaskFormat format, GrGlyph* glyph, |
47 | GrDeferredUploadToken token) { |
48 | SkASSERT(glyph); |
49 | if (updater->add(glyph->fAtlasLocator)) { |
50 | this->getAtlas(format)->setLastUseToken(glyph->fAtlasLocator, token); |
51 | } |
52 | } |
53 | |
54 | #ifdef SK_DEBUG |
55 | #include "src/gpu/GrContextPriv.h" |
56 | #include "src/gpu/GrSurfaceContext.h" |
57 | #include "src/gpu/GrSurfaceProxy.h" |
58 | #include "src/gpu/GrTextureProxy.h" |
59 | |
60 | #include "include/core/SkBitmap.h" |
61 | #include "include/core/SkImageEncoder.h" |
62 | #include "include/core/SkStream.h" |
63 | #include <stdio.h> |
64 | |
65 | /** |
66 | * Write the contents of the surface proxy to a PNG. Returns true if successful. |
67 | * @param filename Full path to desired file |
68 | */ |
69 | static bool save_pixels(GrContext* context, GrSurfaceProxyView view, GrColorType colorType, |
70 | const char* filename) { |
71 | if (!view.proxy()) { |
72 | return false; |
73 | } |
74 | |
75 | SkImageInfo ii = |
76 | SkImageInfo::Make(view.proxy()->dimensions(), kRGBA_8888_SkColorType, |
77 | kPremul_SkAlphaType); |
78 | SkBitmap bm; |
79 | if (!bm.tryAllocPixels(ii)) { |
80 | return false; |
81 | } |
82 | |
83 | auto sContext = GrSurfaceContext::Make(context, std::move(view), colorType, |
84 | kUnknown_SkAlphaType, nullptr); |
85 | if (!sContext || !sContext->asTextureProxy()) { |
86 | return false; |
87 | } |
88 | |
89 | bool result = sContext->readPixels(ii, bm.getPixels(), bm.rowBytes(), {0, 0}); |
90 | if (!result) { |
91 | SkDebugf("------ failed to read pixels for %s\n" , filename); |
92 | return false; |
93 | } |
94 | |
95 | // remove any previous version of this file |
96 | remove(filename); |
97 | |
98 | SkFILEWStream file(filename); |
99 | if (!file.isValid()) { |
100 | SkDebugf("------ failed to create file: %s\n" , filename); |
101 | remove(filename); // remove any partial file |
102 | return false; |
103 | } |
104 | |
105 | if (!SkEncodeImage(&file, bm, SkEncodedImageFormat::kPNG, 100)) { |
106 | SkDebugf("------ failed to encode %s\n" , filename); |
107 | remove(filename); // remove any partial file |
108 | return false; |
109 | } |
110 | |
111 | return true; |
112 | } |
113 | |
114 | void GrAtlasManager::dump(GrContext* context) const { |
115 | static int gDumpCount = 0; |
116 | for (int i = 0; i < kMaskFormatCount; ++i) { |
117 | if (fAtlases[i]) { |
118 | const GrSurfaceProxyView* views = fAtlases[i]->getViews(); |
119 | for (uint32_t pageIdx = 0; pageIdx < fAtlases[i]->numActivePages(); ++pageIdx) { |
120 | SkASSERT(views[pageIdx].proxy()); |
121 | SkString filename; |
122 | #ifdef SK_BUILD_FOR_ANDROID |
123 | filename.printf("/sdcard/fontcache_%d%d%d.png" , gDumpCount, i, pageIdx); |
124 | #else |
125 | filename.printf("fontcache_%d%d%d.png" , gDumpCount, i, pageIdx); |
126 | #endif |
127 | auto ct = GrMaskFormatToColorType(AtlasIndexToMaskFormat(i)); |
128 | save_pixels(context, views[pageIdx], ct, filename.c_str()); |
129 | } |
130 | } |
131 | } |
132 | ++gDumpCount; |
133 | } |
134 | #endif |
135 | |
136 | void GrAtlasManager::setAtlasDimensionsToMinimum_ForTesting() { |
137 | // Delete any old atlases. |
138 | // This should be safe to do as long as we are not in the middle of a flush. |
139 | for (int i = 0; i < kMaskFormatCount; i++) { |
140 | fAtlases[i] = nullptr; |
141 | } |
142 | |
143 | // Set all the atlas sizes to 1x1 plot each. |
144 | new (&fAtlasConfig) GrDrawOpAtlasConfig{}; |
145 | } |
146 | |
147 | bool GrAtlasManager::initAtlas(GrMaskFormat format) { |
148 | int index = MaskFormatToAtlasIndex(format); |
149 | if (fAtlases[index] == nullptr) { |
150 | GrColorType grColorType = GrMaskFormatToColorType(format); |
151 | SkISize atlasDimensions = fAtlasConfig.atlasDimensions(format); |
152 | SkISize plotDimensions = fAtlasConfig.plotDimensions(format); |
153 | |
154 | const GrBackendFormat format = fCaps->getDefaultBackendFormat(grColorType, |
155 | GrRenderable::kNo); |
156 | |
157 | fAtlases[index] = GrDrawOpAtlas::Make( |
158 | fProxyProvider, format, grColorType, |
159 | atlasDimensions.width(), atlasDimensions.height(), |
160 | plotDimensions.width(), plotDimensions.height(), |
161 | this, fAllowMultitexturing, nullptr); |
162 | if (!fAtlases[index]) { |
163 | return false; |
164 | } |
165 | } |
166 | return true; |
167 | } |
168 | |