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