Home | History | Annotate | Download | only in fiddle
      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 
     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 
     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 
     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 
    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 
    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 
    113 static SkCanvas* prepare_canvas(SkCanvas * canvas) {
    114     canvas->clear(SK_ColorWHITE);
    115     return canvas;
    116 }
    117 
    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->priv().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 
    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