blob: 6ca4936fcdf63af6af9d807516883b972ae0f20d [file] [log] [blame]
reed@google.comac10a2d2010-12-22 21:39:39 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2010 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.
reed@google.comac10a2d2010-12-22 21:39:39 +00006 */
7
Robert Phillipsf2361d22016-10-25 14:20:06 -04008#include "GrRenderTargetOpList.h"
joshualitt086cee12016-01-12 06:45:24 -08009#include "GrAuditTrail.h"
bsalomoneb1cb5c2015-05-22 08:01:09 -070010#include "GrCaps.h"
bsalomon4061b122015-05-29 10:26:19 -070011#include "GrGpu.h"
egdaniel9cb63402016-06-23 08:37:05 -070012#include "GrGpuCommandBuffer.h"
Robert Phillips7c525e62018-06-12 10:11:12 -040013#include "GrMemoryPool.h"
Brian Salomona4677b52017-05-04 12:39:56 -040014#include "GrRect.h"
Brian Salomon467921e2017-03-06 16:17:12 -050015#include "GrRenderTargetContext.h"
Robert Phillipsd375dbf2017-09-14 12:45:25 -040016#include "GrResourceAllocator.h"
Brian Salomon89527432016-12-16 09:52:16 -050017#include "ops/GrClearOp.h"
Brian Salomon89527432016-12-16 09:52:16 -050018#include "ops/GrCopySurfaceOp.h"
Stan Iliev2af578d2017-08-16 13:00:28 -040019#include "SkTraceEvent.h"
csmartdaltona7f29642016-07-07 08:49:11 -070020
Robert Phillipsf2361d22016-10-25 14:20:06 -040021
reed@google.comac10a2d2010-12-22 21:39:39 +000022////////////////////////////////////////////////////////////////////////////////
23
Brian Salomon09d994e2016-12-21 11:14:46 -050024// Experimentally we have found that most combining occurs within the first 10 comparisons.
Robert Phillips8185f592017-04-26 08:31:08 -040025static const int kMaxOpLookback = 10;
26static const int kMaxOpLookahead = 10;
bsalomon489147c2015-12-14 12:13:09 -080027
Robert Phillips3a9710b2018-03-27 17:51:55 -040028GrRenderTargetOpList::GrRenderTargetOpList(GrResourceProvider* resourceProvider,
Robert Phillipsc994a932018-06-19 13:09:54 -040029 sk_sp<GrOpMemoryPool> opMemoryPool,
Robert Phillips3a9710b2018-03-27 17:51:55 -040030 GrRenderTargetProxy* proxy,
Robert Phillips8185f592017-04-26 08:31:08 -040031 GrAuditTrail* auditTrail)
Robert Phillipsc994a932018-06-19 13:09:54 -040032 : INHERITED(resourceProvider, std::move(opMemoryPool), proxy, auditTrail)
Brian Salomonc3833b42018-07-09 18:23:58 +000033 , fLastClipStackGenID(SK_InvalidUniqueID)
Robert Phillipsb6deea82017-05-11 14:14:30 -040034 SkDEBUGCODE(, fNumClips(0)) {
bsalomon4061b122015-05-29 10:26:19 -070035}
36
Robert Phillipsc994a932018-06-19 13:09:54 -040037void GrRenderTargetOpList::RecordedOp::deleteOp(GrOpMemoryPool* opMemoryPool) {
38 opMemoryPool->release(std::move(fOp));
39}
40
41void GrRenderTargetOpList::deleteOps() {
42 for (int i = 0; i < fRecordedOps.count(); ++i) {
43 if (fRecordedOps[i].fOp) {
44 fRecordedOps[i].deleteOp(fOpMemoryPool.get());
45 }
46 }
47 fRecordedOps.reset();
48}
49
Robert Phillipsf2361d22016-10-25 14:20:06 -040050GrRenderTargetOpList::~GrRenderTargetOpList() {
Robert Phillipsc994a932018-06-19 13:09:54 -040051 this->deleteOps();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +000052}
53
54////////////////////////////////////////////////////////////////////////////////
55
robertphillips4beb5c12015-10-20 07:50:00 -070056#ifdef SK_DEBUG
Robert Phillips27483912018-04-20 12:43:18 -040057void GrRenderTargetOpList::dump(bool printDependencies) const {
58 INHERITED::dump(printDependencies);
Robert Phillipsf2361d22016-10-25 14:20:06 -040059
Brian Salomon1e41f4a2016-12-07 15:05:04 -050060 SkDebugf("ops (%d):\n", fRecordedOps.count());
61 for (int i = 0; i < fRecordedOps.count(); ++i) {
robertphillips4beb5c12015-10-20 07:50:00 -070062 SkDebugf("*******************************\n");
Brian Salomon1e41f4a2016-12-07 15:05:04 -050063 if (!fRecordedOps[i].fOp) {
Greg Danielaa3dfbe2018-01-29 10:34:25 -050064 SkDebugf("%d: <combined forward or failed instantiation>\n", i);
bsalomonaecc0182016-03-07 11:50:44 -080065 } else {
Brian Salomon1e41f4a2016-12-07 15:05:04 -050066 SkDebugf("%d: %s\n", i, fRecordedOps[i].fOp->name());
67 SkString str = fRecordedOps[i].fOp->dumpInfo();
bsalomonaecc0182016-03-07 11:50:44 -080068 SkDebugf("%s\n", str.c_str());
Brian Salomon9e50f7b2017-03-06 12:02:34 -050069 const SkRect& bounds = fRecordedOps[i].fOp->bounds();
70 SkDebugf("ClippedBounds: [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", bounds.fLeft,
71 bounds.fTop, bounds.fRight, bounds.fBottom);
bsalomonaecc0182016-03-07 11:50:44 -080072 }
robertphillips4beb5c12015-10-20 07:50:00 -070073 }
74}
Chris Dalton706a6ff2017-11-29 22:01:06 -070075
76void GrRenderTargetOpList::visitProxies_debugOnly(const GrOp::VisitProxyFunc& func) const {
77 for (const RecordedOp& recordedOp : fRecordedOps) {
78 recordedOp.visitProxies(func);
79 }
80}
Brian Salomonc525d4f2018-09-17 15:48:20 -040081
82static void assert_chain_bounds(const GrOp* op) {
83 SkASSERT(op->isChainHead());
84 auto headBounds = op->bounds();
85 while ((op = op->nextInChain())) {
86 SkASSERT(headBounds.contains(op->bounds()));
87 }
88}
robertphillips4beb5c12015-10-20 07:50:00 -070089#endif
90
Brian Osman407b3422017-08-22 15:01:32 -040091void GrRenderTargetOpList::onPrepare(GrOpFlushState* flushState) {
Brian Salomonfd98c2c2018-07-31 17:25:29 -040092 SkASSERT(fTarget.get()->peekRenderTarget());
Robert Phillips6cdc22c2017-05-11 16:29:14 -040093 SkASSERT(this->isClosed());
Stan Iliev2af578d2017-08-16 13:00:28 -040094#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
95 TRACE_EVENT0("skia", TRACE_FUNC);
96#endif
robertphillipsa106c622015-10-16 09:07:06 -070097
Brian Salomon1e41f4a2016-12-07 15:05:04 -050098 // Loop over the ops that haven't yet been prepared.
99 for (int i = 0; i < fRecordedOps.count(); ++i) {
Brian Salomond25f5bc2018-08-08 11:25:17 -0400100 if (fRecordedOps[i].fOp && fRecordedOps[i].fOp->isChainHead()) {
Stan Iliev2af578d2017-08-16 13:00:28 -0400101#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
102 TRACE_EVENT0("skia", fRecordedOps[i].fOp->name());
103#endif
Brian Salomon29b60c92017-10-31 14:42:10 -0400104 GrOpFlushState::OpArgs opArgs = {
105 fRecordedOps[i].fOp.get(),
Robert Phillips2890fbf2017-07-26 15:48:41 -0400106 fTarget.get()->asRenderTargetProxy(),
Robert Phillips318c4192017-05-17 09:36:38 -0400107 fRecordedOps[i].fAppliedClip,
Robert Phillipsbb581ce2017-05-29 15:05:15 -0400108 fRecordedOps[i].fDstProxy
Robert Phillips318c4192017-05-17 09:36:38 -0400109 };
Brian Salomonc525d4f2018-09-17 15:48:20 -0400110 SkDEBUGCODE(assert_chain_bounds(opArgs.fOp));
Brian Salomon29b60c92017-10-31 14:42:10 -0400111 flushState->setOpArgs(&opArgs);
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500112 fRecordedOps[i].fOp->prepare(flushState);
Brian Salomon29b60c92017-10-31 14:42:10 -0400113 flushState->setOpArgs(nullptr);
bsalomonaecc0182016-03-07 11:50:44 -0800114 }
bsalomon512be532015-09-10 10:42:55 -0700115 }
robertphillipsa13e2022015-11-11 12:01:09 -0800116}
bsalomon512be532015-09-10 10:42:55 -0700117
Robert Phillips5b5d84c2018-08-09 15:12:18 -0400118static GrGpuRTCommandBuffer* create_command_buffer(GrGpu* gpu,
119 GrRenderTarget* rt,
120 GrSurfaceOrigin origin,
121 GrLoadOp colorLoadOp,
122 GrColor loadClearColor,
123 GrLoadOp stencilLoadOp) {
Robert Phillipscb2e2352017-08-30 16:44:40 -0400124 const GrGpuRTCommandBuffer::LoadAndStoreInfo kColorLoadStoreInfo {
Robert Phillips6b47c7d2017-08-29 07:24:09 -0400125 colorLoadOp,
126 GrStoreOp::kStore,
127 loadClearColor
Robert Phillips178ce3e2017-04-13 09:15:47 -0400128 };
129
Robert Phillips95214472017-08-08 18:00:03 -0400130 // TODO:
131 // We would like to (at this level) only ever clear & discard. We would need
132 // to stop splitting up higher level opLists for copyOps to achieve that.
133 // Note: we would still need SB loads and stores but they would happen at a
134 // lower level (inside the VK command buffer).
Greg Daniel500d58b2017-08-24 15:59:33 -0400135 const GrGpuRTCommandBuffer::StencilLoadAndStoreInfo stencilLoadAndStoreInfo {
Robert Phillips6b47c7d2017-08-29 07:24:09 -0400136 stencilLoadOp,
137 GrStoreOp::kStore,
Robert Phillips95214472017-08-08 18:00:03 -0400138 };
139
Robert Phillips5b5d84c2018-08-09 15:12:18 -0400140 return gpu->getCommandBuffer(rt, origin, kColorLoadStoreInfo, stencilLoadAndStoreInfo);
Robert Phillips178ce3e2017-04-13 09:15:47 -0400141}
142
Brian Salomon25a88092016-12-01 09:36:50 -0500143// TODO: this is where GrOp::renderTarget is used (which is fine since it
Robert Phillips294870f2016-11-11 12:38:40 -0500144// is at flush time). However, we need to store the RenderTargetProxy in the
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500145// Ops and instantiate them here.
Brian Osman407b3422017-08-22 15:01:32 -0400146bool GrRenderTargetOpList::onExecute(GrOpFlushState* flushState) {
Greg Danieldbdba602018-04-20 11:52:43 -0400147 // TODO: Forcing the execution of the discard here isn't ideal since it will cause us to do a
148 // discard and then store the data back in memory so that the load op on future draws doesn't
149 // think the memory is unitialized. Ideally we would want a system where we are tracking whether
150 // the proxy itself has valid data or not, and then use that as a signal on whether we should be
151 // loading or discarding. In that world we wouldni;t need to worry about executing oplists with
152 // no ops just to do a discard.
153 if (0 == fRecordedOps.count() && GrLoadOp::kClear != fColorLoadOp &&
154 GrLoadOp::kDiscard != fColorLoadOp) {
bsalomondc438982016-08-31 11:53:49 -0700155 return false;
egdanielb4021cf2016-07-28 08:53:07 -0700156 }
Robert Phillips4a395042017-04-24 16:27:17 +0000157
Brian Salomonfd98c2c2018-07-31 17:25:29 -0400158 SkASSERT(fTarget.get()->peekRenderTarget());
Stan Iliev2af578d2017-08-16 13:00:28 -0400159 TRACE_EVENT0("skia", TRACE_FUNC);
Robert Phillips6cdc22c2017-05-11 16:29:14 -0400160
Robert Phillips6b47c7d2017-08-29 07:24:09 -0400161 // TODO: at the very least, we want the stencil store op to always be discard (at this
162 // level). In Vulkan, sub-command buffers would still need to load & store the stencil buffer.
Robert Phillips5b5d84c2018-08-09 15:12:18 -0400163 GrGpuRTCommandBuffer* commandBuffer = create_command_buffer(
Robert Phillips95214472017-08-08 18:00:03 -0400164 flushState->gpu(),
Brian Salomonfd98c2c2018-07-31 17:25:29 -0400165 fTarget.get()->peekRenderTarget(),
Robert Phillips95214472017-08-08 18:00:03 -0400166 fTarget.get()->origin(),
Brian Salomonfd98c2c2018-07-31 17:25:29 -0400167 fColorLoadOp,
168 fLoadClearColor,
Robert Phillips6b47c7d2017-08-29 07:24:09 -0400169 fStencilLoadOp);
Robert Phillips5b5d84c2018-08-09 15:12:18 -0400170 flushState->setCommandBuffer(commandBuffer);
Robert Phillips95214472017-08-08 18:00:03 -0400171 commandBuffer->begin();
Robert Phillips6cdc22c2017-05-11 16:29:14 -0400172
173 // Draw all the generated geometry.
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500174 for (int i = 0; i < fRecordedOps.count(); ++i) {
Brian Salomond25f5bc2018-08-08 11:25:17 -0400175 if (!fRecordedOps[i].fOp || !fRecordedOps[i].fOp->isChainHead()) {
bsalomonaecc0182016-03-07 11:50:44 -0800176 continue;
177 }
Stan Iliev2af578d2017-08-16 13:00:28 -0400178#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
179 TRACE_EVENT0("skia", fRecordedOps[i].fOp->name());
180#endif
Robert Phillips178ce3e2017-04-13 09:15:47 -0400181
Brian Salomon29b60c92017-10-31 14:42:10 -0400182 GrOpFlushState::OpArgs opArgs {
183 fRecordedOps[i].fOp.get(),
Robert Phillips2890fbf2017-07-26 15:48:41 -0400184 fTarget.get()->asRenderTargetProxy(),
Robert Phillips178ce3e2017-04-13 09:15:47 -0400185 fRecordedOps[i].fAppliedClip,
Robert Phillipsbb581ce2017-05-29 15:05:15 -0400186 fRecordedOps[i].fDstProxy
Robert Phillips178ce3e2017-04-13 09:15:47 -0400187 };
188
Brian Salomon29b60c92017-10-31 14:42:10 -0400189 flushState->setOpArgs(&opArgs);
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500190 fRecordedOps[i].fOp->execute(flushState);
Brian Salomon29b60c92017-10-31 14:42:10 -0400191 flushState->setOpArgs(nullptr);
bsalomon512be532015-09-10 10:42:55 -0700192 }
Robert Phillips178ce3e2017-04-13 09:15:47 -0400193
Robert Phillips5b5d84c2018-08-09 15:12:18 -0400194 commandBuffer->end();
195 flushState->gpu()->submit(commandBuffer);
Robert Phillips178ce3e2017-04-13 09:15:47 -0400196 flushState->setCommandBuffer(nullptr);
ethannicholas22793252016-01-30 09:59:10 -0800197
bsalomondc438982016-08-31 11:53:49 -0700198 return true;
bsalomona73239a2015-04-28 13:35:17 -0700199}
200
Chris Daltona84cacf2017-10-04 10:30:29 -0600201void GrRenderTargetOpList::endFlush() {
Brian Salomonc3833b42018-07-09 18:23:58 +0000202 fLastClipStackGenID = SK_InvalidUniqueID;
Robert Phillipsc994a932018-06-19 13:09:54 -0400203 this->deleteOps();
Chris Daltonc82dd4e2017-11-20 18:20:28 -0700204 fClipAllocator.reset();
Chris Daltona84cacf2017-10-04 10:30:29 -0600205 INHERITED::endFlush();
bsalomon512be532015-09-10 10:42:55 -0700206}
207
Robert Phillips380b90c2017-08-30 07:41:07 -0400208void GrRenderTargetOpList::discard() {
209 // Discard calls to in-progress opLists are ignored. Calls at the start update the
210 // opLists' color & stencil load ops.
211 if (this->isEmpty()) {
212 fColorLoadOp = GrLoadOp::kDiscard;
213 fStencilLoadOp = GrLoadOp::kDiscard;
214 }
215}
216
Robert Phillips7c525e62018-06-12 10:11:12 -0400217void GrRenderTargetOpList::fullClear(GrContext* context, GrColor color) {
Robert Phillips380b90c2017-08-30 07:41:07 -0400218
219 // This is conservative. If the opList is marked as needing a stencil buffer then there
220 // may be a prior op that writes to the stencil buffer. Although the clear will ignore the
221 // stencil buffer, following draw ops may not so we can't get rid of all the preceding ops.
222 // Beware! If we ever add any ops that have a side effect beyond modifying the stencil
223 // buffer we will need a more elaborate tracking system (skbug.com/7002).
224 if (this->isEmpty() || !fTarget.get()->asRenderTargetProxy()->needsStencil()) {
Robert Phillipsc994a932018-06-19 13:09:54 -0400225 this->deleteOps();
Brian Osman099fa0f2017-10-02 16:38:32 -0400226 fDeferredProxies.reset();
Robert Phillips380b90c2017-08-30 07:41:07 -0400227 fColorLoadOp = GrLoadOp::kClear;
228 fLoadClearColor = color;
bsalomonfd8d0132016-08-11 11:25:33 -0700229 return;
230 }
Robert Phillips380b90c2017-08-30 07:41:07 -0400231
Robert Phillips7c525e62018-06-12 10:11:12 -0400232 std::unique_ptr<GrClearOp> op(GrClearOp::Make(context, GrFixedClip::Disabled(),
233 color, fTarget.get()));
Robert Phillipsf7a72612017-03-31 10:03:45 -0400234 if (!op) {
235 return;
236 }
Robert Phillips5efd5ea2017-05-30 13:47:32 -0400237
Robert Phillips7c525e62018-06-12 10:11:12 -0400238 this->recordOp(std::move(op), *context->contextPriv().caps());
bsalomon9f129de2016-08-10 16:31:05 -0700239}
240
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000241////////////////////////////////////////////////////////////////////////////////
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000242
Robert Phillips81dd3e02017-06-23 11:59:24 -0400243// This closely parallels GrTextureOpList::copySurface but renderTargetOpLists
244// also store the applied clip and dest proxy with the op
Robert Phillips7c525e62018-06-12 10:11:12 -0400245bool GrRenderTargetOpList::copySurface(GrContext* context,
Robert Phillipsa16f6cb2017-06-01 11:06:13 -0400246 GrSurfaceProxy* dst,
Robert Phillipsbf25d432017-04-07 10:08:53 -0400247 GrSurfaceProxy* src,
Robert Phillipsf2361d22016-10-25 14:20:06 -0400248 const SkIRect& srcRect,
249 const SkIPoint& dstPoint) {
Robert Phillips5efd5ea2017-05-30 13:47:32 -0400250 SkASSERT(dst->asRenderTargetProxy() == fTarget.get());
Robert Phillips7c525e62018-06-12 10:11:12 -0400251 std::unique_ptr<GrOp> op = GrCopySurfaceOp::Make(context, dst, src, srcRect, dstPoint);
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500252 if (!op) {
bsalomonb8fea972016-02-16 07:34:17 -0800253 return false;
254 }
robertphillips498d7ac2015-10-30 10:11:30 -0700255
Robert Phillips7c525e62018-06-12 10:11:12 -0400256 this->addOp(std::move(op), *context->contextPriv().caps());
bsalomonb8fea972016-02-16 07:34:17 -0800257 return true;
bsalomon@google.comeb851172013-04-15 13:51:00 +0000258}
259
Greg Danielaa3dfbe2018-01-29 10:34:25 -0500260void GrRenderTargetOpList::purgeOpsWithUninstantiatedProxies() {
261 bool hasUninstantiatedProxy = false;
Brian Salomonfd98c2c2018-07-31 17:25:29 -0400262 auto checkInstantiation = [&hasUninstantiatedProxy](GrSurfaceProxy* p) {
263 if (!p->isInstantiated()) {
Greg Danielaa3dfbe2018-01-29 10:34:25 -0500264 hasUninstantiatedProxy = true;
265 }
266 };
267 for (RecordedOp& recordedOp : fRecordedOps) {
268 hasUninstantiatedProxy = false;
Robert Phillipsed1205a2018-07-13 11:44:53 -0400269 if (recordedOp.fOp) {
270 recordedOp.visitProxies(checkInstantiation);
271 }
Greg Danielaa3dfbe2018-01-29 10:34:25 -0500272 if (hasUninstantiatedProxy) {
273 // When instantiation of the proxy fails we drop the Op
Robert Phillipsc994a932018-06-19 13:09:54 -0400274 recordedOp.deleteOp(fOpMemoryPool.get());
Greg Danielaa3dfbe2018-01-29 10:34:25 -0500275 }
276 }
277}
278
Robert Phillipsd375dbf2017-09-14 12:45:25 -0400279void GrRenderTargetOpList::gatherProxyIntervals(GrResourceAllocator* alloc) const {
280 unsigned int cur = alloc->numOps();
281
Robert Phillips51b20f22017-12-01 15:32:35 -0500282 for (int i = 0; i < fDeferredProxies.count(); ++i) {
Brian Salomonfd98c2c2018-07-31 17:25:29 -0400283 SkASSERT(!fDeferredProxies[i]->isInstantiated());
Robert Phillips51b20f22017-12-01 15:32:35 -0500284 // We give all the deferred proxies a write usage at the very start of flushing. This
285 // locks them out of being reused for the entire flush until they are read - and then
286 // they can be recycled. This is a bit unfortunate because a flush can proceed in waves
287 // with sub-flushes. The deferred proxies only need to be pinned from the start of
288 // the sub-flush in which they appear.
289 alloc->addInterval(fDeferredProxies[i], 0, 0);
290 }
291
Robert Phillipsd375dbf2017-09-14 12:45:25 -0400292 // Add the interval for all the writes to this opList's target
Robert Phillipsf8e25022017-11-08 15:24:31 -0500293 if (fRecordedOps.count()) {
294 alloc->addInterval(fTarget.get(), cur, cur+fRecordedOps.count()-1);
295 } else {
296 // This can happen if there is a loadOp (e.g., a clear) but no other draws. In this case we
297 // still need to add an interval for the destination so we create a fake op# for
298 // the missing clear op.
299 alloc->addInterval(fTarget.get());
300 alloc->incOps();
301 }
Robert Phillipsd375dbf2017-09-14 12:45:25 -0400302
Chris Dalton8816b932017-11-29 16:48:25 -0700303 auto gather = [ alloc SkDEBUGCODE(, this) ] (GrSurfaceProxy* p) {
304 alloc->addInterval(p SkDEBUGCODE(, fTarget.get() == p));
Robert Phillipsd375dbf2017-09-14 12:45:25 -0400305 };
Chris Dalton8816b932017-11-29 16:48:25 -0700306 for (const RecordedOp& recordedOp : fRecordedOps) {
307 recordedOp.visitProxies(gather); // only diff from the GrTextureOpList version
Robert Phillipsf8e25022017-11-08 15:24:31 -0500308
309 // Even though the op may have been moved we still need to increment the op count to
310 // keep all the math consistent.
311 alloc->incOps();
Robert Phillipsd375dbf2017-09-14 12:45:25 -0400312 }
313}
314
Brian Salomona4677b52017-05-04 12:39:56 -0400315static inline bool can_reorder(const SkRect& a, const SkRect& b) { return !GrRectsOverlap(a, b); }
bsalomon88cf17d2016-07-08 06:40:56 -0700316
Brian Salomond25f5bc2018-08-08 11:25:17 -0400317GrOp::CombineResult GrRenderTargetOpList::combineIfPossible(const RecordedOp& a, GrOp* b,
318 const GrAppliedClip* bClip,
319 const DstProxy* bDstProxy,
320 const GrCaps& caps) {
Brian Salomon54d212e2017-03-21 14:22:38 -0400321 if (a.fAppliedClip) {
322 if (!bClip) {
Brian Salomond25f5bc2018-08-08 11:25:17 -0400323 return GrOp::CombineResult::kCannotCombine;
Brian Salomon54d212e2017-03-21 14:22:38 -0400324 }
325 if (*a.fAppliedClip != *bClip) {
Brian Salomond25f5bc2018-08-08 11:25:17 -0400326 return GrOp::CombineResult::kCannotCombine;
Brian Salomon54d212e2017-03-21 14:22:38 -0400327 }
328 } else if (bClip) {
Brian Salomond25f5bc2018-08-08 11:25:17 -0400329 return GrOp::CombineResult::kCannotCombine;
Brian Salomon54d212e2017-03-21 14:22:38 -0400330 }
Robert Phillipsbb581ce2017-05-29 15:05:15 -0400331 if (bDstProxy) {
332 if (a.fDstProxy != *bDstProxy) {
Brian Salomond25f5bc2018-08-08 11:25:17 -0400333 return GrOp::CombineResult::kCannotCombine;
Brian Salomon54d212e2017-03-21 14:22:38 -0400334 }
Robert Phillipsbb581ce2017-05-29 15:05:15 -0400335 } else if (a.fDstProxy.proxy()) {
Brian Salomond25f5bc2018-08-08 11:25:17 -0400336 return GrOp::CombineResult::kCannotCombine;
Brian Salomon54d212e2017-03-21 14:22:38 -0400337 }
Brian Salomond25f5bc2018-08-08 11:25:17 -0400338 return a.fOp->combineIfPossible(b, caps);
Brian Salomon54d212e2017-03-21 14:22:38 -0400339}
340
Chris Daltonf104fec2018-05-22 16:17:48 -0600341uint32_t GrRenderTargetOpList::recordOp(std::unique_ptr<GrOp> op,
342 const GrCaps& caps,
343 GrAppliedClip* clip,
344 const DstProxy* dstProxy) {
Robert Phillips318c4192017-05-17 09:36:38 -0400345 SkASSERT(fTarget.get());
Robert Phillipsee683652017-04-26 11:53:10 -0400346
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500347 // A closed GrOpList should never receive new/more ops
robertphillips6a186652015-10-20 07:37:58 -0700348 SkASSERT(!this->isClosed());
robertphillipsa106c622015-10-16 09:07:06 -0700349
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500350 // Check if there is an op we can combine with by linearly searching back until we either
351 // 1) check every op
bsalomon512be532015-09-10 10:42:55 -0700352 // 2) intersect with something
353 // 3) find a 'blocker'
Robert Phillips5efd5ea2017-05-30 13:47:32 -0400354 GR_AUDIT_TRAIL_ADD_OP(fAuditTrail, op.get(), fTarget.get()->uniqueID());
Robert Phillipsf5442bb2017-04-17 14:18:34 -0400355 GrOP_INFO("opList: %d Recording (%s, opID: %u)\n"
356 "\tBounds [L: %.2f, T: %.2f R: %.2f B: %.2f]\n",
357 this->uniqueID(),
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500358 op->name(),
359 op->uniqueID(),
Robert Phillips1119dc32017-04-11 12:54:57 -0400360 op->bounds().fLeft, op->bounds().fTop,
361 op->bounds().fRight, op->bounds().fBottom);
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500362 GrOP_INFO(SkTabString(op->dumpInfo(), 1).c_str());
Brian Salomon25a88092016-12-01 09:36:50 -0500363 GrOP_INFO("\tOutcome:\n");
Robert Phillips8185f592017-04-26 08:31:08 -0400364 int maxCandidates = SkTMin(kMaxOpLookback, fRecordedOps.count());
Brian Salomond25f5bc2018-08-08 11:25:17 -0400365 int firstChainableIdx = -1;
Robert Phillips318c4192017-05-17 09:36:38 -0400366 if (maxCandidates) {
bsalomon512be532015-09-10 10:42:55 -0700367 int i = 0;
368 while (true) {
Brian Salomon69868af2016-12-22 15:42:51 -0500369 const RecordedOp& candidate = fRecordedOps.fromBack(i);
Brian Salomond25f5bc2018-08-08 11:25:17 -0400370 auto combineResult = this->combineIfPossible(candidate, op.get(), clip, dstProxy, caps);
371 switch (combineResult) {
372 case GrOp::CombineResult::kMayChain:
373 if (candidate.fOp->isChainTail() && firstChainableIdx < 0) {
374 GrOP_INFO("\t\tBackward: Can chain with (%s, opID: %u)\n",
375 candidate.fOp->name(), candidate.fOp->uniqueID());
376 firstChainableIdx = i;
377 }
378 break;
379 case GrOp::CombineResult::kMerged:
380 GrOP_INFO("\t\tBackward: Combining with (%s, opID: %u)\n",
381 candidate.fOp->name(), candidate.fOp->uniqueID());
382 GrOP_INFO("\t\t\tBackward: Combined op info:\n");
383 GrOP_INFO(SkTabString(candidate.fOp->dumpInfo(), 4).c_str());
384 GR_AUDIT_TRAIL_OPS_RESULT_COMBINED(fAuditTrail, candidate.fOp.get(), op.get());
385 fOpMemoryPool->release(std::move(op));
386 return SK_InvalidUniqueID;
387 case GrOp::CombineResult::kCannotCombine:
388 break;
bsalomon512be532015-09-10 10:42:55 -0700389 }
Brian Salomon764e5462018-08-21 12:07:00 -0400390 // Stop going backwards if we would cause a painter's order violation. We only need to
391 // test against chain heads as elements of a chain always draw in their chain head's
392 // slot.
393 if (candidate.fOp->isChainHead() &&
394 !can_reorder(candidate.fOp->bounds(), op->bounds())) {
Robert Phillipsf5442bb2017-04-17 14:18:34 -0400395 GrOP_INFO("\t\tBackward: Intersects with (%s, opID: %u)\n", candidate.fOp->name(),
Brian Salomon69868af2016-12-22 15:42:51 -0500396 candidate.fOp->uniqueID());
bsalomon512be532015-09-10 10:42:55 -0700397 break;
398 }
399 ++i;
400 if (i == maxCandidates) {
Robert Phillipsf5442bb2017-04-17 14:18:34 -0400401 GrOP_INFO("\t\tBackward: Reached max lookback or beginning of op array %d\n", i);
bsalomon512be532015-09-10 10:42:55 -0700402 break;
403 }
404 }
405 } else {
Robert Phillipsf5442bb2017-04-17 14:18:34 -0400406 GrOP_INFO("\t\tBackward: FirstOp\n");
bsalomon512be532015-09-10 10:42:55 -0700407 }
Brian Salomon42ad83a2016-12-20 16:14:45 -0500408 GR_AUDIT_TRAIL_OP_RESULT_NEW(fAuditTrail, op);
Brian Salomon54d212e2017-03-21 14:22:38 -0400409 if (clip) {
410 clip = fClipAllocator.make<GrAppliedClip>(std::move(*clip));
Robert Phillipsc84c0302017-05-08 15:35:11 -0400411 SkDEBUGCODE(fNumClips++;)
Brian Salomon54d212e2017-03-21 14:22:38 -0400412 }
Brian Salomond25f5bc2018-08-08 11:25:17 -0400413 if (firstChainableIdx >= 0) {
Brian Salomon764e5462018-08-21 12:07:00 -0400414 // If we chain this op it will draw in the slot of the head of the chain. We have to check
415 // that the new op's bounds don't intersect any of the other ops between firstChainableIdx
416 // and the head of that op's chain. We only need to test against chain heads as elements of
417 // a chain always draw in their chain head's slot.
418 const GrOp* chainHead = fRecordedOps.fromBack(firstChainableIdx).fOp->chainHead();
419 int idx = firstChainableIdx;
420 bool chain = true;
421 while (fRecordedOps.fromBack(idx).fOp.get() != chainHead) {
422 // If idx is not in the same chain then we have to check against its bounds as we will
423 // draw before it (when chainHead draws).
424 const GrOp* testOp = fRecordedOps.fromBack(idx).fOp.get();
425 if (testOp->isChainHead() && !can_reorder(testOp->bounds(), op->bounds())) {
426 GrOP_INFO("\t\tBackward: Intersects with (%s, opID: %u). Cannot chain.\n",
427 testOp->name(), testOp->uniqueID());
428 chain = false;
429 break;
430 }
431 ++idx;
432 // We must encounter the chain head before running off the beginning of the list.
433 SkASSERT(idx < fRecordedOps.count());
434 }
435 if (chain) {
436 GrOp* prevOp = fRecordedOps.fromBack(firstChainableIdx).fOp.get();
437 GrOP_INFO("\t\t\tBackward: Chained to (%s, opID: %u)\n", prevOp->name(),
438 prevOp->uniqueID());
439 prevOp->setNextInChain(op.get());
440 }
Brian Salomond25f5bc2018-08-08 11:25:17 -0400441 }
Robert Phillipsbb581ce2017-05-29 15:05:15 -0400442 fRecordedOps.emplace_back(std::move(op), clip, dstProxy);
Chris Daltonf104fec2018-05-22 16:17:48 -0600443 return this->uniqueID();
bsalomon512be532015-09-10 10:42:55 -0700444}
445
Robert Phillipsee683652017-04-26 11:53:10 -0400446void GrRenderTargetOpList::forwardCombine(const GrCaps& caps) {
Robert Phillipsf5442bb2017-04-17 14:18:34 -0400447 SkASSERT(!this->isClosed());
448
Robert Phillips48567ac2017-06-01 08:46:00 -0400449 GrOP_INFO("opList: %d ForwardCombine %d ops:\n", this->uniqueID(), fRecordedOps.count());
450
Brian Salomon337432d2017-03-21 17:36:10 -0400451 for (int i = 0; i < fRecordedOps.count() - 1; ++i) {
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500452 GrOp* op = fRecordedOps[i].fOp.get();
Robert Phillips318c4192017-05-17 09:36:38 -0400453
Robert Phillips8185f592017-04-26 08:31:08 -0400454 int maxCandidateIdx = SkTMin(i + kMaxOpLookahead, fRecordedOps.count() - 1);
bsalomonaecc0182016-03-07 11:50:44 -0800455 int j = i + 1;
Brian Salomond25f5bc2018-08-08 11:25:17 -0400456 int firstChainableIdx = -1;
bsalomonaecc0182016-03-07 11:50:44 -0800457 while (true) {
Brian Salomon69868af2016-12-22 15:42:51 -0500458 const RecordedOp& candidate = fRecordedOps[j];
Brian Salomond25f5bc2018-08-08 11:25:17 -0400459 auto combineResult =
460 this->combineIfPossible(fRecordedOps[i], candidate.fOp.get(),
461 candidate.fAppliedClip, &candidate.fDstProxy, caps);
462 switch (combineResult) {
463 case GrOp::CombineResult::kMayChain:
464 if (firstChainableIdx < 0 && !fRecordedOps[i].fOp->isChained() &&
465 !fRecordedOps[j].fOp->isChained()) {
466 GrOP_INFO("\t\tForward: Can chain with (%s, opID: %u)\n",
467 candidate.fOp->name(), candidate.fOp->uniqueID());
468 firstChainableIdx = j;
469 }
470 break;
471 case GrOp::CombineResult::kMerged:
472 GrOP_INFO("\t\t%d: (%s opID: %u) -> Combining with (%s, opID: %u)\n", i,
473 op->name(), op->uniqueID(), candidate.fOp->name(),
474 candidate.fOp->uniqueID());
475 GR_AUDIT_TRAIL_OPS_RESULT_COMBINED(fAuditTrail, op, candidate.fOp.get());
476 fOpMemoryPool->release(std::move(fRecordedOps[j].fOp));
477 fRecordedOps[j].fOp = std::move(fRecordedOps[i].fOp);
478 break;
479 case GrOp::CombineResult::kCannotCombine:
480 break;
481 }
482 if (!fRecordedOps[i].fOp) {
bsalomonaecc0182016-03-07 11:50:44 -0800483 break;
484 }
Robert Phillipsc84c0302017-05-08 15:35:11 -0400485 // Stop traversing if we would cause a painter's order violation.
Brian Salomon764e5462018-08-21 12:07:00 -0400486 if (candidate.fOp->isChainHead() &&
487 !can_reorder(candidate.fOp->bounds(), op->bounds())) {
Robert Phillips48567ac2017-06-01 08:46:00 -0400488 GrOP_INFO("\t\t%d: (%s opID: %u) -> Intersects with (%s, opID: %u)\n",
489 i, op->name(), op->uniqueID(),
490 candidate.fOp->name(), candidate.fOp->uniqueID());
bsalomonaecc0182016-03-07 11:50:44 -0800491 break;
492 }
493 ++j;
494 if (j > maxCandidateIdx) {
Brian Salomond25f5bc2018-08-08 11:25:17 -0400495 if (firstChainableIdx >= 0) {
Brian Salomon764e5462018-08-21 12:07:00 -0400496 GrOp* nextOp = fRecordedOps[firstChainableIdx].fOp.get();
497 GrOP_INFO("\t\t\tForward: Chained to (%s, opID: %u)\n", nextOp->name(),
498 nextOp->uniqueID());
Brian Salomond25f5bc2018-08-08 11:25:17 -0400499 // We have to chain i before firstChainableIdx in order to preserve their
500 // relative order as they may overlap.
Brian Salomon764e5462018-08-21 12:07:00 -0400501 fRecordedOps[i].fOp->setNextInChain(nextOp);
Brian Salomond25f5bc2018-08-08 11:25:17 -0400502 // However we want to draw them *after* any ops that occur between them. So move
503 // the head of the new chain to the later slot as we only execute chain heads.
504 std::swap(fRecordedOps[i].fOp, fRecordedOps[firstChainableIdx].fOp);
505 } else {
506 GrOP_INFO("\t\t%d: (%s opID: %u) -> Reached max lookahead or end of array\n", i,
507 op->name(), op->uniqueID());
508 }
bsalomonaecc0182016-03-07 11:50:44 -0800509 break;
510 }
511 }
512 }
513}
514