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