Home | History | Annotate | Download | only in gpu
      1 /*
      2  * Copyright 2016 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 "GrTextureOpList.h"
      9 
     10 #include "GrAuditTrail.h"
     11 #include "GrContext.h"
     12 #include "GrContextPriv.h"
     13 #include "GrGpu.h"
     14 #include "GrMemoryPool.h"
     15 #include "GrRecordingContext.h"
     16 #include "GrRecordingContextPriv.h"
     17 #include "GrResourceAllocator.h"
     18 #include "GrTextureProxy.h"
     19 #include "SkStringUtils.h"
     20 #include "ops/GrCopySurfaceOp.h"
     21 
     22 ////////////////////////////////////////////////////////////////////////////////
     23 
     24 GrTextureOpList::GrTextureOpList(GrResourceProvider* resourceProvider,
     25                                  sk_sp<GrOpMemoryPool> opMemoryPool,
     26                                  GrTextureProxy* proxy,
     27                                  GrAuditTrail* auditTrail)
     28         : INHERITED(resourceProvider, std::move(opMemoryPool), proxy, auditTrail) {
     29     SkASSERT(fOpMemoryPool);
     30     SkASSERT(!proxy->readOnly());
     31 }
     32 
     33 void GrTextureOpList::deleteOp(int index) {
     34     SkASSERT(index >= 0 && index < fRecordedOps.count());
     35     fOpMemoryPool->release(std::move(fRecordedOps[index]));
     36 }
     37 
     38 void GrTextureOpList::deleteOps() {
     39     for (int i = 0; i < fRecordedOps.count(); ++i) {
     40         if (fRecordedOps[i]) {
     41             fOpMemoryPool->release(std::move(fRecordedOps[i]));
     42         }
     43     }
     44     fRecordedOps.reset();
     45     fOpMemoryPool = nullptr;
     46 }
     47 
     48 GrTextureOpList::~GrTextureOpList() {
     49     this->deleteOps();
     50 }
     51 
     52 ////////////////////////////////////////////////////////////////////////////////
     53 
     54 #ifdef SK_DEBUG
     55 void GrTextureOpList::dump(bool printDependencies) const {
     56     INHERITED::dump(printDependencies);
     57 
     58     SkDebugf("ops (%d):\n", fRecordedOps.count());
     59     for (int i = 0; i < fRecordedOps.count(); ++i) {
     60         if (!fRecordedOps[i]) {
     61             SkDebugf("%d: <failed instantiation>\n", i);
     62         } else {
     63             SkDebugf("*******************************\n");
     64             SkDebugf("%d: %s\n", i, fRecordedOps[i]->name());
     65             SkString str = fRecordedOps[i]->dumpInfo();
     66             SkDebugf("%s\n", str.c_str());
     67             const SkRect& clippedBounds = fRecordedOps[i]->bounds();
     68             SkDebugf("ClippedBounds: [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n",
     69                      clippedBounds.fLeft, clippedBounds.fTop, clippedBounds.fRight,
     70                      clippedBounds.fBottom);
     71         }
     72     }
     73 }
     74 
     75 #endif
     76 
     77 void GrTextureOpList::onPrepare(GrOpFlushState* flushState) {
     78     SkASSERT(fTarget.get()->peekTexture());
     79     SkASSERT(this->isClosed());
     80 
     81     // Loop over the ops that haven't yet generated their geometry
     82     for (int i = 0; i < fRecordedOps.count(); ++i) {
     83         if (fRecordedOps[i]) {
     84             SkASSERT(fRecordedOps[i]->isChainHead());
     85             GrOpFlushState::OpArgs opArgs = {
     86                 fRecordedOps[i].get(),
     87                 nullptr,
     88                 nullptr,
     89                 GrXferProcessor::DstProxy()
     90             };
     91             flushState->setOpArgs(&opArgs);
     92             fRecordedOps[i]->prepare(flushState);
     93             flushState->setOpArgs(nullptr);
     94         }
     95     }
     96 }
     97 
     98 bool GrTextureOpList::onExecute(GrOpFlushState* flushState) {
     99     if (0 == fRecordedOps.count()) {
    100         return false;
    101     }
    102 
    103     SkASSERT(fTarget.get()->peekTexture());
    104 
    105     GrGpuTextureCommandBuffer* commandBuffer(
    106                          flushState->gpu()->getCommandBuffer(fTarget.get()->peekTexture(),
    107                                                              fTarget.get()->origin()));
    108     flushState->setCommandBuffer(commandBuffer);
    109 
    110     for (int i = 0; i < fRecordedOps.count(); ++i) {
    111         if (!fRecordedOps[i]) {
    112             continue;
    113         }
    114         SkASSERT(fRecordedOps[i]->isChainHead());
    115         GrOpFlushState::OpArgs opArgs = {
    116             fRecordedOps[i].get(),
    117             nullptr,
    118             nullptr,
    119             GrXferProcessor::DstProxy()
    120         };
    121         flushState->setOpArgs(&opArgs);
    122         fRecordedOps[i]->execute(flushState, fRecordedOps[i].get()->bounds());
    123         flushState->setOpArgs(nullptr);
    124     }
    125 
    126     flushState->gpu()->submit(commandBuffer);
    127     flushState->setCommandBuffer(nullptr);
    128 
    129     return true;
    130 }
    131 
    132 void GrTextureOpList::endFlush() {
    133     this->deleteOps();
    134     INHERITED::endFlush();
    135 }
    136 
    137 ////////////////////////////////////////////////////////////////////////////////
    138 
    139 // This closely parallels GrRenderTargetOpList::copySurface but renderTargetOpList
    140 // stores extra data with the op
    141 bool GrTextureOpList::copySurface(GrRecordingContext* context,
    142                                   GrSurfaceProxy* dst,
    143                                   GrSurfaceProxy* src,
    144                                   const SkIRect& srcRect,
    145                                   const SkIPoint& dstPoint) {
    146     SkASSERT(dst == fTarget.get());
    147 
    148     std::unique_ptr<GrOp> op = GrCopySurfaceOp::Make(context, dst, src, srcRect, dstPoint);
    149     if (!op) {
    150         return false;
    151     }
    152 
    153     const GrCaps* caps = context->priv().caps();
    154     auto addDependency = [ caps, this ] (GrSurfaceProxy* p) {
    155         this->addDependency(p, *caps);
    156     };
    157     op->visitProxies(addDependency);
    158 
    159     this->recordOp(std::move(op));
    160     return true;
    161 }
    162 
    163 void GrTextureOpList::purgeOpsWithUninstantiatedProxies() {
    164     bool hasUninstantiatedProxy = false;
    165     auto checkInstantiation = [&hasUninstantiatedProxy](GrSurfaceProxy* p) {
    166         if (!p->isInstantiated()) {
    167             hasUninstantiatedProxy = true;
    168         }
    169     };
    170     for (int i = 0; i < fRecordedOps.count(); ++i) {
    171         const GrOp* op = fRecordedOps[i].get(); // only diff from the GrRenderTargetOpList version
    172         hasUninstantiatedProxy = false;
    173         if (op) {
    174             op->visitProxies(checkInstantiation);
    175         }
    176         if (hasUninstantiatedProxy) {
    177             // When instantiation of the proxy fails we drop the Op
    178             this->deleteOp(i);
    179         }
    180     }
    181 }
    182 
    183 void GrTextureOpList::gatherProxyIntervals(GrResourceAllocator* alloc) const {
    184     unsigned int cur = alloc->numOps();
    185 
    186     // Add the interval for all the writes to this opList's target
    187     if (fRecordedOps.count()) {
    188         alloc->addInterval(fTarget.get(), cur, cur+fRecordedOps.count()-1);
    189     } else {
    190         // This can happen if there is a loadOp (e.g., a clear) but no other draws. In this case we
    191         // still need to add an interval for the destination so we create a fake op# for
    192         // the missing clear op.
    193         alloc->addInterval(fTarget.get());
    194         alloc->incOps();
    195     }
    196 
    197     auto gather = [ alloc SkDEBUGCODE(, this) ] (GrSurfaceProxy* p) {
    198         alloc->addInterval(p SkDEBUGCODE(, p == fTarget.get()));
    199     };
    200     for (int i = 0; i < fRecordedOps.count(); ++i) {
    201         const GrOp* op = fRecordedOps[i].get(); // only diff from the GrRenderTargetOpList version
    202         if (op) {
    203             op->visitProxies(gather, GrOp::VisitorType::kAllocatorGather);
    204         }
    205 
    206         // Even though the op may have been moved we still need to increment the op count to
    207         // keep all the math consistent.
    208         alloc->incOps();
    209     }
    210 }
    211 
    212 void GrTextureOpList::recordOp(std::unique_ptr<GrOp> op) {
    213     SkASSERT(fTarget.get());
    214     // A closed GrOpList should never receive new/more ops
    215     SkASSERT(!this->isClosed());
    216 
    217     GR_AUDIT_TRAIL_ADD_OP(fAuditTrail, op.get(), fTarget.get()->uniqueID());
    218     GrOP_INFO("Re-Recording (%s, opID: %u)\n"
    219         "\tBounds LRTB (%f, %f, %f, %f)\n",
    220         op->name(),
    221         op->uniqueID(),
    222         op->bounds().fLeft, op->bounds().fRight,
    223         op->bounds().fTop, op->bounds().fBottom);
    224     GrOP_INFO(SkTabString(op->dumpInfo(), 1).c_str());
    225 
    226     fRecordedOps.emplace_back(std::move(op));
    227 }
    228