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