blob: ad20771ccdf7f16ab1b20b7ab9ac84fb09a0cc93 [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
bsalomon9f129de2016-08-10 16:31:05 -070030#include "batches/GrClearBatch.h"
robertphillips9199a9f2016-07-13 07:48:43 -070031#include "batches/GrClearStencilClipBatch.h"
bsalomon872062c2015-08-18 12:12:35 -070032#include "batches/GrCopySurfaceBatch.h"
bsalomon53469832015-08-18 09:20:09 -070033#include "batches/GrDiscardBatch.h"
bsalomon16b99132015-08-13 14:55:50 -070034#include "batches/GrDrawBatch.h"
bsalomonadd79ef2015-08-19 13:26:49 -070035#include "batches/GrDrawPathBatch.h"
joshualittecd1a692015-08-10 10:08:26 -070036#include "batches/GrRectBatchFactory.h"
bsalomona44919e2015-08-18 13:28:19 -070037#include "batches/GrStencilPathBatch.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
bsalomon489147c2015-12-14 12:13:09 -080045// Experimentally we have found that most batching occurs within the first 10 comparisons.
bsalomonaecc0182016-03-07 11:50:44 -080046static const int kDefaultMaxBatchLookback = 10;
47static const int kDefaultMaxBatchLookahead = 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)
Robert Phillipsf2361d22016-10-25 14:20:06 -040053 , fLastFullClearBatch(nullptr)
bsalomonfd8d0132016-08-11 11:25:33 -070054 , fGpu(SkRef(gpu))
csmartdalton7cdda992016-11-01 07:03:03 -070055 , fResourceProvider(resourceProvider)
56 , fLastClipStackGenID(SK_InvalidUniqueID) {
csmartdaltonc6f411e2016-08-05 22:32:12 -070057 // TODO: Stop extracting the context (currently needed by GrClip)
bsalomonb3b9aec2015-09-10 11:16:35 -070058 fContext = fGpu->getContext();
robertphillips4beb5c12015-10-20 07:50:00 -070059
cdalton862cff32016-05-12 15:09:48 -070060 fClipBatchToBounds = options.fClipBatchToBounds;
bsalomon489147c2015-12-14 12:13:09 -080061 fMaxBatchLookback = (options.fMaxBatchLookback < 0) ? kDefaultMaxBatchLookback :
62 options.fMaxBatchLookback;
bsalomonaecc0182016-03-07 11:50:44 -080063 fMaxBatchLookahead = (options.fMaxBatchLookahead < 0) ? kDefaultMaxBatchLookahead :
64 options.fMaxBatchLookahead;
bsalomon6dea83f2015-12-03 12:58:06 -080065
csmartdaltone0d36292016-07-29 08:14:20 -070066 if (GrCaps::InstancedSupport::kNone != this->caps()->instancedSupport()) {
67 fInstancedRendering.reset(fGpu->createInstancedRendering());
68 }
bsalomon4061b122015-05-29 10:26:19 -070069}
70
Robert Phillipsf2361d22016-10-25 14:20:06 -040071GrRenderTargetOpList::~GrRenderTargetOpList() {
bsalomon4061b122015-05-29 10:26:19 -070072 fGpu->unref();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +000073}
74
75////////////////////////////////////////////////////////////////////////////////
76
robertphillips4beb5c12015-10-20 07:50:00 -070077#ifdef SK_DEBUG
Robert Phillipsf2361d22016-10-25 14:20:06 -040078void GrRenderTargetOpList::dump() const {
79 INHERITED::dump();
80
bsalomon6cc90062016-07-08 11:31:22 -070081 SkDebugf("batches (%d):\n", fRecordedBatches.count());
82 for (int i = 0; i < fRecordedBatches.count(); ++i) {
robertphillips4beb5c12015-10-20 07:50:00 -070083 SkDebugf("*******************************\n");
bsalomon6cc90062016-07-08 11:31:22 -070084 if (!fRecordedBatches[i].fBatch) {
bsalomonaecc0182016-03-07 11:50:44 -080085 SkDebugf("%d: <combined forward>\n", i);
86 } else {
bsalomon6cc90062016-07-08 11:31:22 -070087 SkDebugf("%d: %s\n", i, fRecordedBatches[i].fBatch->name());
88 SkString str = fRecordedBatches[i].fBatch->dumpInfo();
bsalomonaecc0182016-03-07 11:50:44 -080089 SkDebugf("%s\n", str.c_str());
bsalomon6cc90062016-07-08 11:31:22 -070090 const SkRect& clippedBounds = fRecordedBatches[i].fClippedBounds;
91 SkDebugf("ClippedBounds: [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n",
92 clippedBounds.fLeft, clippedBounds.fTop, clippedBounds.fRight,
93 clippedBounds.fBottom);
bsalomonaecc0182016-03-07 11:50:44 -080094 }
robertphillips4beb5c12015-10-20 07:50:00 -070095 }
96}
97#endif
98
Robert Phillipsf2361d22016-10-25 14:20:06 -040099bool GrRenderTargetOpList::setupDstReadIfNecessary(const GrPipelineBuilder& pipelineBuilder,
100 GrRenderTarget* rt,
101 const GrClip& clip,
102 const GrPipelineOptimizations& optimizations,
103 GrXferProcessor::DstTexture* dstTexture,
104 const SkRect& batchBounds) {
bsalomonad792c12015-09-10 11:10:50 -0700105 SkRect bounds = batchBounds;
106 bounds.outset(0.5f, 0.5f);
107
ethannicholasde4166a2015-11-30 08:57:38 -0800108 if (!pipelineBuilder.willXPNeedDstTexture(*this->caps(), optimizations)) {
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000109 return true;
110 }
cdalton9954bc32015-04-29 14:17:00 -0700111
cdalton9954bc32015-04-29 14:17:00 -0700112 if (this->caps()->textureBarrierSupport()) {
113 if (GrTexture* rtTex = rt->asTexture()) {
bsalomondc47ff72015-05-26 12:16:59 -0700114 // The render target is a texture, so we can read from it directly in the shader. The XP
cdalton9954bc32015-04-29 14:17:00 -0700115 // will be responsible to detect this situation and request a texture barrier.
bungeman6bd52842016-10-27 09:30:08 -0700116 dstTexture->setTexture(sk_ref_sp(rtTex));
bsalomon6a44c6a2015-05-26 09:49:05 -0700117 dstTexture->setOffset(0, 0);
cdalton9954bc32015-04-29 14:17:00 -0700118 return true;
119 }
120 }
121
122 SkIRect copyRect;
cdalton862cff32016-05-12 15:09:48 -0700123 clip.getConservativeBounds(rt->width(), rt->height(), &copyRect);
commit-bot@chromium.orgc4dc0ad2013-10-09 14:11:33 +0000124
bsalomonad792c12015-09-10 11:10:50 -0700125 SkIRect drawIBounds;
126 bounds.roundOut(&drawIBounds);
127 if (!copyRect.intersect(drawIBounds)) {
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000128#ifdef SK_DEBUG
bsalomonb3b9aec2015-09-10 11:16:35 -0700129 GrCapsDebugf(this->caps(), "Missed an early reject. "
130 "Bailing on draw from setupDstReadIfNecessary.\n");
commit-bot@chromium.orgbb5c4652013-04-01 12:49:31 +0000131#endif
bsalomonad792c12015-09-10 11:10:50 -0700132 return false;
commit-bot@chromium.orgbb5c4652013-04-01 12:49:31 +0000133 }
skia.committer@gmail.com05a2ee02013-04-02 07:01:34 +0000134
commit-bot@chromium.org63150af2013-04-11 22:00:22 +0000135 // MSAA consideration: When there is support for reading MSAA samples in the shader we could
136 // have per-sample dst values by making the copy multisampled.
bsalomonf2703d82014-10-28 14:33:06 -0700137 GrSurfaceDesc desc;
egdaniel4bcd62e2016-08-31 07:37:31 -0700138 if (!fGpu->initDescForDstCopy(rt, &desc)) {
bsalomona73239a2015-04-28 13:35:17 -0700139 desc.fOrigin = kDefault_GrSurfaceOrigin;
140 desc.fFlags = kRenderTarget_GrSurfaceFlag;
141 desc.fConfig = rt->config();
142 }
143
commit-bot@chromium.orgbb5c4652013-04-01 12:49:31 +0000144 desc.fWidth = copyRect.width();
145 desc.fHeight = copyRect.height();
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000146
bsalomoneae62002015-07-31 13:59:30 -0700147 static const uint32_t kFlags = 0;
bungeman6bd52842016-10-27 09:30:08 -0700148 sk_sp<GrTexture> copy(fResourceProvider->createApproxTexture(desc, kFlags));
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000149
bsalomone3059732014-10-14 11:47:22 -0700150 if (!copy) {
tfarina38406c82014-10-31 07:11:12 -0700151 SkDebugf("Failed to create temporary copy of destination texture.\n");
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000152 return false;
153 }
bsalomon@google.come4617bf2013-04-03 14:56:40 +0000154 SkIPoint dstPoint = {0, 0};
bungeman6bd52842016-10-27 09:30:08 -0700155 this->copySurface(copy.get(), rt, copyRect, dstPoint);
156 dstTexture->setTexture(std::move(copy));
bsalomon6df86402015-06-01 10:41:49 -0700157 dstTexture->setOffset(copyRect.fLeft, copyRect.fTop);
158 return true;
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000159}
160
Robert Phillipsf2361d22016-10-25 14:20:06 -0400161void GrRenderTargetOpList::prepareBatches(GrBatchFlushState* flushState) {
162 // Semi-usually the GrOpLists are already closed at this point, but sometimes Ganesh
163 // needs to flush mid-draw. In that case, the SkGpuDevice's GrOpLists won't be closed
164 // but need to be flushed anyway. Closing such GrOpLists here will mean new
165 // GrOpLists will be created to replace them if the SkGpuDevice(s) write to them again.
robertphillipsa106c622015-10-16 09:07:06 -0700166 this->makeClosed();
167
robertphillips498d7ac2015-10-30 10:11:30 -0700168 // Loop over the batches that haven't yet generated their geometry
bsalomon6cc90062016-07-08 11:31:22 -0700169 for (int i = 0; i < fRecordedBatches.count(); ++i) {
170 if (fRecordedBatches[i].fBatch) {
171 fRecordedBatches[i].fBatch->prepare(flushState);
bsalomonaecc0182016-03-07 11:50:44 -0800172 }
bsalomon512be532015-09-10 10:42:55 -0700173 }
csmartdaltona7f29642016-07-07 08:49:11 -0700174
175 if (fInstancedRendering) {
176 fInstancedRendering->beginFlush(flushState->resourceProvider());
177 }
robertphillipsa13e2022015-11-11 12:01:09 -0800178}
bsalomon512be532015-09-10 10:42:55 -0700179
Brian Salomon25a88092016-12-01 09:36:50 -0500180// TODO: this is where GrOp::renderTarget is used (which is fine since it
Robert Phillips294870f2016-11-11 12:38:40 -0500181// is at flush time). However, we need to store the RenderTargetProxy in the
182// Batches and instantiate them here.
Robert Phillipsf2361d22016-10-25 14:20:06 -0400183bool GrRenderTargetOpList::drawBatches(GrBatchFlushState* flushState) {
egdanielb4021cf2016-07-28 08:53:07 -0700184 if (0 == fRecordedBatches.count()) {
bsalomondc438982016-08-31 11:53:49 -0700185 return false;
egdanielb4021cf2016-07-28 08:53:07 -0700186 }
bsalomon512be532015-09-10 10:42:55 -0700187 // Draw all the generated geometry.
bsalomon6dea83f2015-12-03 12:58:06 -0800188 SkRandom random;
Brian Salomon3a7492f2016-11-30 10:52:10 -0500189 GrGpuResource::UniqueID currentRTID = GrGpuResource::UniqueID::InvalidID();
Ben Wagner145dbcd2016-11-03 14:40:50 -0400190 std::unique_ptr<GrGpuCommandBuffer> commandBuffer;
bsalomon6cc90062016-07-08 11:31:22 -0700191 for (int i = 0; i < fRecordedBatches.count(); ++i) {
192 if (!fRecordedBatches[i].fBatch) {
bsalomonaecc0182016-03-07 11:50:44 -0800193 continue;
194 }
Brian Salomon3a7492f2016-11-30 10:52:10 -0500195 if (fRecordedBatches[i].fBatch->renderTargetUniqueID() != currentRTID) {
egdaniel9cb63402016-06-23 08:37:05 -0700196 if (commandBuffer) {
197 commandBuffer->end();
Greg Daniel36a77ee2016-10-18 10:33:25 -0400198 commandBuffer->submit();
egdaniel9cb63402016-06-23 08:37:05 -0700199 commandBuffer.reset();
200 }
Brian Salomon3a7492f2016-11-30 10:52:10 -0500201 currentRTID = fRecordedBatches[i].fBatch->renderTargetUniqueID();
202 if (!currentRTID.isInvalid()) {
egdaniel9cb63402016-06-23 08:37:05 -0700203 static const GrGpuCommandBuffer::LoadAndStoreInfo kBasicLoadStoreInfo
204 { GrGpuCommandBuffer::LoadOp::kLoad,GrGpuCommandBuffer::StoreOp::kStore,
205 GrColor_ILLEGAL };
Brian Salomonc293a292016-11-30 13:38:32 -0500206 commandBuffer.reset(fGpu->createCommandBuffer(kBasicLoadStoreInfo, // Color
egdaniel9cb63402016-06-23 08:37:05 -0700207 kBasicLoadStoreInfo)); // Stencil
208 }
Ben Wagner145dbcd2016-11-03 14:40:50 -0400209 flushState->setCommandBuffer(commandBuffer.get());
egdaniel9cb63402016-06-23 08:37:05 -0700210 }
Greg Daniel36a77ee2016-10-18 10:33:25 -0400211 fRecordedBatches[i].fBatch->draw(flushState, fRecordedBatches[i].fClippedBounds);
bsalomon512be532015-09-10 10:42:55 -0700212 }
egdaniel9cb63402016-06-23 08:37:05 -0700213 if (commandBuffer) {
214 commandBuffer->end();
Greg Daniel36a77ee2016-10-18 10:33:25 -0400215 commandBuffer->submit();
egdaniel9cb63402016-06-23 08:37:05 -0700216 flushState->setCommandBuffer(nullptr);
217 }
ethannicholas22793252016-01-30 09:59:10 -0800218
Robert Phillipsf2361d22016-10-25 14:20:06 -0400219 fGpu->finishOpList();
bsalomondc438982016-08-31 11:53:49 -0700220 return true;
bsalomona73239a2015-04-28 13:35:17 -0700221}
222
Robert Phillipsf2361d22016-10-25 14:20:06 -0400223void GrRenderTargetOpList::reset() {
bsalomonfd8d0132016-08-11 11:25:33 -0700224 fLastFullClearBatch = nullptr;
bsalomon6cc90062016-07-08 11:31:22 -0700225 fRecordedBatches.reset();
csmartdaltona7f29642016-07-07 08:49:11 -0700226 if (fInstancedRendering) {
227 fInstancedRendering->endFlush();
228 }
bsalomon512be532015-09-10 10:42:55 -0700229}
230
Robert Phillipsf2361d22016-10-25 14:20:06 -0400231void GrRenderTargetOpList::abandonGpuResources() {
232 if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport()) {
233 InstancedRendering* ir = this->instancedRendering();
234 ir->resetGpuResources(InstancedRendering::ResetType::kAbandon);
235 }
236}
237
238void GrRenderTargetOpList::freeGpuResources() {
239 if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport()) {
240 InstancedRendering* ir = this->instancedRendering();
241 ir->resetGpuResources(InstancedRendering::ResetType::kDestroy);
242 }
243}
244
Brian Salomon25a88092016-12-01 09:36:50 -0500245static void batch_bounds(SkRect* bounds, const GrOp* batch) {
bsalomon88cf17d2016-07-08 06:40:56 -0700246 *bounds = batch->bounds();
247 if (batch->hasZeroArea()) {
248 if (batch->hasAABloat()) {
249 bounds->outset(0.5f, 0.5f);
250 } else {
251 // We don't know which way the particular GPU will snap lines or points at integer
252 // coords. So we ensure that the bounds is large enough for either snap.
253 SkRect before = *bounds;
254 bounds->roundOut(bounds);
255 if (bounds->fLeft == before.fLeft) {
256 bounds->fLeft -= 1;
257 }
258 if (bounds->fTop == before.fTop) {
259 bounds->fTop -= 1;
260 }
261 if (bounds->fRight == before.fRight) {
262 bounds->fRight += 1;
263 }
264 if (bounds->fBottom == before.fBottom) {
265 bounds->fBottom += 1;
266 }
267 }
268 }
269}
270
Robert Phillipsf2361d22016-10-25 14:20:06 -0400271void GrRenderTargetOpList::drawBatch(const GrPipelineBuilder& pipelineBuilder,
Brian Osman11052242016-10-27 14:47:55 -0400272 GrRenderTargetContext* renderTargetContext,
Robert Phillipsf2361d22016-10-25 14:20:06 -0400273 const GrClip& clip,
274 GrDrawBatch* batch) {
joshualitt4d8da812015-01-28 12:53:54 -0800275 // Setup clip
bsalomon88cf17d2016-07-08 06:40:56 -0700276 SkRect bounds;
277 batch_bounds(&bounds, batch);
csmartdaltond211e782016-08-15 11:17:19 -0700278 GrAppliedClip appliedClip(bounds);
Brian Osman11052242016-10-27 14:47:55 -0400279 if (!clip.apply(fContext, renderTargetContext, pipelineBuilder.isHWAntialias(),
csmartdaltond211e782016-08-15 11:17:19 -0700280 pipelineBuilder.hasUserStencilSettings(), &appliedClip)) {
cdalton862cff32016-05-12 15:09:48 -0700281 return;
joshualitt4d8da812015-01-28 12:53:54 -0800282 }
robertphillips391395d2016-03-02 09:26:36 -0800283
robertphillips55fdccc2016-06-06 06:16:20 -0700284 // TODO: this is the only remaining usage of the AutoRestoreFragmentProcessorState - remove it
cdaltond4727922015-11-10 12:49:06 -0800285 GrPipelineBuilder::AutoRestoreFragmentProcessorState arfps;
csmartdaltond211e782016-08-15 11:17:19 -0700286 if (appliedClip.clipCoverageFragmentProcessor()) {
cdaltond4727922015-11-10 12:49:06 -0800287 arfps.set(&pipelineBuilder);
csmartdaltond211e782016-08-15 11:17:19 -0700288 arfps.addCoverageFragmentProcessor(sk_ref_sp(appliedClip.clipCoverageFragmentProcessor()));
cdaltond4727922015-11-10 12:49:06 -0800289 }
joshualitt4d8da812015-01-28 12:53:54 -0800290
cdalton862cff32016-05-12 15:09:48 -0700291 if (pipelineBuilder.hasUserStencilSettings() || appliedClip.hasStencilClip()) {
Robert Phillipse60ad622016-11-17 10:22:48 -0500292 if (!renderTargetContext->accessRenderTarget()) {
293 return;
294 }
295
Brian Osman11052242016-10-27 14:47:55 -0400296 if (!fResourceProvider->attachStencilAttachment(
297 renderTargetContext->accessRenderTarget())) {
cdalton17bf8202016-05-13 11:27:15 -0700298 SkDebugf("ERROR creating stencil attachment. Draw skipped.\n");
299 return;
300 }
cdalton193d9cf2016-05-12 11:52:02 -0700301 }
csmartdaltond211e782016-08-15 11:17:19 -0700302
303 GrPipeline::CreateArgs args;
304 args.fPipelineBuilder = &pipelineBuilder;
Brian Osman11052242016-10-27 14:47:55 -0400305 args.fRenderTargetContext = renderTargetContext;
csmartdaltond211e782016-08-15 11:17:19 -0700306 args.fCaps = this->caps();
cdalton193d9cf2016-05-12 11:52:02 -0700307 batch->getPipelineOptimizations(&args.fOpts);
cdalton862cff32016-05-12 15:09:48 -0700308 if (args.fOpts.fOverrides.fUsePLSDstRead || fClipBatchToBounds) {
cdalton193d9cf2016-05-12 11:52:02 -0700309 GrGLIRect viewport;
310 viewport.fLeft = 0;
311 viewport.fBottom = 0;
Brian Osman11052242016-10-27 14:47:55 -0400312 viewport.fWidth = renderTargetContext->width();
313 viewport.fHeight = renderTargetContext->height();
cdalton193d9cf2016-05-12 11:52:02 -0700314 SkIRect ibounds;
315 ibounds.fLeft = SkTPin(SkScalarFloorToInt(batch->bounds().fLeft), viewport.fLeft,
316 viewport.fWidth);
317 ibounds.fTop = SkTPin(SkScalarFloorToInt(batch->bounds().fTop), viewport.fBottom,
318 viewport.fHeight);
319 ibounds.fRight = SkTPin(SkScalarCeilToInt(batch->bounds().fRight), viewport.fLeft,
320 viewport.fWidth);
321 ibounds.fBottom = SkTPin(SkScalarCeilToInt(batch->bounds().fBottom), viewport.fBottom,
322 viewport.fHeight);
csmartdaltond211e782016-08-15 11:17:19 -0700323 if (!appliedClip.addScissor(ibounds)) {
324 return;
cdalton193d9cf2016-05-12 11:52:02 -0700325 }
cdalton193d9cf2016-05-12 11:52:02 -0700326 }
bungeman06ca8ec2016-06-09 08:01:03 -0700327 args.fOpts.fColorPOI.completeCalculations(
328 sk_sp_address_as_pointer_address(pipelineBuilder.fColorFragmentProcessors.begin()),
329 pipelineBuilder.numColorFragmentProcessors());
cdalton193d9cf2016-05-12 11:52:02 -0700330 args.fOpts.fCoveragePOI.completeCalculations(
bungeman06ca8ec2016-06-09 08:01:03 -0700331 sk_sp_address_as_pointer_address(pipelineBuilder.fCoverageFragmentProcessors.begin()),
332 pipelineBuilder.numCoverageFragmentProcessors());
csmartdaltond211e782016-08-15 11:17:19 -0700333 args.fScissor = &appliedClip.scissorState();
csmartdaltonbf4a8f92016-09-06 10:01:06 -0700334 args.fWindowRectsState = &appliedClip.windowRectsState();
csmartdaltond211e782016-08-15 11:17:19 -0700335 args.fHasStencilClip = appliedClip.hasStencilClip();
Robert Phillipse60ad622016-11-17 10:22:48 -0500336 if (!renderTargetContext->accessRenderTarget()) {
337 return;
338 }
339
Brian Osman11052242016-10-27 14:47:55 -0400340 if (!this->setupDstReadIfNecessary(pipelineBuilder, renderTargetContext->accessRenderTarget(),
robertphillips55fdccc2016-06-06 06:16:20 -0700341 clip, args.fOpts,
342 &args.fDstTexture, batch->bounds())) {
cdalton193d9cf2016-05-12 11:52:02 -0700343 return;
344 }
345
346 if (!batch->installPipeline(args)) {
egdaniele36914c2015-02-13 09:00:33 -0800347 return;
348 }
bsalomonad792c12015-09-10 11:10:50 -0700349
robertphillips498d7ac2015-10-30 10:11:30 -0700350#ifdef ENABLE_MDB
Robert Phillipsf2361d22016-10-25 14:20:06 -0400351 SkASSERT(fSurface);
352 batch->pipeline()->addDependenciesTo(fSurface);
robertphillips498d7ac2015-10-30 10:11:30 -0700353#endif
csmartdaltond211e782016-08-15 11:17:19 -0700354 this->recordBatch(batch, appliedClip.clippedDrawBounds());
joshualitt4d8da812015-01-28 12:53:54 -0800355}
356
Brian Osman11052242016-10-27 14:47:55 -0400357void GrRenderTargetOpList::stencilPath(GrRenderTargetContext* renderTargetContext,
Robert Phillipsf2361d22016-10-25 14:20:06 -0400358 const GrClip& clip,
359 bool useHWAA,
360 const SkMatrix& viewMatrix,
361 const GrPath* path) {
bsalomon@google.com64aef2b2012-06-11 15:36:13 +0000362 // TODO: extract portions of checkDraw that are relevant to path stenciling.
bsalomon49f085d2014-09-05 13:34:00 -0700363 SkASSERT(path);
jvanverthe9c0fc62015-04-29 11:18:05 -0700364 SkASSERT(this->caps()->shaderCaps()->pathRenderingSupport());
joshualitt2c93efe2014-11-06 12:57:13 -0800365
csmartdaltond211e782016-08-15 11:17:19 -0700366 // FIXME: Use path bounds instead of this WAR once
367 // https://bugs.chromium.org/p/skia/issues/detail?id=5640 is resolved.
Brian Osman11052242016-10-27 14:47:55 -0400368 SkRect bounds = SkRect::MakeIWH(renderTargetContext->width(), renderTargetContext->height());
csmartdaltond211e782016-08-15 11:17:19 -0700369
joshualitt2c93efe2014-11-06 12:57:13 -0800370 // Setup clip
csmartdaltond211e782016-08-15 11:17:19 -0700371 GrAppliedClip appliedClip(bounds);
Brian Osman11052242016-10-27 14:47:55 -0400372 if (!clip.apply(fContext, renderTargetContext, useHWAA, true, &appliedClip)) {
joshualitt2c93efe2014-11-06 12:57:13 -0800373 return;
374 }
cdalton862cff32016-05-12 15:09:48 -0700375 // TODO: respect fClipBatchToBounds if we ever start computing bounds here.
joshualitt2c93efe2014-11-06 12:57:13 -0800376
cdalton846c0512016-05-13 10:25:00 -0700377 // Coverage AA does not make sense when rendering to the stencil buffer. The caller should never
378 // attempt this in a situation that would require coverage AA.
csmartdaltond211e782016-08-15 11:17:19 -0700379 SkASSERT(!appliedClip.clipCoverageFragmentProcessor());
bsalomon0ba8c242015-10-07 09:20:28 -0700380
Robert Phillipse60ad622016-11-17 10:22:48 -0500381 if (!renderTargetContext->accessRenderTarget()) {
382 return;
383 }
robertphillips55fdccc2016-06-06 06:16:20 -0700384 GrStencilAttachment* stencilAttachment = fResourceProvider->attachStencilAttachment(
Brian Osman11052242016-10-27 14:47:55 -0400385 renderTargetContext->accessRenderTarget());
cdalton17bf8202016-05-13 11:27:15 -0700386 if (!stencilAttachment) {
387 SkDebugf("ERROR creating stencil attachment. Draw skipped.\n");
388 return;
389 }
joshualitt2c93efe2014-11-06 12:57:13 -0800390
Brian Salomon25a88092016-12-01 09:36:50 -0500391 GrOp* batch = GrStencilPathBatch::Create(viewMatrix,
392 useHWAA,
393 path->getFillType(),
394 appliedClip.hasStencilClip(),
395 stencilAttachment->bits(),
396 appliedClip.scissorState(),
397 renderTargetContext->accessRenderTarget(),
398 path);
csmartdaltond211e782016-08-15 11:17:19 -0700399 this->recordBatch(batch, appliedClip.clippedDrawBounds());
bsalomona44919e2015-08-18 13:28:19 -0700400 batch->unref();
bsalomon@google.com64aef2b2012-06-11 15:36:13 +0000401}
402
Brian Salomon25a88092016-12-01 09:36:50 -0500403void GrRenderTargetOpList::addBatch(sk_sp<GrOp> batch) {
robertphillips9199a9f2016-07-13 07:48:43 -0700404 this->recordBatch(batch.get(), batch->bounds());
bsalomon53469832015-08-18 09:20:09 -0700405}
406
Robert Phillipsf2361d22016-10-25 14:20:06 -0400407void GrRenderTargetOpList::fullClear(GrRenderTarget* renderTarget, GrColor color) {
bsalomonfd8d0132016-08-11 11:25:33 -0700408 // Currently this just inserts or updates the last clear batch. However, once in MDB this can
409 // remove all the previously recorded batches and change the load op to clear with supplied
410 // color.
Robert Phillips294870f2016-11-11 12:38:40 -0500411 // TODO: this needs to be updated to use GrSurfaceProxy::UniqueID
bsalomonfd8d0132016-08-11 11:25:33 -0700412 if (fLastFullClearBatch &&
robertphillips8abb3702016-08-31 14:04:06 -0700413 fLastFullClearBatch->renderTargetUniqueID() == renderTarget->uniqueID()) {
bsalomonfd8d0132016-08-11 11:25:33 -0700414 // As currently implemented, fLastFullClearBatch should be the last batch because we would
415 // have cleared it when another batch was recorded.
416 SkASSERT(fRecordedBatches.back().fBatch.get() == fLastFullClearBatch);
417 fLastFullClearBatch->setColor(color);
418 return;
419 }
csmartdalton29df7602016-08-31 11:55:52 -0700420 sk_sp<GrClearBatch> batch(GrClearBatch::Make(GrFixedClip::Disabled(), color, renderTarget));
bsalomonfd8d0132016-08-11 11:25:33 -0700421 if (batch.get() == this->recordBatch(batch.get(), batch->bounds())) {
422 fLastFullClearBatch = batch.get();
423 }
bsalomon9f129de2016-08-10 16:31:05 -0700424}
425
Robert Phillipsf2361d22016-10-25 14:20:06 -0400426void GrRenderTargetOpList::discard(GrRenderTarget* renderTarget) {
bsalomon9f129de2016-08-10 16:31:05 -0700427 // Currently this just inserts a discard batch. However, once in MDB this can remove all the
428 // previously recorded batches and change the load op to discard.
bsalomon53469832015-08-18 09:20:09 -0700429 if (this->caps()->discardRenderTargetSupport()) {
Brian Salomon25a88092016-12-01 09:36:50 -0500430 GrOp* batch = new GrDiscardBatch(renderTarget);
bsalomon6cc90062016-07-08 11:31:22 -0700431 this->recordBatch(batch, batch->bounds());
bsalomon53469832015-08-18 09:20:09 -0700432 batch->unref();
bsalomon63b21962014-11-05 07:05:34 -0800433 }
434}
435
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000436////////////////////////////////////////////////////////////////////////////////
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000437
Robert Phillipsf2361d22016-10-25 14:20:06 -0400438bool GrRenderTargetOpList::copySurface(GrSurface* dst,
439 GrSurface* src,
440 const SkIRect& srcRect,
441 const SkIPoint& dstPoint) {
Brian Salomon25a88092016-12-01 09:36:50 -0500442 GrOp* batch = GrCopySurfaceBatch::Create(dst, src, srcRect, dstPoint);
bsalomonb8fea972016-02-16 07:34:17 -0800443 if (!batch) {
444 return false;
445 }
robertphillips498d7ac2015-10-30 10:11:30 -0700446#ifdef ENABLE_MDB
bsalomonb8fea972016-02-16 07:34:17 -0800447 this->addDependency(src);
robertphillips498d7ac2015-10-30 10:11:30 -0700448#endif
449
bsalomon6cc90062016-07-08 11:31:22 -0700450 this->recordBatch(batch, batch->bounds());
bsalomonb8fea972016-02-16 07:34:17 -0800451 batch->unref();
452 return true;
bsalomon@google.comeb851172013-04-15 13:51:00 +0000453}
454
bsalomon6cc90062016-07-08 11:31:22 -0700455static inline bool can_reorder(const SkRect& a, const SkRect& b) {
bsalomon88cf17d2016-07-08 06:40:56 -0700456 return a.fRight <= b.fLeft || a.fBottom <= b.fTop ||
457 b.fRight <= a.fLeft || b.fBottom <= a.fTop;
458}
459
bsalomon6cc90062016-07-08 11:31:22 -0700460static void join(SkRect* out, const SkRect& a, const SkRect& b) {
461 SkASSERT(a.fLeft <= a.fRight && a.fTop <= a.fBottom);
462 SkASSERT(b.fLeft <= b.fRight && b.fTop <= b.fBottom);
463 out->fLeft = SkTMin(a.fLeft, b.fLeft);
464 out->fTop = SkTMin(a.fTop, b.fTop);
465 out->fRight = SkTMax(a.fRight, b.fRight);
466 out->fBottom = SkTMax(a.fBottom, b.fBottom);
bsalomon512be532015-09-10 10:42:55 -0700467}
468
Brian Salomon25a88092016-12-01 09:36:50 -0500469GrOp* GrRenderTargetOpList::recordBatch(GrOp* batch, const SkRect& clippedBounds) {
Robert Phillipsf2361d22016-10-25 14:20:06 -0400470 // A closed GrOpList should never receive new/more batches
robertphillips6a186652015-10-20 07:37:58 -0700471 SkASSERT(!this->isClosed());
robertphillipsa106c622015-10-16 09:07:06 -0700472
bsalomon512be532015-09-10 10:42:55 -0700473 // Check if there is a Batch Draw we can batch with by linearly searching back until we either
474 // 1) check every draw
475 // 2) intersect with something
476 // 3) find a 'blocker'
joshualittb0666ad2016-03-08 10:43:41 -0800477 GR_AUDIT_TRAIL_ADDBATCH(fAuditTrail, batch);
Brian Salomon25a88092016-12-01 09:36:50 -0500478 GrOP_INFO("Re-Recording (%s, B%u)\n"
479 "\tBounds LRTB (%f, %f, %f, %f)\n",
480 batch->name(),
481 batch->uniqueID(),
482 batch->bounds().fLeft, batch->bounds().fRight,
483 batch->bounds().fTop, batch->bounds().fBottom);
484 GrOP_INFO(SkTabString(batch->dumpInfo(), 1).c_str());
485 GrOP_INFO("\tClipped Bounds: [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n",
486 clippedBounds.fLeft, clippedBounds.fTop, clippedBounds.fRight,
487 clippedBounds.fBottom);
488 GrOP_INFO("\tOutcome:\n");
bsalomon6cc90062016-07-08 11:31:22 -0700489 int maxCandidates = SkTMin(fMaxBatchLookback, fRecordedBatches.count());
bsalomon512be532015-09-10 10:42:55 -0700490 if (maxCandidates) {
491 int i = 0;
492 while (true) {
Brian Salomon25a88092016-12-01 09:36:50 -0500493 GrOp* candidate = fRecordedBatches.fromBack(i).fBatch.get();
bsalomon512be532015-09-10 10:42:55 -0700494 // We cannot continue to search backwards if the render target changes
495 if (candidate->renderTargetUniqueID() != batch->renderTargetUniqueID()) {
Brian Salomon25a88092016-12-01 09:36:50 -0500496 GrOP_INFO("\t\tBreaking because of (%s, B%u) Rendertarget\n",
497 candidate->name(), candidate->uniqueID());
bsalomon512be532015-09-10 10:42:55 -0700498 break;
499 }
500 if (candidate->combineIfPossible(batch, *this->caps())) {
Brian Salomon25a88092016-12-01 09:36:50 -0500501 GrOP_INFO("\t\tCombining with (%s, B%u)\n", candidate->name(),
502 candidate->uniqueID());
joshualittb0666ad2016-03-08 10:43:41 -0800503 GR_AUDIT_TRAIL_BATCHING_RESULT_COMBINED(fAuditTrail, candidate, batch);
bsalomon6cc90062016-07-08 11:31:22 -0700504 join(&fRecordedBatches.fromBack(i).fClippedBounds,
505 fRecordedBatches.fromBack(i).fClippedBounds, clippedBounds);
bsalomonfd8d0132016-08-11 11:25:33 -0700506 return candidate;
bsalomon512be532015-09-10 10:42:55 -0700507 }
508 // Stop going backwards if we would cause a painter's order violation.
bsalomon6cc90062016-07-08 11:31:22 -0700509 const SkRect& candidateBounds = fRecordedBatches.fromBack(i).fClippedBounds;
510 if (!can_reorder(candidateBounds, clippedBounds)) {
Brian Salomon25a88092016-12-01 09:36:50 -0500511 GrOP_INFO("\t\tIntersects with (%s, B%u)\n", candidate->name(),
512 candidate->uniqueID());
bsalomon512be532015-09-10 10:42:55 -0700513 break;
514 }
515 ++i;
516 if (i == maxCandidates) {
Brian Salomon25a88092016-12-01 09:36:50 -0500517 GrOP_INFO("\t\tReached max lookback or beginning of batch array %d\n", i);
bsalomon512be532015-09-10 10:42:55 -0700518 break;
519 }
520 }
521 } else {
Brian Salomon25a88092016-12-01 09:36:50 -0500522 GrOP_INFO("\t\tFirstBatch\n");
bsalomon512be532015-09-10 10:42:55 -0700523 }
joshualitt18d6b752016-02-26 08:07:50 -0800524 GR_AUDIT_TRAIL_BATCHING_RESULT_NEW(fAuditTrail, batch);
bsalomon6cc90062016-07-08 11:31:22 -0700525 fRecordedBatches.emplace_back(RecordedBatch{sk_ref_sp(batch), clippedBounds});
bsalomonfd8d0132016-08-11 11:25:33 -0700526 fLastFullClearBatch = nullptr;
527 return batch;
bsalomon512be532015-09-10 10:42:55 -0700528}
529
Robert Phillipsf2361d22016-10-25 14:20:06 -0400530void GrRenderTargetOpList::forwardCombine() {
bsalomondb27fc52016-08-29 12:43:27 -0700531 if (fMaxBatchLookahead <= 0) {
532 return;
533 }
bsalomon6cc90062016-07-08 11:31:22 -0700534 for (int i = 0; i < fRecordedBatches.count() - 2; ++i) {
Brian Salomon25a88092016-12-01 09:36:50 -0500535 GrOp* batch = fRecordedBatches[i].fBatch.get();
bsalomon6cc90062016-07-08 11:31:22 -0700536 const SkRect& batchBounds = fRecordedBatches[i].fClippedBounds;
537 int maxCandidateIdx = SkTMin(i + fMaxBatchLookahead, fRecordedBatches.count() - 1);
bsalomonaecc0182016-03-07 11:50:44 -0800538 int j = i + 1;
539 while (true) {
Brian Salomon25a88092016-12-01 09:36:50 -0500540 GrOp* candidate = fRecordedBatches[j].fBatch.get();
bsalomonaecc0182016-03-07 11:50:44 -0800541 // We cannot continue to search if the render target changes
542 if (candidate->renderTargetUniqueID() != batch->renderTargetUniqueID()) {
Brian Salomon25a88092016-12-01 09:36:50 -0500543 GrOP_INFO("\t\tBreaking because of (%s, B%u) Rendertarget\n",
544 candidate->name(), candidate->uniqueID());
bsalomonaecc0182016-03-07 11:50:44 -0800545 break;
546 }
547 if (j == i +1) {
548 // We assume batch would have combined with candidate when the candidate was added
549 // via backwards combining in recordBatch.
550 SkASSERT(!batch->combineIfPossible(candidate, *this->caps()));
551 } else if (batch->combineIfPossible(candidate, *this->caps())) {
Brian Salomon25a88092016-12-01 09:36:50 -0500552 GrOP_INFO("\t\tCombining with (%s, B%u)\n", candidate->name(),
553 candidate->uniqueID());
joshualittb0666ad2016-03-08 10:43:41 -0800554 GR_AUDIT_TRAIL_BATCHING_RESULT_COMBINED(fAuditTrail, batch, candidate);
bsalomon6cc90062016-07-08 11:31:22 -0700555 fRecordedBatches[j].fBatch = std::move(fRecordedBatches[i].fBatch);
556 join(&fRecordedBatches[j].fClippedBounds, fRecordedBatches[j].fClippedBounds,
557 batchBounds);
bsalomonaecc0182016-03-07 11:50:44 -0800558 break;
559 }
560 // Stop going traversing if we would cause a painter's order violation.
bsalomon6cc90062016-07-08 11:31:22 -0700561 const SkRect& candidateBounds = fRecordedBatches[j].fClippedBounds;
562 if (!can_reorder(candidateBounds, batchBounds)) {
Brian Salomon25a88092016-12-01 09:36:50 -0500563 GrOP_INFO("\t\tIntersects with (%s, B%u)\n", candidate->name(),
564 candidate->uniqueID());
bsalomonaecc0182016-03-07 11:50:44 -0800565 break;
566 }
567 ++j;
568 if (j > maxCandidateIdx) {
Brian Salomon25a88092016-12-01 09:36:50 -0500569 GrOP_INFO("\t\tReached max lookahead or end of batch array %d\n", i);
bsalomonaecc0182016-03-07 11:50:44 -0800570 break;
571 }
572 }
573 }
574}
575
egdaniele36914c2015-02-13 09:00:33 -0800576///////////////////////////////////////////////////////////////////////////////
577
Robert Phillipsf2361d22016-10-25 14:20:06 -0400578void GrRenderTargetOpList::clearStencilClip(const GrFixedClip& clip,
579 bool insideStencilMask,
580 GrRenderTarget* rt) {
Brian Salomon25a88092016-12-01 09:36:50 -0500581 GrOp* batch = new GrClearStencilClipBatch(clip, insideStencilMask, rt);
bsalomon6cc90062016-07-08 11:31:22 -0700582 this->recordBatch(batch, batch->bounds());
bsalomon5ea03632015-08-18 10:33:30 -0700583 batch->unref();
584}