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