blob: 9fb2dcbd1ca18d09a861a9b5e03c030a68682c91 [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"
ethannicholas22793252016-01-30 09:59:10 -080026#include "gl/GrGLRenderTarget.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000027
joshualitt086cee12016-01-12 06:45:24 -080028#include "SkStrokeRec.h"
29
Brian Salomon89527432016-12-16 09:52:16 -050030#include "ops/GrClearOp.h"
31#include "ops/GrClearStencilClipOp.h"
32#include "ops/GrCopySurfaceOp.h"
33#include "ops/GrDiscardOp.h"
34#include "ops/GrDrawOp.h"
35#include "ops/GrDrawPathOp.h"
36#include "ops/GrRectOpFactory.h"
37#include "ops/GrStencilPathOp.h"
joshualitt74417822015-08-07 11:42:16 -070038
csmartdaltona7f29642016-07-07 08:49:11 -070039#include "instanced/InstancedRendering.h"
40
Robert Phillipsf2361d22016-10-25 14:20:06 -040041using gr_instanced::InstancedRendering;
42
reed@google.comac10a2d2010-12-22 21:39:39 +000043////////////////////////////////////////////////////////////////////////////////
44
Brian Salomon09d994e2016-12-21 11:14:46 -050045// Experimentally we have found that most combining occurs within the first 10 comparisons.
46static const int kDefaultMaxOpLookback = 10;
47static const int kDefaultMaxOpLookahead = 10;
bsalomon489147c2015-12-14 12:13:09 -080048
Robert Phillipsc7635fa2016-10-28 13:25:24 -040049GrRenderTargetOpList::GrRenderTargetOpList(GrRenderTargetProxy* rtp, GrGpu* gpu,
Robert Phillipsf2361d22016-10-25 14:20:06 -040050 GrResourceProvider* resourceProvider,
51 GrAuditTrail* auditTrail, const Options& options)
Robert Phillipsc7635fa2016-10-28 13:25:24 -040052 : INHERITED(rtp, auditTrail)
bsalomonfd8d0132016-08-11 11:25:33 -070053 , fGpu(SkRef(gpu))
csmartdalton7cdda992016-11-01 07:03:03 -070054 , fResourceProvider(resourceProvider)
55 , fLastClipStackGenID(SK_InvalidUniqueID) {
csmartdaltonc6f411e2016-08-05 22:32:12 -070056 // TODO: Stop extracting the context (currently needed by GrClip)
bsalomonb3b9aec2015-09-10 11:16:35 -070057 fContext = fGpu->getContext();
robertphillips4beb5c12015-10-20 07:50:00 -070058
Brian Salomon09d994e2016-12-21 11:14:46 -050059 fClipOpToBounds = options.fClipDrawOpsToBounds;
60 fMaxOpLookback = (options.fMaxOpCombineLookback < 0) ? kDefaultMaxOpLookback
61 : options.fMaxOpCombineLookback;
62 fMaxOpLookahead = (options.fMaxOpCombineLookahead < 0) ? kDefaultMaxOpLookahead
63 : options.fMaxOpCombineLookahead;
bsalomon6dea83f2015-12-03 12:58:06 -080064
csmartdaltone0d36292016-07-29 08:14:20 -070065 if (GrCaps::InstancedSupport::kNone != this->caps()->instancedSupport()) {
66 fInstancedRendering.reset(fGpu->createInstancedRendering());
67 }
bsalomon4061b122015-05-29 10:26:19 -070068}
69
Robert Phillipsf2361d22016-10-25 14:20:06 -040070GrRenderTargetOpList::~GrRenderTargetOpList() {
bsalomon4061b122015-05-29 10:26:19 -070071 fGpu->unref();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +000072}
73
74////////////////////////////////////////////////////////////////////////////////
75
robertphillips4beb5c12015-10-20 07:50:00 -070076#ifdef SK_DEBUG
Robert Phillipsf2361d22016-10-25 14:20:06 -040077void GrRenderTargetOpList::dump() const {
78 INHERITED::dump();
79
Brian Salomon1e41f4a2016-12-07 15:05:04 -050080 SkDebugf("ops (%d):\n", fRecordedOps.count());
81 for (int i = 0; i < fRecordedOps.count(); ++i) {
robertphillips4beb5c12015-10-20 07:50:00 -070082 SkDebugf("*******************************\n");
Brian Salomon1e41f4a2016-12-07 15:05:04 -050083 if (!fRecordedOps[i].fOp) {
bsalomonaecc0182016-03-07 11:50:44 -080084 SkDebugf("%d: <combined forward>\n", i);
85 } else {
Brian Salomon1e41f4a2016-12-07 15:05:04 -050086 SkDebugf("%d: %s\n", i, fRecordedOps[i].fOp->name());
87 SkString str = fRecordedOps[i].fOp->dumpInfo();
bsalomonaecc0182016-03-07 11:50:44 -080088 SkDebugf("%s\n", str.c_str());
Brian Salomon1e41f4a2016-12-07 15:05:04 -050089 const SkRect& clippedBounds = fRecordedOps[i].fClippedBounds;
bsalomon6cc90062016-07-08 11:31:22 -070090 SkDebugf("ClippedBounds: [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n",
91 clippedBounds.fLeft, clippedBounds.fTop, clippedBounds.fRight,
92 clippedBounds.fBottom);
bsalomonaecc0182016-03-07 11:50:44 -080093 }
robertphillips4beb5c12015-10-20 07:50:00 -070094 }
95}
96#endif
97
Brian Salomon5b7b49f2016-12-07 14:31:00 -050098void GrRenderTargetOpList::setupDstTexture(GrRenderTarget* rt,
99 const GrClip& clip,
Brian Salomon09d994e2016-12-21 11:14:46 -0500100 const SkRect& opBounds,
Brian Salomon5b7b49f2016-12-07 14:31:00 -0500101 GrXferProcessor::DstTexture* dstTexture) {
Brian Salomon09d994e2016-12-21 11:14:46 -0500102 SkRect bounds = opBounds;
bsalomonad792c12015-09-10 11:10:50 -0700103 bounds.outset(0.5f, 0.5f);
104
cdalton9954bc32015-04-29 14:17:00 -0700105 if (this->caps()->textureBarrierSupport()) {
106 if (GrTexture* rtTex = rt->asTexture()) {
bsalomondc47ff72015-05-26 12:16:59 -0700107 // The render target is a texture, so we can read from it directly in the shader. The XP
cdalton9954bc32015-04-29 14:17:00 -0700108 // will be responsible to detect this situation and request a texture barrier.
bungeman6bd52842016-10-27 09:30:08 -0700109 dstTexture->setTexture(sk_ref_sp(rtTex));
bsalomon6a44c6a2015-05-26 09:49:05 -0700110 dstTexture->setOffset(0, 0);
Brian Salomon5b7b49f2016-12-07 14:31:00 -0500111 return;
cdalton9954bc32015-04-29 14:17:00 -0700112 }
113 }
114
115 SkIRect copyRect;
cdalton862cff32016-05-12 15:09:48 -0700116 clip.getConservativeBounds(rt->width(), rt->height(), &copyRect);
commit-bot@chromium.orgc4dc0ad2013-10-09 14:11:33 +0000117
bsalomonad792c12015-09-10 11:10:50 -0700118 SkIRect drawIBounds;
119 bounds.roundOut(&drawIBounds);
120 if (!copyRect.intersect(drawIBounds)) {
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000121#ifdef SK_DEBUG
bsalomonb3b9aec2015-09-10 11:16:35 -0700122 GrCapsDebugf(this->caps(), "Missed an early reject. "
Brian Salomon5b7b49f2016-12-07 14:31:00 -0500123 "Bailing on draw from setupDstTexture.\n");
commit-bot@chromium.orgbb5c4652013-04-01 12:49:31 +0000124#endif
Brian Salomon5b7b49f2016-12-07 14:31:00 -0500125 return;
commit-bot@chromium.orgbb5c4652013-04-01 12:49:31 +0000126 }
skia.committer@gmail.com05a2ee02013-04-02 07:01:34 +0000127
commit-bot@chromium.org63150af2013-04-11 22:00:22 +0000128 // MSAA consideration: When there is support for reading MSAA samples in the shader we could
129 // have per-sample dst values by making the copy multisampled.
bsalomonf2703d82014-10-28 14:33:06 -0700130 GrSurfaceDesc desc;
egdaniel4bcd62e2016-08-31 07:37:31 -0700131 if (!fGpu->initDescForDstCopy(rt, &desc)) {
bsalomona73239a2015-04-28 13:35:17 -0700132 desc.fOrigin = kDefault_GrSurfaceOrigin;
133 desc.fFlags = kRenderTarget_GrSurfaceFlag;
134 desc.fConfig = rt->config();
135 }
136
commit-bot@chromium.orgbb5c4652013-04-01 12:49:31 +0000137 desc.fWidth = copyRect.width();
138 desc.fHeight = copyRect.height();
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000139
bsalomoneae62002015-07-31 13:59:30 -0700140 static const uint32_t kFlags = 0;
bungeman6bd52842016-10-27 09:30:08 -0700141 sk_sp<GrTexture> copy(fResourceProvider->createApproxTexture(desc, kFlags));
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000142
bsalomone3059732014-10-14 11:47:22 -0700143 if (!copy) {
tfarina38406c82014-10-31 07:11:12 -0700144 SkDebugf("Failed to create temporary copy of destination texture.\n");
Brian Salomon5b7b49f2016-12-07 14:31:00 -0500145 return;
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000146 }
bsalomon@google.come4617bf2013-04-03 14:56:40 +0000147 SkIPoint dstPoint = {0, 0};
bungeman6bd52842016-10-27 09:30:08 -0700148 this->copySurface(copy.get(), rt, copyRect, dstPoint);
149 dstTexture->setTexture(std::move(copy));
bsalomon6df86402015-06-01 10:41:49 -0700150 dstTexture->setOffset(copyRect.fLeft, copyRect.fTop);
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000151}
152
Brian Salomon742e31d2016-12-07 17:06:19 -0500153void GrRenderTargetOpList::prepareOps(GrOpFlushState* flushState) {
Robert Phillipsf2361d22016-10-25 14:20:06 -0400154 // Semi-usually the GrOpLists are already closed at this point, but sometimes Ganesh
155 // needs to flush mid-draw. In that case, the SkGpuDevice's GrOpLists won't be closed
156 // but need to be flushed anyway. Closing such GrOpLists here will mean new
157 // GrOpLists will be created to replace them if the SkGpuDevice(s) write to them again.
robertphillipsa106c622015-10-16 09:07:06 -0700158 this->makeClosed();
159
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500160 // Loop over the ops that haven't yet been prepared.
161 for (int i = 0; i < fRecordedOps.count(); ++i) {
162 if (fRecordedOps[i].fOp) {
163 fRecordedOps[i].fOp->prepare(flushState);
bsalomonaecc0182016-03-07 11:50:44 -0800164 }
bsalomon512be532015-09-10 10:42:55 -0700165 }
csmartdaltona7f29642016-07-07 08:49:11 -0700166
167 if (fInstancedRendering) {
168 fInstancedRendering->beginFlush(flushState->resourceProvider());
169 }
robertphillipsa13e2022015-11-11 12:01:09 -0800170}
bsalomon512be532015-09-10 10:42:55 -0700171
Brian Salomon25a88092016-12-01 09:36:50 -0500172// TODO: this is where GrOp::renderTarget is used (which is fine since it
Robert Phillips294870f2016-11-11 12:38:40 -0500173// is at flush time). However, we need to store the RenderTargetProxy in the
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500174// Ops and instantiate them here.
Brian Salomon742e31d2016-12-07 17:06:19 -0500175bool GrRenderTargetOpList::executeOps(GrOpFlushState* flushState) {
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500176 if (0 == fRecordedOps.count()) {
bsalomondc438982016-08-31 11:53:49 -0700177 return false;
egdanielb4021cf2016-07-28 08:53:07 -0700178 }
bsalomon512be532015-09-10 10:42:55 -0700179 // Draw all the generated geometry.
bsalomon6dea83f2015-12-03 12:58:06 -0800180 SkRandom random;
Brian Salomon3a7492f2016-11-30 10:52:10 -0500181 GrGpuResource::UniqueID currentRTID = GrGpuResource::UniqueID::InvalidID();
Ben Wagner145dbcd2016-11-03 14:40:50 -0400182 std::unique_ptr<GrGpuCommandBuffer> commandBuffer;
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500183 for (int i = 0; i < fRecordedOps.count(); ++i) {
184 if (!fRecordedOps[i].fOp) {
bsalomonaecc0182016-03-07 11:50:44 -0800185 continue;
186 }
Brian Salomon69868af2016-12-22 15:42:51 -0500187 if (fRecordedOps[i].fRenderTargetID != currentRTID) {
egdaniel9cb63402016-06-23 08:37:05 -0700188 if (commandBuffer) {
189 commandBuffer->end();
Greg Daniel36a77ee2016-10-18 10:33:25 -0400190 commandBuffer->submit();
egdaniel9cb63402016-06-23 08:37:05 -0700191 commandBuffer.reset();
192 }
Brian Salomon69868af2016-12-22 15:42:51 -0500193 currentRTID = fRecordedOps[i].fRenderTargetID;
Brian Salomon3a7492f2016-11-30 10:52:10 -0500194 if (!currentRTID.isInvalid()) {
egdaniel9cb63402016-06-23 08:37:05 -0700195 static const GrGpuCommandBuffer::LoadAndStoreInfo kBasicLoadStoreInfo
196 { GrGpuCommandBuffer::LoadOp::kLoad,GrGpuCommandBuffer::StoreOp::kStore,
197 GrColor_ILLEGAL };
Brian Salomonc293a292016-11-30 13:38:32 -0500198 commandBuffer.reset(fGpu->createCommandBuffer(kBasicLoadStoreInfo, // Color
egdaniel9cb63402016-06-23 08:37:05 -0700199 kBasicLoadStoreInfo)); // Stencil
200 }
Ben Wagner145dbcd2016-11-03 14:40:50 -0400201 flushState->setCommandBuffer(commandBuffer.get());
egdaniel9cb63402016-06-23 08:37:05 -0700202 }
Brian Salomonbde42852016-12-21 11:37:49 -0500203 fRecordedOps[i].fOp->execute(flushState, fRecordedOps[i].fClippedBounds);
bsalomon512be532015-09-10 10:42:55 -0700204 }
egdaniel9cb63402016-06-23 08:37:05 -0700205 if (commandBuffer) {
206 commandBuffer->end();
Greg Daniel36a77ee2016-10-18 10:33:25 -0400207 commandBuffer->submit();
egdaniel9cb63402016-06-23 08:37:05 -0700208 flushState->setCommandBuffer(nullptr);
209 }
ethannicholas22793252016-01-30 09:59:10 -0800210
Robert Phillipsf2361d22016-10-25 14:20:06 -0400211 fGpu->finishOpList();
bsalomondc438982016-08-31 11:53:49 -0700212 return true;
bsalomona73239a2015-04-28 13:35:17 -0700213}
214
Robert Phillipsf2361d22016-10-25 14:20:06 -0400215void GrRenderTargetOpList::reset() {
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500216 fLastFullClearOp = nullptr;
Brian Salomon69868af2016-12-22 15:42:51 -0500217 fLastFullClearRenderTargetID.makeInvalid();
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500218 fRecordedOps.reset();
csmartdaltona7f29642016-07-07 08:49:11 -0700219 if (fInstancedRendering) {
220 fInstancedRendering->endFlush();
221 }
bsalomon512be532015-09-10 10:42:55 -0700222}
223
Robert Phillipsf2361d22016-10-25 14:20:06 -0400224void GrRenderTargetOpList::abandonGpuResources() {
225 if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport()) {
226 InstancedRendering* ir = this->instancedRendering();
227 ir->resetGpuResources(InstancedRendering::ResetType::kAbandon);
228 }
229}
230
231void GrRenderTargetOpList::freeGpuResources() {
232 if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport()) {
233 InstancedRendering* ir = this->instancedRendering();
234 ir->resetGpuResources(InstancedRendering::ResetType::kDestroy);
235 }
236}
237
Brian Salomon09d994e2016-12-21 11:14:46 -0500238static void op_bounds(SkRect* bounds, const GrOp* op) {
239 *bounds = op->bounds();
240 if (op->hasZeroArea()) {
241 if (op->hasAABloat()) {
bsalomon88cf17d2016-07-08 06:40:56 -0700242 bounds->outset(0.5f, 0.5f);
243 } else {
244 // We don't know which way the particular GPU will snap lines or points at integer
245 // coords. So we ensure that the bounds is large enough for either snap.
246 SkRect before = *bounds;
247 bounds->roundOut(bounds);
248 if (bounds->fLeft == before.fLeft) {
249 bounds->fLeft -= 1;
250 }
251 if (bounds->fTop == before.fTop) {
252 bounds->fTop -= 1;
253 }
254 if (bounds->fRight == before.fRight) {
255 bounds->fRight += 1;
256 }
257 if (bounds->fBottom == before.fBottom) {
258 bounds->fBottom += 1;
259 }
260 }
261 }
262}
263
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500264void GrRenderTargetOpList::addDrawOp(const GrPipelineBuilder& pipelineBuilder,
Brian Osman11052242016-10-27 14:47:55 -0400265 GrRenderTargetContext* renderTargetContext,
Robert Phillipsf2361d22016-10-25 14:20:06 -0400266 const GrClip& clip,
Brian Salomonf8334782017-01-03 09:42:58 -0500267 std::unique_ptr<GrDrawOp>
268 op) {
joshualitt4d8da812015-01-28 12:53:54 -0800269 // Setup clip
bsalomon88cf17d2016-07-08 06:40:56 -0700270 SkRect bounds;
Brian Salomon09d994e2016-12-21 11:14:46 -0500271 op_bounds(&bounds, op.get());
csmartdaltond211e782016-08-15 11:17:19 -0700272 GrAppliedClip appliedClip(bounds);
Brian Osman11052242016-10-27 14:47:55 -0400273 if (!clip.apply(fContext, renderTargetContext, pipelineBuilder.isHWAntialias(),
csmartdaltond211e782016-08-15 11:17:19 -0700274 pipelineBuilder.hasUserStencilSettings(), &appliedClip)) {
cdalton862cff32016-05-12 15:09:48 -0700275 return;
joshualitt4d8da812015-01-28 12:53:54 -0800276 }
robertphillips391395d2016-03-02 09:26:36 -0800277
robertphillips55fdccc2016-06-06 06:16:20 -0700278 // TODO: this is the only remaining usage of the AutoRestoreFragmentProcessorState - remove it
cdaltond4727922015-11-10 12:49:06 -0800279 GrPipelineBuilder::AutoRestoreFragmentProcessorState arfps;
csmartdaltond211e782016-08-15 11:17:19 -0700280 if (appliedClip.clipCoverageFragmentProcessor()) {
cdaltond4727922015-11-10 12:49:06 -0800281 arfps.set(&pipelineBuilder);
csmartdaltond211e782016-08-15 11:17:19 -0700282 arfps.addCoverageFragmentProcessor(sk_ref_sp(appliedClip.clipCoverageFragmentProcessor()));
cdaltond4727922015-11-10 12:49:06 -0800283 }
joshualitt4d8da812015-01-28 12:53:54 -0800284
cdalton862cff32016-05-12 15:09:48 -0700285 if (pipelineBuilder.hasUserStencilSettings() || appliedClip.hasStencilClip()) {
Robert Phillipse60ad622016-11-17 10:22:48 -0500286 if (!renderTargetContext->accessRenderTarget()) {
287 return;
288 }
289
Brian Osman11052242016-10-27 14:47:55 -0400290 if (!fResourceProvider->attachStencilAttachment(
291 renderTargetContext->accessRenderTarget())) {
cdalton17bf8202016-05-13 11:27:15 -0700292 SkDebugf("ERROR creating stencil attachment. Draw skipped.\n");
293 return;
294 }
cdalton193d9cf2016-05-12 11:52:02 -0700295 }
csmartdaltond211e782016-08-15 11:17:19 -0700296
297 GrPipeline::CreateArgs args;
298 args.fPipelineBuilder = &pipelineBuilder;
Brian Osman11052242016-10-27 14:47:55 -0400299 args.fRenderTargetContext = renderTargetContext;
csmartdaltond211e782016-08-15 11:17:19 -0700300 args.fCaps = this->caps();
Brian Salomon92aee3d2016-12-21 09:20:25 -0500301 op->initPipelineAnalysis(&args.fAnalysis);
302 if (args.fAnalysis.fUsesPLSDstRead || fClipOpToBounds) {
cdalton193d9cf2016-05-12 11:52:02 -0700303 GrGLIRect viewport;
304 viewport.fLeft = 0;
305 viewport.fBottom = 0;
Brian Osman11052242016-10-27 14:47:55 -0400306 viewport.fWidth = renderTargetContext->width();
307 viewport.fHeight = renderTargetContext->height();
cdalton193d9cf2016-05-12 11:52:02 -0700308 SkIRect ibounds;
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500309 ibounds.fLeft = SkTPin(SkScalarFloorToInt(op->bounds().fLeft), viewport.fLeft,
cdalton193d9cf2016-05-12 11:52:02 -0700310 viewport.fWidth);
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500311 ibounds.fTop = SkTPin(SkScalarFloorToInt(op->bounds().fTop), viewport.fBottom,
cdalton193d9cf2016-05-12 11:52:02 -0700312 viewport.fHeight);
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500313 ibounds.fRight = SkTPin(SkScalarCeilToInt(op->bounds().fRight), viewport.fLeft,
cdalton193d9cf2016-05-12 11:52:02 -0700314 viewport.fWidth);
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500315 ibounds.fBottom = SkTPin(SkScalarCeilToInt(op->bounds().fBottom), viewport.fBottom,
cdalton193d9cf2016-05-12 11:52:02 -0700316 viewport.fHeight);
csmartdaltond211e782016-08-15 11:17:19 -0700317 if (!appliedClip.addScissor(ibounds)) {
318 return;
cdalton193d9cf2016-05-12 11:52:02 -0700319 }
cdalton193d9cf2016-05-12 11:52:02 -0700320 }
Brian Salomon92aee3d2016-12-21 09:20:25 -0500321 args.fAnalysis.fColorPOI.completeCalculations(
322 sk_sp_address_as_pointer_address(pipelineBuilder.fColorFragmentProcessors.begin()),
323 pipelineBuilder.numColorFragmentProcessors());
324 args.fAnalysis.fCoveragePOI.completeCalculations(
325 sk_sp_address_as_pointer_address(pipelineBuilder.fCoverageFragmentProcessors.begin()),
326 pipelineBuilder.numCoverageFragmentProcessors());
csmartdaltond211e782016-08-15 11:17:19 -0700327 args.fScissor = &appliedClip.scissorState();
csmartdaltonbf4a8f92016-09-06 10:01:06 -0700328 args.fWindowRectsState = &appliedClip.windowRectsState();
csmartdaltond211e782016-08-15 11:17:19 -0700329 args.fHasStencilClip = appliedClip.hasStencilClip();
Robert Phillipse60ad622016-11-17 10:22:48 -0500330 if (!renderTargetContext->accessRenderTarget()) {
331 return;
332 }
333
Brian Salomon92aee3d2016-12-21 09:20:25 -0500334 if (pipelineBuilder.willXPNeedDstTexture(*this->caps(), args.fAnalysis)) {
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500335 this->setupDstTexture(renderTargetContext->accessRenderTarget(), clip, op->bounds(),
Brian Salomon5b7b49f2016-12-07 14:31:00 -0500336 &args.fDstTexture);
337 if (!args.fDstTexture.texture()) {
338 return;
339 }
cdalton193d9cf2016-05-12 11:52:02 -0700340 }
341
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500342 if (!op->installPipeline(args)) {
egdaniele36914c2015-02-13 09:00:33 -0800343 return;
344 }
bsalomonad792c12015-09-10 11:10:50 -0700345
robertphillips498d7ac2015-10-30 10:11:30 -0700346#ifdef ENABLE_MDB
Robert Phillipsf2361d22016-10-25 14:20:06 -0400347 SkASSERT(fSurface);
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500348 op->pipeline()->addDependenciesTo(fSurface);
robertphillips498d7ac2015-10-30 10:11:30 -0700349#endif
Brian Salomon69868af2016-12-22 15:42:51 -0500350 this->recordOp(std::move(op), renderTargetContext, appliedClip.clippedDrawBounds());
joshualitt4d8da812015-01-28 12:53:54 -0800351}
352
Brian Osman11052242016-10-27 14:47:55 -0400353void GrRenderTargetOpList::stencilPath(GrRenderTargetContext* renderTargetContext,
Robert Phillipsf2361d22016-10-25 14:20:06 -0400354 const GrClip& clip,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500355 GrAAType aaType,
Robert Phillipsf2361d22016-10-25 14:20:06 -0400356 const SkMatrix& viewMatrix,
357 const GrPath* path) {
Brian Salomon0abc8b42016-12-13 10:22:54 -0500358 bool useHWAA = GrAATypeIsHW(aaType);
bsalomon@google.com64aef2b2012-06-11 15:36:13 +0000359 // TODO: extract portions of checkDraw that are relevant to path stenciling.
bsalomon49f085d2014-09-05 13:34:00 -0700360 SkASSERT(path);
jvanverthe9c0fc62015-04-29 11:18:05 -0700361 SkASSERT(this->caps()->shaderCaps()->pathRenderingSupport());
joshualitt2c93efe2014-11-06 12:57:13 -0800362
csmartdaltond211e782016-08-15 11:17:19 -0700363 // FIXME: Use path bounds instead of this WAR once
364 // https://bugs.chromium.org/p/skia/issues/detail?id=5640 is resolved.
Brian Osman11052242016-10-27 14:47:55 -0400365 SkRect bounds = SkRect::MakeIWH(renderTargetContext->width(), renderTargetContext->height());
csmartdaltond211e782016-08-15 11:17:19 -0700366
joshualitt2c93efe2014-11-06 12:57:13 -0800367 // Setup clip
csmartdaltond211e782016-08-15 11:17:19 -0700368 GrAppliedClip appliedClip(bounds);
Brian Osman11052242016-10-27 14:47:55 -0400369 if (!clip.apply(fContext, renderTargetContext, useHWAA, true, &appliedClip)) {
joshualitt2c93efe2014-11-06 12:57:13 -0800370 return;
371 }
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500372 // TODO: respect fClipOpToBounds if we ever start computing bounds here.
joshualitt2c93efe2014-11-06 12:57:13 -0800373
cdalton846c0512016-05-13 10:25:00 -0700374 // Coverage AA does not make sense when rendering to the stencil buffer. The caller should never
375 // attempt this in a situation that would require coverage AA.
csmartdaltond211e782016-08-15 11:17:19 -0700376 SkASSERT(!appliedClip.clipCoverageFragmentProcessor());
bsalomon0ba8c242015-10-07 09:20:28 -0700377
Robert Phillipse60ad622016-11-17 10:22:48 -0500378 if (!renderTargetContext->accessRenderTarget()) {
379 return;
380 }
robertphillips55fdccc2016-06-06 06:16:20 -0700381 GrStencilAttachment* stencilAttachment = fResourceProvider->attachStencilAttachment(
Brian Osman11052242016-10-27 14:47:55 -0400382 renderTargetContext->accessRenderTarget());
cdalton17bf8202016-05-13 11:27:15 -0700383 if (!stencilAttachment) {
384 SkDebugf("ERROR creating stencil attachment. Draw skipped.\n");
385 return;
386 }
joshualitt2c93efe2014-11-06 12:57:13 -0800387
Brian Salomonf8334782017-01-03 09:42:58 -0500388 std::unique_ptr<GrOp> op = GrStencilPathOp::Make(viewMatrix,
389 useHWAA,
390 path->getFillType(),
391 appliedClip.hasStencilClip(),
392 stencilAttachment->bits(),
393 appliedClip.scissorState(),
394 renderTargetContext->accessRenderTarget(),
395 path);
Brian Salomon69868af2016-12-22 15:42:51 -0500396 this->recordOp(std::move(op), renderTargetContext, appliedClip.clippedDrawBounds());
bsalomon@google.com64aef2b2012-06-11 15:36:13 +0000397}
398
Brian Salomon69868af2016-12-22 15:42:51 -0500399void GrRenderTargetOpList::fullClear(GrRenderTargetContext* renderTargetContext, GrColor color) {
400 GrRenderTarget* renderTarget = renderTargetContext->accessRenderTarget();
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500401 // Currently this just inserts or updates the last clear op. However, once in MDB this can
402 // remove all the previously recorded ops and change the load op to clear with supplied
bsalomonfd8d0132016-08-11 11:25:33 -0700403 // color.
Robert Phillips294870f2016-11-11 12:38:40 -0500404 // TODO: this needs to be updated to use GrSurfaceProxy::UniqueID
Brian Salomon69868af2016-12-22 15:42:51 -0500405 if (fLastFullClearRenderTargetID == renderTarget->uniqueID()) {
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500406 // As currently implemented, fLastFullClearOp should be the last op because we would
407 // have cleared it when another op was recorded.
408 SkASSERT(fRecordedOps.back().fOp.get() == fLastFullClearOp);
409 fLastFullClearOp->setColor(color);
bsalomonfd8d0132016-08-11 11:25:33 -0700410 return;
411 }
Brian Salomonf8334782017-01-03 09:42:58 -0500412 std::unique_ptr<GrClearOp> op(GrClearOp::Make(GrFixedClip::Disabled(), color, renderTarget));
Brian Salomon69868af2016-12-22 15:42:51 -0500413 if (GrOp* clearOp = this->recordOp(std::move(op), renderTargetContext)) {
Brian Salomon2790c522016-12-09 16:32:23 -0500414 // This is either the clear op we just created or another one that it combined with.
Brian Salomon7dae46a2016-12-14 16:21:37 -0500415 fLastFullClearOp = static_cast<GrClearOp*>(clearOp);
Brian Salomon69868af2016-12-22 15:42:51 -0500416 fLastFullClearRenderTargetID = renderTarget->uniqueID();
bsalomonfd8d0132016-08-11 11:25:33 -0700417 }
bsalomon9f129de2016-08-10 16:31:05 -0700418}
419
Brian Salomon69868af2016-12-22 15:42:51 -0500420void GrRenderTargetOpList::discard(GrRenderTargetContext* renderTargetContext) {
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500421 // Currently this just inserts a discard op. However, once in MDB this can remove all the
422 // previously recorded ops and change the load op to discard.
bsalomon53469832015-08-18 09:20:09 -0700423 if (this->caps()->discardRenderTargetSupport()) {
Brian Salomon69868af2016-12-22 15:42:51 -0500424 this->recordOp(GrDiscardOp::Make(renderTargetContext->accessRenderTarget()),
425 renderTargetContext);
bsalomon63b21962014-11-05 07:05:34 -0800426 }
427}
428
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000429////////////////////////////////////////////////////////////////////////////////
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000430
Robert Phillipsf2361d22016-10-25 14:20:06 -0400431bool GrRenderTargetOpList::copySurface(GrSurface* dst,
432 GrSurface* src,
433 const SkIRect& srcRect,
434 const SkIPoint& dstPoint) {
Brian Salomonf8334782017-01-03 09:42:58 -0500435 std::unique_ptr<GrOp> op = GrCopySurfaceOp::Make(dst, src, srcRect, dstPoint);
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500436 if (!op) {
bsalomonb8fea972016-02-16 07:34:17 -0800437 return false;
438 }
robertphillips498d7ac2015-10-30 10:11:30 -0700439#ifdef ENABLE_MDB
bsalomonb8fea972016-02-16 07:34:17 -0800440 this->addDependency(src);
robertphillips498d7ac2015-10-30 10:11:30 -0700441#endif
442
Brian Salomon69868af2016-12-22 15:42:51 -0500443 // Copy surface doesn't work through a GrGpuCommandBuffer. By passing nullptr for the context we
444 // force this to occur between command buffers and execute directly on GrGpu. This workaround
445 // goes away with MDB.
446 this->recordOp(std::move(op), nullptr);
bsalomonb8fea972016-02-16 07:34:17 -0800447 return true;
bsalomon@google.comeb851172013-04-15 13:51:00 +0000448}
449
bsalomon6cc90062016-07-08 11:31:22 -0700450static inline bool can_reorder(const SkRect& a, const SkRect& b) {
bsalomon88cf17d2016-07-08 06:40:56 -0700451 return a.fRight <= b.fLeft || a.fBottom <= b.fTop ||
452 b.fRight <= a.fLeft || b.fBottom <= a.fTop;
453}
454
bsalomon6cc90062016-07-08 11:31:22 -0700455static void join(SkRect* out, const SkRect& a, const SkRect& b) {
456 SkASSERT(a.fLeft <= a.fRight && a.fTop <= a.fBottom);
457 SkASSERT(b.fLeft <= b.fRight && b.fTop <= b.fBottom);
458 out->fLeft = SkTMin(a.fLeft, b.fLeft);
459 out->fTop = SkTMin(a.fTop, b.fTop);
460 out->fRight = SkTMax(a.fRight, b.fRight);
461 out->fBottom = SkTMax(a.fBottom, b.fBottom);
bsalomon512be532015-09-10 10:42:55 -0700462}
463
Brian Salomonf8334782017-01-03 09:42:58 -0500464GrOp* GrRenderTargetOpList::recordOp(std::unique_ptr<GrOp> op,
465 GrRenderTargetContext* renderTargetContext,
Brian Salomon69868af2016-12-22 15:42:51 -0500466 const SkRect& clippedBounds) {
467 // TODO: Should be proxy ID.
468 GrGpuResource::UniqueID renderTargetID =
469 renderTargetContext ? renderTargetContext->accessRenderTarget()->uniqueID()
470 : GrGpuResource::UniqueID::InvalidID();
471
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500472 // A closed GrOpList should never receive new/more ops
robertphillips6a186652015-10-20 07:37:58 -0700473 SkASSERT(!this->isClosed());
robertphillipsa106c622015-10-16 09:07:06 -0700474
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500475 // Check if there is an op we can combine with by linearly searching back until we either
476 // 1) check every op
bsalomon512be532015-09-10 10:42:55 -0700477 // 2) intersect with something
478 // 3) find a 'blocker'
Brian Salomon69868af2016-12-22 15:42:51 -0500479 GR_AUDIT_TRAIL_ADD_OP(fAuditTrail, op.get(), renderTargetID);
Brian Salomon25a88092016-12-01 09:36:50 -0500480 GrOP_INFO("Re-Recording (%s, B%u)\n"
481 "\tBounds LRTB (%f, %f, %f, %f)\n",
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500482 op->name(),
483 op->uniqueID(),
484 op->bounds().fLeft, op->bounds().fRight,
485 op->bounds().fTop, op->bounds().fBottom);
486 GrOP_INFO(SkTabString(op->dumpInfo(), 1).c_str());
Brian Salomon25a88092016-12-01 09:36:50 -0500487 GrOP_INFO("\tClipped Bounds: [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n",
488 clippedBounds.fLeft, clippedBounds.fTop, clippedBounds.fRight,
489 clippedBounds.fBottom);
490 GrOP_INFO("\tOutcome:\n");
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500491 int maxCandidates = SkTMin(fMaxOpLookback, fRecordedOps.count());
Brian Salomon69868af2016-12-22 15:42:51 -0500492 // If we don't have a valid destination render target ID then we cannot reorder.
493 if (maxCandidates && !renderTargetID.isInvalid()) {
bsalomon512be532015-09-10 10:42:55 -0700494 int i = 0;
495 while (true) {
Brian Salomon69868af2016-12-22 15:42:51 -0500496 const RecordedOp& candidate = fRecordedOps.fromBack(i);
bsalomon512be532015-09-10 10:42:55 -0700497 // We cannot continue to search backwards if the render target changes
Brian Salomon69868af2016-12-22 15:42:51 -0500498 if (candidate.fRenderTargetID != renderTargetID) {
499 GrOP_INFO("\t\tBreaking because of (%s, B%u) Rendertarget\n", candidate.fOp->name(),
500 candidate.fOp->uniqueID());
bsalomon512be532015-09-10 10:42:55 -0700501 break;
502 }
Brian Salomon69868af2016-12-22 15:42:51 -0500503 if (candidate.fOp->combineIfPossible(op.get(), *this->caps())) {
504 GrOP_INFO("\t\tCombining with (%s, B%u)\n", candidate.fOp->name(),
505 candidate.fOp->uniqueID());
506 GR_AUDIT_TRAIL_OPS_RESULT_COMBINED(fAuditTrail, candidate.fOp.get(), op.get());
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500507 join(&fRecordedOps.fromBack(i).fClippedBounds,
508 fRecordedOps.fromBack(i).fClippedBounds, clippedBounds);
Brian Salomon69868af2016-12-22 15:42:51 -0500509 return candidate.fOp.get();
bsalomon512be532015-09-10 10:42:55 -0700510 }
511 // Stop going backwards if we would cause a painter's order violation.
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500512 const SkRect& candidateBounds = fRecordedOps.fromBack(i).fClippedBounds;
bsalomon6cc90062016-07-08 11:31:22 -0700513 if (!can_reorder(candidateBounds, clippedBounds)) {
Brian Salomon69868af2016-12-22 15:42:51 -0500514 GrOP_INFO("\t\tIntersects with (%s, B%u)\n", candidate.fOp->name(),
515 candidate.fOp->uniqueID());
bsalomon512be532015-09-10 10:42:55 -0700516 break;
517 }
518 ++i;
519 if (i == maxCandidates) {
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500520 GrOP_INFO("\t\tReached max lookback or beginning of op array %d\n", i);
bsalomon512be532015-09-10 10:42:55 -0700521 break;
522 }
523 }
524 } else {
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500525 GrOP_INFO("\t\tFirstOp\n");
bsalomon512be532015-09-10 10:42:55 -0700526 }
Brian Salomon42ad83a2016-12-20 16:14:45 -0500527 GR_AUDIT_TRAIL_OP_RESULT_NEW(fAuditTrail, op);
Brian Salomon69868af2016-12-22 15:42:51 -0500528 fRecordedOps.emplace_back(RecordedOp{std::move(op), clippedBounds, renderTargetID});
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500529 fLastFullClearOp = nullptr;
Brian Salomon69868af2016-12-22 15:42:51 -0500530 fLastFullClearRenderTargetID.makeInvalid();
Brian Salomon2790c522016-12-09 16:32:23 -0500531 return fRecordedOps.back().fOp.get();
bsalomon512be532015-09-10 10:42:55 -0700532}
533
Robert Phillipsf2361d22016-10-25 14:20:06 -0400534void GrRenderTargetOpList::forwardCombine() {
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500535 if (fMaxOpLookahead <= 0) {
bsalomondb27fc52016-08-29 12:43:27 -0700536 return;
537 }
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500538 for (int i = 0; i < fRecordedOps.count() - 2; ++i) {
539 GrOp* op = fRecordedOps[i].fOp.get();
Brian Salomon69868af2016-12-22 15:42:51 -0500540 GrGpuResource::UniqueID renderTargetID = fRecordedOps[i].fRenderTargetID;
541 // If we don't have a valid destination render target ID then we cannot reorder.
542 if (renderTargetID.isInvalid()) {
543 continue;
544 }
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500545 const SkRect& opBounds = fRecordedOps[i].fClippedBounds;
546 int maxCandidateIdx = SkTMin(i + fMaxOpLookahead, fRecordedOps.count() - 1);
bsalomonaecc0182016-03-07 11:50:44 -0800547 int j = i + 1;
548 while (true) {
Brian Salomon69868af2016-12-22 15:42:51 -0500549 const RecordedOp& candidate = fRecordedOps[j];
bsalomonaecc0182016-03-07 11:50:44 -0800550 // We cannot continue to search if the render target changes
Brian Salomon69868af2016-12-22 15:42:51 -0500551 if (candidate.fRenderTargetID != renderTargetID) {
552 GrOP_INFO("\t\tBreaking because of (%s, B%u) Rendertarget\n", candidate.fOp->name(),
553 candidate.fOp->uniqueID());
bsalomonaecc0182016-03-07 11:50:44 -0800554 break;
555 }
556 if (j == i +1) {
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500557 // We assume op would have combined with candidate when the candidate was added
558 // via backwards combining in recordOp.
Brian Salomon69868af2016-12-22 15:42:51 -0500559 SkASSERT(!op->combineIfPossible(candidate.fOp.get(), *this->caps()));
560 } else if (op->combineIfPossible(candidate.fOp.get(), *this->caps())) {
561 GrOP_INFO("\t\tCombining with (%s, B%u)\n", candidate.fOp->name(),
562 candidate.fOp->uniqueID());
563 GR_AUDIT_TRAIL_OPS_RESULT_COMBINED(fAuditTrail, op, candidate.fOp.get());
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500564 fRecordedOps[j].fOp = std::move(fRecordedOps[i].fOp);
565 join(&fRecordedOps[j].fClippedBounds, fRecordedOps[j].fClippedBounds, opBounds);
bsalomonaecc0182016-03-07 11:50:44 -0800566 break;
567 }
568 // Stop going traversing if we would cause a painter's order violation.
Brian Salomon1e41f4a2016-12-07 15:05:04 -0500569 const SkRect& candidateBounds = fRecordedOps[j].fClippedBounds;
570 if (!can_reorder(candidateBounds, opBounds)) {
Brian Salomon69868af2016-12-22 15:42:51 -0500571 GrOP_INFO("\t\tIntersects with (%s, B%u)\n", candidate.fOp->name(),
572 candidate.fOp->uniqueID());
bsalomonaecc0182016-03-07 11:50:44 -0800573 break;
574 }
575 ++j;
576 if (j > maxCandidateIdx) {
Brian Salomon09d994e2016-12-21 11:14:46 -0500577 GrOP_INFO("\t\tReached max lookahead or end of op array %d\n", i);
bsalomonaecc0182016-03-07 11:50:44 -0800578 break;
579 }
580 }
581 }
582}
583
egdaniele36914c2015-02-13 09:00:33 -0800584///////////////////////////////////////////////////////////////////////////////
585
Robert Phillipsf2361d22016-10-25 14:20:06 -0400586void GrRenderTargetOpList::clearStencilClip(const GrFixedClip& clip,
587 bool insideStencilMask,
Brian Salomon69868af2016-12-22 15:42:51 -0500588 GrRenderTargetContext* renderTargetContext) {
589 this->recordOp(GrClearStencilClipOp::Make(clip, insideStencilMask,
590 renderTargetContext->accessRenderTarget()),
591 renderTargetContext);
bsalomon5ea03632015-08-18 10:33:30 -0700592}