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