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 if (kN32_SkColorType != kRGBA_8888_SkColorType) {
143 if (!rgbaPixmap.tryAlloc(bm.info().makeColorType(kRGBA_8888_SkColorType))) {
144 fputs("Unable to alloc rgbaPixmap.\n", stderr);
145 return false;
146 }
147 if (!bm.readPixels(rgbaPixmap)) {
148 fputs("Unable to read rgbaPixmap.\n", stderr);
149 return false;
150 }
151 pixmap = &rgbaPixmap;
152 }
153
154 backEndTexture = sk_gpu_test::ManagedBackendTexture::MakeFromPixmap(dContext,
155 *pixmap,
156 options.fMipMapping,
157 GrRenderable::kNo,
158 GrProtected::kNo);
159 if (!backEndTexture) {
160 fputs("Failed to create backEndTexture.\n", stderr);
161 return false;
162 }
163 }
164
165 {
166 auto resourceProvider = dContext->priv().resourceProvider();
167
168 SkISize offscreenDims = {options.fOffScreenWidth, options.fOffScreenHeight};
169 SkAutoTMalloc<uint32_t> data(offscreenDims.area());
170 sk_memset32(data.get(), 0, offscreenDims.area());
171
172 // This backend object should be renderable but not textureable. Given the limitations
173 // of how we're creating it though it will wind up being secretly textureable.
174 // We use this fact to initialize it with data but don't allow mipmaps
175 GrMipLevel level0 = {data.get(), offscreenDims.width()*sizeof(uint32_t), nullptr};
176
177 constexpr int kSampleCnt = 0;
178 sk_sp<GrTexture> tmp = resourceProvider->createTexture(
179 offscreenDims, renderableFormat, GrTextureType::k2D, GrColorType::kRGBA_8888,
180 GrRenderable::kYes, kSampleCnt, SkBudgeted::kNo, GrMipMapped::kNo, GrProtected::kNo,
181 &level0);
182 if (!tmp || !tmp->asRenderTarget()) {
183 fputs("GrTexture is invalid.\n", stderr);
184 return false;
185 }
186
187 backingRenderTarget = sk_ref_sp(tmp->asRenderTarget());
188
189 backEndRenderTarget = backingRenderTarget->getBackendRenderTarget();
190 if (!backEndRenderTarget.isValid()) {
191 fputs("BackEndRenderTarget is invalid.\n", stderr);
192 return false;
193 }
194 }
195
196 {
197 backEndTextureRenderTarget = sk_gpu_test::ManagedBackendTexture::MakeWithData(
198 dContext,
199 options.fOffScreenWidth,
200 options.fOffScreenHeight,
201 renderableFormat,
202 SkColors::kTransparent,
203 options.fOffScreenMipMapping,
204 GrRenderable::kYes,
205 GrProtected::kNo);
206 if (!backEndTextureRenderTarget) {
207 fputs("Failed to create backendTextureRenderTarget.\n", stderr);
208 return false;
209 }
210 }
211
212 return true;
213 }
214 #endif
215
main(int argc,char ** argv)216 int main(int argc, char** argv) {
217 CommandLineFlags::Parse(argc, argv);
218 duration = FLAGS_duration;
219 frame = FLAGS_frame;
220 DrawOptions options = GetDrawOptions();
221 // If textOnly then only do one type of image, otherwise the text
222 // output is duplicated for each type.
223 if (options.textOnly) {
224 options.raster = true;
225 options.gpu = false;
226 options.pdf = false;
227 options.skp = false;
228 }
229 if (options.source) {
230 sk_sp<SkData> data(SkData::MakeFromFileName(options.source));
231 if (!data) {
232 perror(options.source);
233 return 1;
234 } else {
235 image = SkImage::MakeFromEncoded(std::move(data));
236 if (!image) {
237 perror("Unable to decode the source image.");
238 return 1;
239 }
240 SkAssertResult(image->asLegacyBitmap(&source));
241 }
242 }
243 sk_sp<SkData> rasterData, gpuData, pdfData, skpData;
244 SkColorType colorType = kN32_SkColorType;
245 sk_sp<SkColorSpace> colorSpace = nullptr;
246 if (options.f16) {
247 SkASSERT(options.srgb);
248 colorType = kRGBA_F16_SkColorType;
249 colorSpace = SkColorSpace::MakeSRGBLinear();
250 } else if (options.srgb) {
251 colorSpace = SkColorSpace::MakeSRGB();
252 }
253 SkImageInfo info = SkImageInfo::Make(options.size.width(), options.size.height(), colorType,
254 kPremul_SkAlphaType, colorSpace);
255 if (options.raster) {
256 auto rasterSurface = SkSurface::MakeRaster(info);
257 srand(0);
258 draw(prepare_canvas(rasterSurface->getCanvas()));
259 rasterData = encode_snapshot(rasterSurface);
260 }
261 #ifdef SK_GL
262 if (options.gpu) {
263 std::unique_ptr<sk_gpu_test::GLTestContext> glContext;
264 sk_sp<GrDirectContext> direct = create_direct_context(gGLDriverInfo, &glContext);
265 if (!direct) {
266 fputs("Unable to get GrContext.\n", stderr);
267 } else {
268 if (!setup_backend_objects(direct.get(), source, options)) {
269 fputs("Unable to create backend objects.\n", stderr);
270 exit(1);
271 }
272
273 auto surface = SkSurface::MakeRenderTarget(direct.get(), SkBudgeted::kNo, info);
274 if (!surface) {
275 fputs("Unable to get render surface.\n", stderr);
276 exit(1);
277 }
278 srand(0);
279 draw(prepare_canvas(surface->getCanvas()));
280 gpuData = encode_snapshot(surface);
281 }
282 }
283 #endif
284
285 #ifdef SK_SUPPORT_PDF
286 if (options.pdf) {
287 SkDynamicMemoryWStream pdfStream;
288 auto document = SkPDF::MakeDocument(&pdfStream);
289 if (document) {
290 srand(0);
291 draw(prepare_canvas(document->beginPage(options.size.width(), options.size.height())));
292 document->close();
293 pdfData = pdfStream.detachAsData();
294 }
295 }
296 #endif
297
298 if (options.skp) {
299 auto size = SkSize::Make(options.size);
300 SkPictureRecorder recorder;
301 srand(0);
302 draw(prepare_canvas(recorder.beginRecording(size.width(), size.height())));
303 auto picture = recorder.finishRecordingAsPicture();
304 SkDynamicMemoryWStream skpStream;
305 picture->serialize(&skpStream);
306 skpData = skpStream.detachAsData();
307 }
308
309 printf("{\n");
310 if (!options.textOnly) {
311 dump_output(rasterData, "Raster", false);
312 dump_output(gpuData, "Gpu", false);
313 dump_output(pdfData, "Pdf", false);
314 dump_output(skpData, "Skp", false);
315 } else {
316 std::string textoutput = gTextOutput.str();
317 dump_output(textoutput.c_str(), textoutput.length(), "Text", false);
318 }
319 std::string glinfo = gGLDriverInfo.str();
320 dump_output(glinfo.c_str(), glinfo.length(), "GLInfo", true);
321 printf("}\n");
322
323 return 0;
324 }
325