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