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