| OLD | NEW | 
|---|
|  | (Empty) | 
| 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 "SkBigPicture.h" |  | 
| 9 #include "SkCanvas.h" |  | 
| 10 #include "SkImageFilterCache.h" |  | 
| 11 #include "SkLayerInfo.h" |  | 
| 12 #include "SkRecordDraw.h" |  | 
| 13 #include "SkSpecialImage.h" |  | 
| 14 #include "SkSurface.h" |  | 
| 15 |  | 
| 16 #include "GrLayerHoister.h" |  | 
| 17 |  | 
| 18 #if !defined(SK_IGNORE_GPU_LAYER_HOISTING) && SK_SUPPORT_GPU |  | 
| 19 |  | 
| 20 #include "GrContext.h" |  | 
| 21 #include "GrLayerCache.h" |  | 
| 22 #include "GrRecordReplaceDraw.h" |  | 
| 23 |  | 
| 24 // Create the layer information for the hoisted layer and secure the |  | 
| 25 // required texture/render target resources. |  | 
| 26 static void prepare_for_hoisting(GrLayerCache* layerCache, |  | 
| 27                                  const SkPicture* topLevelPicture, |  | 
| 28                                  const SkMatrix& initialMat, |  | 
| 29                                  const SkLayerInfo::BlockInfo& info, |  | 
| 30                                  const SkIRect& srcIR, |  | 
| 31                                  const SkIRect& dstIR, |  | 
| 32                                  SkTDArray<GrHoistedLayer>* needRendering, |  | 
| 33                                  SkTDArray<GrHoistedLayer>* recycled, |  | 
| 34                                  bool attemptToAtlas, |  | 
| 35                                  int numSamples) { |  | 
| 36     const SkPicture* pict = info.fPicture ? info.fPicture : topLevelPicture; |  | 
| 37 |  | 
| 38     GrCachedLayer* layer = layerCache->findLayerOrCreate(topLevelPicture->unique
     ID(), |  | 
| 39                                                          SkToInt(info.fSaveLayer
     OpID), |  | 
| 40                                                          SkToInt(info.fRestoreOp
     ID), |  | 
| 41                                                          srcIR, |  | 
| 42                                                          dstIR, |  | 
| 43                                                          initialMat, |  | 
| 44                                                          info.fKey, |  | 
| 45                                                          info.fKeySize, |  | 
| 46                                                          info.fPaint); |  | 
| 47     GrSurfaceDesc desc; |  | 
| 48     desc.fFlags = kRenderTarget_GrSurfaceFlag; |  | 
| 49     desc.fWidth = srcIR.width(); |  | 
| 50     desc.fHeight = srcIR.height(); |  | 
| 51     desc.fConfig = kSkia8888_GrPixelConfig; |  | 
| 52     desc.fSampleCnt = numSamples; |  | 
| 53 |  | 
| 54     bool locked, needsRendering; |  | 
| 55     if (attemptToAtlas) { |  | 
| 56         locked = layerCache->tryToAtlas(layer, desc, &needsRendering); |  | 
| 57     } else { |  | 
| 58         locked = layerCache->lock(layer, desc, &needsRendering); |  | 
| 59     } |  | 
| 60     if (!locked) { |  | 
| 61         // GPU resources could not be secured for the hoisting of this layer |  | 
| 62         return; |  | 
| 63     } |  | 
| 64 |  | 
| 65     if (attemptToAtlas) { |  | 
| 66         SkASSERT(layer->isAtlased()); |  | 
| 67     } |  | 
| 68 |  | 
| 69     GrHoistedLayer* hl; |  | 
| 70 |  | 
| 71     if (needsRendering) { |  | 
| 72         if (!attemptToAtlas) { |  | 
| 73             SkASSERT(!layer->isAtlased()); |  | 
| 74         } |  | 
| 75         hl = needRendering->append(); |  | 
| 76     } else { |  | 
| 77         hl = recycled->append(); |  | 
| 78     } |  | 
| 79 |  | 
| 80     layerCache->addUse(layer); |  | 
| 81     hl->fLayer = layer; |  | 
| 82     hl->fPicture = pict; |  | 
| 83     hl->fLocalMat = info.fLocalMat; |  | 
| 84     hl->fInitialMat = initialMat; |  | 
| 85     hl->fPreMat = initialMat; |  | 
| 86     hl->fPreMat.preConcat(info.fPreMat); |  | 
| 87 } |  | 
| 88 |  | 
| 89 // Compute the source rect and return false if it is empty. |  | 
| 90 static bool compute_source_rect(const SkLayerInfo::BlockInfo& info, const SkMatr
     ix& initialMat, |  | 
| 91                                 const SkIRect& dstIR, SkIRect* srcIR) { |  | 
| 92     SkIRect clipBounds = dstIR; |  | 
| 93 |  | 
| 94     SkMatrix totMat = initialMat; |  | 
| 95     totMat.preConcat(info.fPreMat); |  | 
| 96     totMat.preConcat(info.fLocalMat); |  | 
| 97 |  | 
| 98     if (info.fPaint && info.fPaint->getImageFilter()) { |  | 
| 99         clipBounds = info.fPaint->getImageFilter()->filterBounds(clipBounds, tot
     Mat); |  | 
| 100     } |  | 
| 101 |  | 
| 102     if (!info.fSrcBounds.isEmpty()) { |  | 
| 103         SkRect r; |  | 
| 104 |  | 
| 105         totMat.mapRect(&r, info.fSrcBounds); |  | 
| 106         r.roundOut(srcIR); |  | 
| 107 |  | 
| 108         if (!srcIR->intersect(clipBounds)) { |  | 
| 109             return false; |  | 
| 110         } |  | 
| 111     } else { |  | 
| 112         *srcIR = clipBounds; |  | 
| 113     } |  | 
| 114 |  | 
| 115     return true; |  | 
| 116 } |  | 
| 117 |  | 
| 118 // Atlased layers must be small enough to fit in the atlas, not have a |  | 
| 119 // paint with an image filter and be neither nested nor nesting. |  | 
| 120 // TODO: allow leaf nested layers to appear in the atlas. |  | 
| 121 void GrLayerHoister::FindLayersToAtlas(GrContext* context, |  | 
| 122                                        const SkPicture* topLevelPicture, |  | 
| 123                                        const SkMatrix& initialMat, |  | 
| 124                                        const SkRect& query, |  | 
| 125                                        SkTDArray<GrHoistedLayer>* atlased, |  | 
| 126                                        SkTDArray<GrHoistedLayer>* recycled, |  | 
| 127                                        int numSamples) { |  | 
| 128     if (0 != numSamples) { |  | 
| 129         // MSAA layers are currently never atlased |  | 
| 130         return; |  | 
| 131     } |  | 
| 132 |  | 
| 133     GrLayerCache* layerCache = context->getLayerCache(); |  | 
| 134     layerCache->processDeletedPictures(); |  | 
| 135 |  | 
| 136     const SkBigPicture::AccelData* topLevelData = nullptr; |  | 
| 137     if (const SkBigPicture* bp = topLevelPicture->asSkBigPicture()) { |  | 
| 138         topLevelData = bp->accelData(); |  | 
| 139     } |  | 
| 140     if (!topLevelData) { |  | 
| 141         return; |  | 
| 142     } |  | 
| 143 |  | 
| 144     const SkLayerInfo *topLevelGPUData = static_cast<const SkLayerInfo*>(topLeve
     lData); |  | 
| 145     if (0 == topLevelGPUData->numBlocks()) { |  | 
| 146         return; |  | 
| 147     } |  | 
| 148 |  | 
| 149     atlased->setReserve(atlased->count() + topLevelGPUData->numBlocks()); |  | 
| 150 |  | 
| 151     for (int i = 0; i < topLevelGPUData->numBlocks(); ++i) { |  | 
| 152         const SkLayerInfo::BlockInfo& info = topLevelGPUData->block(i); |  | 
| 153 |  | 
| 154         // TODO: ignore perspective projected layers here? |  | 
| 155         bool disallowAtlasing = info.fHasNestedLayers || info.fIsNested || |  | 
| 156                                 (info.fPaint && info.fPaint->getImageFilter()); |  | 
| 157 |  | 
| 158         if (disallowAtlasing) { |  | 
| 159             continue; |  | 
| 160         } |  | 
| 161 |  | 
| 162         SkRect layerRect; |  | 
| 163         initialMat.mapRect(&layerRect, info.fBounds); |  | 
| 164         if (!layerRect.intersect(query)) { |  | 
| 165             continue; |  | 
| 166         } |  | 
| 167 |  | 
| 168         const SkIRect dstIR = layerRect.roundOut(); |  | 
| 169 |  | 
| 170         SkIRect srcIR; |  | 
| 171 |  | 
| 172         if (!compute_source_rect(info, initialMat, dstIR, &srcIR) || |  | 
| 173             !GrLayerCache::PlausiblyAtlasable(srcIR.width(), srcIR.height())) { |  | 
| 174             continue; |  | 
| 175         } |  | 
| 176 |  | 
| 177         prepare_for_hoisting(layerCache, topLevelPicture, initialMat, |  | 
| 178                              info, srcIR, dstIR, atlased, recycled, true, 0); |  | 
| 179     } |  | 
| 180 |  | 
| 181 } |  | 
| 182 |  | 
| 183 void GrLayerHoister::FindLayersToHoist(GrContext* context, |  | 
| 184                                        const SkPicture* topLevelPicture, |  | 
| 185                                        const SkMatrix& initialMat, |  | 
| 186                                        const SkRect& query, |  | 
| 187                                        SkTDArray<GrHoistedLayer>* needRendering, |  | 
| 188                                        SkTDArray<GrHoistedLayer>* recycled, |  | 
| 189                                        int numSamples) { |  | 
| 190     GrLayerCache* layerCache = context->getLayerCache(); |  | 
| 191 |  | 
| 192     layerCache->processDeletedPictures(); |  | 
| 193 |  | 
| 194     const SkBigPicture::AccelData* topLevelData = nullptr; |  | 
| 195     if (const SkBigPicture* bp = topLevelPicture->asSkBigPicture()) { |  | 
| 196         topLevelData = bp->accelData(); |  | 
| 197     } |  | 
| 198     if (!topLevelData) { |  | 
| 199         return; |  | 
| 200     } |  | 
| 201 |  | 
| 202     const SkLayerInfo *topLevelGPUData = static_cast<const SkLayerInfo*>(topLeve
     lData); |  | 
| 203     if (0 == topLevelGPUData->numBlocks()) { |  | 
| 204         return; |  | 
| 205     } |  | 
| 206 |  | 
| 207     // Find and prepare for hoisting all the layers that intersect the query rec
     t |  | 
| 208     for (int i = 0; i < topLevelGPUData->numBlocks(); ++i) { |  | 
| 209         const SkLayerInfo::BlockInfo& info = topLevelGPUData->block(i); |  | 
| 210         if (info.fIsNested) { |  | 
| 211             // Parent layers are currently hoisted while nested layers are not. |  | 
| 212             continue; |  | 
| 213         } |  | 
| 214 |  | 
| 215         SkRect layerRect; |  | 
| 216         initialMat.mapRect(&layerRect, info.fBounds); |  | 
| 217         if (!layerRect.intersect(query)) { |  | 
| 218             continue; |  | 
| 219         } |  | 
| 220 |  | 
| 221         const SkIRect dstIR = layerRect.roundOut(); |  | 
| 222 |  | 
| 223         SkIRect srcIR; |  | 
| 224         if (!compute_source_rect(info, initialMat, dstIR, &srcIR)) { |  | 
| 225             continue; |  | 
| 226         } |  | 
| 227 |  | 
| 228         prepare_for_hoisting(layerCache, topLevelPicture, initialMat, info, srcI
     R, dstIR, |  | 
| 229                              needRendering, recycled, false, numSamples); |  | 
| 230     } |  | 
| 231 } |  | 
| 232 |  | 
| 233 void GrLayerHoister::DrawLayersToAtlas(GrContext* context, |  | 
| 234                                        const SkTDArray<GrHoistedLayer>& atlased)
      { |  | 
| 235     if (atlased.count() > 0) { |  | 
| 236         // All the atlased layers are rendered into the same GrTexture |  | 
| 237         SkSurfaceProps props(0, kUnknown_SkPixelGeometry); |  | 
| 238         sk_sp<SkSurface> surface(SkSurface::MakeRenderTargetDirect( |  | 
| 239                                         atlased[0].fLayer->texture()->asRenderTa
     rget(), &props)); |  | 
| 240 |  | 
| 241         SkCanvas* atlasCanvas = surface->getCanvas(); |  | 
| 242 |  | 
| 243         for (int i = 0; i < atlased.count(); ++i) { |  | 
| 244             const GrCachedLayer* layer = atlased[i].fLayer; |  | 
| 245             const SkBigPicture* pict = atlased[i].fPicture->asSkBigPicture(); |  | 
| 246             if (!pict) { |  | 
| 247                 // TODO: can we assume / assert this? |  | 
| 248                 continue; |  | 
| 249             } |  | 
| 250             const SkIPoint offset = SkIPoint::Make(layer->srcIR().fLeft, layer->
     srcIR().fTop); |  | 
| 251             SkDEBUGCODE(const SkPaint* layerPaint = layer->paint();) |  | 
| 252 |  | 
| 253             SkASSERT(!layerPaint || !layerPaint->getImageFilter()); |  | 
| 254             SkASSERT(!layer->filter()); |  | 
| 255 |  | 
| 256             atlasCanvas->save(); |  | 
| 257 |  | 
| 258             // Add a rect clip to make sure the rendering doesn't |  | 
| 259             // extend beyond the boundaries of the atlased sub-rect |  | 
| 260             const SkRect bound = SkRect::Make(layer->rect()); |  | 
| 261             atlasCanvas->clipRect(bound); |  | 
| 262             atlasCanvas->clear(0); |  | 
| 263 |  | 
| 264             // '-offset' maps the layer's top/left to the origin. |  | 
| 265             // Since this layer is atlased, the top/left corner needs |  | 
| 266             // to be offset to the correct location in the backing texture. |  | 
| 267             SkMatrix initialCTM; |  | 
| 268             initialCTM.setTranslate(SkIntToScalar(-offset.fX), SkIntToScalar(-of
     fset.fY)); |  | 
| 269             initialCTM.preTranslate(bound.fLeft, bound.fTop); |  | 
| 270             initialCTM.preConcat(atlased[i].fPreMat); |  | 
| 271 |  | 
| 272             atlasCanvas->setMatrix(initialCTM); |  | 
| 273             atlasCanvas->concat(atlased[i].fLocalMat); |  | 
| 274 |  | 
| 275             pict->partialPlayback(atlasCanvas, layer->start() + 1, layer->stop()
     , initialCTM); |  | 
| 276             atlasCanvas->restore(); |  | 
| 277         } |  | 
| 278 |  | 
| 279         atlasCanvas->flush(); |  | 
| 280     } |  | 
| 281 } |  | 
| 282 |  | 
| 283 void GrLayerHoister::FilterLayer(GrContext* context, |  | 
| 284                                  const SkSurfaceProps* props, |  | 
| 285                                  const GrHoistedLayer& info) { |  | 
| 286     GrCachedLayer* layer = info.fLayer; |  | 
| 287 |  | 
| 288     SkASSERT(layer->filter()); |  | 
| 289 |  | 
| 290     static const int kDefaultCacheSize = 32 * 1024 * 1024; |  | 
| 291 |  | 
| 292     const SkIPoint filterOffset = SkIPoint::Make(layer->srcIR().fLeft, layer->sr
     cIR().fTop); |  | 
| 293 |  | 
| 294     SkMatrix totMat(info.fPreMat); |  | 
| 295     totMat.preConcat(info.fLocalMat); |  | 
| 296     totMat.postTranslate(-SkIntToScalar(filterOffset.fX), -SkIntToScalar(filterO
     ffset.fY)); |  | 
| 297 |  | 
| 298     SkASSERT(0 == layer->rect().fLeft && 0 == layer->rect().fTop); |  | 
| 299     const SkIRect& clipBounds = layer->rect(); |  | 
| 300 |  | 
| 301     // This cache is transient, and is freed (along with all its contained |  | 
| 302     // textures) when it goes out of scope. |  | 
| 303     SkAutoTUnref<SkImageFilterCache> cache(SkImageFilterCache::Create(kDefaultCa
     cheSize)); |  | 
| 304     SkImageFilter::Context filterContext(totMat, clipBounds, cache); |  | 
| 305 |  | 
| 306     // TODO: should the layer hoister store stand alone layers as SkSpecialImage
     s internally? |  | 
| 307     SkASSERT(layer->rect().width() == layer->texture()->width() && |  | 
| 308              layer->rect().height() == layer->texture()->height()); |  | 
| 309     const SkIRect subset = SkIRect::MakeWH(layer->rect().width(), layer->rect().
     height()); |  | 
| 310     sk_sp<SkSpecialImage> img(SkSpecialImage::MakeFromGpu(subset, |  | 
| 311                                                           kNeedNewImageUniqueID_
     SpecialImage, |  | 
| 312                                                           sk_ref_sp(layer->textu
     re()), |  | 
| 313                                                           props)); |  | 
| 314 |  | 
| 315     SkIPoint offset = SkIPoint::Make(0, 0); |  | 
| 316     sk_sp<SkSpecialImage> result(layer->filter()->filterImage(img.get(), |  | 
| 317                                                               filterContext, |  | 
| 318                                                               &offset)); |  | 
| 319     if (!result) { |  | 
| 320         // Filtering failed. Press on with the unfiltered version. |  | 
| 321         return; |  | 
| 322     } |  | 
| 323 |  | 
| 324     SkASSERT(result->isTextureBacked()); |  | 
| 325     sk_sp<GrTexture> texture(result->asTextureRef(context)); |  | 
| 326     layer->setTexture(texture.get(), result->subset(), false); |  | 
| 327     layer->setOffset(offset); |  | 
| 328 } |  | 
| 329 |  | 
| 330 void GrLayerHoister::DrawLayers(GrContext* context, const SkTDArray<GrHoistedLay
     er>& layers) { |  | 
| 331     for (int i = 0; i < layers.count(); ++i) { |  | 
| 332         GrCachedLayer* layer = layers[i].fLayer; |  | 
| 333         const SkBigPicture* pict = layers[i].fPicture->asSkBigPicture(); |  | 
| 334         if (!pict) { |  | 
| 335             // TODO: can we assume / assert this? |  | 
| 336             continue; |  | 
| 337         } |  | 
| 338         const SkIPoint offset = SkIPoint::Make(layer->srcIR().fLeft, layer->srcI
     R().fTop); |  | 
| 339 |  | 
| 340         // Each non-atlased layer has its own GrTexture |  | 
| 341         SkSurfaceProps props(0, kUnknown_SkPixelGeometry); |  | 
| 342         auto surface(SkSurface::MakeRenderTargetDirect( |  | 
| 343                                         layer->texture()->asRenderTarget(), &pro
     ps)); |  | 
| 344 |  | 
| 345         SkCanvas* layerCanvas = surface->getCanvas(); |  | 
| 346 |  | 
| 347         SkASSERT(0 == layer->rect().fLeft && 0 == layer->rect().fTop); |  | 
| 348 |  | 
| 349         // Add a rect clip to make sure the rendering doesn't |  | 
| 350         // extend beyond the boundaries of the layer |  | 
| 351         const SkRect bound = SkRect::Make(layer->rect()); |  | 
| 352         layerCanvas->clipRect(bound); |  | 
| 353         layerCanvas->clear(SK_ColorTRANSPARENT); |  | 
| 354 |  | 
| 355         SkMatrix initialCTM; |  | 
| 356         initialCTM.setTranslate(SkIntToScalar(-offset.fX), SkIntToScalar(-offset
     .fY)); |  | 
| 357         initialCTM.preConcat(layers[i].fPreMat); |  | 
| 358 |  | 
| 359         layerCanvas->setMatrix(initialCTM); |  | 
| 360         layerCanvas->concat(layers[i].fLocalMat); |  | 
| 361 |  | 
| 362         pict->partialPlayback(layerCanvas, layer->start()+1, layer->stop(), init
     ialCTM); |  | 
| 363         layerCanvas->flush(); |  | 
| 364 |  | 
| 365         if (layer->filter()) { |  | 
| 366             FilterLayer(context, &surface->props(), layers[i]); |  | 
| 367         } |  | 
| 368     } |  | 
| 369 } |  | 
| 370 |  | 
| 371 void GrLayerHoister::UnlockLayers(GrContext* context, |  | 
| 372                                   const SkTDArray<GrHoistedLayer>& layers) { |  | 
| 373     GrLayerCache* layerCache = context->getLayerCache(); |  | 
| 374 |  | 
| 375     for (int i = 0; i < layers.count(); ++i) { |  | 
| 376         layerCache->removeUse(layers[i].fLayer); |  | 
| 377     } |  | 
| 378 |  | 
| 379     SkDEBUGCODE(layerCache->validate();) |  | 
| 380 } |  | 
| 381 |  | 
| 382 void GrLayerHoister::Begin(GrContext* context) { |  | 
| 383     GrLayerCache* layerCache = context->getLayerCache(); |  | 
| 384 |  | 
| 385     layerCache->begin(); |  | 
| 386 } |  | 
| 387 |  | 
| 388 void GrLayerHoister::End(GrContext* context) { |  | 
| 389     GrLayerCache* layerCache = context->getLayerCache(); |  | 
| 390 |  | 
| 391 #if !GR_CACHE_HOISTED_LAYERS |  | 
| 392 |  | 
| 393     // This code completely clears out the atlas. It is required when |  | 
| 394     // caching is disabled so the atlas doesn't fill up and force more |  | 
| 395     // free floating layers |  | 
| 396     layerCache->purgeAll(); |  | 
| 397 #endif |  | 
| 398 |  | 
| 399     layerCache->end(); |  | 
| 400 } |  | 
| 401 |  | 
| 402 #endif |  | 
| OLD | NEW | 
|---|