void SkDumpCanvas::drawPicture(SkPicture& picture) { this->dump(kDrawPicture_Verb, NULL, "drawPicture(%p) %d:%d", &picture, picture.width(), picture.height()); fNestLevel += 1; this->INHERITED::drawPicture(picture); fNestLevel -= 1; this->dump(kDrawPicture_Verb, NULL, "endPicture(%p) %d:%d", &picture, picture.width(), picture.height()); }
static void rerecord(const SkPicture& src, SkBBHFactory* bbhFactory) { SkPictureRecorder recorder; if (FLAGS_skr) { src.draw(recorder.EXPERIMENTAL_beginRecording(src.width(), src.height(), bbhFactory)); } else { src.draw(recorder.beginRecording(src.width(), src.height(), bbhFactory)); } SkAutoTUnref<SkPicture> pic(recorder.endRecording()); }
// Extract the command ops from the input SkPicture static void gets_ops(SkPicture& input, SkTDArray<DrawType>* ops) { SkDebugCanvas debugCanvas(input.width(), input.height()); debugCanvas.setBounds(input.width(), input.height()); input.draw(&debugCanvas); ops->setCount(debugCanvas.getSize()); for (int i = 0; i < debugCanvas.getSize(); ++i) { (*ops)[i] = debugCanvas.getDrawCommandAt(i)->getType(); } }
static SkPicture* inspect(const char path[]) { SkFILEStream stream(path); if (!stream.isValid()) { printf("-- Can't open '%s'\n", path); return NULL; } printf("Opening '%s'...\n", path); { int32_t header[3]; if (stream.read(header, sizeof(header)) != sizeof(header)) { printf("-- Failed to read header (12 bytes)\n"); return NULL; } printf("version:%d width:%d height:%d\n", header[0], header[1], header[2]); } stream.rewind(); SkPicture* pic = SkPicture::CreateFromStream(&stream, &sk_tools::LazyDecodeBitmap); if (NULL == pic) { SkDebugf("Could not create SkPicture: %s\n", path); return NULL; } printf("picture size:[%d %d]\n", pic->width(), pic->height()); return pic; }
// Do the commands in 'input' match the supplied pattern? Note: this is a pretty // heavy-weight operation since we are drawing the picture into a debug canvas // to extract the commands. static bool check_pattern(SkPicture& input, const SkTDArray<DrawType> &pattern) { SkDebugCanvas debugCanvas(input.width(), input.height()); debugCanvas.setBounds(input.width(), input.height()); input.draw(&debugCanvas); if (pattern.count() != debugCanvas.getSize()) { return false; } for (int i = 0; i < pattern.count(); ++i) { if (pattern[i] != debugCanvas.getDrawCommandAt(i)->getType()) { return false; } } return true; }
static bool render_picture(const SkString& inputPath, const SkString* outputDir, sk_tools::PictureRenderer& renderer, SkBitmap** out, int clones) { SkString inputFilename; sk_tools::get_basename(&inputFilename, inputPath); SkFILEStream inputStream; inputStream.setPath(inputPath.c_str()); if (!inputStream.isValid()) { SkDebugf("Could not open file %s\n", inputPath.c_str()); return false; } bool success = false; SkPicture* picture = SkNEW_ARGS(SkPicture, (&inputStream, &success, &SkImageDecoder::DecodeStream)); if (!success) { SkDebugf("Could not read an SkPicture from %s\n", inputPath.c_str()); return false; } for (int i = 0; i < clones; ++i) { SkPicture* clone = picture->clone(); SkDELETE(picture); picture = clone; } SkDebugf("drawing... [%i %i] %s\n", picture->width(), picture->height(), inputPath.c_str()); renderer.init(picture); renderer.setup(); SkString* outputPath = NULL; if (NULL != outputDir) { outputPath = SkNEW(SkString); make_output_filepath(outputPath, *outputDir, inputFilename); } success = renderer.render(outputPath, out); if (outputPath) { if (!success) { SkDebugf("Could not write to file %s\n", outputPath->c_str()); } SkDELETE(outputPath); } renderer.resetState(); renderer.end(); SkDELETE(picture); return success; }
static void testOne(const SkString& filename) { #if DEBUG_SHOW_TEST_NAME SkString testName(filename); const char http[] = "http"; if (testName.startsWith(http)) { testName.remove(0, sizeof(http) - 1); } while (testName.startsWith("_")) { testName.remove(0, 1); } const char dotSkp[] = ".skp"; if (testName.endsWith(dotSkp)) { size_t len = testName.size(); testName.remove(len - (sizeof(dotSkp) - 1), sizeof(dotSkp) - 1); } testName.prepend("skp"); testName.append("1"); strncpy(DEBUG_FILENAME_STRING, testName.c_str(), DEBUG_FILENAME_STRING_LENGTH); #endif SkString path; make_filepath(&path, pictDir, filename); SkFILEStream stream(path.c_str()); if (!stream.isValid()) { return; } SkPicture* pic = SkPicture::CreateFromStream(&stream, &SkImageDecoder::DecodeMemory); if (!pic) { SkDebugf("unable to decode %s\n", filename.c_str()); return; } int width = pic->width(); int height = pic->height(); SkBitmap bitmap; bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height); bool success = bitmap.allocPixels(); if (!success) { SkDebugf("unable to allocate bitmap for %s\n", filename.c_str()); return; } SkCanvas canvas(bitmap); SkString pngName(filename); pngName.remove(pngName.size() - 3, 3); pngName.append("png"); for (int i = 0; i < 2; ++i) { bool useOp = i ? true : false; canvas.setAllowSimplifyClip(useOp); pic->draw(&canvas); SkString outFile; make_filepath(&outFile, useOp ? outSkpClipDir : outOldClipDir, pngName); SkImageEncoder::EncodeFile(outFile.c_str(), bitmap, SkImageEncoder::kPNG_Type, 100); } SkDELETE(pic); }
static void bench(SkPMColor* scratch, SkPicture& src, const char* name) { SkAutoTUnref<SkPicture> picture(rerecord_with_tilegrid(src)); SkAutoTDelete<EXPERIMENTAL::SkPlayback> record(rerecord_with_skr(src)); SkAutoTDelete<SkCanvas> canvas(SkCanvas::NewRasterDirectN32(src.width(), src.height(), scratch, src.width() * sizeof(SkPMColor))); canvas->clipRect(SkRect::MakeWH(SkIntToScalar(FLAGS_tile), SkIntToScalar(FLAGS_tile))); // Draw once to warm any caches. The first sample otherwise can be very noisy. draw(*record, *picture, canvas.get()); WallTimer timer; const double scale = timescale(); SkAutoTMalloc<double> samples(FLAGS_samples); for (int i = 0; i < FLAGS_samples; i++) { // We assume timer overhead (typically, ~30ns) is insignificant // compared to draw runtime (at least ~100us, usually several ms). timer.start(); draw(*record, *picture, canvas.get()); timer.end(); samples[i] = timer.fWall * scale; } Stats stats(samples.get(), FLAGS_samples); if (FLAGS_verbose == 0) { printf("%g\t%s\n", stats.min, name); } else if (FLAGS_verbose == 1) { // Get a rough idea of how noisy the measurements were. const double noisePercent = 100 * sqrt(stats.var) / stats.mean; printf("%g\t%g\t%g\t±%.0f%%\t%s\n", stats.min, stats.mean, stats.max, noisePercent, name); } else if (FLAGS_verbose == 2) { printf("%s", name); for (int i = 0; i < FLAGS_samples; i++) { printf("\t%g", samples[i]); } printf("\n"); } }
/** * Called only by render_picture(). */ static bool render_picture_internal(const SkString& inputPath, const SkString* outputDir, sk_tools::PictureRenderer& renderer, SkBitmap** out) { SkString inputFilename; sk_tools::get_basename(&inputFilename, inputPath); SkString outputDirString; if (NULL != outputDir && outputDir->size() > 0 && !FLAGS_writeEncodedImages) { outputDirString.set(*outputDir); } SkFILEStream inputStream; inputStream.setPath(inputPath.c_str()); if (!inputStream.isValid()) { SkDebugf("Could not open file %s\n", inputPath.c_str()); return false; } SkPicture::InstallPixelRefProc proc; if (FLAGS_deferImageDecoding) { proc = &sk_tools::LazyDecodeBitmap; } else if (FLAGS_writeEncodedImages) { SkASSERT(!FLAGS_writePath.isEmpty()); reset_image_file_base_name(inputFilename); proc = &write_image_to_file; } else { proc = &SkImageDecoder::DecodeMemory; } SkDebugf("deserializing... %s\n", inputPath.c_str()); SkPicture* picture = SkPicture::CreateFromStream(&inputStream, proc); if (NULL == picture) { SkDebugf("Could not read an SkPicture from %s\n", inputPath.c_str()); return false; } while (FLAGS_bench_record) { const int kRecordFlags = 0; SkPicture other; picture->draw(other.beginRecording(picture->width(), picture->height(), kRecordFlags)); other.endRecording(); } for (int i = 0; i < FLAGS_clone; ++i) { SkPicture* clone = picture->clone(); SkDELETE(picture); picture = clone; } SkDebugf("drawing... [%i %i] %s\n", picture->width(), picture->height(), inputPath.c_str()); renderer.init(picture, &outputDirString, &inputFilename, FLAGS_writeChecksumBasedFilenames); if (FLAGS_preprocess) { if (NULL != renderer.getCanvas()) { renderer.getCanvas()->EXPERIMENTAL_optimize(picture); } } renderer.setup(); bool success = renderer.render(out); if (!success) { SkDebugf("Failed to render %s\n", inputFilename.c_str()); } renderer.end(); SkDELETE(picture); return success; }
static bool run_single_benchmark(const SkString& inputPath, sk_tools::PictureBenchmark& benchmark) { SkFILEStream inputStream; inputStream.setPath(inputPath.c_str()); if (!inputStream.isValid()) { SkString err; err.printf("Could not open file %s\n", inputPath.c_str()); gLogger.logError(err); return false; } // Since the old picture has been deleted, all pixels should be cleared. SkASSERT(gLruImageCache.getImageCacheUsed() == 0); if (FLAGS_countRAM) { // Set the limit to zero, so all pixels will be kept gLruImageCache.setImageCacheLimit(0); } bool success = false; SkPicture* picture; if (FLAGS_deferImageDecoding) { picture = SkNEW_ARGS(SkPicture, (&inputStream, &success, &lazy_decode_bitmap)); } else { picture = SkNEW_ARGS(SkPicture, (&inputStream, &success, &SkImageDecoder::DecodeMemory)); } SkAutoTDelete<SkPicture> ad(picture); if (!success) { SkString err; err.printf("Could not read an SkPicture from %s\n", inputPath.c_str()); gLogger.logError(err); return false; } SkString filename; sk_tools::get_basename(&filename, inputPath); SkString result; result.printf("running bench [%i %i] %s ", picture->width(), picture->height(), filename.c_str()); gLogger.logProgress(result); benchmark.run(picture); #if LAZY_CACHE_STATS if (FLAGS_trackDeferredCaching) { int32_t cacheHits = SkLazyPixelRef::GetCacheHits(); int32_t cacheMisses = SkLazyPixelRef::GetCacheMisses(); SkLazyPixelRef::ResetCacheStats(); SkString hitString; hitString.printf("Cache hit rate: %f\n", (double) cacheHits / (cacheHits + cacheMisses)); gLogger.logProgress(hitString); gTotalCacheHits += cacheHits; gTotalCacheMisses += cacheMisses; } #endif if (FLAGS_countRAM) { SkString ramCount("RAM used for bitmaps: "); size_t bytes = gLruImageCache.getImageCacheUsed(); if (bytes > 1024) { size_t kb = bytes / 1024; if (kb > 1024) { size_t mb = kb / 1024; ramCount.appendf("%zi MB\n", mb); } else { ramCount.appendf("%zi KB\n", kb); } } else { ramCount.appendf("%zi bytes\n", bytes); } gLogger.logProgress(ramCount); } return true; }
CanvasLayer::CanvasLayer(const CanvasLayer& layer) : LayerAndroid(layer) , m_canvas(0) , m_bitmap(0) , m_gpuCanvas(0) { init(); if (!layer.m_canvas) { // The canvas has already been destroyed - this shouldn't happen ALOGW("Creating a CanvasLayer for a destroyed canvas!"); m_visibleContentRect = IntRect(); m_offsetFromRenderer = IntSize(); m_texture->setHwAccelerated(false); return; } // We are making a copy for the UI, sync the interesting bits m_visibleContentRect = layer.visibleContentRect(); m_offsetFromRenderer = layer.offsetFromRenderer(); bool previousState = m_texture->hasValidTexture(); if(layer.m_canvas->isUsingGpuRendering()) return; ImageBuffer* imageBuffer = layer.m_canvas->buffer(); if (!previousState && layer.m_dirtyCanvas.isEmpty() && imageBuffer && !(imageBuffer->drawsUsingRecording())) { // We were previously in software and don't have anything new to draw, // so stay in software m_bitmap = layer.bitmap(); SkSafeRef(m_bitmap); } else { if(imageBuffer && imageBuffer->drawsUsingRecording() && !layer.m_canvas->isUsingGpuRendering()) { bool canUseGpuRendering = imageBuffer->canUseGpuRendering(); if(canUseGpuRendering && layer.m_canvas->canUseGpuRendering()) { layer.m_canvas->enableGpuRendering(); CanvasLayer::setGpuCanvasStatus(layer.uniqueId(), true); } } // If recording is being used if(imageBuffer && imageBuffer->drawsUsingRecording()) { GraphicsContext* gc = imageBuffer->context(); //SkPicture* canvasRecording = gc->platformContext()->getRecordingPicture(); SkPicture* canvasRecording = CanvasLayer::getRecordingPicture(this); SkBitmap* bitmap = CanvasLayer::getRecordingBitmap(this); SkCanvas* canvas = CanvasLayer::getRecordingCanvas(this); if(canvasRecording == NULL) return; if(bitmap == NULL || bitmap->width() != canvasRecording->width() || bitmap->height() != canvasRecording->height()) { SkBitmap* newBitmap = new SkBitmap(); newBitmap->setConfig(SkBitmap::kARGB_8888_Config, canvasRecording->width(), canvasRecording->height()); newBitmap->allocPixels(); newBitmap->eraseColor(0); CanvasLayer::setRecordingBitmap(newBitmap, this); bitmap = newBitmap; if(canvas != NULL) canvas->setBitmapDevice(*bitmap); } if(canvas == NULL) { canvas = new SkCanvas(); canvas->setBitmapDevice(*bitmap); CanvasLayer::setRecordingCanvas(canvas, this); } canvas->drawARGB(0, 0, 0, 0, SkXfermode::kClear_Mode); canvasRecording->draw(canvas); if (!m_texture->uploadImageBitmap(bitmap)) { //SLOGD("+++++++++++++++++++++ Didn't upload bitmap .. fall back to software"); // TODO:: Fix this } } else { if (!m_texture->uploadImageBuffer(layer.m_canvas->buffer())) { // Blargh, no surface texture or ImageBuffer - fall back to software m_bitmap = layer.bitmap(); SkSafeRef(m_bitmap); // Merge the canvas invals with the layer's invals to repaint the needed // tiles. SkRegion::Iterator iter(layer.m_dirtyCanvas); const IntPoint& offset = m_visibleContentRect.location(); for (; !iter.done(); iter.next()) { SkIRect diff = iter.rect(); diff.fLeft += offset.x(); diff.fRight += offset.x(); diff.fTop += offset.y(); diff.fBottom += offset.y(); m_dirtyRegion.op(diff, SkRegion::kUnion_Op); } }else{ ImageBuffer* imageBuffer = layer.m_canvas->buffer(); bool recordingCanvasEnabled = layer.m_canvas->isRecordingCanvasEnabled(); if(recordingCanvasEnabled && imageBuffer && imageBuffer->isAnimating()){ SLOGD("[%s] Animation detected. Converting the HTML5 canvas buffer to a SkPicture.", __FUNCTION__); imageBuffer->convertToRecording(); } }//End of non-recording } if (previousState != m_texture->hasValidTexture()) { // Need to do a full inval of the canvas content as we are mode switching m_dirtyRegion.op(m_visibleContentRect.x(), m_visibleContentRect.y(), m_visibleContentRect.maxX(), m_visibleContentRect.maxY(), SkRegion::kUnion_Op); } } }
/** * Called only by render_picture(). */ static bool render_picture_internal(const SkString& inputPath, const SkString* writePath, const SkString* mismatchPath, sk_tools::PictureRenderer& renderer, SkBitmap** out) { SkString inputFilename = SkOSPath::SkBasename(inputPath.c_str()); SkString writePathString; if (NULL != writePath && writePath->size() > 0 && !FLAGS_writeEncodedImages) { writePathString.set(*writePath); } SkString mismatchPathString; if (NULL != mismatchPath && mismatchPath->size() > 0) { mismatchPathString.set(*mismatchPath); } SkFILEStream inputStream; inputStream.setPath(inputPath.c_str()); if (!inputStream.isValid()) { SkDebugf("Could not open file %s\n", inputPath.c_str()); return false; } SkPicture::InstallPixelRefProc proc; if (FLAGS_deferImageDecoding) { proc = &sk_tools::LazyDecodeBitmap; } else if (FLAGS_writeEncodedImages) { SkASSERT(!FLAGS_writePath.isEmpty()); reset_image_file_base_name(inputFilename); proc = &write_image_to_file; } else { proc = &SkImageDecoder::DecodeMemory; } SkDebugf("deserializing... %s\n", inputPath.c_str()); SkPicture* picture = SkPicture::CreateFromStream(&inputStream, proc); if (NULL == picture) { SkDebugf("Could not read an SkPicture from %s\n", inputPath.c_str()); return false; } while (FLAGS_bench_record) { SkPictureRecorder recorder; picture->draw(recorder.beginRecording(picture->width(), picture->height(), NULL, 0)); SkAutoTUnref<SkPicture> other(recorder.endRecording()); } SkDebugf("drawing... [%i %i] %s\n", picture->width(), picture->height(), inputPath.c_str()); renderer.init(picture, &writePathString, &mismatchPathString, &inputFilename, FLAGS_writeChecksumBasedFilenames); if (FLAGS_preprocess) { if (NULL != renderer.getCanvas()) { renderer.getCanvas()->EXPERIMENTAL_optimize(renderer.getPicture()); } } renderer.setup(); renderer.enableWrites(); bool success = renderer.render(out); if (!success) { SkDebugf("Failed to render %s\n", inputFilename.c_str()); } renderer.end(); SkDELETE(picture); return success; }
void SkBBoxRecord::drawPicture(SkPicture& picture) { if (picture.width() > 0 && picture.height() > 0 && this->transformBounds(SkRect::MakeWH(picture.width(), picture.height()), NULL)) { INHERITED::drawPicture(picture); } }
void TestResult::testOne() { SkPicture* pic = nullptr; { SkString d; d.printf(" {%d, \"%s\"},", fDirNo, fFilename); SkString path = make_filepath(fDirNo, IN_DIR, fFilename); SkFILEStream stream(path.c_str()); if (!stream.isValid()) { SkDebugf("invalid stream %s\n", path.c_str()); goto finish; } if (fTestStep == kEncodeFiles) { size_t length = stream.getLength(); SkTArray<char, true> bytes; bytes.push_back_n(length); stream.read(&bytes[0], length); stream.rewind(); SkString wPath = make_filepath(0, outSkpDir, fFilename); SkFILEWStream wStream(wPath.c_str()); wStream.write(&bytes[0], length); wStream.flush(); } pic = SkPicture::CreateFromStream(&stream, &SkImageDecoder::DecodeMemory); if (!pic) { SkDebugf("unable to decode %s\n", fFilename); goto finish; } int pWidth = pic->width(); int pHeight = pic->height(); int pLargerWH = SkTMax(pWidth, pHeight); GrContextFactory contextFactory; #ifdef SK_BUILD_FOR_WIN GrContext* context = contextFactory.get(kAngle); #else GrContext* context = contextFactory.get(kNative); #endif if (nullptr == context) { SkDebugf("unable to allocate context for %s\n", fFilename); goto finish; } int maxWH = context->getMaxRenderTargetSize(); int scale = 1; while (pLargerWH / scale > maxWH) { scale *= 2; } SkBitmap bitmap; SkIPoint dim; do { dim.fX = (pWidth + scale - 1) / scale; dim.fY = (pHeight + scale - 1) / scale; bool success = bitmap.allocN32Pixels(dim.fX, dim.fY); if (success) { break; } SkDebugf("-%d-", scale); } while ((scale *= 2) < 256); if (scale >= 256) { SkDebugf("unable to allocate bitmap for %s (w=%d h=%d) (sw=%d sh=%d)\n", fFilename, pWidth, pHeight, dim.fX, dim.fY); goto finish; } SkCanvas skCanvas(bitmap); drawPict(pic, &skCanvas, fScaleOversized ? scale : 1); GrTextureDesc desc; desc.fConfig = kSkia8888_GrPixelConfig; desc.fFlags = kRenderTarget_GrTextureFlagBit; desc.fWidth = dim.fX; desc.fHeight = dim.fY; desc.fSampleCnt = 0; SkAutoTUnref<GrTexture> texture(context->createUncachedTexture(desc, nullptr, 0)); if (!texture) { SkDebugf("unable to allocate texture for %s (w=%d h=%d)\n", fFilename, dim.fX, dim.fY); goto finish; } SkGpuDevice grDevice(context, texture.get()); SkCanvas grCanvas(&grDevice); drawPict(pic, &grCanvas, fScaleOversized ? scale : 1); SkBitmap grBitmap; grBitmap.allocPixels(grCanvas.imageInfo()); grCanvas.readPixels(&grBitmap, 0, 0); if (fTestStep == kCompareBits) { fPixelError = similarBits(grBitmap, bitmap); int skTime = timePict(pic, &skCanvas); int grTime = timePict(pic, &grCanvas); fTime = skTime - grTime; } else if (fTestStep == kEncodeFiles) { SkString pngStr = make_png_name(fFilename); const char* pngName = pngStr.c_str(); writePict(grBitmap, outGrDir, pngName); writePict(bitmap, outSkDir, pngName); } } finish: delete pic; }