xref: /aosp_15_r20/external/skia/tools/fiddle/fiddle_main.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2015 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 <cstdio>
9 #include <cstdlib>
10 #include <sstream>
11 #include <string>
12 
13 #include "src/core/SkAutoPixmapStorage.h"
14 #include "src/core/SkMemset.h"
15 #include "src/core/SkMipmap.h"
16 #include "tools/flags/CommandLineFlags.h"
17 
18 #include "tools/fiddle/fiddle_main.h"
19 
20 static DEFINE_double(duration, 1.0,
21                      "The total duration, in seconds, of the animation we are drawing.");
22 static DEFINE_double(frame, 1.0,
23                      "A double value in [0, 1] that specifies the point in animation to draw.");
24 
25 #include "include/codec/SkCodec.h"
26 #include "include/codec/SkJpegDecoder.h"
27 #include "include/codec/SkPngDecoder.h"
28 #include "include/encode/SkPngEncoder.h"
29 #include "include/gpu/ganesh/GrBackendSurface.h"
30 #include "include/gpu/ganesh/SkSurfaceGanesh.h"
31 #include "src/gpu/ganesh/GrDirectContextPriv.h"
32 #include "src/gpu/ganesh/GrGpu.h"
33 #include "src/gpu/ganesh/GrRenderTarget.h"
34 #include "src/gpu/ganesh/GrResourceProvider.h"
35 #include "src/gpu/ganesh/GrTexture.h"
36 #include "tools/gpu/ManagedBackendTexture.h"
37 #include "tools/gpu/gl/GLTestContext.h"
38 
39 #if defined(SK_FONTMGR_FONTCONFIG_AVAILABLE)
40 #include "include/ports/SkFontMgr_fontconfig.h"
41 #include "include/ports/SkFontScanner_FreeType.h"
42 #endif
43 
44 using namespace skia_private;
45 
46 // Globals externed in fiddle_main.h
47 GrBackendTexture backEndTexture;
48 GrBackendRenderTarget backEndRenderTarget;
49 GrBackendTexture backEndTextureRenderTarget;
50 SkBitmap source;
51 sk_sp<SkImage> image;
52 double duration; // The total duration of the animation in seconds.
53 double frame;    // A value in [0, 1] of where we are in the animation.
54 sk_sp<SkFontMgr> fontMgr;
55 
56 // Global used by the local impl of SkDebugf.
57 std::ostringstream gTextOutput;
58 
59 // Global to record the GL driver info via create_direct_context().
60 std::ostringstream gGLDriverInfo;
61 
62 sk_sp<sk_gpu_test::ManagedBackendTexture> managedBackendTextureRenderTarget;
63 sk_sp<sk_gpu_test::ManagedBackendTexture> managedBackendTexture;
64 sk_sp<GrRenderTarget> backingRenderTarget;
65 
SkDebugf(const char * fmt,...)66 void SkDebugf(const char * fmt, ...) {
67     va_list args;
68     va_start(args, fmt);
69     char formatbuffer[1024];
70     int n = vsnprintf(formatbuffer, sizeof(formatbuffer), fmt, args);
71     va_end(args);
72     if (n>=0 && n<=int(sizeof(formatbuffer))) {
73         gTextOutput.write(formatbuffer, n);
74     }
75 }
76 
encode_to_base64(const void * data,size_t size,FILE * out)77 static void encode_to_base64(const void* data, size_t size, FILE* out) {
78     const uint8_t* input = reinterpret_cast<const uint8_t*>(data);
79     const uint8_t* end = &input[size];
80     static const char codes[] =
81             "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
82             "abcdefghijklmnopqrstuvwxyz0123456789+/";
83     while (input != end) {
84         uint8_t b = (*input & 0xFC) >> 2;
85         fputc(codes[b], out);
86         b = (*input & 0x03) << 4;
87         ++input;
88         if (input == end) {
89             fputc(codes[b], out);
90             fputs("==", out);
91             return;
92         }
93         b |= (*input & 0xF0) >> 4;
94         fputc(codes[b], out);
95         b = (*input & 0x0F) << 2;
96         ++input;
97         if (input == end) {
98             fputc(codes[b], out);
99             fputc('=', out);
100             return;
101         }
102         b |= (*input & 0xC0) >> 6;
103         fputc(codes[b], out);
104         b = *input & 0x3F;
105         fputc(codes[b], out);
106         ++input;
107     }
108 }
109 
110 
dump_output(const void * data,size_t size,const char * name,bool last=true)111 static void dump_output(const void* data, size_t size,
112                         const char* name, bool last = true) {
113     printf("\t\"%s\": \"", name);
114     encode_to_base64(data, size, stdout);
115     fputs(last ? "\"\n" : "\",\n", stdout);
116 }
117 
dump_output(const sk_sp<SkData> & data,const char * name,bool last=true)118 static void dump_output(const sk_sp<SkData>& data,
119                         const char* name, bool last = true) {
120     if (data) {
121         dump_output(data->data(), data->size(), name, last);
122     }
123 }
124 
encode_snapshot(GrDirectContext * ctx,const sk_sp<SkSurface> & surface)125 static sk_sp<SkData> encode_snapshot(GrDirectContext* ctx, const sk_sp<SkSurface>& surface) {
126     sk_sp<SkImage> img(surface->makeImageSnapshot());
127     return SkPngEncoder::Encode(ctx, img.get(), {});
128 }
129 
prepare_canvas(SkCanvas * canvas)130 static SkCanvas* prepare_canvas(SkCanvas * canvas) {
131     canvas->clear(SK_ColorWHITE);
132     return canvas;
133 }
134 
135 #ifdef SK_GL
setup_backend_objects(GrDirectContext * dContext,const SkBitmap & bm,const DrawOptions & options)136 static bool setup_backend_objects(GrDirectContext* dContext,
137                                   const SkBitmap& bm,
138                                   const DrawOptions& options) {
139     if (!dContext) {
140         fputs("Context is null.\n", stderr);
141         return false;
142     }
143 
144     // This config must match the SkColorType used in draw.cpp in the SkImage and Surface factories
145     GrBackendFormat renderableFormat = dContext->defaultBackendFormat(kRGBA_8888_SkColorType,
146                                                                       GrRenderable::kYes);
147 
148     if (!bm.empty()) {
149         SkPixmap originalPixmap;
150         SkPixmap* pixmap = &originalPixmap;
151         if (!bm.peekPixels(&originalPixmap)) {
152             fputs("Unable to peekPixels.\n", stderr);
153             return false;
154         }
155 
156         SkAutoPixmapStorage rgbaPixmap;
157         constexpr bool kRGBAIsNative = kN32_SkColorType == kRGBA_8888_SkColorType;
158         if ((!kRGBAIsNative)) {
159             if (!rgbaPixmap.tryAlloc(bm.info().makeColorType(kRGBA_8888_SkColorType))) {
160                 fputs("Unable to alloc rgbaPixmap.\n", stderr);
161                 return false;
162             }
163             if (!bm.readPixels(rgbaPixmap)) {
164                 fputs("Unable to read rgbaPixmap.\n", stderr);
165                 return false;
166             }
167             pixmap = &rgbaPixmap;
168         }
169 
170         managedBackendTexture = sk_gpu_test::ManagedBackendTexture::MakeFromPixmap(
171                 dContext,
172                 *pixmap,
173                 options.fMipMapping,
174                 GrRenderable::kNo,
175                 GrProtected::kNo);
176         if (!managedBackendTexture) {
177             fputs("Failed to create backEndTexture.\n", stderr);
178             return false;
179         }
180         backEndTexture = managedBackendTexture->texture();
181     }
182 
183     {
184         auto resourceProvider = dContext->priv().resourceProvider();
185 
186         SkISize offscreenDims = {options.fOffScreenWidth, options.fOffScreenHeight};
187         AutoTMalloc<uint32_t> data(offscreenDims.area());
188         SkOpts::memset32(data.get(), 0, offscreenDims.area());
189 
190         // This backend object should be renderable but not textureable. Given the limitations
191         // of how we're creating it though it will wind up being secretly textureable.
192         // We use this fact to initialize it with data but don't allow mipmaps
193         GrMipLevel level0 = {data.get(), offscreenDims.width()*sizeof(uint32_t), nullptr};
194 
195         constexpr int kSampleCnt = 1;
196         sk_sp<GrTexture> tmp =
197                 resourceProvider->createTexture(offscreenDims,
198                                                 renderableFormat,
199                                                 GrTextureType::k2D,
200                                                 GrColorType::kRGBA_8888,
201                                                 GrRenderable::kYes,
202                                                 kSampleCnt,
203                                                 skgpu::Budgeted::kNo,
204                                                 skgpu::Mipmapped::kNo,
205                                                 GrProtected::kNo,
206                                                 &level0,
207                                                 /*label=*/"Fiddle_SetupBackendObjects");
208         if (!tmp || !tmp->asRenderTarget()) {
209             fputs("GrTexture is invalid.\n", stderr);
210             return false;
211         }
212 
213         backingRenderTarget = sk_ref_sp(tmp->asRenderTarget());
214 
215         backEndRenderTarget = backingRenderTarget->getBackendRenderTarget();
216         if (!backEndRenderTarget.isValid()) {
217             fputs("BackEndRenderTarget is invalid.\n", stderr);
218             return false;
219         }
220     }
221 
222     {
223         managedBackendTextureRenderTarget = sk_gpu_test::ManagedBackendTexture::MakeWithData(
224             dContext,
225             options.fOffScreenWidth,
226             options.fOffScreenHeight,
227             renderableFormat,
228             SkColors::kTransparent,
229             options.fOffScreenMipMapping,
230             GrRenderable::kYes,
231             GrProtected::kNo);
232         if (!managedBackendTextureRenderTarget) {
233             fputs("Failed to create backendTextureRenderTarget.\n", stderr);
234             return false;
235         }
236         backEndTextureRenderTarget = managedBackendTextureRenderTarget->texture();
237     }
238 
239     return true;
240 }
241 #endif
242 
main(int argc,char ** argv)243 int main(int argc, char** argv) {
244     CommandLineFlags::Parse(argc, argv);
245     duration = FLAGS_duration;
246     frame = FLAGS_frame;
247     DrawOptions options = GetDrawOptions();
248     // If textOnly then only do one type of image, otherwise the text
249     // output is duplicated for each type.
250     if (options.textOnly) {
251         options.raster = true;
252         options.gpu = false;
253         options.pdf = false;
254         options.skp = false;
255     }
256 #if defined(SK_FONTMGR_FONTCONFIG_AVAILABLE)
257     fontMgr = SkFontMgr_New_FontConfig(nullptr, SkFontScanner_Make_FreeType());
258 #else
259     fontMgr = SkFontMgr::RefEmpty();
260 #endif
261     if (options.source) {
262         sk_sp<SkData> data(SkData::MakeFromFileName(options.source));
263         if (!data) {
264             perror(options.source);
265             return 1;
266         }
267         std::unique_ptr<SkCodec> codec = nullptr;
268         if (SkPngDecoder::IsPng(data->data(), data->size())) {
269             codec = SkPngDecoder::Decode(data, nullptr);
270         } else if (SkJpegDecoder::IsJpeg(data->data(), data->size())) {
271             codec = SkJpegDecoder::Decode(data, nullptr);
272         } else {
273             perror("Unsupported file format\n");
274             return 1;
275         }
276         if (!codec) {
277             perror("Corrupt source image file\n");
278             return 1;
279         }
280         image = std::get<0>(codec->getImage());
281         if (!image) {
282             perror("Unable to decode the source image.\n");
283             return 1;
284         }
285         SkAssertResult(image->asLegacyBitmap(&source));
286     }
287     sk_sp<SkData> rasterData, gpuData, pdfData, skpData;
288     SkColorType colorType = kN32_SkColorType;
289     sk_sp<SkColorSpace> colorSpace = nullptr;
290     if (options.f16) {
291         SkASSERT(options.srgb);
292         colorType = kRGBA_F16_SkColorType;
293         colorSpace = SkColorSpace::MakeSRGBLinear();
294     } else if (options.srgb) {
295         colorSpace = SkColorSpace::MakeSRGB();
296     }
297     SkImageInfo info = SkImageInfo::Make(options.size.width(), options.size.height(), colorType,
298                                          kPremul_SkAlphaType, colorSpace);
299     if (options.raster) {
300         auto rasterSurface = SkSurfaces::Raster(info);
301         srand(0);
302         draw(prepare_canvas(rasterSurface->getCanvas()));
303         rasterData = encode_snapshot(nullptr, rasterSurface);
304     }
305 #ifdef SK_GL
306     if (options.gpu) {
307         std::unique_ptr<sk_gpu_test::GLTestContext> glContext;
308         sk_sp<GrDirectContext> direct = create_direct_context(gGLDriverInfo, &glContext);
309         if (!direct) {
310             fputs("Unable to get GrContext.\n", stderr);
311         } else {
312             if (!setup_backend_objects(direct.get(), source, options)) {
313                 fputs("Unable to create backend objects.\n", stderr);
314                 exit(1);
315             }
316 
317             auto surface = SkSurfaces::RenderTarget(direct.get(), skgpu::Budgeted::kNo, info);
318             if (!surface) {
319                 fputs("Unable to get render surface.\n", stderr);
320                 exit(1);
321             }
322             srand(0);
323             draw(prepare_canvas(surface->getCanvas()));
324             gpuData = encode_snapshot(direct.get(), surface);
325         }
326     }
327 #endif
328 
329 #ifdef SK_SUPPORT_PDF
330     if (options.pdf) {
331         SkDynamicMemoryWStream pdfStream;
332         auto document = SkPDF::MakeDocument(&pdfStream);
333         if (document) {
334             srand(0);
335             draw(prepare_canvas(document->beginPage(options.size.width(), options.size.height())));
336             document->close();
337             pdfData = pdfStream.detachAsData();
338         }
339     }
340 #endif
341 
342     if (options.skp) {
343         auto size = SkSize::Make(options.size);
344         SkPictureRecorder recorder;
345         srand(0);
346         draw(prepare_canvas(recorder.beginRecording(size.width(), size.height())));
347         auto picture = recorder.finishRecordingAsPicture();
348         SkDynamicMemoryWStream skpStream;
349         picture->serialize(&skpStream);
350         skpData = skpStream.detachAsData();
351     }
352 
353     printf("{\n");
354     if (!options.textOnly) {
355         dump_output(rasterData, "Raster", false);
356         dump_output(gpuData, "Gpu", false);
357         dump_output(pdfData, "Pdf", false);
358         dump_output(skpData, "Skp", false);
359     } else {
360         std::string textoutput = gTextOutput.str();
361         dump_output(textoutput.c_str(), textoutput.length(), "Text", false);
362     }
363     std::string glinfo = gGLDriverInfo.str();
364     dump_output(glinfo.c_str(), glinfo.length(), "GLInfo", true);
365     printf("}\n");
366 
367     return 0;
368 }
369