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