Home | History | Annotate | Download | only in gpu
      1 /*
      2  * Copyright 2014 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 "GrContext.h"
      9 #include "GrLayerCache.h"
     10 #include "GrRecordReplaceDraw.h"
     11 #include "SkBigPicture.h"
     12 #include "SkCanvasPriv.h"
     13 #include "SkGr.h"
     14 #include "SkImage.h"
     15 #include "SkRecordDraw.h"
     16 #include "SkRecords.h"
     17 
     18 
     19 static inline void draw_replacement_bitmap(GrCachedLayer* layer, SkCanvas* canvas) {
     20 
     21     // Some image filter can totally filter away a layer (e.g., SkPictureImageFilter's with
     22     // no picture).
     23     if (!layer->texture()) {
     24         return;
     25     }
     26 
     27     SkBitmap bm;
     28     GrWrapTextureInBitmap(layer->texture(),
     29                           !layer->isAtlased() ? layer->rect().width()  : layer->texture()->width(),
     30                           !layer->isAtlased() ? layer->rect().height() : layer->texture()->height(),
     31                           false,
     32                           &bm);
     33 
     34     canvas->save();
     35     canvas->setMatrix(SkMatrix::I());
     36     if (layer->isAtlased()) {
     37         const SkRect src = SkRect::Make(layer->rect());
     38         const SkRect dst = SkRect::Make(layer->srcIR());
     39 
     40         SkASSERT(layer->offset().isZero());
     41 
     42         canvas->drawBitmapRect(bm, src, dst, layer->paint(), SkCanvas::kStrict_SrcRectConstraint);
     43     } else {
     44         canvas->drawBitmap(bm,
     45                            SkIntToScalar(layer->srcIR().fLeft + layer->offset().fX),
     46                            SkIntToScalar(layer->srcIR().fTop + layer->offset().fY),
     47                            layer->paint());
     48     }
     49     canvas->restore();
     50 }
     51 
     52 // Used by GrRecordReplaceDraw. It intercepts nested drawPicture calls and
     53 // also draws them with replaced layers.
     54 class ReplaceDraw : public SkRecords::Draw {
     55 public:
     56     ReplaceDraw(SkCanvas* canvas, GrLayerCache* layerCache,
     57                 SkPicture const* const drawablePicts[], int drawableCount,
     58                 const SkPicture* topLevelPicture,
     59                 const SkBigPicture* picture,
     60                 const SkMatrix& initialMatrix,
     61                 SkPicture::AbortCallback* callback,
     62                 const int* opIndices, int numIndices)
     63         : INHERITED(canvas, drawablePicts, nullptr, drawableCount)
     64         , fCanvas(canvas)
     65         , fLayerCache(layerCache)
     66         , fTopLevelPicture(topLevelPicture)
     67         , fPicture(picture)
     68         , fInitialMatrix(initialMatrix)
     69         , fCallback(callback)
     70         , fIndex(0)
     71         , fNumReplaced(0) {
     72         fOpIndexStack.append(numIndices, opIndices);
     73     }
     74 
     75     int draw() {
     76         const SkBBoxHierarchy* bbh = fPicture->bbh();
     77         const SkRecord* record = fPicture->record();
     78         if (nullptr == record) {
     79             return 0;
     80         }
     81 
     82         fNumReplaced = 0;
     83 
     84         fOps.rewind();
     85 
     86         if (bbh) {
     87             // Draw only ops that affect pixels in the canvas's current clip.
     88             // The SkRecord and BBH were recorded in identity space.  This canvas
     89             // is not necessarily in that same space.  getClipBounds() returns us
     90             // this canvas' clip bounds transformed back into identity space, which
     91             // lets us query the BBH.
     92             SkRect query = { 0, 0, 0, 0 };
     93             (void)fCanvas->getClipBounds(&query);
     94 
     95             bbh->search(query, &fOps);
     96 
     97             for (fIndex = 0; fIndex < fOps.count(); ++fIndex) {
     98                 if (fCallback && fCallback->abort()) {
     99                     return fNumReplaced;
    100                 }
    101 
    102                 record->visit<void>(fOps[fIndex], *this);
    103             }
    104 
    105         } else {
    106             for (fIndex = 0; fIndex < (int) record->count(); ++fIndex) {
    107                 if (fCallback && fCallback->abort()) {
    108                     return fNumReplaced;
    109                 }
    110 
    111                 record->visit<void>(fIndex, *this);
    112             }
    113         }
    114 
    115         return fNumReplaced;
    116     }
    117 
    118     // Same as Draw for all ops except DrawPicture and SaveLayer.
    119     template <typename T> void operator()(const T& r) {
    120         this->INHERITED::operator()(r);
    121     }
    122     void operator()(const SkRecords::DrawPicture& dp) {
    123 
    124         int drawPictureOffset;
    125         if (fOps.count()) {
    126             drawPictureOffset = fOps[fIndex];
    127         } else {
    128             drawPictureOffset = fIndex;
    129         }
    130 
    131         fOpIndexStack.push(drawPictureOffset);
    132 
    133         SkAutoCanvasMatrixPaint acmp(fCanvas, &dp.matrix, dp.paint, dp.picture->cullRect());
    134 
    135         if (const SkBigPicture* bp = dp.picture->asSkBigPicture()) {
    136             // Draw sub-pictures with the same replacement list but a different picture
    137             ReplaceDraw draw(fCanvas, fLayerCache,
    138                              this->drawablePicts(), this->drawableCount(),
    139                              fTopLevelPicture, bp, fInitialMatrix, fCallback,
    140                              fOpIndexStack.begin(), fOpIndexStack.count());
    141             fNumReplaced += draw.draw();
    142         } else {
    143             // TODO: can we assume / assert this doesn't happen?
    144             dp.picture->playback(fCanvas, fCallback);
    145         }
    146 
    147         fOpIndexStack.pop();
    148     }
    149     void operator()(const SkRecords::SaveLayer& sl) {
    150 
    151         // For a saveLayer command, check if it can be replaced by a drawBitmap
    152         // call and, if so, draw it and then update the current op index accordingly.
    153         int startOffset;
    154         if (fOps.count()) {
    155             startOffset = fOps[fIndex];
    156         } else {
    157             startOffset = fIndex;
    158         }
    159 
    160         fOpIndexStack.push(startOffset);
    161 
    162         GrCachedLayer* layer = fLayerCache->findLayer(fTopLevelPicture->uniqueID(),
    163                                                       fInitialMatrix,
    164                                                       fOpIndexStack.begin(),
    165                                                       fOpIndexStack.count());
    166 
    167         if (layer) {
    168             fNumReplaced++;
    169 
    170             draw_replacement_bitmap(layer, fCanvas);
    171 
    172             if (fPicture->bbh()) {
    173                 while (fOps[fIndex] < layer->stop()) {
    174                     ++fIndex;
    175                 }
    176                 SkASSERT(fOps[fIndex] == layer->stop());
    177             } else {
    178                 fIndex = layer->stop();
    179             }
    180             fOpIndexStack.pop();
    181             return;
    182         }
    183 
    184         // This is a fail for layer hoisting
    185         this->INHERITED::operator()(sl);
    186 
    187         fOpIndexStack.pop();
    188     }
    189 
    190 private:
    191     SkCanvas*                 fCanvas;
    192     GrLayerCache*             fLayerCache;
    193     const SkPicture*          fTopLevelPicture;
    194     const SkBigPicture*       fPicture;
    195     const SkMatrix            fInitialMatrix;
    196     SkPicture::AbortCallback* fCallback;
    197 
    198     SkTDArray<int>            fOps;
    199     int                       fIndex;
    200     int                       fNumReplaced;
    201 
    202     // The op code indices of all the enclosing drawPicture and saveLayer calls
    203     SkTDArray<int>            fOpIndexStack;
    204 
    205     typedef Draw INHERITED;
    206 };
    207 
    208 int GrRecordReplaceDraw(const SkPicture* picture,
    209                         SkCanvas* canvas,
    210                         GrLayerCache* layerCache,
    211                         const SkMatrix& initialMatrix,
    212                         SkPicture::AbortCallback* callback) {
    213     SkAutoCanvasRestore saveRestore(canvas, true /*save now, restore at exit*/);
    214 
    215     if (const SkBigPicture* bp = picture->asSkBigPicture()) {
    216         // TODO: drawablePicts?
    217         ReplaceDraw draw(canvas, layerCache, nullptr, 0,
    218                          bp, bp,
    219                          initialMatrix, callback, nullptr, 0);
    220         return draw.draw();
    221     } else {
    222         // TODO: can we assume / assert this doesn't happen?
    223         picture->playback(canvas, callback);
    224         return 0;
    225     }
    226 }
    227