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