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