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