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