• 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/SkMipMap.h"
15 #include "src/core/SkUtils.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/gpu/GrBackendSurface.h"
26 #include "src/gpu/GrContextPriv.h"
27 #include "src/gpu/GrGpu.h"
28 #include "src/gpu/GrRenderTarget.h"
29 #include "tools/gpu/gl/GLTestContext.h"
30 
31 // Globals externed in fiddle_main.h
32 sk_sp<GrTexture>      backingTexture;  // not externed
33 GrBackendTexture      backEndTexture;
34 
35 sk_sp<GrRenderTarget> backingRenderTarget; // not externed
36 GrBackendRenderTarget backEndRenderTarget;
37 
38 sk_sp<GrTexture>      backingTextureRenderTarget;  // not externed
39 GrBackendTexture      backEndTextureRenderTarget;
40 
41 SkBitmap source;
42 sk_sp<SkImage> image;
43 double duration; // The total duration of the animation in seconds.
44 double frame;    // A value in [0, 1] of where we are in the animation.
45 
46 // Global used by the local impl of SkDebugf.
47 std::ostringstream gTextOutput;
48 
49 // Global to record the GL driver info via create_grcontext().
50 std::ostringstream gGLDriverInfo;
51 
SkDebugf(const char * fmt,...)52 void SkDebugf(const char * fmt, ...) {
53     va_list args;
54     va_start(args, fmt);
55     char formatbuffer[1024];
56     int n = vsnprintf(formatbuffer, sizeof(formatbuffer), fmt, args);
57     va_end(args);
58     if (n>=0 && n<=int(sizeof(formatbuffer))) {
59         gTextOutput.write(formatbuffer, n);
60     }
61 }
62 
encode_to_base64(const void * data,size_t size,FILE * out)63 static void encode_to_base64(const void* data, size_t size, FILE* out) {
64     const uint8_t* input = reinterpret_cast<const uint8_t*>(data);
65     const uint8_t* end = &input[size];
66     static const char codes[] =
67             "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
68             "abcdefghijklmnopqrstuvwxyz0123456789+/";
69     while (input != end) {
70         uint8_t b = (*input & 0xFC) >> 2;
71         fputc(codes[b], out);
72         b = (*input & 0x03) << 4;
73         ++input;
74         if (input == end) {
75             fputc(codes[b], out);
76             fputs("==", out);
77             return;
78         }
79         b |= (*input & 0xF0) >> 4;
80         fputc(codes[b], out);
81         b = (*input & 0x0F) << 2;
82         ++input;
83         if (input == end) {
84             fputc(codes[b], out);
85             fputc('=', out);
86             return;
87         }
88         b |= (*input & 0xC0) >> 6;
89         fputc(codes[b], out);
90         b = *input & 0x3F;
91         fputc(codes[b], out);
92         ++input;
93     }
94 }
95 
96 
dump_output(const void * data,size_t size,const char * name,bool last=true)97 static void dump_output(const void* data, size_t size,
98                         const char* name, bool last = true) {
99     printf("\t\"%s\": \"", name);
100     encode_to_base64(data, size, stdout);
101     fputs(last ? "\"\n" : "\",\n", stdout);
102 }
103 
dump_output(const sk_sp<SkData> & data,const char * name,bool last=true)104 static void dump_output(const sk_sp<SkData>& data,
105                         const char* name, bool last = true) {
106     if (data) {
107         dump_output(data->data(), data->size(), name, last);
108     }
109 }
110 
encode_snapshot(const sk_sp<SkSurface> & surface)111 static sk_sp<SkData> encode_snapshot(const sk_sp<SkSurface>& surface) {
112     sk_sp<SkImage> img(surface->makeImageSnapshot());
113     return img ? img->encodeToData() : nullptr;
114 }
115 
prepare_canvas(SkCanvas * canvas)116 static SkCanvas* prepare_canvas(SkCanvas * canvas) {
117     canvas->clear(SK_ColorWHITE);
118     return canvas;
119 }
120 
setup_backend_objects(GrContext * context,const SkBitmap & bm,const DrawOptions & options)121 static bool setup_backend_objects(GrContext* context,
122                                   const SkBitmap& bm,
123                                   const DrawOptions& options) {
124     if (!context) {
125         fputs("Context is null.\n", stderr);
126         return false;
127     }
128 
129     auto resourceProvider = context->priv().resourceProvider();
130 
131     // This config must match the SkColorType used in draw.cpp in the SkImage and Surface factories
132     auto format = resourceProvider->caps()->getDefaultBackendFormat(
133             SkColorTypeToGrColorType(kRGBA_8888_SkColorType), GrRenderable::kNo);
134     auto renderableFormat = resourceProvider->caps()->getDefaultBackendFormat(
135             SkColorTypeToGrColorType(kRGBA_8888_SkColorType), GrRenderable::kYes);
136 
137     if (!bm.empty()) {
138         SkPixmap originalPixmap;
139         SkPixmap* pixmap = &originalPixmap;
140         if (!bm.peekPixels(&originalPixmap)) {
141             fputs("Unable to peekPixels.\n", stderr);
142             return false;
143         }
144 
145         SkAutoPixmapStorage rgbaPixmap;
146         if (kN32_SkColorType != kRGBA_8888_SkColorType) {
147             if (!rgbaPixmap.tryAlloc(bm.info().makeColorType(kRGBA_8888_SkColorType))) {
148                 fputs("Unable to alloc rgbaPixmap.\n", stderr);
149                 return false;
150             }
151             if (!bm.readPixels(rgbaPixmap)) {
152                 fputs("Unable to read rgbaPixmap.\n", stderr);
153                 return false;
154             }
155             pixmap = &rgbaPixmap;
156         }
157         int mipLevelCount = GrMipMapped::kYes == options.fMipMapping
158                                     ? SkMipMap::ComputeLevelCount(bm.width(), bm.height())
159                                     : 1;
160         std::unique_ptr<GrMipLevel[]> texels(new GrMipLevel[mipLevelCount]);
161 
162         texels[0].fPixels = pixmap->addr();
163         texels[0].fRowBytes = pixmap->rowBytes();
164 
165         for (int i = 1; i < mipLevelCount; i++) {
166             texels[i].fPixels = nullptr;
167             texels[i].fRowBytes = 0;
168         }
169 
170         backingTexture = resourceProvider->createTexture(
171                 bm.dimensions(), format, GrColorType::kRGBA_8888, GrRenderable::kNo, 1,
172                 SkBudgeted::kNo, GrProtected::kNo, texels.get(), mipLevelCount);
173         if (!backingTexture) {
174             fputs("Failed to create backingTexture.\n", stderr);
175             return false;
176         }
177 
178         backEndTexture = backingTexture->getBackendTexture();
179         if (!backEndTexture.isValid()) {
180             fputs("BackingTexture is invalid.\n", stderr);
181             return false;
182         }
183     }
184 
185     SkISize offscreenDims = {options.fOffScreenWidth, options.fOffScreenHeight};
186     SkAutoTMalloc<uint32_t> data(offscreenDims.area());
187     sk_memset32(data.get(), 0, offscreenDims.area());
188 
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) };
194 
195         sk_sp<GrTexture> tmp = resourceProvider->createTexture(
196                 offscreenDims, renderableFormat, GrColorType::kRGBA_8888, GrRenderable::kYes,
197                 options.fOffScreenSampleCount, SkBudgeted::kNo, GrProtected::kNo, &level0, 1);
198         if (!tmp || !tmp->asRenderTarget()) {
199             fputs("GrTexture is invalid.\n", stderr);
200             return false;
201         }
202 
203         backingRenderTarget = sk_ref_sp(tmp->asRenderTarget());
204 
205         backEndRenderTarget = backingRenderTarget->getBackendRenderTarget();
206         if (!backEndRenderTarget.isValid()) {
207             fputs("BackEndRenderTarget is invalid.\n", stderr);
208             return false;
209         }
210     }
211 
212     {
213         int mipLevelCount =
214                 GrMipMapped::kYes == options.fOffScreenMipMapping
215                         ? SkMipMap::ComputeLevelCount(offscreenDims.width(), offscreenDims.height())
216                         : 1;
217         std::unique_ptr<GrMipLevel[]> texels(new GrMipLevel[mipLevelCount]);
218 
219         texels[0].fPixels = data.get();
220         texels[0].fRowBytes = offscreenDims.width()*sizeof(uint32_t);
221 
222         for (int i = 1; i < mipLevelCount; i++) {
223             texels[i].fPixels = nullptr;
224             texels[i].fRowBytes = 0;
225         }
226 
227         backingTextureRenderTarget = resourceProvider->createTexture(
228                 offscreenDims, renderableFormat, GrColorType::kRGBA_8888, GrRenderable::kYes,
229                 options.fOffScreenSampleCount, SkBudgeted::kNo, GrProtected::kNo, texels.get(),
230                 mipLevelCount);
231         if (!backingTextureRenderTarget || !backingTextureRenderTarget->asRenderTarget()) {
232             fputs("backingTextureRenderTarget is invalid.\n", stderr);
233             return false;
234         }
235 
236         backEndTextureRenderTarget = backingTextureRenderTarget->getBackendTexture();
237         if (!backEndTextureRenderTarget.isValid()) {
238             fputs("backEndTextureRenderTarget is invalid.\n", stderr);
239             return false;
240         }
241     }
242 
243 
244     return true;
245 }
246 
main(int argc,char ** argv)247 int main(int argc, char** argv) {
248     CommandLineFlags::Parse(argc, argv);
249     duration = FLAGS_duration;
250     frame = FLAGS_frame;
251     DrawOptions options = GetDrawOptions();
252     // If textOnly then only do one type of image, otherwise the text
253     // output is duplicated for each type.
254     if (options.textOnly) {
255         options.raster = true;
256         options.gpu = false;
257         options.pdf = false;
258         options.skp = false;
259     }
260     if (options.source) {
261         sk_sp<SkData> data(SkData::MakeFromFileName(options.source));
262         if (!data) {
263             perror(options.source);
264             return 1;
265         } else {
266             image = SkImage::MakeFromEncoded(std::move(data));
267             if (!image) {
268                 perror("Unable to decode the source image.");
269                 return 1;
270             }
271             SkAssertResult(image->asLegacyBitmap(&source));
272         }
273     }
274     sk_sp<SkData> rasterData, gpuData, pdfData, skpData;
275     SkColorType colorType = kN32_SkColorType;
276     sk_sp<SkColorSpace> colorSpace = nullptr;
277     if (options.f16) {
278         SkASSERT(options.srgb);
279         colorType = kRGBA_F16_SkColorType;
280         colorSpace = SkColorSpace::MakeSRGBLinear();
281     } else if (options.srgb) {
282         colorSpace = SkColorSpace::MakeSRGB();
283     }
284     SkImageInfo info = SkImageInfo::Make(options.size.width(), options.size.height(), colorType,
285                                          kPremul_SkAlphaType, colorSpace);
286     if (options.raster) {
287         auto rasterSurface = SkSurface::MakeRaster(info);
288         srand(0);
289         draw(prepare_canvas(rasterSurface->getCanvas()));
290         rasterData = encode_snapshot(rasterSurface);
291     }
292     if (options.gpu) {
293         std::unique_ptr<sk_gpu_test::GLTestContext> glContext;
294         sk_sp<GrContext> grContext = create_grcontext(gGLDriverInfo, &glContext);
295         if (!grContext) {
296             fputs("Unable to get GrContext.\n", stderr);
297         } else {
298             if (!setup_backend_objects(grContext.get(), source, options)) {
299                 fputs("Unable to create backend objects.\n", stderr);
300                 exit(1);
301             }
302 
303             auto surface = SkSurface::MakeRenderTarget(grContext.get(), SkBudgeted::kNo, info);
304             if (!surface) {
305                 fputs("Unable to get render surface.\n", stderr);
306                 exit(1);
307             }
308             srand(0);
309             draw(prepare_canvas(surface->getCanvas()));
310             gpuData = encode_snapshot(surface);
311         }
312     }
313     if (options.pdf) {
314         SkDynamicMemoryWStream pdfStream;
315         auto document = SkPDF::MakeDocument(&pdfStream);
316         if (document) {
317             srand(0);
318             draw(prepare_canvas(document->beginPage(options.size.width(), options.size.height())));
319             document->close();
320             pdfData = pdfStream.detachAsData();
321         }
322     }
323     if (options.skp) {
324         auto size = SkSize::Make(options.size);
325         SkPictureRecorder recorder;
326         srand(0);
327         draw(prepare_canvas(recorder.beginRecording(size.width(), size.height())));
328         auto picture = recorder.finishRecordingAsPicture();
329         SkDynamicMemoryWStream skpStream;
330         picture->serialize(&skpStream);
331         skpData = skpStream.detachAsData();
332     }
333 
334     printf("{\n");
335     if (!options.textOnly) {
336         dump_output(rasterData, "Raster", false);
337         dump_output(gpuData, "Gpu", false);
338         dump_output(pdfData, "Pdf", false);
339         dump_output(skpData, "Skp", false);
340     } else {
341         std::string textoutput = gTextOutput.str();
342         dump_output(textoutput.c_str(), textoutput.length(), "Text", false);
343     }
344     std::string glinfo = gGLDriverInfo.str();
345     dump_output(glinfo.c_str(), glinfo.length(), "GLInfo", true);
346     printf("}\n");
347 
348     return 0;
349 }
350