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
GrTextureOpList(GrResourceProvider * resourceProvider,sk_sp<GrOpMemoryPool> opMemoryPool,GrTextureProxy * proxy,GrAuditTrail * auditTrail)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
deleteOp(int index)31 void GrTextureOpList::deleteOp(int index) {
32 SkASSERT(index >= 0 && index < fRecordedOps.count());
33 fOpMemoryPool->release(std::move(fRecordedOps[index]));
34 }
35
deleteOps()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
~GrTextureOpList()46 GrTextureOpList::~GrTextureOpList() {
47 this->deleteOps();
48 }
49
50 ////////////////////////////////////////////////////////////////////////////////
51
52 #ifdef SK_DEBUG
dump(bool printDependencies) const53 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
onPrepare(GrOpFlushState * flushState)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
onExecute(GrOpFlushState * flushState)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
endFlush()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
copySurface(GrContext * context,GrSurfaceProxy * dst,GrSurfaceProxy * src,const SkIRect & srcRect,const SkIPoint & dstPoint)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
purgeOpsWithUninstantiatedProxies()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
gatherProxyIntervals(GrResourceAllocator * alloc) const181 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
recordOp(std::unique_ptr<GrOp> op)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