blob: 2b05a16b5026a7c85f2463e54fd9845884179dae [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"
joshualitt4d8da812015-01-28 12:53:54 -08009
csmartdalton28341fa2016-08-17 10:00:21 -070010#include "GrAppliedClip.h"
joshualitt086cee12016-01-12 06:45:24 -080011#include "GrAuditTrail.h"
bsalomoneb1cb5c2015-05-22 08:01:09 -070012#include "GrCaps.h"
Brian Osman11052242016-10-27 14:47:55 -040013#include "GrRenderTargetContext.h"
bsalomon4061b122015-05-29 10:26:19 -070014#include "GrGpu.h"
egdaniel9cb63402016-06-23 08:37:05 -070015#include "GrGpuCommandBuffer.h"
commit-bot@chromium.orgc4dc0ad2013-10-09 14:11:33 +000016#include "GrPath.h"
egdaniele36914c2015-02-13 09:00:33 -080017#include "GrPipeline.h"
joshualittb7133be2015-04-08 09:08:31 -070018#include "GrMemoryPool.h"
robertphillips5fa7f302016-07-21 09:21:04 -070019#include "GrPipelineBuilder.h"
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +000020#include "GrRenderTarget.h"
bsalomon4061b122015-05-29 10:26:19 -070021#include "GrResourceProvider.h"
bsalomon6bc1b5f2015-02-23 09:06:38 -080022#include "GrRenderTargetPriv.h"
cdalton93a379b2016-05-11 13:58:08 -070023#include "GrStencilAttachment.h"
bsalomonafbf2d62014-09-30 12:18:44 -070024#include "GrSurfacePriv.h"
bsalomon@google.com86afc2a2011-02-16 16:12:19 +000025#include "GrTexture.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000026
joshualitt086cee12016-01-12 06:45:24 -080027#include "SkStrokeRec.h"
28
Brian Salomon89527432016-12-16 09:52:16 -050029#include "ops/GrClearOp.h"
30#include "ops/GrClearStencilClipOp.h"
31#include "ops/GrCopySurfaceOp.h"
32#include "ops/GrDiscardOp.h"
33#include "ops/GrDrawOp.h"
34#include "ops/GrDrawPathOp.h"
35#include "ops/GrRectOpFactory.h"
36#include "ops/GrStencilPathOp.h"
joshualitt74417822015-08-07 11:42:16 -070037
csmartdaltona7f29642016-07-07 08:49:11 -070038#include "instanced/InstancedRendering.h"
39
Robert Phillipsf2361d22016-10-25 14:20:06 -040040using gr_instanced::InstancedRendering;
41
reed@google.comac10a2d2010-12-22 21:39:39 +000042////////////////////////////////////////////////////////////////////////////////
43
Brian Salomon09d994e2016-12-21 11:14:46 -050044// Experimentally we have found that most combining occurs within the first 10 comparisons.
45static const int kDefaultMaxOpLookback = 10;
46static const int kDefaultMaxOpLookahead = 10;
bsalomon489147c2015-12-14 12:13:09 -080047
Robert Phillipsc7635fa2016-10-28 13:25:24 -040048GrRenderTargetOpList::GrRenderTargetOpList(GrRenderTargetProxy* rtp, GrGpu* gpu,
Robert Phillipsf2361d22016-10-25 14:20:06 -040049 GrResourceProvider* resourceProvider,
50 GrAuditTrail* auditTrail, const Options& options)
Robert Phillipsc7635fa2016-10-28 13:25:24 -040051 : INHERITED(rtp, auditTrail)
bsalomonfd8d0132016-08-11 11:25:33 -070052 , fGpu(SkRef(gpu))
csmartdalton7cdda992016-11-01 07:03:03 -070053 , fResourceProvider(resourceProvider)
54 , fLastClipStackGenID(SK_InvalidUniqueID) {
csmartdaltonc6f411e2016-08-05 22:32:12 -070055 // TODO: Stop extracting the context (currently needed by GrClip)
bsalomonb3b9aec2015-09-10 11:16:35 -070056 fContext = fGpu->getContext();
robertphillips4beb5c12015-10-20 07:50:00 -070057
Brian Salomon09d994e2016-12-21 11:14:46 -050058 fMaxOpLookback = (options.fMaxOpCombineLookback < 0) ? kDefaultMaxOpLookback
59 : options.fMaxOpCombineLookback;
60 fMaxOpLookahead = (options.fMaxOpCombineLookahead < 0) ? kDefaultMaxOpLookahead
61 : options.fMaxOpCombineLookahead;
bsalomon6dea83f2015-12-03 12:58:06 -080062
csmartdaltone0d36292016-07-29 08:14:20 -070063 if (GrCaps::InstancedSupport::kNone != this->caps()->instancedSupport()) {
64 fInstancedRendering.reset(fGpu->createInstancedRendering());
65 }
bsalomon4061b122015-05-29 10:26:19 -070066}
67
Robert Phillipsf2361d22016-10-25 14:20:06 -040068GrRenderTargetOpList::~GrRenderTargetOpList() {
bsalomon4061b122015-05-29 10:26:19 -070069 fGpu->unref();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +000070}
71
72////////////////////////////////////////////////////////////////////////////////
73
robertphillips4beb5c12015-10-20 07:50:00 -070074#ifdef SK_DEBUG
Robert Phillipsf2361d22016-10-25 14:20:06 -040075void GrRenderTargetOpList::dump() const {
76 INHERITED::dump();
77
Brian Salomon1e41f4a2016-12-07 15:05:04 -050078 SkDebugf("ops (%d):\n", fRecordedOps.count());
79 for (int i = 0; i < fRecordedOps.count(); ++i) {
robertphillips4beb5c12015-10-20 07:50:00 -070080 SkDebugf("*******************************\n");
Brian Salomon1e41f4a2016-12-07 15:05:04 -050081 if (!fRecordedOps[i].fOp) {
bsalomonaecc0182016-03-07 11:50:44 -080082 SkDebugf("%d: <combined forward>\n", i);
83 } else {
Brian Salomon1e41f4a2016-12-07 15:05:04 -050084 SkDebugf("%d: %s\n", i, fRecordedOps[i].fOp->name());
85 SkString str = fRecordedOps[i].fOp->dumpInfo();
bsalomonaecc0182016-03-07 11:50:44 -080086 SkDebugf("%s\n", str.c_str());
Brian Salomon9e50f7b2017-03-06 12:02:34 -050087 const SkRect& bounds = fRecordedOps[i].fOp->bounds();
88 SkDebugf("ClippedBounds: [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", bounds.fLeft,
89 bounds.fTop, bounds.fRight, bounds.fBottom);
bsalomonaecc0182016-03-07 11:50:44 -080090 }
robertphillips4beb5c12015-10-20 07:50:00 -070091 }
92}
93#endif
94
Brian Salomon5b7b49f2016-12-07 14:31:00 -050095void GrRenderTargetOpList::setupDstTexture(GrRenderTarget* rt,
96 const GrClip& clip,
Brian Salomon09d994e2016-12-21 11:14:46 -050097 const SkRect& opBounds,
Brian Salomon5b7b49f2016-12-07 14:31:00 -050098 GrXferProcessor::DstTexture* dstTexture) {
cdalton9954bc32015-04-29 14:17:00 -070099 if (this->caps()->textureBarrierSupport()) {
100 if (GrTexture* rtTex = rt->asTexture()) {
bsalomondc47ff72015-05-26 12:16:59 -0700101 // The render target is a texture, so we can read from it directly in the shader. The XP
cdalton9954bc32015-04-29 14:17:00 -0700102 // will be responsible to detect this situation and request a texture barrier.
bungeman6bd52842016-10-27 09:30:08 -0700103 dstTexture->setTexture(sk_ref_sp(rtTex));
bsalomon6a44c6a2015-05-26 09:49:05 -0700104 dstTexture->setOffset(0, 0);
Brian Salomon5b7b49f2016-12-07 14:31:00 -0500105 return;
cdalton9954bc32015-04-29 14:17:00 -0700106 }
107 }
108
109 SkIRect copyRect;
cdalton862cff32016-05-12 15:09:48 -0700110 clip.getConservativeBounds(rt->width(), rt->height(), &copyRect);
commit-bot@chromium.orgc4dc0ad2013-10-09 14:11:33 +0000111
bsalomonad792c12015-09-10 11:10:50 -0700112 SkIRect drawIBounds;
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500113 opBounds.roundOut(&drawIBounds);
bsalomonad792c12015-09-10 11:10:50 -0700114 if (!copyRect.intersect(drawIBounds)) {
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000115#ifdef SK_DEBUG
bsalomonb3b9aec2015-09-10 11:16:35 -0700116 GrCapsDebugf(this->caps(), "Missed an early reject. "
Brian Salomon5b7b49f2016-12-07 14:31:00 -0500117 "Bailing on draw from setupDstTexture.\n");
commit-bot@chromium.orgbb5c4652013-04-01 12:49:31 +0000118#endif
Brian Salomon5b7b49f2016-12-07 14:31:00 -0500119 return;
commit-bot@chromium.orgbb5c4652013-04-01 12:49:31 +0000120 }
skia.committer@gmail.com05a2ee02013-04-02 07:01:34 +0000121
commit-bot@chromium.org63150af2013-04-11 22:00:22 +0000122 // MSAA consideration: When there is support for reading MSAA samples in the shader we could
123 // have per-sample dst values by making the copy multisampled.
bsalomonf2703d82014-10-28 14:33:06 -0700124 GrSurfaceDesc desc;
egdaniel4bcd62e2016-08-31 07:37:31 -0700125 if (!fGpu->initDescForDstCopy(rt, &desc)) {
bsalomona73239a2015-04-28 13:35:17 -0700126 desc.fOrigin = kDefault_GrSurfaceOrigin;
127 desc.fFlags = kRenderTarget_GrSurfaceFlag;
128 desc.fConfig = rt->config();
129 }
130
commit-bot@chromium.orgbb5c4652013-04-01 12:49:31 +0000131 desc.fWidth = copyRect.width();
132 desc.fHeight = copyRect.height();
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000133
bsalomoneae62002015-07-31 13:59:30 -0700134 static const uint32_t kFlags = 0;
bungeman6bd52842016-10-27 09:30:08 -0700135 sk_sp<GrTexture> copy(fResourceProvider->createApproxTexture(desc, kFlags));
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000136
bsalomone3059732014-10-14 11:47:22 -0700137 if (!copy) {
tfarina38406c82014-10-31 07:11:12 -0700138 SkDebugf("Failed to create temporary copy of destination texture.\n");
Brian Salomon5b7b49f2016-12-07 14:31:00 -0500139 return;
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000140 }
bsalomon@google.come4617bf2013-04-03 14:56:40 +0000141 SkIPoint dstPoint = {0, 0};
bungeman6bd52842016-10-27 09:30:08 -0700142 this->copySurface(copy.get(), rt, copyRect, dstPoint);
143 dstTexture->setTexture(std::move(copy));
bsalomon6df86402015-06-01 10:41:49 -0700144 dstTexture->setOffset(copyRect.fLeft, copyRect.fTop);
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000145}
146
Brian Salomon742e31d2016-12-07 17:06:19 -0500147void GrRenderTargetOpList::prepareOps(GrOpFlushState* flushState) {
Robert Phillipsf2361d22016-10-25 14:20:06 -0400148 // Semi-usually the GrOpLists are already closed at this point, but sometimes Ganesh
149 // needs to flush mid-draw. In that case, the SkGpuDevice's GrOpLists won't be closed
150 // but need to be flushed anyway. Closing such GrOpLists here will mean new
151 // GrOpLists will be created to replace them if the SkGpuDevice(s) write to them again.
robertphillipsa106c622015-10-16 09:07:06 -0700152 this->makeClosed();
153
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500154 // Loop over the ops that haven't yet been prepared.
155 for (int i = 0; i < fRecordedOps.count(); ++i) {
156 if (fRecordedOps[i].fOp) {
157 fRecordedOps[i].fOp->prepare(flushState);
bsalomonaecc0182016-03-07 11:50:44 -0800158 }
bsalomon512be532015-09-10 10:42:55 -0700159 }
csmartdaltona7f29642016-07-07 08:49:11 -0700160
161 if (fInstancedRendering) {
162 fInstancedRendering->beginFlush(flushState->resourceProvider());
163 }
robertphillipsa13e2022015-11-11 12:01:09 -0800164}
bsalomon512be532015-09-10 10:42:55 -0700165
Brian Salomon25a88092016-12-01 09:36:50 -0500166// TODO: this is where GrOp::renderTarget is used (which is fine since it
Robert Phillips294870f2016-11-11 12:38:40 -0500167// is at flush time). However, we need to store the RenderTargetProxy in the
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500168// Ops and instantiate them here.
Brian Salomon742e31d2016-12-07 17:06:19 -0500169bool GrRenderTargetOpList::executeOps(GrOpFlushState* flushState) {
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500170 if (0 == fRecordedOps.count()) {
bsalomondc438982016-08-31 11:53:49 -0700171 return false;
egdanielb4021cf2016-07-28 08:53:07 -0700172 }
bsalomon512be532015-09-10 10:42:55 -0700173 // Draw all the generated geometry.
bsalomon6dea83f2015-12-03 12:58:06 -0800174 SkRandom random;
Brian Salomoncdcc33f2017-02-21 09:49:20 -0500175 const GrRenderTarget* currentRenderTarget = nullptr;
Ben Wagner145dbcd2016-11-03 14:40:50 -0400176 std::unique_ptr<GrGpuCommandBuffer> commandBuffer;
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500177 for (int i = 0; i < fRecordedOps.count(); ++i) {
178 if (!fRecordedOps[i].fOp) {
bsalomonaecc0182016-03-07 11:50:44 -0800179 continue;
180 }
Brian Salomoncdcc33f2017-02-21 09:49:20 -0500181 if (fRecordedOps[i].fRenderTarget.get() != currentRenderTarget) {
egdaniel9cb63402016-06-23 08:37:05 -0700182 if (commandBuffer) {
183 commandBuffer->end();
Greg Daniel36a77ee2016-10-18 10:33:25 -0400184 commandBuffer->submit();
egdaniel9cb63402016-06-23 08:37:05 -0700185 commandBuffer.reset();
186 }
Brian Salomoncdcc33f2017-02-21 09:49:20 -0500187 currentRenderTarget = fRecordedOps[i].fRenderTarget.get();
188 if (currentRenderTarget) {
egdaniel9cb63402016-06-23 08:37:05 -0700189 static const GrGpuCommandBuffer::LoadAndStoreInfo kBasicLoadStoreInfo
190 { GrGpuCommandBuffer::LoadOp::kLoad,GrGpuCommandBuffer::StoreOp::kStore,
191 GrColor_ILLEGAL };
Brian Salomonc293a292016-11-30 13:38:32 -0500192 commandBuffer.reset(fGpu->createCommandBuffer(kBasicLoadStoreInfo, // Color
egdaniel9cb63402016-06-23 08:37:05 -0700193 kBasicLoadStoreInfo)); // Stencil
194 }
Ben Wagner145dbcd2016-11-03 14:40:50 -0400195 flushState->setCommandBuffer(commandBuffer.get());
egdaniel9cb63402016-06-23 08:37:05 -0700196 }
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500197 fRecordedOps[i].fOp->execute(flushState);
bsalomon512be532015-09-10 10:42:55 -0700198 }
egdaniel9cb63402016-06-23 08:37:05 -0700199 if (commandBuffer) {
200 commandBuffer->end();
Greg Daniel36a77ee2016-10-18 10:33:25 -0400201 commandBuffer->submit();
egdaniel9cb63402016-06-23 08:37:05 -0700202 flushState->setCommandBuffer(nullptr);
203 }
ethannicholas22793252016-01-30 09:59:10 -0800204
Robert Phillipsf2361d22016-10-25 14:20:06 -0400205 fGpu->finishOpList();
bsalomondc438982016-08-31 11:53:49 -0700206 return true;
bsalomona73239a2015-04-28 13:35:17 -0700207}
208
Robert Phillipsf2361d22016-10-25 14:20:06 -0400209void GrRenderTargetOpList::reset() {
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500210 fLastFullClearOp = nullptr;
Brian Salomon69868af2016-12-22 15:42:51 -0500211 fLastFullClearRenderTargetID.makeInvalid();
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500212 fRecordedOps.reset();
csmartdaltona7f29642016-07-07 08:49:11 -0700213 if (fInstancedRendering) {
214 fInstancedRendering->endFlush();
215 }
bsalomon512be532015-09-10 10:42:55 -0700216}
217
Robert Phillipsf2361d22016-10-25 14:20:06 -0400218void GrRenderTargetOpList::abandonGpuResources() {
219 if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport()) {
220 InstancedRendering* ir = this->instancedRendering();
221 ir->resetGpuResources(InstancedRendering::ResetType::kAbandon);
222 }
223}
224
225void GrRenderTargetOpList::freeGpuResources() {
226 if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport()) {
227 InstancedRendering* ir = this->instancedRendering();
228 ir->resetGpuResources(InstancedRendering::ResetType::kDestroy);
229 }
230}
231
Brian Salomon09d994e2016-12-21 11:14:46 -0500232static void op_bounds(SkRect* bounds, const GrOp* op) {
233 *bounds = op->bounds();
234 if (op->hasZeroArea()) {
235 if (op->hasAABloat()) {
bsalomon88cf17d2016-07-08 06:40:56 -0700236 bounds->outset(0.5f, 0.5f);
237 } else {
238 // We don't know which way the particular GPU will snap lines or points at integer
239 // coords. So we ensure that the bounds is large enough for either snap.
240 SkRect before = *bounds;
241 bounds->roundOut(bounds);
242 if (bounds->fLeft == before.fLeft) {
243 bounds->fLeft -= 1;
244 }
245 if (bounds->fTop == before.fTop) {
246 bounds->fTop -= 1;
247 }
248 if (bounds->fRight == before.fRight) {
249 bounds->fRight += 1;
250 }
251 if (bounds->fBottom == before.fBottom) {
252 bounds->fBottom += 1;
253 }
254 }
255 }
256}
257
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500258void GrRenderTargetOpList::addDrawOp(const GrPipelineBuilder& pipelineBuilder,
Brian Osman11052242016-10-27 14:47:55 -0400259 GrRenderTargetContext* renderTargetContext,
Robert Phillipsf2361d22016-10-25 14:20:06 -0400260 const GrClip& clip,
Brian Salomon92ce5942017-01-18 11:01:10 -0500261 std::unique_ptr<GrDrawOp> op) {
joshualitt4d8da812015-01-28 12:53:54 -0800262 // Setup clip
bsalomon88cf17d2016-07-08 06:40:56 -0700263 SkRect bounds;
Brian Salomon09d994e2016-12-21 11:14:46 -0500264 op_bounds(&bounds, op.get());
csmartdaltond211e782016-08-15 11:17:19 -0700265 GrAppliedClip appliedClip(bounds);
Brian Osman11052242016-10-27 14:47:55 -0400266 if (!clip.apply(fContext, renderTargetContext, pipelineBuilder.isHWAntialias(),
csmartdaltond211e782016-08-15 11:17:19 -0700267 pipelineBuilder.hasUserStencilSettings(), &appliedClip)) {
cdalton862cff32016-05-12 15:09:48 -0700268 return;
joshualitt4d8da812015-01-28 12:53:54 -0800269 }
robertphillips391395d2016-03-02 09:26:36 -0800270
cdalton862cff32016-05-12 15:09:48 -0700271 if (pipelineBuilder.hasUserStencilSettings() || appliedClip.hasStencilClip()) {
Robert Phillipse60ad622016-11-17 10:22:48 -0500272 if (!renderTargetContext->accessRenderTarget()) {
273 return;
274 }
275
Brian Osman11052242016-10-27 14:47:55 -0400276 if (!fResourceProvider->attachStencilAttachment(
277 renderTargetContext->accessRenderTarget())) {
cdalton17bf8202016-05-13 11:27:15 -0700278 SkDebugf("ERROR creating stencil attachment. Draw skipped.\n");
279 return;
280 }
cdalton193d9cf2016-05-12 11:52:02 -0700281 }
csmartdaltond211e782016-08-15 11:17:19 -0700282
Brian Salomon5298dc82017-02-22 11:52:03 -0500283 GrProcessorSet::FragmentProcessorAnalysis analysis;
284 op->analyzeProcessors(&analysis, pipelineBuilder.processors(), appliedClip, *this->caps());
285
Brian Salomonb5cb6832017-02-24 11:01:15 -0500286 GrPipeline::InitArgs args;
287 pipelineBuilder.getPipelineInitArgs(&args);
Brian Salomon652ecb52017-01-17 12:39:53 -0500288 args.fAppliedClip = &appliedClip;
Brian Salomonb16e8ac2017-02-22 11:52:36 -0500289 // This forces instantiation of the render target. Pipeline creation is moving to flush time
290 // by which point instantiation must have occurred anyway.
291 args.fRenderTarget = renderTargetContext->accessRenderTarget();
292 if (!args.fRenderTarget) {
293 return;
294 }
csmartdaltond211e782016-08-15 11:17:19 -0700295 args.fCaps = this->caps();
Brian Salomon5298dc82017-02-22 11:52:03 -0500296 args.fAnalysis = &analysis;
Brian Salomon652ecb52017-01-17 12:39:53 -0500297
Robert Phillipse60ad622016-11-17 10:22:48 -0500298 if (!renderTargetContext->accessRenderTarget()) {
299 return;
300 }
301
Brian Salomon5298dc82017-02-22 11:52:03 -0500302 if (pipelineBuilder.willXPNeedDstTexture(*this->caps(), analysis)) {
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500303 this->setupDstTexture(renderTargetContext->accessRenderTarget(), clip, bounds,
Brian Salomon5b7b49f2016-12-07 14:31:00 -0500304 &args.fDstTexture);
305 if (!args.fDstTexture.texture()) {
306 return;
307 }
cdalton193d9cf2016-05-12 11:52:02 -0700308 }
Brian Salomonb5cb6832017-02-24 11:01:15 -0500309 op->initPipeline(args);
bsalomonad792c12015-09-10 11:10:50 -0700310
robertphillips498d7ac2015-10-30 10:11:30 -0700311#ifdef ENABLE_MDB
Robert Phillipsf2361d22016-10-25 14:20:06 -0400312 SkASSERT(fSurface);
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500313 op->pipeline()->addDependenciesTo(fSurface);
robertphillips498d7ac2015-10-30 10:11:30 -0700314#endif
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500315 op->setClippedBounds(appliedClip.clippedDrawBounds());
316 this->recordOp(std::move(op), renderTargetContext);
joshualitt4d8da812015-01-28 12:53:54 -0800317}
318
Brian Osman11052242016-10-27 14:47:55 -0400319void GrRenderTargetOpList::stencilPath(GrRenderTargetContext* renderTargetContext,
Robert Phillipsf2361d22016-10-25 14:20:06 -0400320 const GrClip& clip,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500321 GrAAType aaType,
Robert Phillipsf2361d22016-10-25 14:20:06 -0400322 const SkMatrix& viewMatrix,
323 const GrPath* path) {
Brian Salomon0abc8b42016-12-13 10:22:54 -0500324 bool useHWAA = GrAATypeIsHW(aaType);
bsalomon@google.com64aef2b2012-06-11 15:36:13 +0000325 // TODO: extract portions of checkDraw that are relevant to path stenciling.
bsalomon49f085d2014-09-05 13:34:00 -0700326 SkASSERT(path);
jvanverthe9c0fc62015-04-29 11:18:05 -0700327 SkASSERT(this->caps()->shaderCaps()->pathRenderingSupport());
joshualitt2c93efe2014-11-06 12:57:13 -0800328
csmartdaltond211e782016-08-15 11:17:19 -0700329 // FIXME: Use path bounds instead of this WAR once
330 // https://bugs.chromium.org/p/skia/issues/detail?id=5640 is resolved.
Brian Osman11052242016-10-27 14:47:55 -0400331 SkRect bounds = SkRect::MakeIWH(renderTargetContext->width(), renderTargetContext->height());
csmartdaltond211e782016-08-15 11:17:19 -0700332
joshualitt2c93efe2014-11-06 12:57:13 -0800333 // Setup clip
csmartdaltond211e782016-08-15 11:17:19 -0700334 GrAppliedClip appliedClip(bounds);
Brian Osman11052242016-10-27 14:47:55 -0400335 if (!clip.apply(fContext, renderTargetContext, useHWAA, true, &appliedClip)) {
joshualitt2c93efe2014-11-06 12:57:13 -0800336 return;
337 }
338
cdalton846c0512016-05-13 10:25:00 -0700339 // Coverage AA does not make sense when rendering to the stencil buffer. The caller should never
340 // attempt this in a situation that would require coverage AA.
csmartdaltond211e782016-08-15 11:17:19 -0700341 SkASSERT(!appliedClip.clipCoverageFragmentProcessor());
bsalomon0ba8c242015-10-07 09:20:28 -0700342
Robert Phillipse60ad622016-11-17 10:22:48 -0500343 if (!renderTargetContext->accessRenderTarget()) {
344 return;
345 }
robertphillips55fdccc2016-06-06 06:16:20 -0700346 GrStencilAttachment* stencilAttachment = fResourceProvider->attachStencilAttachment(
Brian Osman11052242016-10-27 14:47:55 -0400347 renderTargetContext->accessRenderTarget());
cdalton17bf8202016-05-13 11:27:15 -0700348 if (!stencilAttachment) {
349 SkDebugf("ERROR creating stencil attachment. Draw skipped.\n");
350 return;
351 }
joshualitt2c93efe2014-11-06 12:57:13 -0800352
Brian Salomonf8334782017-01-03 09:42:58 -0500353 std::unique_ptr<GrOp> op = GrStencilPathOp::Make(viewMatrix,
354 useHWAA,
355 path->getFillType(),
356 appliedClip.hasStencilClip(),
357 stencilAttachment->bits(),
358 appliedClip.scissorState(),
359 renderTargetContext->accessRenderTarget(),
360 path);
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500361 op->setClippedBounds(appliedClip.clippedDrawBounds());
362 this->recordOp(std::move(op), renderTargetContext);
bsalomon@google.com64aef2b2012-06-11 15:36:13 +0000363}
364
Brian Salomon69868af2016-12-22 15:42:51 -0500365void GrRenderTargetOpList::fullClear(GrRenderTargetContext* renderTargetContext, GrColor color) {
366 GrRenderTarget* renderTarget = renderTargetContext->accessRenderTarget();
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500367 // Currently this just inserts or updates the last clear op. However, once in MDB this can
368 // remove all the previously recorded ops and change the load op to clear with supplied
bsalomonfd8d0132016-08-11 11:25:33 -0700369 // color.
Robert Phillips294870f2016-11-11 12:38:40 -0500370 // TODO: this needs to be updated to use GrSurfaceProxy::UniqueID
Brian Salomon69868af2016-12-22 15:42:51 -0500371 if (fLastFullClearRenderTargetID == renderTarget->uniqueID()) {
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500372 // As currently implemented, fLastFullClearOp should be the last op because we would
373 // have cleared it when another op was recorded.
374 SkASSERT(fRecordedOps.back().fOp.get() == fLastFullClearOp);
375 fLastFullClearOp->setColor(color);
bsalomonfd8d0132016-08-11 11:25:33 -0700376 return;
377 }
Brian Salomonf8334782017-01-03 09:42:58 -0500378 std::unique_ptr<GrClearOp> op(GrClearOp::Make(GrFixedClip::Disabled(), color, renderTarget));
Brian Salomon69868af2016-12-22 15:42:51 -0500379 if (GrOp* clearOp = this->recordOp(std::move(op), renderTargetContext)) {
Brian Salomon2790c522016-12-09 16:32:23 -0500380 // This is either the clear op we just created or another one that it combined with.
Brian Salomon7dae46a2016-12-14 16:21:37 -0500381 fLastFullClearOp = static_cast<GrClearOp*>(clearOp);
Brian Salomon69868af2016-12-22 15:42:51 -0500382 fLastFullClearRenderTargetID = renderTarget->uniqueID();
bsalomonfd8d0132016-08-11 11:25:33 -0700383 }
bsalomon9f129de2016-08-10 16:31:05 -0700384}
385
Brian Salomon69868af2016-12-22 15:42:51 -0500386void GrRenderTargetOpList::discard(GrRenderTargetContext* renderTargetContext) {
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500387 // Currently this just inserts a discard op. However, once in MDB this can remove all the
388 // previously recorded ops and change the load op to discard.
bsalomon53469832015-08-18 09:20:09 -0700389 if (this->caps()->discardRenderTargetSupport()) {
Brian Salomon69868af2016-12-22 15:42:51 -0500390 this->recordOp(GrDiscardOp::Make(renderTargetContext->accessRenderTarget()),
391 renderTargetContext);
bsalomon63b21962014-11-05 07:05:34 -0800392 }
393}
394
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000395////////////////////////////////////////////////////////////////////////////////
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000396
Robert Phillipsf2361d22016-10-25 14:20:06 -0400397bool GrRenderTargetOpList::copySurface(GrSurface* dst,
398 GrSurface* src,
399 const SkIRect& srcRect,
400 const SkIPoint& dstPoint) {
Brian Salomonf8334782017-01-03 09:42:58 -0500401 std::unique_ptr<GrOp> op = GrCopySurfaceOp::Make(dst, src, srcRect, dstPoint);
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500402 if (!op) {
bsalomonb8fea972016-02-16 07:34:17 -0800403 return false;
404 }
robertphillips498d7ac2015-10-30 10:11:30 -0700405#ifdef ENABLE_MDB
bsalomonb8fea972016-02-16 07:34:17 -0800406 this->addDependency(src);
robertphillips498d7ac2015-10-30 10:11:30 -0700407#endif
408
Brian Salomon69868af2016-12-22 15:42:51 -0500409 // Copy surface doesn't work through a GrGpuCommandBuffer. By passing nullptr for the context we
410 // force this to occur between command buffers and execute directly on GrGpu. This workaround
411 // goes away with MDB.
412 this->recordOp(std::move(op), nullptr);
bsalomonb8fea972016-02-16 07:34:17 -0800413 return true;
bsalomon@google.comeb851172013-04-15 13:51:00 +0000414}
415
bsalomon6cc90062016-07-08 11:31:22 -0700416static inline bool can_reorder(const SkRect& a, const SkRect& b) {
bsalomon88cf17d2016-07-08 06:40:56 -0700417 return a.fRight <= b.fLeft || a.fBottom <= b.fTop ||
418 b.fRight <= a.fLeft || b.fBottom <= a.fTop;
419}
420
Brian Salomonf8334782017-01-03 09:42:58 -0500421GrOp* GrRenderTargetOpList::recordOp(std::unique_ptr<GrOp> op,
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500422 GrRenderTargetContext* renderTargetContext) {
Brian Salomoncdcc33f2017-02-21 09:49:20 -0500423 GrRenderTarget* renderTarget =
424 renderTargetContext ? renderTargetContext->accessRenderTarget()
425 : nullptr;
Brian Salomon69868af2016-12-22 15:42:51 -0500426
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500427 // A closed GrOpList should never receive new/more ops
robertphillips6a186652015-10-20 07:37:58 -0700428 SkASSERT(!this->isClosed());
robertphillipsa106c622015-10-16 09:07:06 -0700429
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500430 // Check if there is an op we can combine with by linearly searching back until we either
431 // 1) check every op
bsalomon512be532015-09-10 10:42:55 -0700432 // 2) intersect with something
433 // 3) find a 'blocker'
Brian Salomoncdcc33f2017-02-21 09:49:20 -0500434 GR_AUDIT_TRAIL_ADD_OP(fAuditTrail, op.get(), renderTarget->uniqueID());
Brian Salomon199fb872017-02-06 09:41:10 -0500435 GrOP_INFO("Recording (%s, B%u)\n"
Brian Salomon25a88092016-12-01 09:36:50 -0500436 "\tBounds LRTB (%f, %f, %f, %f)\n",
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500437 op->name(),
438 op->uniqueID(),
439 op->bounds().fLeft, op->bounds().fRight,
440 op->bounds().fTop, op->bounds().fBottom);
441 GrOP_INFO(SkTabString(op->dumpInfo(), 1).c_str());
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500442 GrOP_INFO("\tClipped Bounds: [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", op->bounds().fLeft,
443 op->bounds().fTop, op->bounds().fRight, op->bounds().fBottom);
Brian Salomon25a88092016-12-01 09:36:50 -0500444 GrOP_INFO("\tOutcome:\n");
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500445 int maxCandidates = SkTMin(fMaxOpLookback, fRecordedOps.count());
Brian Salomoncdcc33f2017-02-21 09:49:20 -0500446 // If we don't have a valid destination render target then we cannot reorder.
447 if (maxCandidates && renderTarget) {
bsalomon512be532015-09-10 10:42:55 -0700448 int i = 0;
449 while (true) {
Brian Salomon69868af2016-12-22 15:42:51 -0500450 const RecordedOp& candidate = fRecordedOps.fromBack(i);
bsalomon512be532015-09-10 10:42:55 -0700451 // We cannot continue to search backwards if the render target changes
Brian Salomoncdcc33f2017-02-21 09:49:20 -0500452 if (candidate.fRenderTarget.get() != renderTarget) {
Brian Salomon69868af2016-12-22 15:42:51 -0500453 GrOP_INFO("\t\tBreaking because of (%s, B%u) Rendertarget\n", candidate.fOp->name(),
454 candidate.fOp->uniqueID());
bsalomon512be532015-09-10 10:42:55 -0700455 break;
456 }
Brian Salomon69868af2016-12-22 15:42:51 -0500457 if (candidate.fOp->combineIfPossible(op.get(), *this->caps())) {
458 GrOP_INFO("\t\tCombining with (%s, B%u)\n", candidate.fOp->name(),
459 candidate.fOp->uniqueID());
Brian Salomon199fb872017-02-06 09:41:10 -0500460 GrOP_INFO("\t\t\tCombined op info:\n");
461 GrOP_INFO(SkTabString(candidate.fOp->dumpInfo(), 4).c_str());
Brian Salomon69868af2016-12-22 15:42:51 -0500462 GR_AUDIT_TRAIL_OPS_RESULT_COMBINED(fAuditTrail, candidate.fOp.get(), op.get());
Brian Salomon69868af2016-12-22 15:42:51 -0500463 return candidate.fOp.get();
bsalomon512be532015-09-10 10:42:55 -0700464 }
465 // Stop going backwards if we would cause a painter's order violation.
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500466 if (!can_reorder(fRecordedOps.fromBack(i).fOp->bounds(), op->bounds())) {
Brian Salomon69868af2016-12-22 15:42:51 -0500467 GrOP_INFO("\t\tIntersects with (%s, B%u)\n", candidate.fOp->name(),
468 candidate.fOp->uniqueID());
bsalomon512be532015-09-10 10:42:55 -0700469 break;
470 }
471 ++i;
472 if (i == maxCandidates) {
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500473 GrOP_INFO("\t\tReached max lookback or beginning of op array %d\n", i);
bsalomon512be532015-09-10 10:42:55 -0700474 break;
475 }
476 }
477 } else {
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500478 GrOP_INFO("\t\tFirstOp\n");
bsalomon512be532015-09-10 10:42:55 -0700479 }
Brian Salomon42ad83a2016-12-20 16:14:45 -0500480 GR_AUDIT_TRAIL_OP_RESULT_NEW(fAuditTrail, op);
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500481 fRecordedOps.emplace_back(std::move(op), renderTarget);
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500482 fLastFullClearOp = nullptr;
Brian Salomon69868af2016-12-22 15:42:51 -0500483 fLastFullClearRenderTargetID.makeInvalid();
Brian Salomon2790c522016-12-09 16:32:23 -0500484 return fRecordedOps.back().fOp.get();
bsalomon512be532015-09-10 10:42:55 -0700485}
486
Robert Phillipsf2361d22016-10-25 14:20:06 -0400487void GrRenderTargetOpList::forwardCombine() {
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500488 if (fMaxOpLookahead <= 0) {
bsalomondb27fc52016-08-29 12:43:27 -0700489 return;
490 }
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500491 for (int i = 0; i < fRecordedOps.count() - 2; ++i) {
492 GrOp* op = fRecordedOps[i].fOp.get();
Brian Salomoncdcc33f2017-02-21 09:49:20 -0500493 GrRenderTarget* renderTarget = fRecordedOps[i].fRenderTarget.get();
Brian Salomon69868af2016-12-22 15:42:51 -0500494 // If we don't have a valid destination render target ID then we cannot reorder.
Brian Salomoncdcc33f2017-02-21 09:49:20 -0500495 if (!renderTarget) {
Brian Salomon69868af2016-12-22 15:42:51 -0500496 continue;
497 }
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500498 int maxCandidateIdx = SkTMin(i + fMaxOpLookahead, fRecordedOps.count() - 1);
bsalomonaecc0182016-03-07 11:50:44 -0800499 int j = i + 1;
500 while (true) {
Brian Salomon69868af2016-12-22 15:42:51 -0500501 const RecordedOp& candidate = fRecordedOps[j];
bsalomonaecc0182016-03-07 11:50:44 -0800502 // We cannot continue to search if the render target changes
Brian Salomoncdcc33f2017-02-21 09:49:20 -0500503 if (candidate.fRenderTarget.get() != renderTarget) {
Brian Salomon69868af2016-12-22 15:42:51 -0500504 GrOP_INFO("\t\tBreaking because of (%s, B%u) Rendertarget\n", candidate.fOp->name(),
505 candidate.fOp->uniqueID());
bsalomonaecc0182016-03-07 11:50:44 -0800506 break;
507 }
508 if (j == i +1) {
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500509 // We assume op would have combined with candidate when the candidate was added
510 // via backwards combining in recordOp.
Mike Reed27d07f02017-03-04 21:47:47 +0000511#ifndef SK_USE_DEVICE_CLIPPING
Mike Reedd519d482017-02-16 11:04:52 -0500512 // not sure why this fires with device-clipping in gm/complexclip4.cpp
Mike Reed27d07f02017-03-04 21:47:47 +0000513 SkASSERT(!op->combineIfPossible(candidate.fOp.get(), *this->caps()));
514#endif
Brian Salomon69868af2016-12-22 15:42:51 -0500515 } else if (op->combineIfPossible(candidate.fOp.get(), *this->caps())) {
516 GrOP_INFO("\t\tCombining with (%s, B%u)\n", candidate.fOp->name(),
517 candidate.fOp->uniqueID());
518 GR_AUDIT_TRAIL_OPS_RESULT_COMBINED(fAuditTrail, op, candidate.fOp.get());
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500519 fRecordedOps[j].fOp = std::move(fRecordedOps[i].fOp);
bsalomonaecc0182016-03-07 11:50:44 -0800520 break;
521 }
522 // Stop going traversing if we would cause a painter's order violation.
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500523 if (!can_reorder(fRecordedOps[j].fOp->bounds(), op->bounds())) {
Brian Salomon69868af2016-12-22 15:42:51 -0500524 GrOP_INFO("\t\tIntersects with (%s, B%u)\n", candidate.fOp->name(),
525 candidate.fOp->uniqueID());
bsalomonaecc0182016-03-07 11:50:44 -0800526 break;
527 }
528 ++j;
529 if (j > maxCandidateIdx) {
Brian Salomon09d994e2016-12-21 11:14:46 -0500530 GrOP_INFO("\t\tReached max lookahead or end of op array %d\n", i);
bsalomonaecc0182016-03-07 11:50:44 -0800531 break;
532 }
533 }
534 }
535}
536
egdaniele36914c2015-02-13 09:00:33 -0800537///////////////////////////////////////////////////////////////////////////////
538
Robert Phillipsf2361d22016-10-25 14:20:06 -0400539void GrRenderTargetOpList::clearStencilClip(const GrFixedClip& clip,
540 bool insideStencilMask,
Brian Salomon69868af2016-12-22 15:42:51 -0500541 GrRenderTargetContext* renderTargetContext) {
542 this->recordOp(GrClearStencilClipOp::Make(clip, insideStencilMask,
543 renderTargetContext->accessRenderTarget()),
544 renderTargetContext);
bsalomon5ea03632015-08-18 10:33:30 -0700545}