blob: 356c480da8cda1c2d345dbcf17ede21a2623dcae [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
joshualittc2893c52015-01-28 06:54:30 -08008#include "GrDrawTarget.h"
joshualitt4d8da812015-01-28 12:53:54 -08009
joshualitt086cee12016-01-12 06:45:24 -080010#include "GrAuditTrail.h"
bsalomoneb1cb5c2015-05-22 08:01:09 -070011#include "GrCaps.h"
robertphillips976f5f02016-06-03 10:59:20 -070012#include "GrDrawContext.h"
bsalomon4061b122015-05-29 10:26:19 -070013#include "GrGpu.h"
egdaniel9cb63402016-06-23 08:37:05 -070014#include "GrGpuCommandBuffer.h"
commit-bot@chromium.orgc4dc0ad2013-10-09 14:11:33 +000015#include "GrPath.h"
egdaniele36914c2015-02-13 09:00:33 -080016#include "GrPipeline.h"
joshualittb7133be2015-04-08 09:08:31 -070017#include "GrMemoryPool.h"
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +000018#include "GrRenderTarget.h"
bsalomon4061b122015-05-29 10:26:19 -070019#include "GrResourceProvider.h"
bsalomon6bc1b5f2015-02-23 09:06:38 -080020#include "GrRenderTargetPriv.h"
cdalton93a379b2016-05-11 13:58:08 -070021#include "GrStencilAttachment.h"
bsalomonafbf2d62014-09-30 12:18:44 -070022#include "GrSurfacePriv.h"
bsalomon@google.com86afc2a2011-02-16 16:12:19 +000023#include "GrTexture.h"
ethannicholas22793252016-01-30 09:59:10 -080024#include "gl/GrGLRenderTarget.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000025
joshualitt086cee12016-01-12 06:45:24 -080026#include "SkStrokeRec.h"
27
bsalomon53469832015-08-18 09:20:09 -070028#include "batches/GrClearBatch.h"
bsalomon872062c2015-08-18 12:12:35 -070029#include "batches/GrCopySurfaceBatch.h"
bsalomon53469832015-08-18 09:20:09 -070030#include "batches/GrDiscardBatch.h"
bsalomon16b99132015-08-13 14:55:50 -070031#include "batches/GrDrawBatch.h"
bsalomonadd79ef2015-08-19 13:26:49 -070032#include "batches/GrDrawPathBatch.h"
joshualittecd1a692015-08-10 10:08:26 -070033#include "batches/GrRectBatchFactory.h"
bsalomona44919e2015-08-18 13:28:19 -070034#include "batches/GrStencilPathBatch.h"
joshualitt74417822015-08-07 11:42:16 -070035
csmartdaltona7f29642016-07-07 08:49:11 -070036#include "instanced/InstancedRendering.h"
37
reed@google.comac10a2d2010-12-22 21:39:39 +000038////////////////////////////////////////////////////////////////////////////////
39
bsalomon489147c2015-12-14 12:13:09 -080040// Experimentally we have found that most batching occurs within the first 10 comparisons.
bsalomonaecc0182016-03-07 11:50:44 -080041static const int kDefaultMaxBatchLookback = 10;
42static const int kDefaultMaxBatchLookahead = 10;
bsalomon489147c2015-12-14 12:13:09 -080043
bsalomon69cfe952015-11-30 13:27:47 -080044GrDrawTarget::GrDrawTarget(GrRenderTarget* rt, GrGpu* gpu, GrResourceProvider* resourceProvider,
joshualitt086cee12016-01-12 06:45:24 -080045 GrAuditTrail* auditTrail, const Options& options)
bsalomon4061b122015-05-29 10:26:19 -070046 : fGpu(SkRef(gpu))
bsalomon4061b122015-05-29 10:26:19 -070047 , fResourceProvider(resourceProvider)
joshualitt086cee12016-01-12 06:45:24 -080048 , fAuditTrail(auditTrail)
bsalomon648c6962015-10-23 09:06:59 -070049 , fFlags(0)
csmartdaltona7f29642016-07-07 08:49:11 -070050 , fRenderTarget(rt)
51 , fInstancedRendering(fGpu->createInstancedRenderingIfSupported()) {
bsalomonb3b9aec2015-09-10 11:16:35 -070052 // TODO: Stop extracting the context (currently needed by GrClipMaskManager)
53 fContext = fGpu->getContext();
robertphillips4beb5c12015-10-20 07:50:00 -070054
cdalton862cff32016-05-12 15:09:48 -070055 fClipBatchToBounds = options.fClipBatchToBounds;
bsalomon6dea83f2015-12-03 12:58:06 -080056 fDrawBatchBounds = options.fDrawBatchBounds;
bsalomon489147c2015-12-14 12:13:09 -080057 fMaxBatchLookback = (options.fMaxBatchLookback < 0) ? kDefaultMaxBatchLookback :
58 options.fMaxBatchLookback;
bsalomonaecc0182016-03-07 11:50:44 -080059 fMaxBatchLookahead = (options.fMaxBatchLookahead < 0) ? kDefaultMaxBatchLookahead :
60 options.fMaxBatchLookahead;
bsalomon6dea83f2015-12-03 12:58:06 -080061
robertphillips0dfa62c2015-11-16 06:23:31 -080062 rt->setLastDrawTarget(this);
63
robertphillips4beb5c12015-10-20 07:50:00 -070064#ifdef SK_DEBUG
65 static int debugID = 0;
66 fDebugID = debugID++;
67#endif
bsalomon4061b122015-05-29 10:26:19 -070068}
69
70GrDrawTarget::~GrDrawTarget() {
robertphillips498d7ac2015-10-30 10:11:30 -070071 if (fRenderTarget && this == fRenderTarget->getLastDrawTarget()) {
72 fRenderTarget->setLastDrawTarget(nullptr);
73 }
74
bsalomon4061b122015-05-29 10:26:19 -070075 fGpu->unref();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +000076}
77
78////////////////////////////////////////////////////////////////////////////////
79
robertphillips6a186652015-10-20 07:37:58 -070080// Add a GrDrawTarget-based dependency
81void GrDrawTarget::addDependency(GrDrawTarget* dependedOn) {
82 SkASSERT(!dependedOn->dependsOn(this)); // loops are bad
83
84 if (this->dependsOn(dependedOn)) {
85 return; // don't add duplicate dependencies
86 }
87
88 *fDependencies.push() = dependedOn;
89}
90
91// Convert from a GrSurface-based dependency to a GrDrawTarget one
92void GrDrawTarget::addDependency(GrSurface* dependedOn) {
93 if (dependedOn->asRenderTarget() && dependedOn->asRenderTarget()->getLastDrawTarget()) {
94 // If it is still receiving dependencies, this DT shouldn't be closed
95 SkASSERT(!this->isClosed());
96
97 GrDrawTarget* dt = dependedOn->asRenderTarget()->getLastDrawTarget();
98 if (dt == this) {
99 // self-read - presumably for dst reads
100 } else {
101 this->addDependency(dt);
102
103 // Can't make it closed in the self-read case
104 dt->makeClosed();
105 }
106 }
107}
108
robertphillips4beb5c12015-10-20 07:50:00 -0700109#ifdef SK_DEBUG
110void GrDrawTarget::dump() const {
111 SkDebugf("--------------------------------------------------------------\n");
robertphillipse004bfc2015-11-16 09:06:59 -0800112 SkDebugf("node: %d -> RT: %d\n", fDebugID, fRenderTarget ? fRenderTarget->getUniqueID() : -1);
robertphillips4beb5c12015-10-20 07:50:00 -0700113 SkDebugf("relies On (%d): ", fDependencies.count());
114 for (int i = 0; i < fDependencies.count(); ++i) {
115 SkDebugf("%d, ", fDependencies[i]->fDebugID);
116 }
117 SkDebugf("\n");
118 SkDebugf("batches (%d):\n", fBatches.count());
119 for (int i = 0; i < fBatches.count(); ++i) {
robertphillips4beb5c12015-10-20 07:50:00 -0700120 SkDebugf("*******************************\n");
robertphillips26726d12016-06-28 14:45:31 -0700121 if (!fBatches[i]) {
bsalomonaecc0182016-03-07 11:50:44 -0800122 SkDebugf("%d: <combined forward>\n", i);
123 } else {
124 SkDebugf("%d: %s\n", i, fBatches[i]->name());
bsalomonaecc0182016-03-07 11:50:44 -0800125 SkString str = fBatches[i]->dumpInfo();
126 SkDebugf("%s\n", str.c_str());
bsalomonaecc0182016-03-07 11:50:44 -0800127 }
robertphillips4beb5c12015-10-20 07:50:00 -0700128 }
129}
130#endif
131
bsalomon50785a32015-02-06 07:02:37 -0800132bool GrDrawTarget::setupDstReadIfNecessary(const GrPipelineBuilder& pipelineBuilder,
robertphillips55fdccc2016-06-06 06:16:20 -0700133 GrRenderTarget* rt,
cdalton862cff32016-05-12 15:09:48 -0700134 const GrClip& clip,
ethannicholasde4166a2015-11-30 08:57:38 -0800135 const GrPipelineOptimizations& optimizations,
bsalomon6a44c6a2015-05-26 09:49:05 -0700136 GrXferProcessor::DstTexture* dstTexture,
bsalomonad792c12015-09-10 11:10:50 -0700137 const SkRect& batchBounds) {
138 SkRect bounds = batchBounds;
139 bounds.outset(0.5f, 0.5f);
140
ethannicholasde4166a2015-11-30 08:57:38 -0800141 if (!pipelineBuilder.willXPNeedDstTexture(*this->caps(), optimizations)) {
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000142 return true;
143 }
cdalton9954bc32015-04-29 14:17:00 -0700144
cdalton9954bc32015-04-29 14:17:00 -0700145 if (this->caps()->textureBarrierSupport()) {
146 if (GrTexture* rtTex = rt->asTexture()) {
bsalomondc47ff72015-05-26 12:16:59 -0700147 // The render target is a texture, so we can read from it directly in the shader. The XP
cdalton9954bc32015-04-29 14:17:00 -0700148 // will be responsible to detect this situation and request a texture barrier.
bsalomon6a44c6a2015-05-26 09:49:05 -0700149 dstTexture->setTexture(rtTex);
150 dstTexture->setOffset(0, 0);
cdalton9954bc32015-04-29 14:17:00 -0700151 return true;
152 }
153 }
154
155 SkIRect copyRect;
cdalton862cff32016-05-12 15:09:48 -0700156 clip.getConservativeBounds(rt->width(), rt->height(), &copyRect);
commit-bot@chromium.orgc4dc0ad2013-10-09 14:11:33 +0000157
bsalomonad792c12015-09-10 11:10:50 -0700158 SkIRect drawIBounds;
159 bounds.roundOut(&drawIBounds);
160 if (!copyRect.intersect(drawIBounds)) {
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000161#ifdef SK_DEBUG
bsalomonb3b9aec2015-09-10 11:16:35 -0700162 GrCapsDebugf(this->caps(), "Missed an early reject. "
163 "Bailing on draw from setupDstReadIfNecessary.\n");
commit-bot@chromium.orgbb5c4652013-04-01 12:49:31 +0000164#endif
bsalomonad792c12015-09-10 11:10:50 -0700165 return false;
commit-bot@chromium.orgbb5c4652013-04-01 12:49:31 +0000166 }
skia.committer@gmail.com05a2ee02013-04-02 07:01:34 +0000167
commit-bot@chromium.org63150af2013-04-11 22:00:22 +0000168 // MSAA consideration: When there is support for reading MSAA samples in the shader we could
169 // have per-sample dst values by making the copy multisampled.
bsalomonf2703d82014-10-28 14:33:06 -0700170 GrSurfaceDesc desc;
bsalomonb3b9aec2015-09-10 11:16:35 -0700171 if (!fGpu->initCopySurfaceDstDesc(rt, &desc)) {
bsalomona73239a2015-04-28 13:35:17 -0700172 desc.fOrigin = kDefault_GrSurfaceOrigin;
173 desc.fFlags = kRenderTarget_GrSurfaceFlag;
174 desc.fConfig = rt->config();
175 }
176
commit-bot@chromium.orgbb5c4652013-04-01 12:49:31 +0000177 desc.fWidth = copyRect.width();
178 desc.fHeight = copyRect.height();
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000179
bsalomoneae62002015-07-31 13:59:30 -0700180 static const uint32_t kFlags = 0;
181 SkAutoTUnref<GrTexture> copy(fResourceProvider->createApproxTexture(desc, kFlags));
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000182
bsalomone3059732014-10-14 11:47:22 -0700183 if (!copy) {
tfarina38406c82014-10-31 07:11:12 -0700184 SkDebugf("Failed to create temporary copy of destination texture.\n");
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000185 return false;
186 }
bsalomon@google.come4617bf2013-04-03 14:56:40 +0000187 SkIPoint dstPoint = {0, 0};
bsalomon6df86402015-06-01 10:41:49 -0700188 this->copySurface(copy, rt, copyRect, dstPoint);
189 dstTexture->setTexture(copy);
190 dstTexture->setOffset(copyRect.fLeft, copyRect.fTop);
191 return true;
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000192}
193
robertphillipsa13e2022015-11-11 12:01:09 -0800194void GrDrawTarget::prepareBatches(GrBatchFlushState* flushState) {
robertphillipsa106c622015-10-16 09:07:06 -0700195 // Semi-usually the drawTargets are already closed at this point, but sometimes Ganesh
196 // needs to flush mid-draw. In that case, the SkGpuDevice's drawTargets won't be closed
197 // but need to be flushed anyway. Closing such drawTargets here will mean new
198 // drawTargets will be created to replace them if the SkGpuDevice(s) write to them again.
199 this->makeClosed();
200
robertphillips498d7ac2015-10-30 10:11:30 -0700201 // Loop over the batches that haven't yet generated their geometry
robertphillips1f0e3502015-11-10 10:19:50 -0800202 for (int i = 0; i < fBatches.count(); ++i) {
bsalomonaecc0182016-03-07 11:50:44 -0800203 if (fBatches[i]) {
204 fBatches[i]->prepare(flushState);
205 }
bsalomon512be532015-09-10 10:42:55 -0700206 }
csmartdaltona7f29642016-07-07 08:49:11 -0700207
208 if (fInstancedRendering) {
209 fInstancedRendering->beginFlush(flushState->resourceProvider());
210 }
robertphillipsa13e2022015-11-11 12:01:09 -0800211}
bsalomon512be532015-09-10 10:42:55 -0700212
robertphillipsa13e2022015-11-11 12:01:09 -0800213void GrDrawTarget::drawBatches(GrBatchFlushState* flushState) {
bsalomon512be532015-09-10 10:42:55 -0700214 // Draw all the generated geometry.
bsalomon6dea83f2015-12-03 12:58:06 -0800215 SkRandom random;
egdaniel9cb63402016-06-23 08:37:05 -0700216 GrRenderTarget* currentRT = nullptr;
217 SkAutoTDelete<GrGpuCommandBuffer> commandBuffer;
egdaniele7d1b242016-07-01 08:06:45 -0700218 SkRect bounds = SkRect::MakeEmpty();
bsalomon512be532015-09-10 10:42:55 -0700219 for (int i = 0; i < fBatches.count(); ++i) {
bsalomonaecc0182016-03-07 11:50:44 -0800220 if (!fBatches[i]) {
221 continue;
222 }
egdaniel9cb63402016-06-23 08:37:05 -0700223 if (fBatches[i]->renderTarget() != currentRT) {
224 if (commandBuffer) {
225 commandBuffer->end();
egdaniele7d1b242016-07-01 08:06:45 -0700226 if (bounds.intersect(0, 0,
227 SkIntToScalar(currentRT->width()),
228 SkIntToScalar(currentRT->height()))) {
229 SkIRect iBounds;
230 bounds.roundOut(&iBounds);
231 commandBuffer->submit(iBounds);
232 }
egdaniel9cb63402016-06-23 08:37:05 -0700233 commandBuffer.reset();
234 }
egdaniele7d1b242016-07-01 08:06:45 -0700235 bounds.setEmpty();
egdaniel9cb63402016-06-23 08:37:05 -0700236 currentRT = fBatches[i]->renderTarget();
237 if (currentRT) {
238 static const GrGpuCommandBuffer::LoadAndStoreInfo kBasicLoadStoreInfo
239 { GrGpuCommandBuffer::LoadOp::kLoad,GrGpuCommandBuffer::StoreOp::kStore,
240 GrColor_ILLEGAL };
241 commandBuffer.reset(fGpu->createCommandBuffer(currentRT,
242 kBasicLoadStoreInfo, // Color
243 kBasicLoadStoreInfo)); // Stencil
244 }
245 flushState->setCommandBuffer(commandBuffer);
246 }
egdaniele7d1b242016-07-01 08:06:45 -0700247 if (commandBuffer) {
248 bounds.join(fBatches[i]->bounds());
249 }
bsalomon6dea83f2015-12-03 12:58:06 -0800250 if (fDrawBatchBounds) {
egdaniele7d1b242016-07-01 08:06:45 -0700251 const SkRect& batchBounds = fBatches[i]->bounds();
252 SkIRect iBatchBounds;
253 batchBounds.roundOut(&iBatchBounds);
bsalomon6dea83f2015-12-03 12:58:06 -0800254 // In multi-draw buffer all the batches use the same render target and we won't need to
255 // get the batchs bounds.
256 if (GrRenderTarget* rt = fBatches[i]->renderTarget()) {
egdaniele7d1b242016-07-01 08:06:45 -0700257 fGpu->drawDebugWireRect(rt, iBatchBounds, 0xFF000000 | random.nextU());
bsalomon6dea83f2015-12-03 12:58:06 -0800258 }
259 }
robertphillipsa13e2022015-11-11 12:01:09 -0800260 fBatches[i]->draw(flushState);
bsalomon512be532015-09-10 10:42:55 -0700261 }
egdaniel9cb63402016-06-23 08:37:05 -0700262 if (commandBuffer) {
263 commandBuffer->end();
egdaniele7d1b242016-07-01 08:06:45 -0700264 if (bounds.intersect(0, 0,
265 SkIntToScalar(currentRT->width()),
266 SkIntToScalar(currentRT->height()))) {
267 SkIRect iBounds;
268 bounds.roundOut(&iBounds);
269 commandBuffer->submit(iBounds);
270 }
egdaniel9cb63402016-06-23 08:37:05 -0700271 flushState->setCommandBuffer(nullptr);
272 }
ethannicholas22793252016-01-30 09:59:10 -0800273
jvanverthd2d2eb92016-02-17 14:04:46 -0800274 fGpu->finishDrawTarget();
bsalomona73239a2015-04-28 13:35:17 -0700275}
276
bsalomon512be532015-09-10 10:42:55 -0700277void GrDrawTarget::reset() {
278 fBatches.reset();
csmartdaltona7f29642016-07-07 08:49:11 -0700279 if (fInstancedRendering) {
280 fInstancedRendering->endFlush();
281 }
bsalomon512be532015-09-10 10:42:55 -0700282}
283
bsalomon88cf17d2016-07-08 06:40:56 -0700284static void batch_bounds(SkRect* bounds, const GrBatch* batch) {
285 *bounds = batch->bounds();
286 if (batch->hasZeroArea()) {
287 if (batch->hasAABloat()) {
288 bounds->outset(0.5f, 0.5f);
289 } else {
290 // We don't know which way the particular GPU will snap lines or points at integer
291 // coords. So we ensure that the bounds is large enough for either snap.
292 SkRect before = *bounds;
293 bounds->roundOut(bounds);
294 if (bounds->fLeft == before.fLeft) {
295 bounds->fLeft -= 1;
296 }
297 if (bounds->fTop == before.fTop) {
298 bounds->fTop -= 1;
299 }
300 if (bounds->fRight == before.fRight) {
301 bounds->fRight += 1;
302 }
303 if (bounds->fBottom == before.fBottom) {
304 bounds->fBottom += 1;
305 }
306 }
307 }
308}
309
robertphillips391395d2016-03-02 09:26:36 -0800310void GrDrawTarget::drawBatch(const GrPipelineBuilder& pipelineBuilder,
robertphillips976f5f02016-06-03 10:59:20 -0700311 GrDrawContext* drawContext,
cdalton862cff32016-05-12 15:09:48 -0700312 const GrClip& clip,
313 GrDrawBatch* batch) {
joshualitt4d8da812015-01-28 12:53:54 -0800314 // Setup clip
cdalton862cff32016-05-12 15:09:48 -0700315 GrAppliedClip appliedClip;
bsalomon88cf17d2016-07-08 06:40:56 -0700316 SkRect bounds;
317 batch_bounds(&bounds, batch);
318 if (!clip.apply(fContext, pipelineBuilder, drawContext, &bounds, &appliedClip)) {
cdalton862cff32016-05-12 15:09:48 -0700319 return;
joshualitt4d8da812015-01-28 12:53:54 -0800320 }
robertphillips391395d2016-03-02 09:26:36 -0800321
robertphillips55fdccc2016-06-06 06:16:20 -0700322 // TODO: this is the only remaining usage of the AutoRestoreFragmentProcessorState - remove it
cdaltond4727922015-11-10 12:49:06 -0800323 GrPipelineBuilder::AutoRestoreFragmentProcessorState arfps;
bungeman06ca8ec2016-06-09 08:01:03 -0700324 if (appliedClip.getClipCoverageFragmentProcessor()) {
cdaltond4727922015-11-10 12:49:06 -0800325 arfps.set(&pipelineBuilder);
bungeman06ca8ec2016-06-09 08:01:03 -0700326 arfps.addCoverageFragmentProcessor(sk_ref_sp(appliedClip.getClipCoverageFragmentProcessor()));
cdaltond4727922015-11-10 12:49:06 -0800327 }
joshualitt4d8da812015-01-28 12:53:54 -0800328
bsalomonad792c12015-09-10 11:10:50 -0700329 GrPipeline::CreateArgs args;
cdalton193d9cf2016-05-12 11:52:02 -0700330 args.fPipelineBuilder = &pipelineBuilder;
robertphillips55fdccc2016-06-06 06:16:20 -0700331 args.fDrawContext = drawContext;
cdalton193d9cf2016-05-12 11:52:02 -0700332 args.fCaps = this->caps();
cdalton862cff32016-05-12 15:09:48 -0700333 args.fScissor = &appliedClip.scissorState();
334 args.fHasStencilClip = appliedClip.hasStencilClip();
335 if (pipelineBuilder.hasUserStencilSettings() || appliedClip.hasStencilClip()) {
robertphillips55fdccc2016-06-06 06:16:20 -0700336 if (!fResourceProvider->attachStencilAttachment(drawContext->accessRenderTarget())) {
cdalton17bf8202016-05-13 11:27:15 -0700337 SkDebugf("ERROR creating stencil attachment. Draw skipped.\n");
338 return;
339 }
cdalton193d9cf2016-05-12 11:52:02 -0700340 }
341 batch->getPipelineOptimizations(&args.fOpts);
342 GrScissorState finalScissor;
cdalton862cff32016-05-12 15:09:48 -0700343 if (args.fOpts.fOverrides.fUsePLSDstRead || fClipBatchToBounds) {
cdalton193d9cf2016-05-12 11:52:02 -0700344 GrGLIRect viewport;
345 viewport.fLeft = 0;
346 viewport.fBottom = 0;
robertphillips55fdccc2016-06-06 06:16:20 -0700347 viewport.fWidth = drawContext->width();
348 viewport.fHeight = drawContext->height();
cdalton193d9cf2016-05-12 11:52:02 -0700349 SkIRect ibounds;
350 ibounds.fLeft = SkTPin(SkScalarFloorToInt(batch->bounds().fLeft), viewport.fLeft,
351 viewport.fWidth);
352 ibounds.fTop = SkTPin(SkScalarFloorToInt(batch->bounds().fTop), viewport.fBottom,
353 viewport.fHeight);
354 ibounds.fRight = SkTPin(SkScalarCeilToInt(batch->bounds().fRight), viewport.fLeft,
355 viewport.fWidth);
356 ibounds.fBottom = SkTPin(SkScalarCeilToInt(batch->bounds().fBottom), viewport.fBottom,
357 viewport.fHeight);
cdalton862cff32016-05-12 15:09:48 -0700358 if (appliedClip.scissorState().enabled()) {
359 const SkIRect& scissorRect = appliedClip.scissorState().rect();
cdalton193d9cf2016-05-12 11:52:02 -0700360 if (!ibounds.intersect(scissorRect)) {
cdalton862cff32016-05-12 15:09:48 -0700361 return;
cdalton193d9cf2016-05-12 11:52:02 -0700362 }
363 }
364 finalScissor.set(ibounds);
365 args.fScissor = &finalScissor;
366 }
bungeman06ca8ec2016-06-09 08:01:03 -0700367 args.fOpts.fColorPOI.completeCalculations(
368 sk_sp_address_as_pointer_address(pipelineBuilder.fColorFragmentProcessors.begin()),
369 pipelineBuilder.numColorFragmentProcessors());
cdalton193d9cf2016-05-12 11:52:02 -0700370 args.fOpts.fCoveragePOI.completeCalculations(
bungeman06ca8ec2016-06-09 08:01:03 -0700371 sk_sp_address_as_pointer_address(pipelineBuilder.fCoverageFragmentProcessors.begin()),
372 pipelineBuilder.numCoverageFragmentProcessors());
robertphillips55fdccc2016-06-06 06:16:20 -0700373 if (!this->setupDstReadIfNecessary(pipelineBuilder, drawContext->accessRenderTarget(),
374 clip, args.fOpts,
375 &args.fDstTexture, batch->bounds())) {
cdalton193d9cf2016-05-12 11:52:02 -0700376 return;
377 }
378
379 if (!batch->installPipeline(args)) {
egdaniele36914c2015-02-13 09:00:33 -0800380 return;
381 }
bsalomonad792c12015-09-10 11:10:50 -0700382
robertphillips498d7ac2015-10-30 10:11:30 -0700383#ifdef ENABLE_MDB
384 SkASSERT(fRenderTarget);
385 batch->pipeline()->addDependenciesTo(fRenderTarget);
386#endif
387
bsalomon512be532015-09-10 10:42:55 -0700388 this->recordBatch(batch);
joshualitt4d8da812015-01-28 12:53:54 -0800389}
390
joshualitt1c735482015-07-13 08:08:25 -0700391void GrDrawTarget::stencilPath(const GrPipelineBuilder& pipelineBuilder,
robertphillips976f5f02016-06-03 10:59:20 -0700392 GrDrawContext* drawContext,
cdalton862cff32016-05-12 15:09:48 -0700393 const GrClip& clip,
joshualittf2384692015-09-10 11:00:51 -0700394 const SkMatrix& viewMatrix,
joshualitt9853cce2014-11-17 14:22:48 -0800395 const GrPath* path,
396 GrPathRendering::FillType fill) {
bsalomon@google.com64aef2b2012-06-11 15:36:13 +0000397 // TODO: extract portions of checkDraw that are relevant to path stenciling.
bsalomon49f085d2014-09-05 13:34:00 -0700398 SkASSERT(path);
jvanverthe9c0fc62015-04-29 11:18:05 -0700399 SkASSERT(this->caps()->shaderCaps()->pathRenderingSupport());
joshualitt2c93efe2014-11-06 12:57:13 -0800400
401 // Setup clip
cdalton862cff32016-05-12 15:09:48 -0700402 GrAppliedClip appliedClip;
robertphillips976f5f02016-06-03 10:59:20 -0700403 if (!clip.apply(fContext, pipelineBuilder, drawContext, nullptr, &appliedClip)) {
joshualitt2c93efe2014-11-06 12:57:13 -0800404 return;
405 }
cdalton862cff32016-05-12 15:09:48 -0700406 // TODO: respect fClipBatchToBounds if we ever start computing bounds here.
joshualitt2c93efe2014-11-06 12:57:13 -0800407
cdalton846c0512016-05-13 10:25:00 -0700408 // Coverage AA does not make sense when rendering to the stencil buffer. The caller should never
409 // attempt this in a situation that would require coverage AA.
bungeman06ca8ec2016-06-09 08:01:03 -0700410 SkASSERT(!appliedClip.getClipCoverageFragmentProcessor());
bsalomon0ba8c242015-10-07 09:20:28 -0700411
robertphillips55fdccc2016-06-06 06:16:20 -0700412 GrStencilAttachment* stencilAttachment = fResourceProvider->attachStencilAttachment(
413 drawContext->accessRenderTarget());
cdalton17bf8202016-05-13 11:27:15 -0700414 if (!stencilAttachment) {
415 SkDebugf("ERROR creating stencil attachment. Draw skipped.\n");
416 return;
417 }
joshualitt2c93efe2014-11-06 12:57:13 -0800418
joshualittf2384692015-09-10 11:00:51 -0700419 GrBatch* batch = GrStencilPathBatch::Create(viewMatrix,
bsalomona44919e2015-08-18 13:28:19 -0700420 pipelineBuilder.isHWAntialias(),
cdalton193d9cf2016-05-12 11:52:02 -0700421 fill,
cdalton862cff32016-05-12 15:09:48 -0700422 appliedClip.hasStencilClip(),
cdalton93a379b2016-05-11 13:58:08 -0700423 stencilAttachment->bits(),
cdalton862cff32016-05-12 15:09:48 -0700424 appliedClip.scissorState(),
robertphillips55fdccc2016-06-06 06:16:20 -0700425 drawContext->accessRenderTarget(),
bsalomona44919e2015-08-18 13:28:19 -0700426 path);
bsalomon512be532015-09-10 10:42:55 -0700427 this->recordBatch(batch);
bsalomona44919e2015-08-18 13:28:19 -0700428 batch->unref();
bsalomon@google.com64aef2b2012-06-11 15:36:13 +0000429}
430
joshualitt9853cce2014-11-17 14:22:48 -0800431void GrDrawTarget::clear(const SkIRect* rect,
432 GrColor color,
433 bool canIgnoreRect,
robertphillips976f5f02016-06-03 10:59:20 -0700434 GrDrawContext* drawContext) {
435 SkIRect rtRect = SkIRect::MakeWH(drawContext->width(), drawContext->height());
egdaniel51c8d402015-08-06 10:54:13 -0700436 SkIRect clippedRect;
437 if (!rect ||
438 (canIgnoreRect && this->caps()->fullClearIsFree()) ||
439 rect->contains(rtRect)) {
440 rect = &rtRect;
441 } else {
442 clippedRect = *rect;
443 if (!clippedRect.intersect(rtRect)) {
444 return;
445 }
446 rect = &clippedRect;
447 }
448
bsalomonb3b9aec2015-09-10 11:16:35 -0700449 if (this->caps()->useDrawInsteadOfClear()) {
bsalomon63b21962014-11-05 07:05:34 -0800450 // This works around a driver bug with clear by drawing a rect instead.
451 // The driver will ignore a clear if it is the only thing rendered to a
452 // target before the target is read.
egdaniel51c8d402015-08-06 10:54:13 -0700453 if (rect == &rtRect) {
robertphillips976f5f02016-06-03 10:59:20 -0700454 drawContext->discard();
bsalomon63b21962014-11-05 07:05:34 -0800455 }
bsalomon63b21962014-11-05 07:05:34 -0800456
robertphillips55fdccc2016-06-06 06:16:20 -0700457 // TODO: flip this into real draw!
egdaniel8dd688b2015-01-22 10:16:09 -0800458 GrPipelineBuilder pipelineBuilder;
bungeman06ca8ec2016-06-09 08:01:03 -0700459 pipelineBuilder.setXPFactory(GrPorterDuffXPFactory::Make(SkXfermode::kSrc_Mode));
joshualitt9853cce2014-11-17 14:22:48 -0800460
joshualitta8b84992016-01-13 13:35:35 -0800461 SkRect scalarRect = SkRect::Make(*rect);
462 SkAutoTUnref<GrDrawBatch> batch(
463 GrRectBatchFactory::CreateNonAAFill(color, SkMatrix::I(), scalarRect,
464 nullptr, nullptr));
robertphillips976f5f02016-06-03 10:59:20 -0700465 this->drawBatch(pipelineBuilder, drawContext, GrNoClip(), batch);
bsalomon53469832015-08-18 09:20:09 -0700466 } else {
robertphillips976f5f02016-06-03 10:59:20 -0700467 GrBatch* batch = new GrClearBatch(*rect, color, drawContext->accessRenderTarget());
bsalomon512be532015-09-10 10:42:55 -0700468 this->recordBatch(batch);
bsalomon53469832015-08-18 09:20:09 -0700469 batch->unref();
470 }
471}
472
473void GrDrawTarget::discard(GrRenderTarget* renderTarget) {
474 if (this->caps()->discardRenderTargetSupport()) {
halcanary385fe4d2015-08-26 13:07:48 -0700475 GrBatch* batch = new GrDiscardBatch(renderTarget);
bsalomon512be532015-09-10 10:42:55 -0700476 this->recordBatch(batch);
bsalomon53469832015-08-18 09:20:09 -0700477 batch->unref();
bsalomon63b21962014-11-05 07:05:34 -0800478 }
479}
480
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000481////////////////////////////////////////////////////////////////////////////////
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000482
bsalomonb8fea972016-02-16 07:34:17 -0800483bool GrDrawTarget::copySurface(GrSurface* dst,
bsalomon@google.com116ad842013-04-09 15:38:19 +0000484 GrSurface* src,
485 const SkIRect& srcRect,
486 const SkIPoint& dstPoint) {
bsalomon872062c2015-08-18 12:12:35 -0700487 GrBatch* batch = GrCopySurfaceBatch::Create(dst, src, srcRect, dstPoint);
bsalomonb8fea972016-02-16 07:34:17 -0800488 if (!batch) {
489 return false;
490 }
robertphillips498d7ac2015-10-30 10:11:30 -0700491#ifdef ENABLE_MDB
bsalomonb8fea972016-02-16 07:34:17 -0800492 this->addDependency(src);
robertphillips498d7ac2015-10-30 10:11:30 -0700493#endif
494
bsalomonb8fea972016-02-16 07:34:17 -0800495 this->recordBatch(batch);
496 batch->unref();
497 return true;
bsalomon@google.comeb851172013-04-15 13:51:00 +0000498}
499
bsalomon88cf17d2016-07-08 06:40:56 -0700500static inline bool exclusive_no_intersection(const SkRect& a, const SkRect& b) {
501 return a.fRight <= b.fLeft || a.fBottom <= b.fTop ||
502 b.fRight <= a.fLeft || b.fBottom <= a.fTop;
503}
504
505static inline bool can_reorder(const GrBatch* a, const GrBatch* b) {
506 SkRect ra;
507 SkRect rb;
508 batch_bounds(&ra, a);
509 batch_bounds(&rb, a);
510 return exclusive_no_intersection(ra, rb);
bsalomon512be532015-09-10 10:42:55 -0700511}
512
513void GrDrawTarget::recordBatch(GrBatch* batch) {
robertphillipsa106c622015-10-16 09:07:06 -0700514 // A closed drawTarget should never receive new/more batches
robertphillips6a186652015-10-20 07:37:58 -0700515 SkASSERT(!this->isClosed());
robertphillipsa106c622015-10-16 09:07:06 -0700516
bsalomon512be532015-09-10 10:42:55 -0700517 // Check if there is a Batch Draw we can batch with by linearly searching back until we either
518 // 1) check every draw
519 // 2) intersect with something
520 // 3) find a 'blocker'
joshualittb0666ad2016-03-08 10:43:41 -0800521 GR_AUDIT_TRAIL_ADDBATCH(fAuditTrail, batch);
bsalomon512be532015-09-10 10:42:55 -0700522 GrBATCH_INFO("Re-Recording (%s, B%u)\n"
joshualitte2bcec32015-09-30 06:22:22 -0700523 "\tBounds LRTB (%f, %f, %f, %f)\n",
bsalomon512be532015-09-10 10:42:55 -0700524 batch->name(),
525 batch->uniqueID(),
526 batch->bounds().fLeft, batch->bounds().fRight,
527 batch->bounds().fTop, batch->bounds().fBottom);
528 GrBATCH_INFO(SkTabString(batch->dumpInfo(), 1).c_str());
halcanary9d524f22016-03-29 09:03:52 -0700529 GrBATCH_INFO("\tOutcome:\n");
bsalomon489147c2015-12-14 12:13:09 -0800530 int maxCandidates = SkTMin(fMaxBatchLookback, fBatches.count());
bsalomon512be532015-09-10 10:42:55 -0700531 if (maxCandidates) {
532 int i = 0;
533 while (true) {
534 GrBatch* candidate = fBatches.fromBack(i);
535 // We cannot continue to search backwards if the render target changes
536 if (candidate->renderTargetUniqueID() != batch->renderTargetUniqueID()) {
537 GrBATCH_INFO("\t\tBreaking because of (%s, B%u) Rendertarget\n",
538 candidate->name(), candidate->uniqueID());
539 break;
540 }
541 if (candidate->combineIfPossible(batch, *this->caps())) {
542 GrBATCH_INFO("\t\tCombining with (%s, B%u)\n", candidate->name(),
543 candidate->uniqueID());
joshualittb0666ad2016-03-08 10:43:41 -0800544 GR_AUDIT_TRAIL_BATCHING_RESULT_COMBINED(fAuditTrail, candidate, batch);
bsalomon512be532015-09-10 10:42:55 -0700545 return;
546 }
547 // Stop going backwards if we would cause a painter's order violation.
bsalomondb4758c2015-11-23 11:14:20 -0800548 // TODO: The bounds used here do not fully consider the clip. It may be advantageous
549 // to clip each batch's bounds to the clip.
bsalomon88cf17d2016-07-08 06:40:56 -0700550 if (!can_reorder(candidate, batch)) {
bsalomon512be532015-09-10 10:42:55 -0700551 GrBATCH_INFO("\t\tIntersects with (%s, B%u)\n", candidate->name(),
552 candidate->uniqueID());
553 break;
554 }
555 ++i;
556 if (i == maxCandidates) {
557 GrBATCH_INFO("\t\tReached max lookback or beginning of batch array %d\n", i);
558 break;
559 }
560 }
561 } else {
562 GrBATCH_INFO("\t\tFirstBatch\n");
563 }
joshualitt18d6b752016-02-26 08:07:50 -0800564 GR_AUDIT_TRAIL_BATCHING_RESULT_NEW(fAuditTrail, batch);
bsalomon512be532015-09-10 10:42:55 -0700565 fBatches.push_back().reset(SkRef(batch));
566}
567
bsalomonaecc0182016-03-07 11:50:44 -0800568void GrDrawTarget::forwardCombine() {
569 for (int i = 0; i < fBatches.count() - 2; ++i) {
570 GrBatch* batch = fBatches[i];
571 int maxCandidateIdx = SkTMin(i + fMaxBatchLookahead, fBatches.count() - 1);
572 int j = i + 1;
573 while (true) {
574 GrBatch* candidate = fBatches[j];
575 // We cannot continue to search if the render target changes
576 if (candidate->renderTargetUniqueID() != batch->renderTargetUniqueID()) {
577 GrBATCH_INFO("\t\tBreaking because of (%s, B%u) Rendertarget\n",
578 candidate->name(), candidate->uniqueID());
579 break;
580 }
581 if (j == i +1) {
582 // We assume batch would have combined with candidate when the candidate was added
583 // via backwards combining in recordBatch.
584 SkASSERT(!batch->combineIfPossible(candidate, *this->caps()));
585 } else if (batch->combineIfPossible(candidate, *this->caps())) {
586 GrBATCH_INFO("\t\tCombining with (%s, B%u)\n", candidate->name(),
587 candidate->uniqueID());
joshualittb0666ad2016-03-08 10:43:41 -0800588 GR_AUDIT_TRAIL_BATCHING_RESULT_COMBINED(fAuditTrail, batch, candidate);
bsalomonaecc0182016-03-07 11:50:44 -0800589 fBatches[j].reset(SkRef(batch));
590 fBatches[i].reset(nullptr);
591 break;
592 }
593 // Stop going traversing if we would cause a painter's order violation.
594 // TODO: The bounds used here do not fully consider the clip. It may be advantageous
595 // to clip each batch's bounds to the clip.
bsalomon88cf17d2016-07-08 06:40:56 -0700596 if (!can_reorder(candidate, batch)) {
bsalomonaecc0182016-03-07 11:50:44 -0800597 GrBATCH_INFO("\t\tIntersects with (%s, B%u)\n", candidate->name(),
598 candidate->uniqueID());
599 break;
600 }
601 ++j;
602 if (j > maxCandidateIdx) {
603 GrBATCH_INFO("\t\tReached max lookahead or end of batch array %d\n", i);
604 break;
605 }
606 }
607 }
608}
609
egdaniele36914c2015-02-13 09:00:33 -0800610///////////////////////////////////////////////////////////////////////////////
611
bsalomonb3b9aec2015-09-10 11:16:35 -0700612void GrDrawTarget::clearStencilClip(const SkIRect& rect, bool insideClip, GrRenderTarget* rt) {
halcanary385fe4d2015-08-26 13:07:48 -0700613 GrBatch* batch = new GrClearStencilClipBatch(rect, insideClip, rt);
bsalomon512be532015-09-10 10:42:55 -0700614 this->recordBatch(batch);
bsalomon5ea03632015-08-18 10:33:30 -0700615 batch->unref();
616}