• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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