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