1 /*
2 * Copyright 2023 Google LLC
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 "tools/gpu/ganesh/GrAtlasTools.h"
9
10 #include "include/core/SkAlphaType.h"
11 #include "include/core/SkBitmap.h"
12 #include "include/core/SkColorSpace.h"
13 #include "include/core/SkColorType.h"
14 #include "include/core/SkDataTable.h"
15 #include "include/core/SkImageInfo.h"
16 #include "include/core/SkStream.h"
17 #include "include/core/SkString.h"
18 #include "include/encode/SkPngEncoder.h"
19 #include "include/gpu/ganesh/GrDirectContext.h"
20 #include "include/private/base/SkDebug.h"
21 #include "src/gpu/ganesh/GrDirectContextPriv.h"
22 #include "src/gpu/ganesh/GrSurfaceProxy.h"
23 #include "src/gpu/ganesh/GrSurfaceProxyView.h"
24 #include "src/gpu/ganesh/SurfaceContext.h"
25
26 #include <cstdio>
27 #include <utility>
28
29 /**
30 * Write the contents of the surface proxy to a PNG. Returns true if successful.
31 * @param filename Full path to desired file
32 */
save_pixels(GrDirectContext * dContext,GrSurfaceProxyView view,GrColorType colorType,const char * filename)33 static bool save_pixels(GrDirectContext* dContext,
34 GrSurfaceProxyView view,
35 GrColorType colorType,
36 const char* filename) {
37 if (!view.proxy()) {
38 return false;
39 }
40
41 auto ii = SkImageInfo::Make(
42 view.proxy()->dimensions(), kRGBA_8888_SkColorType, kPremul_SkAlphaType);
43 SkBitmap bm;
44 if (!bm.tryAllocPixels(ii)) {
45 return false;
46 }
47
48 auto sContext =
49 dContext->priv().makeSC(std::move(view), {colorType, kUnknown_SkAlphaType, nullptr});
50 if (!sContext || !sContext->asTextureProxy()) {
51 return false;
52 }
53
54 bool result = sContext->readPixels(dContext, bm.pixmap(), {0, 0});
55 if (!result) {
56 SkDebugf("------ failed to read pixels for %s\n", filename);
57 return false;
58 }
59
60 // remove any previous version of this file
61 remove(filename);
62
63 SkFILEWStream file(filename);
64 if (!file.isValid()) {
65 SkDebugf("------ failed to create file: %s\n", filename);
66 remove(filename); // remove any partial file
67 return false;
68 }
69
70 if (!SkPngEncoder::Encode(&file, bm.pixmap(), {})) {
71 SkDebugf("------ failed to encode %s\n", filename);
72 remove(filename); // remove any partial file
73 return false;
74 }
75
76 return true;
77 }
78
Dump(const GrAtlasManager * am,GrDirectContext * context)79 void GrAtlasManagerTools::Dump(const GrAtlasManager* am, GrDirectContext* context) {
80 SkASSERT(am);
81 static int gDumpCount = 0;
82 for (int i = 0; i < skgpu::kMaskFormatCount; ++i) {
83 if (am->fAtlases[i]) {
84 const GrSurfaceProxyView* views = am->fAtlases[i]->getViews();
85 for (uint32_t pageIdx = 0; pageIdx < am->fAtlases[i]->numActivePages(); ++pageIdx) {
86 SkASSERT(views[pageIdx].proxy());
87 SkString filename;
88 #ifdef SK_BUILD_FOR_ANDROID
89 filename.printf("/sdcard/fontcache_%d%d%d.png", gDumpCount, i, pageIdx);
90 #else
91 filename.printf("fontcache_%d%d%u.png", gDumpCount, i, pageIdx);
92 #endif
93 SkColorType ct = MaskFormatToColorType(GrAtlasManager::AtlasIndexToMaskFormat(i));
94 save_pixels(
95 context, views[pageIdx], SkColorTypeToGrColorType(ct), filename.c_str());
96 }
97 }
98 }
99 ++gDumpCount;
100 }
101
SetAtlasDimensionsToMinimum(GrAtlasManager * am)102 void GrAtlasManagerTools::SetAtlasDimensionsToMinimum(GrAtlasManager* am) {
103 SkASSERT(am);
104 // Delete any old atlases.
105 // This should be safe to do as long as we are not in the middle of a flush.
106 for (int i = 0; i < skgpu::kMaskFormatCount; i++) {
107 am->fAtlases[i] = nullptr;
108 }
109
110 // Set all the atlas sizes to 1x1 plot each.
111 new (&am->fAtlasConfig) GrDrawOpAtlasConfig{};
112 }
113
SetMaxPages(GrAtlasManager * am,uint32_t maxPages)114 void GrAtlasManagerTools::SetMaxPages(GrAtlasManager* am, uint32_t maxPages) {
115 SkASSERT(am);
116 for (int i = 0; i < skgpu::kMaskFormatCount; i++) {
117 if (am->fAtlases[i]) {
118 GrDrawOpAtlasTools::SetMaxPages(am->fAtlases[i].get(), maxPages);
119 }
120 }
121 }
122
NumAllocated(const GrDrawOpAtlas * doa)123 int GrDrawOpAtlasTools::NumAllocated(const GrDrawOpAtlas* doa) {
124 SkASSERT(doa);
125 int count = 0;
126 for (uint32_t i = 0; i < doa->maxPages(); ++i) {
127 if (doa->fViews[i].proxy()->isInstantiated()) {
128 ++count;
129 }
130 }
131
132 return count;
133 }
134
SetMaxPages(GrDrawOpAtlas * doa,uint32_t maxPages)135 void GrDrawOpAtlasTools::SetMaxPages(GrDrawOpAtlas* doa, uint32_t maxPages) {
136 SkASSERT(!doa->fNumActivePages);
137
138 doa->fMaxPages = maxPages;
139 }
140