• 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 "src/gpu/GrTextureOpList.h"
9 
10 #include "include/gpu/GrContext.h"
11 #include "include/private/GrRecordingContext.h"
12 #include "src/core/SkStringUtils.h"
13 #include "src/gpu/GrAuditTrail.h"
14 #include "src/gpu/GrContextPriv.h"
15 #include "src/gpu/GrGpu.h"
16 #include "src/gpu/GrMemoryPool.h"
17 #include "src/gpu/GrRecordingContextPriv.h"
18 #include "src/gpu/GrResourceAllocator.h"
19 #include "src/gpu/GrTexturePriv.h"
20 #include "src/gpu/GrTextureProxy.h"
21 #include "src/gpu/ops/GrCopySurfaceOp.h"
22 #include "src/gpu/ops/GrTransferFromOp.h"
23 
24 ////////////////////////////////////////////////////////////////////////////////
25 
GrTextureOpList(sk_sp<GrOpMemoryPool> opMemoryPool,sk_sp<GrTextureProxy> proxy,GrAuditTrail * auditTrail)26 GrTextureOpList::GrTextureOpList(sk_sp<GrOpMemoryPool> opMemoryPool,
27                                  sk_sp<GrTextureProxy> proxy,
28                                  GrAuditTrail* auditTrail)
29         : INHERITED(std::move(opMemoryPool), proxy, auditTrail) {
30     SkASSERT(fOpMemoryPool);
31     SkASSERT(!proxy->readOnly());
32     if (GrMipMapped::kYes == proxy->mipMapped()) {
33         proxy->markMipMapsDirty();
34     }
35     fTarget->setLastRenderTask(this);
36 }
37 
deleteOp(int index)38 void GrTextureOpList::deleteOp(int index) {
39     SkASSERT(index >= 0 && index < fRecordedOps.count());
40     fOpMemoryPool->release(std::move(fRecordedOps[index]));
41 }
42 
deleteOps()43 void GrTextureOpList::deleteOps() {
44     for (int i = 0; i < fRecordedOps.count(); ++i) {
45         if (fRecordedOps[i]) {
46             fOpMemoryPool->release(std::move(fRecordedOps[i]));
47         }
48     }
49     fRecordedOps.reset();
50     fOpMemoryPool = nullptr;
51 }
52 
~GrTextureOpList()53 GrTextureOpList::~GrTextureOpList() {
54     this->deleteOps();
55 }
56 
57 ////////////////////////////////////////////////////////////////////////////////
58 
59 #ifdef SK_DEBUG
dump(bool printDependencies) const60 void GrTextureOpList::dump(bool printDependencies) const {
61     INHERITED::dump(printDependencies);
62 
63     SkDebugf("ops (%d):\n", fRecordedOps.count());
64     for (int i = 0; i < fRecordedOps.count(); ++i) {
65         if (!fRecordedOps[i]) {
66             SkDebugf("%d: <failed instantiation>\n", i);
67         } else {
68             SkDebugf("*******************************\n");
69             SkDebugf("%d: %s\n", i, fRecordedOps[i]->name());
70             SkString str = fRecordedOps[i]->dumpInfo();
71             SkDebugf("%s\n", str.c_str());
72             const SkRect& clippedBounds = fRecordedOps[i]->bounds();
73             SkDebugf("ClippedBounds: [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n",
74                      clippedBounds.fLeft, clippedBounds.fTop, clippedBounds.fRight,
75                      clippedBounds.fBottom);
76         }
77     }
78 }
79 
80 #endif
81 
onPrepare(GrOpFlushState * flushState)82 void GrTextureOpList::onPrepare(GrOpFlushState* flushState) {
83     SkASSERT(fTarget->peekTexture());
84     SkASSERT(this->isClosed());
85 
86     // Loop over the ops that haven't yet generated their geometry
87     for (int i = 0; i < fRecordedOps.count(); ++i) {
88         if (fRecordedOps[i]) {
89             SkASSERT(fRecordedOps[i]->isChainHead());
90             GrOpFlushState::OpArgs opArgs = {
91                 fRecordedOps[i].get(),
92                 nullptr,
93                 nullptr,
94                 GrSwizzle(),
95                 GrXferProcessor::DstProxy()
96             };
97             flushState->setOpArgs(&opArgs);
98             fRecordedOps[i]->prepare(flushState);
99             flushState->setOpArgs(nullptr);
100         }
101     }
102 }
103 
onExecute(GrOpFlushState * flushState)104 bool GrTextureOpList::onExecute(GrOpFlushState* flushState) {
105     if (0 == fRecordedOps.count()) {
106         // TEMPORARY: We are in the process of moving GrMipMapsStatus from the texture to the proxy.
107         // During this time we want to assert that the proxy resolves mipmaps at the exact same
108         // times the old code would have. A null opList is very exceptional, and the proxy will have
109         // assumed mipmaps are dirty in this scenario. We mark them dirty here on the texture as
110         // well, in order to keep the assert passing.
111         GrTexture* tex = fTarget->peekTexture();
112         if (tex && GrMipMapped::kYes == tex->texturePriv().mipMapped()) {
113             tex->texturePriv().markMipMapsDirty();
114         }
115         return false;
116     }
117 
118     SkASSERT(fTarget->peekTexture());
119 
120     GrGpuTextureCommandBuffer* commandBuffer(
121                          flushState->gpu()->getCommandBuffer(fTarget->peekTexture(),
122                                                              fTarget->origin()));
123     flushState->setCommandBuffer(commandBuffer);
124 
125     for (int i = 0; i < fRecordedOps.count(); ++i) {
126         if (!fRecordedOps[i]) {
127             continue;
128         }
129         SkASSERT(fRecordedOps[i]->isChainHead());
130         GrOpFlushState::OpArgs opArgs = {
131             fRecordedOps[i].get(),
132             nullptr,
133             nullptr,
134             GrSwizzle(),
135             GrXferProcessor::DstProxy()
136         };
137         flushState->setOpArgs(&opArgs);
138         fRecordedOps[i]->execute(flushState, fRecordedOps[i].get()->bounds());
139         flushState->setOpArgs(nullptr);
140     }
141 
142     flushState->gpu()->submit(commandBuffer);
143     flushState->setCommandBuffer(nullptr);
144 
145     return true;
146 }
147 
endFlush()148 void GrTextureOpList::endFlush() {
149     this->deleteOps();
150     INHERITED::endFlush();
151 }
152 
153 ////////////////////////////////////////////////////////////////////////////////
154 
155 // This closely parallels GrRenderTargetOpList::copySurface but renderTargetOpList
156 // stores extra data with the op
copySurface(GrRecordingContext * context,GrSurfaceProxy * src,const SkIRect & srcRect,const SkIPoint & dstPoint)157 bool GrTextureOpList::copySurface(GrRecordingContext* context,
158                                   GrSurfaceProxy* src,
159                                   const SkIRect& srcRect,
160                                   const SkIPoint& dstPoint) {
161     std::unique_ptr<GrOp> op = GrCopySurfaceOp::Make(
162             context, fTarget.get(), src, srcRect, dstPoint);
163     if (!op) {
164         return false;
165     }
166 
167     GrTextureResolveManager textureResolveManager(context->priv().drawingManager());
168     const GrCaps* caps = context->priv().caps();
169     auto addDependency = [ textureResolveManager, caps, this ] (
170             GrSurfaceProxy* p, GrMipMapped mipmapped) {
171         this->addDependency(p, mipmapped, textureResolveManager, *caps);
172     };
173     op->visitProxies(addDependency);
174 
175     this->recordOp(std::move(op));
176     return true;
177 }
178 
transferFrom(GrRecordingContext * context,const SkIRect & srcRect,GrColorType surfaceColorType,GrColorType dstColorType,sk_sp<GrGpuBuffer> dst,size_t dstOffset)179 void GrTextureOpList::transferFrom(GrRecordingContext* context,
180                                    const SkIRect& srcRect,
181                                    GrColorType surfaceColorType,
182                                    GrColorType dstColorType,
183                                    sk_sp<GrGpuBuffer> dst,
184                                    size_t dstOffset) {
185     auto op = GrTransferFromOp::Make(context, srcRect, surfaceColorType, dstColorType,
186                                      std::move(dst), dstOffset);
187     this->recordOp(std::move(op));
188 }
189 
handleInternalAllocationFailure()190 void GrTextureOpList::handleInternalAllocationFailure() {
191     bool hasUninstantiatedProxy = false;
192     auto checkInstantiation = [&hasUninstantiatedProxy](GrSurfaceProxy* p, GrMipMapped) {
193         if (!p->isInstantiated()) {
194             hasUninstantiatedProxy = true;
195         }
196     };
197     for (int i = 0; i < fRecordedOps.count(); ++i) {
198         const GrOp* op = fRecordedOps[i].get(); // only diff from the GrRenderTargetOpList version
199         hasUninstantiatedProxy = false;
200         if (op) {
201             op->visitProxies(checkInstantiation);
202         }
203         if (hasUninstantiatedProxy) {
204             // When instantiation of the proxy fails we drop the Op
205             this->deleteOp(i);
206         }
207     }
208 }
209 
onIsUsed(GrSurfaceProxy * proxyToCheck) const210 bool GrTextureOpList::onIsUsed(GrSurfaceProxy* proxyToCheck) const {
211     bool used = false;
212 
213     auto visit = [ proxyToCheck, &used ] (GrSurfaceProxy* p, GrMipMapped) {
214         if (p == proxyToCheck) {
215             used = true;
216         }
217     };
218     for (int i = 0; i < fRecordedOps.count(); ++i) {
219         const GrOp* op = fRecordedOps[i].get();
220         if (op) {
221             op->visitProxies(visit);
222         }
223     }
224 
225     return used;
226 }
227 
gatherProxyIntervals(GrResourceAllocator * alloc) const228 void GrTextureOpList::gatherProxyIntervals(GrResourceAllocator* alloc) const {
229 
230     // Add the interval for all the writes to this opList's target
231     if (fRecordedOps.count()) {
232         unsigned int cur = alloc->curOp();
233 
234         alloc->addInterval(fTarget.get(), cur, cur+fRecordedOps.count()-1,
235                            GrResourceAllocator::ActualUse::kYes);
236     } else {
237         // This can happen if there is a loadOp (e.g., a clear) but no other draws. In this case we
238         // still need to add an interval for the destination so we create a fake op# for
239         // the missing clear op.
240         alloc->addInterval(fTarget.get(), alloc->curOp(), alloc->curOp(),
241                            GrResourceAllocator::ActualUse::kYes);
242         alloc->incOps();
243     }
244 
245     auto gather = [ alloc SkDEBUGCODE(, this) ] (GrSurfaceProxy* p, GrMipMapped) {
246         alloc->addInterval(p, alloc->curOp(), alloc->curOp(), GrResourceAllocator::ActualUse::kYes
247                            SkDEBUGCODE(, p == fTarget.get()));
248     };
249     for (int i = 0; i < fRecordedOps.count(); ++i) {
250         const GrOp* op = fRecordedOps[i].get(); // only diff from the GrRenderTargetOpList version
251         if (op) {
252             op->visitProxies(gather);
253         }
254 
255         // Even though the op may have been (re)moved we still need to increment the op count to
256         // keep all the math consistent.
257         alloc->incOps();
258     }
259 }
260 
recordOp(std::unique_ptr<GrOp> op)261 void GrTextureOpList::recordOp(std::unique_ptr<GrOp> op) {
262     SkASSERT(fTarget);
263     // A closed GrOpList should never receive new/more ops
264     SkASSERT(!this->isClosed());
265 
266     GR_AUDIT_TRAIL_ADD_OP(fAuditTrail, op.get(), fTarget->uniqueID());
267     GrOP_INFO("Re-Recording (%s, opID: %u)\n"
268         "\tBounds LRTB (%f, %f, %f, %f)\n",
269         op->name(),
270         op->uniqueID(),
271         op->bounds().fLeft, op->bounds().fRight,
272         op->bounds().fTop, op->bounds().fBottom);
273     GrOP_INFO(SkTabString(op->dumpInfo(), 1).c_str());
274 
275     fRecordedOps.emplace_back(std::move(op));
276 }
277