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