LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/gpu - GrRenderTargetOpList.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 199 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 17 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright 2010 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 "GrRenderTargetOpList.h"
       9             : #include "GrAuditTrail.h"
      10             : #include "GrCaps.h"
      11             : #include "GrGpu.h"
      12             : #include "GrGpuCommandBuffer.h"
      13             : #include "GrRenderTarget.h"
      14             : #include "GrRenderTargetContext.h"
      15             : #include "GrResourceProvider.h"
      16             : #include "ops/GrClearOp.h"
      17             : #include "ops/GrCopySurfaceOp.h"
      18             : #include "ops/GrDiscardOp.h"
      19             : #include "instanced/InstancedRendering.h"
      20             : 
      21             : using gr_instanced::InstancedRendering;
      22             : 
      23             : ////////////////////////////////////////////////////////////////////////////////
      24             : 
      25             : // Experimentally we have found that most combining occurs within the first 10 comparisons.
      26             : static const int kDefaultMaxOpLookback = 10;
      27             : static const int kDefaultMaxOpLookahead = 10;
      28             : 
      29           0 : GrRenderTargetOpList::GrRenderTargetOpList(GrRenderTargetProxy* rtp, GrGpu* gpu,
      30             :                                            GrResourceProvider* resourceProvider,
      31           0 :                                            GrAuditTrail* auditTrail, const Options& options)
      32             :         : INHERITED(rtp, auditTrail)
      33           0 :         , fGpu(SkRef(gpu))
      34             :         , fResourceProvider(resourceProvider)
      35             :         , fLastClipStackGenID(SK_InvalidUniqueID)
      36             :         , fClipAllocator(fClipAllocatorStorage, sizeof(fClipAllocatorStorage),
      37           0 :                          sizeof(fClipAllocatorStorage)) {
      38             : 
      39           0 :     fMaxOpLookback = (options.fMaxOpCombineLookback < 0) ? kDefaultMaxOpLookback
      40             :                                                          : options.fMaxOpCombineLookback;
      41           0 :     fMaxOpLookahead = (options.fMaxOpCombineLookahead < 0) ? kDefaultMaxOpLookahead
      42             :                                                            : options.fMaxOpCombineLookahead;
      43             : 
      44           0 :     if (GrCaps::InstancedSupport::kNone != this->caps()->instancedSupport()) {
      45           0 :         fInstancedRendering.reset(fGpu->createInstancedRendering());
      46             :     }
      47           0 : }
      48             : 
      49           0 : GrRenderTargetOpList::~GrRenderTargetOpList() {
      50           0 :     fGpu->unref();
      51           0 : }
      52             : 
      53             : ////////////////////////////////////////////////////////////////////////////////
      54             : 
      55             : #ifdef SK_DEBUG
      56           0 : void GrRenderTargetOpList::dump() const {
      57           0 :     INHERITED::dump();
      58             : 
      59           0 :     SkDebugf("ops (%d):\n", fRecordedOps.count());
      60           0 :     for (int i = 0; i < fRecordedOps.count(); ++i) {
      61           0 :         SkDebugf("*******************************\n");
      62           0 :         if (!fRecordedOps[i].fOp) {
      63           0 :             SkDebugf("%d: <combined forward>\n", i);
      64             :         } else {
      65           0 :             SkDebugf("%d: %s\n", i, fRecordedOps[i].fOp->name());
      66           0 :             SkString str = fRecordedOps[i].fOp->dumpInfo();
      67           0 :             SkDebugf("%s\n", str.c_str());
      68           0 :             const SkRect& bounds = fRecordedOps[i].fOp->bounds();
      69           0 :             SkDebugf("ClippedBounds: [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", bounds.fLeft,
      70           0 :                      bounds.fTop, bounds.fRight, bounds.fBottom);
      71             :         }
      72             :     }
      73           0 : }
      74             : 
      75           0 : void GrRenderTargetOpList::validateTargetsSingleRenderTarget() const {
      76           0 :     GrRenderTarget* rt = nullptr;
      77           0 :     for (int i = 0; i < fRecordedOps.count(); ++i) {
      78           0 :         if (!fRecordedOps[i].fOp) {
      79           0 :             continue;       // combined forward
      80             :         }
      81             : 
      82           0 :         if (!rt) {
      83           0 :             rt = fRecordedOps[i].fRenderTarget.get();
      84             :         } else {
      85           0 :             SkASSERT(fRecordedOps[i].fRenderTarget.get() == rt);
      86             :         }
      87             :     }
      88           0 : }
      89             : #endif
      90             : 
      91           0 : void GrRenderTargetOpList::prepareOps(GrOpFlushState* flushState) {
      92             :     // MDB TODO: add SkASSERT(this->isClosed());
      93             : 
      94             :     // Loop over the ops that haven't yet been prepared.
      95           0 :     for (int i = 0; i < fRecordedOps.count(); ++i) {
      96           0 :         if (fRecordedOps[i].fOp) {
      97           0 :             GrOpFlushState::DrawOpArgs opArgs;
      98           0 :             if (fRecordedOps[i].fRenderTarget) {
      99             :                 opArgs = {
     100           0 :                     fRecordedOps[i].fRenderTarget.get(),
     101           0 :                     fRecordedOps[i].fAppliedClip,
     102           0 :                     fRecordedOps[i].fDstTexture
     103           0 :                 };
     104             :             }
     105           0 :             flushState->setDrawOpArgs(&opArgs);
     106           0 :             fRecordedOps[i].fOp->prepare(flushState);
     107           0 :             flushState->setDrawOpArgs(nullptr);
     108             :         }
     109             :     }
     110             : 
     111           0 :     if (fInstancedRendering) {
     112           0 :         fInstancedRendering->beginFlush(flushState->resourceProvider());
     113             :     }
     114           0 : }
     115             : 
     116             : // TODO: this is where GrOp::renderTarget is used (which is fine since it
     117             : // is at flush time). However, we need to store the RenderTargetProxy in the
     118             : // Ops and instantiate them here.
     119           0 : bool GrRenderTargetOpList::executeOps(GrOpFlushState* flushState) {
     120           0 :     if (0 == fRecordedOps.count()) {
     121           0 :         return false;
     122             :     }
     123             :     // Draw all the generated geometry.
     124           0 :     SkRandom random;
     125           0 :     const GrRenderTarget* currentRenderTarget = nullptr;
     126           0 :     std::unique_ptr<GrGpuCommandBuffer> commandBuffer;
     127           0 :     for (int i = 0; i < fRecordedOps.count(); ++i) {
     128           0 :         if (!fRecordedOps[i].fOp) {
     129           0 :             continue;
     130             :         }
     131           0 :         if (fRecordedOps[i].fRenderTarget.get() != currentRenderTarget) {
     132           0 :             if (commandBuffer) {
     133           0 :                 commandBuffer->end();
     134           0 :                 commandBuffer->submit();
     135           0 :                 commandBuffer.reset();
     136             :             }
     137           0 :             currentRenderTarget = fRecordedOps[i].fRenderTarget.get();
     138           0 :             if (currentRenderTarget) {
     139             :                 static const GrGpuCommandBuffer::LoadAndStoreInfo kBasicLoadStoreInfo
     140             :                     { GrGpuCommandBuffer::LoadOp::kLoad,GrGpuCommandBuffer::StoreOp::kStore,
     141             :                       GrColor_ILLEGAL };
     142           0 :                 commandBuffer.reset(fGpu->createCommandBuffer(kBasicLoadStoreInfo,   // Color
     143           0 :                                                               kBasicLoadStoreInfo)); // Stencil
     144             :             }
     145           0 :             flushState->setCommandBuffer(commandBuffer.get());
     146             :         }
     147           0 :         GrOpFlushState::DrawOpArgs opArgs;
     148           0 :         if (fRecordedOps[i].fRenderTarget) {
     149             :             opArgs = {
     150           0 :                 fRecordedOps[i].fRenderTarget.get(),
     151           0 :                 fRecordedOps[i].fAppliedClip,
     152           0 :                 fRecordedOps[i].fDstTexture
     153           0 :             };
     154           0 :             flushState->setDrawOpArgs(&opArgs);
     155             :         }
     156           0 :         fRecordedOps[i].fOp->execute(flushState);
     157           0 :         flushState->setDrawOpArgs(nullptr);
     158             :     }
     159           0 :     if (commandBuffer) {
     160           0 :         commandBuffer->end();
     161           0 :         commandBuffer->submit();
     162           0 :         flushState->setCommandBuffer(nullptr);
     163             :     }
     164             : 
     165           0 :     fGpu->finishOpList();
     166           0 :     return true;
     167             : }
     168             : 
     169           0 : void GrRenderTargetOpList::reset() {
     170           0 :     fLastFullClearOp = nullptr;
     171           0 :     fLastFullClearResourceID.makeInvalid();
     172           0 :     fLastFullClearProxyID.makeInvalid();
     173           0 :     fRecordedOps.reset();
     174           0 :     if (fInstancedRendering) {
     175           0 :         fInstancedRendering->endFlush();
     176             :     }
     177           0 : }
     178             : 
     179           0 : void GrRenderTargetOpList::abandonGpuResources() {
     180           0 :     if (GrCaps::InstancedSupport::kNone != this->caps()->instancedSupport()) {
     181           0 :         InstancedRendering* ir = this->instancedRendering();
     182           0 :         ir->resetGpuResources(InstancedRendering::ResetType::kAbandon);
     183             :     }
     184           0 : }
     185             : 
     186           0 : void GrRenderTargetOpList::freeGpuResources() {
     187           0 :     if (GrCaps::InstancedSupport::kNone != this->caps()->instancedSupport()) {
     188           0 :         InstancedRendering* ir = this->instancedRendering();
     189           0 :         ir->resetGpuResources(InstancedRendering::ResetType::kDestroy);
     190             :     }
     191           0 : }
     192             : 
     193           0 : void GrRenderTargetOpList::fullClear(GrRenderTargetContext* renderTargetContext, GrColor color) {
     194             :     // MDB TODO: remove this. Right now we need the renderTargetContext for the
     195             :     // accessRenderTarget call. This method should just take the renderTargetProxy.
     196           0 :     GrRenderTarget* renderTarget = renderTargetContext->accessRenderTarget();
     197           0 :     if (!renderTarget) {
     198           0 :         return;
     199             :     }
     200             : 
     201             :     // Currently this just inserts or updates the last clear op. However, once in MDB this can
     202             :     // remove all the previously recorded ops and change the load op to clear with supplied
     203             :     // color.
     204             :     // TODO: this needs to be updated to use GrSurfaceProxy::UniqueID
     205           0 :     SkASSERT((fLastFullClearResourceID == renderTarget->uniqueID()) ==
     206             :              (fLastFullClearProxyID == renderTargetContext->asRenderTargetProxy()->uniqueID()));
     207           0 :     if (fLastFullClearResourceID == renderTarget->uniqueID()) {
     208             :         // As currently implemented, fLastFullClearOp should be the last op because we would
     209             :         // have cleared it when another op was recorded.
     210           0 :         SkASSERT(fRecordedOps.back().fOp.get() == fLastFullClearOp);
     211           0 :         fLastFullClearOp->setColor(color);
     212           0 :         return;
     213             :     }
     214             :     std::unique_ptr<GrClearOp> op(GrClearOp::Make(GrFixedClip::Disabled(), color,
     215           0 :                                                   renderTargetContext));
     216           0 :     if (!op) {
     217           0 :         return;
     218             :     }
     219           0 :     if (GrOp* clearOp = this->recordOp(std::move(op), renderTargetContext)) {
     220             :         // This is either the clear op we just created or another one that it combined with.
     221           0 :         fLastFullClearOp = static_cast<GrClearOp*>(clearOp);
     222           0 :         fLastFullClearResourceID = renderTarget->uniqueID();
     223           0 :         fLastFullClearProxyID = renderTargetContext->asRenderTargetProxy()->uniqueID();
     224             :     }
     225             : }
     226             : 
     227           0 : void GrRenderTargetOpList::discard(GrRenderTargetContext* renderTargetContext) {
     228             :     // Currently this just inserts a discard op. However, once in MDB this can remove all the
     229             :     // previously recorded ops and change the load op to discard.
     230           0 :     if (this->caps()->discardRenderTargetSupport()) {
     231           0 :         std::unique_ptr<GrOp> op(GrDiscardOp::Make(renderTargetContext));
     232           0 :         if (!op) {
     233           0 :             return;
     234             :         }
     235           0 :         this->recordOp(std::move(op), renderTargetContext);
     236             :     }
     237             : }
     238             : 
     239             : ////////////////////////////////////////////////////////////////////////////////
     240             : 
     241           0 : bool GrRenderTargetOpList::copySurface(GrResourceProvider* resourceProvider,
     242             :                                        GrSurfaceProxy* dst,
     243             :                                        GrSurfaceProxy* src,
     244             :                                        const SkIRect& srcRect,
     245             :                                        const SkIPoint& dstPoint) {
     246           0 :     std::unique_ptr<GrOp> op = GrCopySurfaceOp::Make(resourceProvider, dst, src, srcRect, dstPoint);
     247           0 :     if (!op) {
     248           0 :         return false;
     249             :     }
     250             : #ifdef ENABLE_MDB
     251             :     this->addDependency(src);
     252             : #endif
     253             : 
     254             :     // Copy surface doesn't work through a GrGpuCommandBuffer. By passing nullptr for the context we
     255             :     // force this to occur between command buffers and execute directly on GrGpu. This workaround
     256             :     // goes away with MDB.
     257           0 :     this->recordOp(std::move(op), nullptr);
     258           0 :     return true;
     259             : }
     260             : 
     261           0 : static inline bool can_reorder(const SkRect& a, const SkRect& b) {
     262           0 :     return a.fRight <= b.fLeft || a.fBottom <= b.fTop ||
     263           0 :            b.fRight <= a.fLeft || b.fBottom <= a.fTop;
     264             : }
     265             : 
     266           0 : bool GrRenderTargetOpList::combineIfPossible(const RecordedOp& a, GrOp* b,
     267             :                                              const GrAppliedClip* bClip,
     268             :                                              const DstTexture* bDstTexture) {
     269           0 :     if (a.fAppliedClip) {
     270           0 :         if (!bClip) {
     271           0 :             return false;
     272             :         }
     273           0 :         if (*a.fAppliedClip != *bClip) {
     274           0 :             return false;
     275             :         }
     276           0 :     } else if (bClip) {
     277           0 :         return false;
     278             :     }
     279           0 :     if (bDstTexture) {
     280           0 :         if (a.fDstTexture != *bDstTexture) {
     281           0 :             return false;
     282             :         }
     283           0 :     } else if (a.fDstTexture.texture()) {
     284           0 :         return false;
     285             :     }
     286           0 :     return a.fOp->combineIfPossible(b, *this->caps());
     287             : }
     288             : 
     289           0 : GrOp* GrRenderTargetOpList::recordOp(std::unique_ptr<GrOp> op,
     290             :                                      GrRenderTargetContext* renderTargetContext,
     291             :                                      GrAppliedClip* clip,
     292             :                                      const DstTexture* dstTexture) {
     293             :     GrRenderTarget* renderTarget =
     294           0 :             renderTargetContext ? renderTargetContext->accessRenderTarget()
     295           0 :                                 : nullptr;
     296             : 
     297             :     // A closed GrOpList should never receive new/more ops
     298           0 :     SkASSERT(!this->isClosed());
     299             : 
     300             :     // Check if there is an op we can combine with by linearly searching back until we either
     301             :     // 1) check every op
     302             :     // 2) intersect with something
     303             :     // 3) find a 'blocker'
     304           0 :     GR_AUDIT_TRAIL_ADD_OP(fAuditTrail, op.get(), renderTarget->uniqueID(),
     305             :                           renderTargetContext->asRenderTargetProxy()->uniqueID());
     306             :     GrOP_INFO("Recording (%s, opID: %u)\n"
     307             :               "\tBounds: [L: %f T: %f R: %f B: %f]\n",
     308             :                op->name(),
     309             :                op->uniqueID(),
     310             :                op->bounds().fLeft, op->bounds().fTop,
     311             :                op->bounds().fRight, op->bounds().fBottom);
     312             :     GrOP_INFO(SkTabString(op->dumpInfo(), 1).c_str());
     313             :     GrOP_INFO("\tClipped Bounds: [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", op->bounds().fLeft,
     314             :               op->bounds().fTop, op->bounds().fRight, op->bounds().fBottom);
     315             :     GrOP_INFO("\tOutcome:\n");
     316           0 :     int maxCandidates = SkTMin(fMaxOpLookback, fRecordedOps.count());
     317             :     // If we don't have a valid destination render target then we cannot reorder.
     318           0 :     if (maxCandidates && renderTarget) {
     319           0 :         int i = 0;
     320             :         while (true) {
     321           0 :             const RecordedOp& candidate = fRecordedOps.fromBack(i);
     322             :             // We cannot continue to search backwards if the render target changes
     323           0 :             if (candidate.fRenderTarget.get() != renderTarget) {
     324             :                 GrOP_INFO("\t\tBreaking because of (%s, opID: %u) Rendertarget mismatch\n",
     325             :                           candidate.fOp->name(),
     326             :                           candidate.fOp->uniqueID());
     327           0 :                 break;
     328             :             }
     329           0 :             if (this->combineIfPossible(candidate, op.get(), clip, dstTexture)) {
     330             :                 GrOP_INFO("\t\tCombining with (%s, opID: %u)\n", candidate.fOp->name(),
     331             :                           candidate.fOp->uniqueID());
     332             :                 GrOP_INFO("\t\t\tCombined op info:\n");
     333             :                 GrOP_INFO(SkTabString(candidate.fOp->dumpInfo(), 4).c_str());
     334           0 :                 GR_AUDIT_TRAIL_OPS_RESULT_COMBINED(fAuditTrail, candidate.fOp.get(), op.get());
     335           0 :                 return candidate.fOp.get();
     336             :             }
     337             :             // Stop going backwards if we would cause a painter's order violation.
     338           0 :             if (!can_reorder(fRecordedOps.fromBack(i).fOp->bounds(), op->bounds())) {
     339             :                 GrOP_INFO("\t\tIntersects with (%s, opID: %u)\n", candidate.fOp->name(),
     340             :                           candidate.fOp->uniqueID());
     341           0 :                 break;
     342             :             }
     343           0 :             ++i;
     344           0 :             if (i == maxCandidates) {
     345             :                 GrOP_INFO("\t\tReached max lookback or beginning of op array %d\n", i);
     346           0 :                 break;
     347             :             }
     348           0 :         }
     349             :     } else {
     350             :         GrOP_INFO("\t\tFirstOp\n");
     351             :     }
     352             :     GR_AUDIT_TRAIL_OP_RESULT_NEW(fAuditTrail, op);
     353           0 :     if (clip) {
     354           0 :         clip = fClipAllocator.make<GrAppliedClip>(std::move(*clip));
     355             :     }
     356           0 :     fRecordedOps.emplace_back(std::move(op), renderTarget, clip, dstTexture);
     357           0 :     fRecordedOps.back().fOp->wasRecorded();
     358           0 :     fLastFullClearOp = nullptr;
     359           0 :     fLastFullClearResourceID.makeInvalid();
     360           0 :     fLastFullClearProxyID.makeInvalid();
     361           0 :     return fRecordedOps.back().fOp.get();
     362             : }
     363             : 
     364           0 : void GrRenderTargetOpList::forwardCombine() {
     365           0 :     if (fMaxOpLookahead <= 0) {
     366           0 :         return;
     367             :     }
     368           0 :     for (int i = 0; i < fRecordedOps.count() - 1; ++i) {
     369           0 :         GrOp* op = fRecordedOps[i].fOp.get();
     370           0 :         GrRenderTarget* renderTarget = fRecordedOps[i].fRenderTarget.get();
     371             :         // If we don't have a valid destination render target ID then we cannot reorder.
     372           0 :         if (!renderTarget) {
     373           0 :             continue;
     374             :         }
     375           0 :         int maxCandidateIdx = SkTMin(i + fMaxOpLookahead, fRecordedOps.count() - 1);
     376           0 :         int j = i + 1;
     377             :         while (true) {
     378           0 :             const RecordedOp& candidate = fRecordedOps[j];
     379             :             // We cannot continue to search if the render target changes
     380           0 :             if (candidate.fRenderTarget.get() != renderTarget) {
     381             :                 GrOP_INFO("\t\tBreaking because of (%s, B%u) Rendertarget\n", candidate.fOp->name(),
     382             :                           candidate.fOp->uniqueID());
     383           0 :                 break;
     384             :             }
     385           0 :             if (this->combineIfPossible(fRecordedOps[i], candidate.fOp.get(),
     386           0 :                                         candidate.fAppliedClip, &candidate.fDstTexture)) {
     387             :                 GrOP_INFO("\t\tCombining with (%s, B%u)\n", candidate.fOp->name(),
     388             :                           candidate.fOp->uniqueID());
     389           0 :                 GR_AUDIT_TRAIL_OPS_RESULT_COMBINED(fAuditTrail, op, candidate.fOp.get());
     390           0 :                 fRecordedOps[j].fOp = std::move(fRecordedOps[i].fOp);
     391           0 :                 break;
     392             :             }
     393             :             // Stop going traversing if we would cause a painter's order violation.
     394           0 :             if (!can_reorder(fRecordedOps[j].fOp->bounds(), op->bounds())) {
     395             :                 GrOP_INFO("\t\tIntersects with (%s, B%u)\n", candidate.fOp->name(),
     396             :                           candidate.fOp->uniqueID());
     397           0 :                 break;
     398             :             }
     399           0 :             ++j;
     400           0 :             if (j > maxCandidateIdx) {
     401             :                 GrOP_INFO("\t\tReached max lookahead or end of op array %d\n", i);
     402           0 :                 break;
     403             :             }
     404           0 :         }
     405             :     }
     406             : }
     407             : 

Generated by: LCOV version 1.13