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->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 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