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 "GrPictureUtils.h"
      9 
     10 #include "SkPaintPriv.h"
     11 #include "SkRecord.h"
     12 #include "SkRecords.h"
     13 
     14 SkPicture::AccelData::Key GrAccelData::ComputeAccelDataKey() {
     15     static const SkPicture::AccelData::Key gGPUID = SkPicture::AccelData::GenerateDomain();
     16 
     17     return gGPUID;
     18 }
     19 
     20 // SkRecord visitor to gather saveLayer/restore information.
     21 class CollectLayers {
     22 public:
     23     CollectLayers(const SkPicture* pict, GrAccelData* accelData)
     24         : fPictureID(pict->uniqueID())
     25         , fCTM(&SkMatrix::I())
     26         , fSaveLayersInStack(0)
     27         , fAccelData(accelData) {
     28 
     29         pict->cullRect().roundOut(&fCurrentClipBounds);
     30 
     31         if (NULL == pict->fRecord.get()) {
     32             return;
     33         }
     34 
     35         for (fCurrentOp = 0; fCurrentOp < pict->fRecord->count(); ++fCurrentOp) {
     36             pict->fRecord->visit<void>(fCurrentOp, *this);
     37         }
     38 
     39         while (!fSaveStack.isEmpty()) {
     40             this->popSaveBlock();
     41         }
     42     }
     43 
     44     template <typename T> void operator()(const T& op) {
     45         this->updateCTM(op);
     46         this->updateClipBounds(op);
     47         this->trackSaveLayers(op);
     48     }
     49 
     50 private:
     51 
     52     class SaveInfo {
     53     public:
     54         SaveInfo() { }
     55         SaveInfo(int opIndex, bool isSaveLayer, const SkPaint* paint, const SkIRect& bounds)
     56             : fStartIndex(opIndex)
     57             , fIsSaveLayer(isSaveLayer)
     58             , fHasNestedSaveLayer(false)
     59             , fPaint(paint)
     60             , fBounds(bounds) {
     61 
     62         }
     63 
     64         int            fStartIndex;
     65         bool           fIsSaveLayer;
     66         bool           fHasNestedSaveLayer;
     67         const SkPaint* fPaint;
     68         SkIRect        fBounds;
     69     };
     70 
     71     uint32_t            fPictureID;
     72     unsigned int        fCurrentOp;
     73     const SkMatrix*     fCTM;
     74     SkIRect             fCurrentClipBounds;
     75     int                 fSaveLayersInStack;
     76     SkTDArray<SaveInfo> fSaveStack;
     77     GrAccelData*        fAccelData;
     78 
     79     template <typename T> void updateCTM(const T&) { /* most ops don't change the CTM */ }
     80     void updateCTM(const SkRecords::Restore& op)   { fCTM = &op.matrix; }
     81     void updateCTM(const SkRecords::SetMatrix& op) { fCTM = &op.matrix; }
     82 
     83     template <typename T> void updateClipBounds(const T&) { /* most ops don't change the clip */ }
     84     // Each of these devBounds fields is the state of the device bounds after the op.
     85     // So Restore's devBounds are those bounds saved by its paired Save or SaveLayer.
     86     void updateClipBounds(const SkRecords::Restore& op)    { fCurrentClipBounds = op.devBounds; }
     87     void updateClipBounds(const SkRecords::ClipPath& op)   { fCurrentClipBounds = op.devBounds; }
     88     void updateClipBounds(const SkRecords::ClipRRect& op)  { fCurrentClipBounds = op.devBounds; }
     89     void updateClipBounds(const SkRecords::ClipRect& op)   { fCurrentClipBounds = op.devBounds; }
     90     void updateClipBounds(const SkRecords::ClipRegion& op) { fCurrentClipBounds = op.devBounds; }
     91     void updateClipBounds(const SkRecords::SaveLayer& op)  {
     92         if (op.bounds) {
     93             fCurrentClipBounds.intersect(this->adjustAndMap(*op.bounds, op.paint));
     94         }
     95     }
     96 
     97     template <typename T> void trackSaveLayers(const T& op) {
     98         /* most ops aren't involved in saveLayers */
     99     }
    100     void trackSaveLayers(const SkRecords::Save& s) { this->pushSaveBlock(); }
    101     void trackSaveLayers(const SkRecords::SaveLayer& sl) { this->pushSaveLayerBlock(sl.paint); }
    102     void trackSaveLayers(const SkRecords::Restore& r) { this->popSaveBlock(); }
    103     void trackSaveLayers(const SkRecords::DrawPicture& dp) {
    104         // For sub-pictures, we wrap their layer information within the parent
    105         // picture's rendering hierarchy
    106         const GrAccelData* childData = GPUOptimize(dp.picture);
    107 
    108         for (int i = 0; i < childData->numSaveLayers(); ++i) {
    109             const GrAccelData::SaveLayerInfo& src = childData->saveLayerInfo(i);
    110 
    111             this->updateStackForSaveLayer();
    112 
    113             // TODO: need to store an SkRect in GrAccelData::SaveLayerInfo?
    114             SkRect srcRect = SkRect::MakeXYWH(SkIntToScalar(src.fOffset.fX),
    115                                               SkIntToScalar(src.fOffset.fY),
    116                                               SkIntToScalar(src.fSize.width()),
    117                                               SkIntToScalar(src.fSize.height()));
    118             SkIRect newClip(fCurrentClipBounds);
    119             newClip.intersect(this->adjustAndMap(srcRect, dp.paint));
    120 
    121             GrAccelData::SaveLayerInfo& dst = fAccelData->addSaveLayerInfo();
    122 
    123             dst.fValid = true;
    124             // If src.fPicture is NULL the layer is in dp.picture; otherwise
    125             // it belongs to a sub-picture.
    126             dst.fPicture = src.fPicture ? src.fPicture : static_cast<const SkPicture*>(dp.picture);
    127             dst.fPicture->ref();
    128             dst.fSize = SkISize::Make(newClip.width(), newClip.height());
    129             dst.fOffset = SkIPoint::Make(newClip.fLeft, newClip.fTop);
    130             dst.fOriginXform = *fCTM;
    131             dst.fOriginXform.postConcat(src.fOriginXform);
    132             if (src.fPaint) {
    133                 dst.fPaint = SkNEW_ARGS(SkPaint, (*src.fPaint));
    134             }
    135             dst.fSaveLayerOpID = src.fSaveLayerOpID;
    136             dst.fRestoreOpID = src.fRestoreOpID;
    137             dst.fHasNestedLayers = src.fHasNestedLayers;
    138             dst.fIsNested = fSaveLayersInStack > 0 || src.fIsNested;
    139         }
    140     }
    141 
    142     void pushSaveBlock() {
    143         fSaveStack.push(SaveInfo(fCurrentOp, false, NULL, SkIRect::MakeEmpty()));
    144     }
    145 
    146     // Inform all the saveLayers already on the stack that they now have a
    147     // nested saveLayer inside them
    148     void updateStackForSaveLayer() {
    149         for (int index = fSaveStack.count() - 1; index >= 0; --index) {
    150             if (fSaveStack[index].fHasNestedSaveLayer) {
    151                 break;
    152             }
    153             fSaveStack[index].fHasNestedSaveLayer = true;
    154             if (fSaveStack[index].fIsSaveLayer) {
    155                 break;
    156             }
    157         }
    158     }
    159 
    160     void pushSaveLayerBlock(const SkPaint* paint) {
    161         this->updateStackForSaveLayer();
    162 
    163         fSaveStack.push(SaveInfo(fCurrentOp, true, paint, fCurrentClipBounds));
    164         ++fSaveLayersInStack;
    165     }
    166 
    167     void popSaveBlock() {
    168         if (fSaveStack.count() <= 0) {
    169             SkASSERT(false);
    170             return;
    171         }
    172 
    173         SaveInfo si;
    174         fSaveStack.pop(&si);
    175 
    176         if (!si.fIsSaveLayer) {
    177             return;
    178         }
    179 
    180         --fSaveLayersInStack;
    181 
    182         GrAccelData::SaveLayerInfo& slInfo = fAccelData->addSaveLayerInfo();
    183 
    184         slInfo.fValid = true;
    185         SkASSERT(NULL == slInfo.fPicture);  // This layer is in the top-most picture
    186         slInfo.fSize = SkISize::Make(si.fBounds.width(), si.fBounds.height());
    187         slInfo.fOffset = SkIPoint::Make(si.fBounds.fLeft, si.fBounds.fTop);
    188         slInfo.fOriginXform = *fCTM;
    189         if (si.fPaint) {
    190             slInfo.fPaint = SkNEW_ARGS(SkPaint, (*si.fPaint));
    191         }
    192         slInfo.fSaveLayerOpID = si.fStartIndex;
    193         slInfo.fRestoreOpID = fCurrentOp;
    194         slInfo.fHasNestedLayers = si.fHasNestedSaveLayer;
    195         slInfo.fIsNested = fSaveLayersInStack > 0;
    196     }
    197 
    198     // Returns true if rect was meaningfully adjusted for the effects of paint,
    199     // false if the paint could affect the rect in unknown ways.
    200     static bool AdjustForPaint(const SkPaint* paint, SkRect* rect) {
    201         if (paint) {
    202             if (paint->canComputeFastBounds()) {
    203                 *rect = paint->computeFastBounds(*rect, rect);
    204                 return true;
    205             }
    206             return false;
    207         }
    208         return true;
    209     }
    210 
    211     // Adjust rect for all paints that may affect its geometry, then map it to device space.
    212     SkIRect adjustAndMap(SkRect rect, const SkPaint* paint) const {
    213         // Inverted rectangles really confuse our BBHs.
    214         rect.sort();
    215 
    216         // Adjust the rect for its own paint.
    217         if (!AdjustForPaint(paint, &rect)) {
    218             // The paint could do anything to our bounds.  The only safe answer is the current clip.
    219             return fCurrentClipBounds;
    220         }
    221 
    222         // Adjust rect for all the paints from the SaveLayers we're inside.
    223         for (int i = fSaveStack.count() - 1; i >= 0; i--) {
    224             if (!AdjustForPaint(fSaveStack[i].fPaint, &rect)) {
    225                 // Same deal as above.
    226                 return fCurrentClipBounds;
    227             }
    228         }
    229 
    230         // Map the rect back to device space.
    231         fCTM->mapRect(&rect);
    232         SkIRect devRect;
    233         rect.roundOut(&devRect);
    234 
    235         // Nothing can draw outside the current clip.
    236         // (Only bounded ops call into this method, so oddballs like Clear don't matter here.)
    237         devRect.intersect(fCurrentClipBounds);
    238         return devRect;
    239     }
    240 };
    241 
    242 
    243 // GPUOptimize is only intended to be called within the context of SkGpuDevice's
    244 // EXPERIMENTAL_optimize method.
    245 const GrAccelData* GPUOptimize(const SkPicture* pict) {
    246     if (NULL == pict || pict->cullRect().isEmpty()) {
    247         return NULL;
    248     }
    249 
    250     SkPicture::AccelData::Key key = GrAccelData::ComputeAccelDataKey();
    251 
    252     const GrAccelData* existing =
    253                             static_cast<const GrAccelData*>(pict->EXPERIMENTAL_getAccelData(key));
    254     if (existing) {
    255         return existing;
    256     }
    257 
    258     SkAutoTUnref<GrAccelData> data(SkNEW_ARGS(GrAccelData, (key)));
    259 
    260     pict->EXPERIMENTAL_addAccelData(data);
    261 
    262     CollectLayers collector(pict, data);
    263 
    264     return data;
    265 }
    266