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