Home | History | Annotate | Download | only in dm
      1 #include "DMQuiltTask.h"
      2 #include "DMUtil.h"
      3 #include "DMWriteTask.h"
      4 
      5 #include "SkBBHFactory.h"
      6 #include "SkCommandLineFlags.h"
      7 #include "SkPicture.h"
      8 #include "SkTaskGroup.h"
      9 
     10 DEFINE_bool(quilt, true, "If true, draw GM via a picture into a quilt of small tiles and compare.");
     11 DEFINE_int32(quiltTile, 256, "Dimension of (square) quilt tile.");
     12 
     13 namespace DM {
     14 
     15 static SkString suffix(QuiltTask::Backend backend, QuiltTask::BBH bbh) {
     16     static const char* kBackends[] = { "default", "skrecord" };
     17     static const char* kBBHs[]     = { "nobbh", "rtree", "tilegrid" };
     18     return SkStringPrintf("%s-%s", kBackends[backend], kBBHs[bbh]);
     19 }
     20 
     21 QuiltTask::QuiltTask(const Task& parent, skiagm::GM* gm, SkBitmap reference,
     22                      QuiltTask::BBH bbh, QuiltTask::Backend backend)
     23     : CpuTask(parent)
     24     , fBBH(bbh)
     25     , fBackend(backend)
     26     , fName(UnderJoin(parent.name().c_str(), suffix(backend, bbh).c_str()))
     27     , fGM(gm)
     28     , fReference(reference)
     29     {}
     30 
     31 static int tiles_needed(int fullDimension, int tileDimension) {
     32     return (fullDimension + tileDimension - 1) / tileDimension;
     33 }
     34 
     35 class Tile : public SkRunnable {
     36 public:
     37     Tile(int x, int y, const SkPicture& picture, SkBitmap* quilt)
     38         : fX(x * FLAGS_quiltTile)
     39         , fY(y * FLAGS_quiltTile)
     40         , fPicture(picture)
     41         , fQuilt(quilt) {}
     42 
     43     virtual void run() SK_OVERRIDE {
     44         SkBitmap tile;
     45         fQuilt->extractSubset(&tile, SkIRect::MakeXYWH(fX, fY, FLAGS_quiltTile, FLAGS_quiltTile));
     46         SkCanvas tileCanvas(tile);
     47 
     48         tileCanvas.translate(SkIntToScalar(-fX), SkIntToScalar(-fY));
     49         fPicture.playback(&tileCanvas);
     50         tileCanvas.flush();
     51 
     52         delete this;
     53     }
     54 
     55 private:
     56     const int fX, fY;
     57     const SkPicture& fPicture;
     58     SkBitmap* fQuilt;
     59 };
     60 
     61 void QuiltTask::draw() {
     62     SkAutoTDelete<SkBBHFactory> factory;
     63     switch (fBBH) {
     64         case kNone_BBH: break;
     65         case kRTree_BBH:
     66             factory.reset(SkNEW(SkRTreeFactory));
     67             break;
     68         case kTileGrid_BBH: {
     69             const SkTileGridFactory::TileGridInfo tiles = {
     70                 { FLAGS_quiltTile, FLAGS_quiltTile },
     71                 /*overlap: */{0, 0},
     72                 /*offset:  */{0, 0},
     73             };
     74             factory.reset(SkNEW_ARGS(SkTileGridFactory, (tiles)));
     75             break;
     76         }
     77     }
     78 
     79     // A couple GMs draw wrong when using a bounding box hierarchy.
     80     // This almost certainly means we have a bug to fix, but for now
     81     // just draw without a bounding box hierarchy.
     82     if (fGM->getFlags() & skiagm::GM::kNoBBH_Flag) {
     83         factory.reset(NULL);
     84     }
     85 
     86     SkAutoTUnref<const SkPicture> recorded(
     87             RecordPicture(fGM.get(), factory.get(), kSkRecord_Backend == fBackend));
     88 
     89     SkBitmap full;
     90     AllocatePixels(fReference, &full);
     91 
     92     if (fGM->getFlags() & skiagm::GM::kSkipTiled_Flag) {
     93         // Some GMs don't draw exactly the same when tiled.  Draw them in one go.
     94         SkCanvas canvas(full);
     95         recorded->playback(&canvas);
     96         canvas.flush();
     97     } else {
     98         // Draw tiles in parallel into the same bitmap, simulating aggressive impl-side painting.
     99         SkTaskGroup tg;
    100         for (int y = 0; y < tiles_needed(full.height(), FLAGS_quiltTile); y++) {
    101             for (int x = 0; x < tiles_needed(full.width(), FLAGS_quiltTile); x++) {
    102                 // Deletes itself when done.
    103                 tg.add(new Tile(x, y, *recorded, &full));
    104             }
    105         }
    106     }
    107 
    108     if (!BitmapsEqual(full, fReference)) {
    109         this->fail();
    110         this->spawnChild(SkNEW_ARGS(WriteTask, (*this, "GM", full)));
    111     }
    112 }
    113 
    114 bool QuiltTask::shouldSkip() const {
    115     if (fGM->getFlags() & skiagm::GM::kSkipPicture_Flag) {
    116         return true;
    117     }
    118     return !FLAGS_quilt;
    119 }
    120 
    121 }  // namespace DM
    122