Home | History | Annotate | Download | only in gpu
      1 
      2 /*
      3  * Copyright 2010 Google Inc.
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 
      9 #include "GrDrawTarget.h"
     10 
     11 #include "GrAuditTrail.h"
     12 #include "GrCaps.h"
     13 #include "GrGpu.h"
     14 #include "GrPath.h"
     15 #include "GrPipeline.h"
     16 #include "GrMemoryPool.h"
     17 #include "GrRenderTarget.h"
     18 #include "GrResourceProvider.h"
     19 #include "GrRenderTargetPriv.h"
     20 #include "GrSurfacePriv.h"
     21 #include "GrTexture.h"
     22 #include "GrVertexBuffer.h"
     23 #include "gl/GrGLRenderTarget.h"
     24 
     25 #include "SkStrokeRec.h"
     26 
     27 #include "batches/GrClearBatch.h"
     28 #include "batches/GrCopySurfaceBatch.h"
     29 #include "batches/GrDiscardBatch.h"
     30 #include "batches/GrDrawBatch.h"
     31 #include "batches/GrDrawPathBatch.h"
     32 #include "batches/GrRectBatchFactory.h"
     33 #include "batches/GrStencilPathBatch.h"
     34 
     35 ////////////////////////////////////////////////////////////////////////////////
     36 
     37 // Experimentally we have found that most batching occurs within the first 10 comparisons.
     38 static const int kDefaultMaxBatchLookback = 10;
     39 
     40 GrDrawTarget::GrDrawTarget(GrRenderTarget* rt, GrGpu* gpu, GrResourceProvider* resourceProvider,
     41                            GrAuditTrail* auditTrail, const Options& options)
     42     : fGpu(SkRef(gpu))
     43     , fResourceProvider(resourceProvider)
     44     , fAuditTrail(auditTrail)
     45     , fFlags(0)
     46     , fRenderTarget(rt) {
     47     // TODO: Stop extracting the context (currently needed by GrClipMaskManager)
     48     fContext = fGpu->getContext();
     49     fClipMaskManager.reset(new GrClipMaskManager(this, options.fClipBatchToBounds));
     50 
     51     fDrawBatchBounds = options.fDrawBatchBounds;
     52     fMaxBatchLookback = (options.fMaxBatchLookback < 0) ? kDefaultMaxBatchLookback :
     53                                                           options.fMaxBatchLookback;
     54 
     55     rt->setLastDrawTarget(this);
     56 
     57 #ifdef SK_DEBUG
     58     static int debugID = 0;
     59     fDebugID = debugID++;
     60 #endif
     61 }
     62 
     63 GrDrawTarget::~GrDrawTarget() {
     64     if (fRenderTarget && this == fRenderTarget->getLastDrawTarget()) {
     65         fRenderTarget->setLastDrawTarget(nullptr);
     66     }
     67 
     68     fGpu->unref();
     69 }
     70 
     71 ////////////////////////////////////////////////////////////////////////////////
     72 
     73 // Add a GrDrawTarget-based dependency
     74 void GrDrawTarget::addDependency(GrDrawTarget* dependedOn) {
     75     SkASSERT(!dependedOn->dependsOn(this));  // loops are bad
     76 
     77     if (this->dependsOn(dependedOn)) {
     78         return;  // don't add duplicate dependencies
     79     }
     80 
     81     *fDependencies.push() = dependedOn;
     82 }
     83 
     84 // Convert from a GrSurface-based dependency to a GrDrawTarget one
     85 void GrDrawTarget::addDependency(GrSurface* dependedOn) {
     86     if (dependedOn->asRenderTarget() && dependedOn->asRenderTarget()->getLastDrawTarget()) {
     87         // If it is still receiving dependencies, this DT shouldn't be closed
     88         SkASSERT(!this->isClosed());
     89 
     90         GrDrawTarget* dt = dependedOn->asRenderTarget()->getLastDrawTarget();
     91         if (dt == this) {
     92             // self-read - presumably for dst reads
     93         } else {
     94             this->addDependency(dt);
     95 
     96             // Can't make it closed in the self-read case
     97             dt->makeClosed();
     98         }
     99     }
    100 }
    101 
    102 #ifdef SK_DEBUG
    103 void GrDrawTarget::dump() const {
    104     SkDebugf("--------------------------------------------------------------\n");
    105     SkDebugf("node: %d -> RT: %d\n", fDebugID, fRenderTarget ? fRenderTarget->getUniqueID() : -1);
    106     SkDebugf("relies On (%d): ", fDependencies.count());
    107     for (int i = 0; i < fDependencies.count(); ++i) {
    108         SkDebugf("%d, ", fDependencies[i]->fDebugID);
    109     }
    110     SkDebugf("\n");
    111     SkDebugf("batches (%d):\n", fBatches.count());
    112     for (int i = 0; i < fBatches.count(); ++i) {
    113 #if 0
    114         SkDebugf("*******************************\n");
    115 #endif
    116         SkDebugf("%d: %s\n", i, fBatches[i]->name());
    117 #if 0
    118         SkString str = fBatches[i]->dumpInfo();
    119         SkDebugf("%s\n", str.c_str());
    120 #endif
    121     }
    122 }
    123 #endif
    124 
    125 bool GrDrawTarget::setupDstReadIfNecessary(const GrPipelineBuilder& pipelineBuilder,
    126                                            const GrPipelineOptimizations& optimizations,
    127                                            GrXferProcessor::DstTexture* dstTexture,
    128                                            const SkRect& batchBounds) {
    129     SkRect bounds = batchBounds;
    130     bounds.outset(0.5f, 0.5f);
    131 
    132     if (!pipelineBuilder.willXPNeedDstTexture(*this->caps(), optimizations)) {
    133         return true;
    134     }
    135 
    136     GrRenderTarget* rt = pipelineBuilder.getRenderTarget();
    137 
    138     if (this->caps()->textureBarrierSupport()) {
    139         if (GrTexture* rtTex = rt->asTexture()) {
    140             // The render target is a texture, so we can read from it directly in the shader. The XP
    141             // will be responsible to detect this situation and request a texture barrier.
    142             dstTexture->setTexture(rtTex);
    143             dstTexture->setOffset(0, 0);
    144             return true;
    145         }
    146     }
    147 
    148     SkIRect copyRect;
    149     pipelineBuilder.clip().getConservativeBounds(rt->width(), rt->height(), &copyRect);
    150 
    151     SkIRect drawIBounds;
    152     bounds.roundOut(&drawIBounds);
    153     if (!copyRect.intersect(drawIBounds)) {
    154 #ifdef SK_DEBUG
    155         GrCapsDebugf(this->caps(), "Missed an early reject. "
    156                                    "Bailing on draw from setupDstReadIfNecessary.\n");
    157 #endif
    158         return false;
    159     }
    160 
    161     // MSAA consideration: When there is support for reading MSAA samples in the shader we could
    162     // have per-sample dst values by making the copy multisampled.
    163     GrSurfaceDesc desc;
    164     if (!fGpu->initCopySurfaceDstDesc(rt, &desc)) {
    165         desc.fOrigin = kDefault_GrSurfaceOrigin;
    166         desc.fFlags = kRenderTarget_GrSurfaceFlag;
    167         desc.fConfig = rt->config();
    168     }
    169 
    170     desc.fWidth = copyRect.width();
    171     desc.fHeight = copyRect.height();
    172 
    173     static const uint32_t kFlags = 0;
    174     SkAutoTUnref<GrTexture> copy(fResourceProvider->createApproxTexture(desc, kFlags));
    175 
    176     if (!copy) {
    177         SkDebugf("Failed to create temporary copy of destination texture.\n");
    178         return false;
    179     }
    180     SkIPoint dstPoint = {0, 0};
    181     this->copySurface(copy, rt, copyRect, dstPoint);
    182     dstTexture->setTexture(copy);
    183     dstTexture->setOffset(copyRect.fLeft, copyRect.fTop);
    184     return true;
    185 }
    186 
    187 void GrDrawTarget::prepareBatches(GrBatchFlushState* flushState) {
    188     // Semi-usually the drawTargets are already closed at this point, but sometimes Ganesh
    189     // needs to flush mid-draw. In that case, the SkGpuDevice's drawTargets won't be closed
    190     // but need to be flushed anyway. Closing such drawTargets here will mean new
    191     // drawTargets will be created to replace them if the SkGpuDevice(s) write to them again.
    192     this->makeClosed();
    193 
    194     // Loop over the batches that haven't yet generated their geometry
    195     for (int i = 0; i < fBatches.count(); ++i) {
    196         fBatches[i]->prepare(flushState);
    197     }
    198 }
    199 
    200 void GrDrawTarget::drawBatches(GrBatchFlushState* flushState) {
    201     // Draw all the generated geometry.
    202     SkRandom random;
    203     for (int i = 0; i < fBatches.count(); ++i) {
    204         if (fDrawBatchBounds) {
    205             const SkRect& bounds = fBatches[i]->bounds();
    206             SkIRect ibounds;
    207             bounds.roundOut(&ibounds);
    208             // In multi-draw buffer all the batches use the same render target and we won't need to
    209             // get the batchs bounds.
    210             if (GrRenderTarget* rt = fBatches[i]->renderTarget()) {
    211                 fGpu->drawDebugWireRect(rt, ibounds, 0xFF000000 | random.nextU());
    212             }
    213         }
    214         fBatches[i]->draw(flushState);
    215     }
    216 
    217     fGpu->finishDrawTarget();
    218 }
    219 
    220 void GrDrawTarget::reset() {
    221     fBatches.reset();
    222 }
    223 
    224 void GrDrawTarget::drawBatch(const GrPipelineBuilder& pipelineBuilder, GrDrawBatch* batch) {
    225     // Setup clip
    226     GrPipelineBuilder::AutoRestoreStencil ars;
    227     GrAppliedClip clip;
    228     if (!fClipMaskManager->setupClipping(pipelineBuilder, &ars, &batch->bounds(), &clip)) {
    229         return;
    230     }
    231     GrPipelineBuilder::AutoRestoreFragmentProcessorState arfps;
    232     if (clip.clipCoverageFragmentProcessor()) {
    233         arfps.set(&pipelineBuilder);
    234         arfps.addCoverageFragmentProcessor(clip.clipCoverageFragmentProcessor());
    235     }
    236 
    237     GrPipeline::CreateArgs args;
    238     if (!this->installPipelineInDrawBatch(&pipelineBuilder, &clip.scissorState(), batch)) {
    239         return;
    240     }
    241 
    242 #ifdef ENABLE_MDB
    243     SkASSERT(fRenderTarget);
    244     batch->pipeline()->addDependenciesTo(fRenderTarget);
    245 #endif
    246 
    247     this->recordBatch(batch);
    248 }
    249 
    250 static const GrStencilSettings& winding_path_stencil_settings() {
    251     GR_STATIC_CONST_SAME_STENCIL_STRUCT(gSettings,
    252         kIncClamp_StencilOp,
    253         kIncClamp_StencilOp,
    254         kAlwaysIfInClip_StencilFunc,
    255         0xFFFF, 0xFFFF, 0xFFFF);
    256     return *GR_CONST_STENCIL_SETTINGS_PTR_FROM_STRUCT_PTR(&gSettings);
    257 }
    258 
    259 static const GrStencilSettings& even_odd_path_stencil_settings() {
    260     GR_STATIC_CONST_SAME_STENCIL_STRUCT(gSettings,
    261         kInvert_StencilOp,
    262         kInvert_StencilOp,
    263         kAlwaysIfInClip_StencilFunc,
    264         0xFFFF, 0xFFFF, 0xFFFF);
    265     return *GR_CONST_STENCIL_SETTINGS_PTR_FROM_STRUCT_PTR(&gSettings);
    266 }
    267 
    268 void GrDrawTarget::getPathStencilSettingsForFilltype(GrPathRendering::FillType fill,
    269                                                      const GrStencilAttachment* sb,
    270                                                      GrStencilSettings* outStencilSettings) {
    271 
    272     switch (fill) {
    273         default:
    274             SkFAIL("Unexpected path fill.");
    275         case GrPathRendering::kWinding_FillType:
    276             *outStencilSettings = winding_path_stencil_settings();
    277             break;
    278         case GrPathRendering::kEvenOdd_FillType:
    279             *outStencilSettings = even_odd_path_stencil_settings();
    280             break;
    281     }
    282     fClipMaskManager->adjustPathStencilParams(sb, outStencilSettings);
    283 }
    284 
    285 void GrDrawTarget::stencilPath(const GrPipelineBuilder& pipelineBuilder,
    286                                const SkMatrix& viewMatrix,
    287                                const GrPath* path,
    288                                GrPathRendering::FillType fill) {
    289     // TODO: extract portions of checkDraw that are relevant to path stenciling.
    290     SkASSERT(path);
    291     SkASSERT(this->caps()->shaderCaps()->pathRenderingSupport());
    292 
    293     // Setup clip
    294     GrPipelineBuilder::AutoRestoreStencil ars;
    295     GrAppliedClip clip;
    296     if (!fClipMaskManager->setupClipping(pipelineBuilder, &ars, nullptr, &clip)) {
    297         return;
    298     }
    299 
    300     GrPipelineBuilder::AutoRestoreFragmentProcessorState arfps;
    301     if (clip.clipCoverageFragmentProcessor()) {
    302         arfps.set(&pipelineBuilder);
    303         arfps.addCoverageFragmentProcessor(clip.clipCoverageFragmentProcessor());
    304     }
    305 
    306     // set stencil settings for path
    307     GrStencilSettings stencilSettings;
    308     GrRenderTarget* rt = pipelineBuilder.getRenderTarget();
    309     GrStencilAttachment* sb = fResourceProvider->attachStencilAttachment(rt);
    310     this->getPathStencilSettingsForFilltype(fill, sb, &stencilSettings);
    311 
    312     GrBatch* batch = GrStencilPathBatch::Create(viewMatrix,
    313                                                 pipelineBuilder.isHWAntialias(),
    314                                                 stencilSettings, clip.scissorState(),
    315                                                 pipelineBuilder.getRenderTarget(),
    316                                                 path);
    317     this->recordBatch(batch);
    318     batch->unref();
    319 }
    320 
    321 void GrDrawTarget::drawPathBatch(const GrPipelineBuilder& pipelineBuilder,
    322                                  GrDrawPathBatchBase* batch) {
    323     // This looks like drawBatch() but there is an added wrinkle that stencil settings get inserted
    324     // after setting up clipping but before onDrawBatch(). TODO: Figure out a better model for
    325     // handling stencil settings WRT interactions between pipeline(builder), clipmaskmanager, and
    326     // batches.
    327     SkASSERT(this->caps()->shaderCaps()->pathRenderingSupport());
    328 
    329     GrPipelineBuilder::AutoRestoreStencil ars;
    330     GrAppliedClip clip;
    331     if (!fClipMaskManager->setupClipping(pipelineBuilder, &ars, &batch->bounds(), &clip)) {
    332         return;
    333     }
    334 
    335     GrPipelineBuilder::AutoRestoreFragmentProcessorState arfps;
    336     if (clip.clipCoverageFragmentProcessor()) {
    337         arfps.set(&pipelineBuilder);
    338         arfps.addCoverageFragmentProcessor(clip.clipCoverageFragmentProcessor());
    339     }
    340 
    341     // Ensure the render target has a stencil buffer and get the stencil settings.
    342     GrStencilSettings stencilSettings;
    343     GrRenderTarget* rt = pipelineBuilder.getRenderTarget();
    344     GrStencilAttachment* sb = fResourceProvider->attachStencilAttachment(rt);
    345     this->getPathStencilSettingsForFilltype(batch->fillType(), sb, &stencilSettings);
    346     batch->setStencilSettings(stencilSettings);
    347 
    348     GrPipeline::CreateArgs args;
    349     if (!this->installPipelineInDrawBatch(&pipelineBuilder, &clip.scissorState(), batch)) {
    350         return;
    351     }
    352 
    353     this->recordBatch(batch);
    354 }
    355 
    356 void GrDrawTarget::clear(const SkIRect* rect,
    357                          GrColor color,
    358                          bool canIgnoreRect,
    359                          GrRenderTarget* renderTarget) {
    360     SkIRect rtRect = SkIRect::MakeWH(renderTarget->width(), renderTarget->height());
    361     SkIRect clippedRect;
    362     if (!rect ||
    363         (canIgnoreRect && this->caps()->fullClearIsFree()) ||
    364         rect->contains(rtRect)) {
    365         rect = &rtRect;
    366     } else {
    367         clippedRect = *rect;
    368         if (!clippedRect.intersect(rtRect)) {
    369             return;
    370         }
    371         rect = &clippedRect;
    372     }
    373 
    374     if (this->caps()->useDrawInsteadOfClear()) {
    375         // This works around a driver bug with clear by drawing a rect instead.
    376         // The driver will ignore a clear if it is the only thing rendered to a
    377         // target before the target is read.
    378         if (rect == &rtRect) {
    379             this->discard(renderTarget);
    380         }
    381 
    382         GrPipelineBuilder pipelineBuilder;
    383         pipelineBuilder.setXPFactory(
    384             GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref();
    385         pipelineBuilder.setRenderTarget(renderTarget);
    386 
    387         SkRect scalarRect = SkRect::Make(*rect);
    388         SkAutoTUnref<GrDrawBatch> batch(
    389                 GrRectBatchFactory::CreateNonAAFill(color, SkMatrix::I(), scalarRect,
    390                                                     nullptr, nullptr));
    391         this->drawBatch(pipelineBuilder, batch);
    392     } else {
    393         GrBatch* batch = new GrClearBatch(*rect, color, renderTarget);
    394         this->recordBatch(batch);
    395         batch->unref();
    396     }
    397 }
    398 
    399 void GrDrawTarget::discard(GrRenderTarget* renderTarget) {
    400     if (this->caps()->discardRenderTargetSupport()) {
    401         GrBatch* batch = new GrDiscardBatch(renderTarget);
    402         this->recordBatch(batch);
    403         batch->unref();
    404     }
    405 }
    406 
    407 ////////////////////////////////////////////////////////////////////////////////
    408 
    409 bool GrDrawTarget::copySurface(GrSurface* dst,
    410                                GrSurface* src,
    411                                const SkIRect& srcRect,
    412                                const SkIPoint& dstPoint) {
    413     GrBatch* batch = GrCopySurfaceBatch::Create(dst, src, srcRect, dstPoint);
    414     if (!batch) {
    415         return false;
    416     }
    417 #ifdef ENABLE_MDB
    418     this->addDependency(src);
    419 #endif
    420 
    421     this->recordBatch(batch);
    422     batch->unref();
    423     return true;
    424 }
    425 
    426 template <class Left, class Right> static bool intersect(const Left& a, const Right& b) {
    427     SkASSERT(a.fLeft <= a.fRight && a.fTop <= a.fBottom &&
    428              b.fLeft <= b.fRight && b.fTop <= b.fBottom);
    429     return a.fLeft < b.fRight && b.fLeft < a.fRight && a.fTop < b.fBottom && b.fTop < a.fBottom;
    430 }
    431 
    432 void GrDrawTarget::recordBatch(GrBatch* batch) {
    433     // A closed drawTarget should never receive new/more batches
    434     SkASSERT(!this->isClosed());
    435 
    436     // Check if there is a Batch Draw we can batch with by linearly searching back until we either
    437     // 1) check every draw
    438     // 2) intersect with something
    439     // 3) find a 'blocker'
    440     GR_AUDIT_TRAIL_ADDBATCH(fAuditTrail, batch->name(), batch->bounds());
    441     GrBATCH_INFO("Re-Recording (%s, B%u)\n"
    442         "\tBounds LRTB (%f, %f, %f, %f)\n",
    443         batch->name(),
    444         batch->uniqueID(),
    445         batch->bounds().fLeft, batch->bounds().fRight,
    446         batch->bounds().fTop, batch->bounds().fBottom);
    447     GrBATCH_INFO(SkTabString(batch->dumpInfo(), 1).c_str());
    448     GrBATCH_INFO("\tOutcome:\n");
    449     int maxCandidates = SkTMin(fMaxBatchLookback, fBatches.count());
    450     if (maxCandidates) {
    451         int i = 0;
    452         while (true) {
    453             GrBatch* candidate = fBatches.fromBack(i);
    454             // We cannot continue to search backwards if the render target changes
    455             if (candidate->renderTargetUniqueID() != batch->renderTargetUniqueID()) {
    456                 GrBATCH_INFO("\t\tBreaking because of (%s, B%u) Rendertarget\n",
    457                     candidate->name(), candidate->uniqueID());
    458                 break;
    459             }
    460             if (candidate->combineIfPossible(batch, *this->caps())) {
    461                 GrBATCH_INFO("\t\tCombining with (%s, B%u)\n", candidate->name(),
    462                     candidate->uniqueID());
    463                 return;
    464             }
    465             // Stop going backwards if we would cause a painter's order violation.
    466             // TODO: The bounds used here do not fully consider the clip. It may be advantageous
    467             // to clip each batch's bounds to the clip.
    468             if (intersect(candidate->bounds(), batch->bounds())) {
    469                 GrBATCH_INFO("\t\tIntersects with (%s, B%u)\n", candidate->name(),
    470                     candidate->uniqueID());
    471                 break;
    472             }
    473             ++i;
    474             if (i == maxCandidates) {
    475                 GrBATCH_INFO("\t\tReached max lookback or beginning of batch array %d\n", i);
    476                 break;
    477             }
    478         }
    479     } else {
    480         GrBATCH_INFO("\t\tFirstBatch\n");
    481     }
    482     fBatches.push_back().reset(SkRef(batch));
    483 }
    484 
    485 ///////////////////////////////////////////////////////////////////////////////
    486 
    487 bool GrDrawTarget::installPipelineInDrawBatch(const GrPipelineBuilder* pipelineBuilder,
    488                                               const GrScissorState* scissor,
    489                                               GrDrawBatch* batch) {
    490     GrPipeline::CreateArgs args;
    491     args.fPipelineBuilder = pipelineBuilder;
    492     args.fCaps = this->caps();
    493     args.fScissor = scissor;
    494     batch->getPipelineOptimizations(&args.fOpts);
    495     GrScissorState finalScissor;
    496     if (args.fOpts.fOverrides.fUsePLSDstRead) {
    497         GrRenderTarget* rt = pipelineBuilder->getRenderTarget();
    498         GrGLIRect viewport;
    499         viewport.fLeft = 0;
    500         viewport.fBottom = 0;
    501         viewport.fWidth = rt->width();
    502         viewport.fHeight = rt->height();
    503         SkIRect ibounds;
    504         ibounds.fLeft = SkTPin(SkScalarFloorToInt(batch->bounds().fLeft), viewport.fLeft,
    505                               viewport.fWidth);
    506         ibounds.fTop = SkTPin(SkScalarFloorToInt(batch->bounds().fTop), viewport.fBottom,
    507                              viewport.fHeight);
    508         ibounds.fRight = SkTPin(SkScalarCeilToInt(batch->bounds().fRight), viewport.fLeft,
    509                                viewport.fWidth);
    510         ibounds.fBottom = SkTPin(SkScalarCeilToInt(batch->bounds().fBottom), viewport.fBottom,
    511                                 viewport.fHeight);
    512         if (scissor != nullptr && scissor->enabled()) {
    513             if (!ibounds.intersect(scissor->rect())) {
    514                 ibounds = scissor->rect();
    515             }
    516         }
    517         finalScissor.set(ibounds);
    518         args.fScissor = &finalScissor;
    519     }
    520     args.fOpts.fColorPOI.completeCalculations(pipelineBuilder->fColorFragmentProcessors.begin(),
    521                                               pipelineBuilder->numColorFragmentProcessors());
    522     args.fOpts.fCoveragePOI.completeCalculations(
    523                                                pipelineBuilder->fCoverageFragmentProcessors.begin(),
    524                                                pipelineBuilder->numCoverageFragmentProcessors());
    525     if (!this->setupDstReadIfNecessary(*pipelineBuilder, args.fOpts, &args.fDstTexture,
    526                                        batch->bounds())) {
    527         return false;
    528     }
    529 
    530     if (!batch->installPipeline(args)) {
    531         return false;
    532     }
    533 
    534     return true;
    535 }
    536 
    537 void GrDrawTarget::clearStencilClip(const SkIRect& rect, bool insideClip, GrRenderTarget* rt) {
    538     GrBatch* batch = new GrClearStencilClipBatch(rect, insideClip, rt);
    539     this->recordBatch(batch);
    540     batch->unref();
    541 }
    542