blob: 32f755e0ebd5d086503db1add97777dee9f48e2f [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"
robertphillips5fa7f302016-07-21 09:21:04 -070018#include "GrPipelineBuilder.h"
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +000019#include "GrRenderTarget.h"
bsalomon4061b122015-05-29 10:26:19 -070020#include "GrResourceProvider.h"
bsalomon6bc1b5f2015-02-23 09:06:38 -080021#include "GrRenderTargetPriv.h"
cdalton93a379b2016-05-11 13:58:08 -070022#include "GrStencilAttachment.h"
bsalomonafbf2d62014-09-30 12:18:44 -070023#include "GrSurfacePriv.h"
bsalomon@google.com86afc2a2011-02-16 16:12:19 +000024#include "GrTexture.h"
ethannicholas22793252016-01-30 09:59:10 -080025#include "gl/GrGLRenderTarget.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000026
joshualitt086cee12016-01-12 06:45:24 -080027#include "SkStrokeRec.h"
28
bsalomon9f129de2016-08-10 16:31:05 -070029#include "batches/GrClearBatch.h"
robertphillips9199a9f2016-07-13 07:48:43 -070030#include "batches/GrClearStencilClipBatch.h"
bsalomon872062c2015-08-18 12:12:35 -070031#include "batches/GrCopySurfaceBatch.h"
bsalomon53469832015-08-18 09:20:09 -070032#include "batches/GrDiscardBatch.h"
bsalomon16b99132015-08-13 14:55:50 -070033#include "batches/GrDrawBatch.h"
bsalomonadd79ef2015-08-19 13:26:49 -070034#include "batches/GrDrawPathBatch.h"
joshualittecd1a692015-08-10 10:08:26 -070035#include "batches/GrRectBatchFactory.h"
bsalomona44919e2015-08-18 13:28:19 -070036#include "batches/GrStencilPathBatch.h"
joshualitt74417822015-08-07 11:42:16 -070037
csmartdaltona7f29642016-07-07 08:49:11 -070038#include "instanced/InstancedRendering.h"
39
reed@google.comac10a2d2010-12-22 21:39:39 +000040////////////////////////////////////////////////////////////////////////////////
41
bsalomon489147c2015-12-14 12:13:09 -080042// Experimentally we have found that most batching occurs within the first 10 comparisons.
bsalomonaecc0182016-03-07 11:50:44 -080043static const int kDefaultMaxBatchLookback = 10;
44static const int kDefaultMaxBatchLookahead = 10;
bsalomon489147c2015-12-14 12:13:09 -080045
bsalomon69cfe952015-11-30 13:27:47 -080046GrDrawTarget::GrDrawTarget(GrRenderTarget* rt, GrGpu* gpu, GrResourceProvider* resourceProvider,
joshualitt086cee12016-01-12 06:45:24 -080047 GrAuditTrail* auditTrail, const Options& options)
bsalomonfd8d0132016-08-11 11:25:33 -070048 : fLastFullClearBatch(nullptr)
49 , fGpu(SkRef(gpu))
bsalomon4061b122015-05-29 10:26:19 -070050 , fResourceProvider(resourceProvider)
joshualitt086cee12016-01-12 06:45:24 -080051 , fAuditTrail(auditTrail)
bsalomon648c6962015-10-23 09:06:59 -070052 , fFlags(0)
csmartdaltone0d36292016-07-29 08:14:20 -070053 , fRenderTarget(rt) {
csmartdaltonc6f411e2016-08-05 22:32:12 -070054 // TODO: Stop extracting the context (currently needed by GrClip)
bsalomonb3b9aec2015-09-10 11:16:35 -070055 fContext = fGpu->getContext();
robertphillips4beb5c12015-10-20 07:50:00 -070056
cdalton862cff32016-05-12 15:09:48 -070057 fClipBatchToBounds = options.fClipBatchToBounds;
bsalomon6dea83f2015-12-03 12:58:06 -080058 fDrawBatchBounds = options.fDrawBatchBounds;
bsalomon489147c2015-12-14 12:13:09 -080059 fMaxBatchLookback = (options.fMaxBatchLookback < 0) ? kDefaultMaxBatchLookback :
60 options.fMaxBatchLookback;
bsalomonaecc0182016-03-07 11:50:44 -080061 fMaxBatchLookahead = (options.fMaxBatchLookahead < 0) ? kDefaultMaxBatchLookahead :
62 options.fMaxBatchLookahead;
bsalomon6dea83f2015-12-03 12:58:06 -080063
csmartdaltone0d36292016-07-29 08:14:20 -070064 if (GrCaps::InstancedSupport::kNone != this->caps()->instancedSupport()) {
65 fInstancedRendering.reset(fGpu->createInstancedRendering());
66 }
67
robertphillips0dfa62c2015-11-16 06:23:31 -080068 rt->setLastDrawTarget(this);
69
robertphillips4beb5c12015-10-20 07:50:00 -070070#ifdef SK_DEBUG
71 static int debugID = 0;
72 fDebugID = debugID++;
73#endif
bsalomon4061b122015-05-29 10:26:19 -070074}
75
76GrDrawTarget::~GrDrawTarget() {
robertphillips498d7ac2015-10-30 10:11:30 -070077 if (fRenderTarget && this == fRenderTarget->getLastDrawTarget()) {
78 fRenderTarget->setLastDrawTarget(nullptr);
79 }
80
bsalomon4061b122015-05-29 10:26:19 -070081 fGpu->unref();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +000082}
83
84////////////////////////////////////////////////////////////////////////////////
85
robertphillips6a186652015-10-20 07:37:58 -070086// Add a GrDrawTarget-based dependency
87void GrDrawTarget::addDependency(GrDrawTarget* dependedOn) {
88 SkASSERT(!dependedOn->dependsOn(this)); // loops are bad
89
90 if (this->dependsOn(dependedOn)) {
91 return; // don't add duplicate dependencies
92 }
93
94 *fDependencies.push() = dependedOn;
95}
96
97// Convert from a GrSurface-based dependency to a GrDrawTarget one
98void GrDrawTarget::addDependency(GrSurface* dependedOn) {
99 if (dependedOn->asRenderTarget() && dependedOn->asRenderTarget()->getLastDrawTarget()) {
100 // If it is still receiving dependencies, this DT shouldn't be closed
101 SkASSERT(!this->isClosed());
102
103 GrDrawTarget* dt = dependedOn->asRenderTarget()->getLastDrawTarget();
104 if (dt == this) {
105 // self-read - presumably for dst reads
106 } else {
107 this->addDependency(dt);
108
109 // Can't make it closed in the self-read case
110 dt->makeClosed();
111 }
112 }
113}
114
robertphillips4beb5c12015-10-20 07:50:00 -0700115#ifdef SK_DEBUG
116void GrDrawTarget::dump() const {
117 SkDebugf("--------------------------------------------------------------\n");
robertphillipse004bfc2015-11-16 09:06:59 -0800118 SkDebugf("node: %d -> RT: %d\n", fDebugID, fRenderTarget ? fRenderTarget->getUniqueID() : -1);
robertphillips4beb5c12015-10-20 07:50:00 -0700119 SkDebugf("relies On (%d): ", fDependencies.count());
120 for (int i = 0; i < fDependencies.count(); ++i) {
121 SkDebugf("%d, ", fDependencies[i]->fDebugID);
122 }
123 SkDebugf("\n");
bsalomon6cc90062016-07-08 11:31:22 -0700124 SkDebugf("batches (%d):\n", fRecordedBatches.count());
125 for (int i = 0; i < fRecordedBatches.count(); ++i) {
robertphillips4beb5c12015-10-20 07:50:00 -0700126 SkDebugf("*******************************\n");
bsalomon6cc90062016-07-08 11:31:22 -0700127 if (!fRecordedBatches[i].fBatch) {
bsalomonaecc0182016-03-07 11:50:44 -0800128 SkDebugf("%d: <combined forward>\n", i);
129 } else {
bsalomon6cc90062016-07-08 11:31:22 -0700130 SkDebugf("%d: %s\n", i, fRecordedBatches[i].fBatch->name());
131 SkString str = fRecordedBatches[i].fBatch->dumpInfo();
bsalomonaecc0182016-03-07 11:50:44 -0800132 SkDebugf("%s\n", str.c_str());
bsalomon6cc90062016-07-08 11:31:22 -0700133 const SkRect& clippedBounds = fRecordedBatches[i].fClippedBounds;
134 SkDebugf("ClippedBounds: [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n",
135 clippedBounds.fLeft, clippedBounds.fTop, clippedBounds.fRight,
136 clippedBounds.fBottom);
bsalomonaecc0182016-03-07 11:50:44 -0800137 }
robertphillips4beb5c12015-10-20 07:50:00 -0700138 }
139}
140#endif
141
bsalomon50785a32015-02-06 07:02:37 -0800142bool GrDrawTarget::setupDstReadIfNecessary(const GrPipelineBuilder& pipelineBuilder,
robertphillips55fdccc2016-06-06 06:16:20 -0700143 GrRenderTarget* rt,
cdalton862cff32016-05-12 15:09:48 -0700144 const GrClip& clip,
ethannicholasde4166a2015-11-30 08:57:38 -0800145 const GrPipelineOptimizations& optimizations,
bsalomon6a44c6a2015-05-26 09:49:05 -0700146 GrXferProcessor::DstTexture* dstTexture,
bsalomonad792c12015-09-10 11:10:50 -0700147 const SkRect& batchBounds) {
148 SkRect bounds = batchBounds;
149 bounds.outset(0.5f, 0.5f);
150
ethannicholasde4166a2015-11-30 08:57:38 -0800151 if (!pipelineBuilder.willXPNeedDstTexture(*this->caps(), optimizations)) {
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000152 return true;
153 }
cdalton9954bc32015-04-29 14:17:00 -0700154
cdalton9954bc32015-04-29 14:17:00 -0700155 if (this->caps()->textureBarrierSupport()) {
156 if (GrTexture* rtTex = rt->asTexture()) {
bsalomondc47ff72015-05-26 12:16:59 -0700157 // The render target is a texture, so we can read from it directly in the shader. The XP
cdalton9954bc32015-04-29 14:17:00 -0700158 // will be responsible to detect this situation and request a texture barrier.
bsalomon6a44c6a2015-05-26 09:49:05 -0700159 dstTexture->setTexture(rtTex);
160 dstTexture->setOffset(0, 0);
cdalton9954bc32015-04-29 14:17:00 -0700161 return true;
162 }
163 }
164
165 SkIRect copyRect;
cdalton862cff32016-05-12 15:09:48 -0700166 clip.getConservativeBounds(rt->width(), rt->height(), &copyRect);
commit-bot@chromium.orgc4dc0ad2013-10-09 14:11:33 +0000167
bsalomonad792c12015-09-10 11:10:50 -0700168 SkIRect drawIBounds;
169 bounds.roundOut(&drawIBounds);
170 if (!copyRect.intersect(drawIBounds)) {
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000171#ifdef SK_DEBUG
bsalomonb3b9aec2015-09-10 11:16:35 -0700172 GrCapsDebugf(this->caps(), "Missed an early reject. "
173 "Bailing on draw from setupDstReadIfNecessary.\n");
commit-bot@chromium.orgbb5c4652013-04-01 12:49:31 +0000174#endif
bsalomonad792c12015-09-10 11:10:50 -0700175 return false;
commit-bot@chromium.orgbb5c4652013-04-01 12:49:31 +0000176 }
skia.committer@gmail.com05a2ee02013-04-02 07:01:34 +0000177
commit-bot@chromium.org63150af2013-04-11 22:00:22 +0000178 // MSAA consideration: When there is support for reading MSAA samples in the shader we could
179 // have per-sample dst values by making the copy multisampled.
bsalomonf2703d82014-10-28 14:33:06 -0700180 GrSurfaceDesc desc;
bsalomonb3b9aec2015-09-10 11:16:35 -0700181 if (!fGpu->initCopySurfaceDstDesc(rt, &desc)) {
bsalomona73239a2015-04-28 13:35:17 -0700182 desc.fOrigin = kDefault_GrSurfaceOrigin;
183 desc.fFlags = kRenderTarget_GrSurfaceFlag;
184 desc.fConfig = rt->config();
185 }
186
commit-bot@chromium.orgbb5c4652013-04-01 12:49:31 +0000187 desc.fWidth = copyRect.width();
188 desc.fHeight = copyRect.height();
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000189
bsalomoneae62002015-07-31 13:59:30 -0700190 static const uint32_t kFlags = 0;
191 SkAutoTUnref<GrTexture> copy(fResourceProvider->createApproxTexture(desc, kFlags));
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000192
bsalomone3059732014-10-14 11:47:22 -0700193 if (!copy) {
tfarina38406c82014-10-31 07:11:12 -0700194 SkDebugf("Failed to create temporary copy of destination texture.\n");
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000195 return false;
196 }
bsalomon@google.come4617bf2013-04-03 14:56:40 +0000197 SkIPoint dstPoint = {0, 0};
bsalomon6df86402015-06-01 10:41:49 -0700198 this->copySurface(copy, rt, copyRect, dstPoint);
199 dstTexture->setTexture(copy);
200 dstTexture->setOffset(copyRect.fLeft, copyRect.fTop);
201 return true;
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000202}
203
robertphillipsa13e2022015-11-11 12:01:09 -0800204void GrDrawTarget::prepareBatches(GrBatchFlushState* flushState) {
robertphillipsa106c622015-10-16 09:07:06 -0700205 // Semi-usually the drawTargets are already closed at this point, but sometimes Ganesh
206 // needs to flush mid-draw. In that case, the SkGpuDevice's drawTargets won't be closed
207 // but need to be flushed anyway. Closing such drawTargets here will mean new
208 // drawTargets will be created to replace them if the SkGpuDevice(s) write to them again.
209 this->makeClosed();
210
robertphillips498d7ac2015-10-30 10:11:30 -0700211 // Loop over the batches that haven't yet generated their geometry
bsalomon6cc90062016-07-08 11:31:22 -0700212 for (int i = 0; i < fRecordedBatches.count(); ++i) {
213 if (fRecordedBatches[i].fBatch) {
214 fRecordedBatches[i].fBatch->prepare(flushState);
bsalomonaecc0182016-03-07 11:50:44 -0800215 }
bsalomon512be532015-09-10 10:42:55 -0700216 }
csmartdaltona7f29642016-07-07 08:49:11 -0700217
218 if (fInstancedRendering) {
219 fInstancedRendering->beginFlush(flushState->resourceProvider());
220 }
robertphillipsa13e2022015-11-11 12:01:09 -0800221}
bsalomon512be532015-09-10 10:42:55 -0700222
robertphillipsa13e2022015-11-11 12:01:09 -0800223void GrDrawTarget::drawBatches(GrBatchFlushState* flushState) {
egdanielb4021cf2016-07-28 08:53:07 -0700224 if (0 == fRecordedBatches.count()) {
225 return;
226 }
bsalomon512be532015-09-10 10:42:55 -0700227 // Draw all the generated geometry.
bsalomon6dea83f2015-12-03 12:58:06 -0800228 SkRandom random;
egdaniel9cb63402016-06-23 08:37:05 -0700229 GrRenderTarget* currentRT = nullptr;
230 SkAutoTDelete<GrGpuCommandBuffer> commandBuffer;
egdaniele7d1b242016-07-01 08:06:45 -0700231 SkRect bounds = SkRect::MakeEmpty();
bsalomon6cc90062016-07-08 11:31:22 -0700232 for (int i = 0; i < fRecordedBatches.count(); ++i) {
233 if (!fRecordedBatches[i].fBatch) {
bsalomonaecc0182016-03-07 11:50:44 -0800234 continue;
235 }
bsalomon6cc90062016-07-08 11:31:22 -0700236 if (fRecordedBatches[i].fBatch->renderTarget() != currentRT) {
egdaniel9cb63402016-06-23 08:37:05 -0700237 if (commandBuffer) {
238 commandBuffer->end();
egdaniele7d1b242016-07-01 08:06:45 -0700239 if (bounds.intersect(0, 0,
240 SkIntToScalar(currentRT->width()),
241 SkIntToScalar(currentRT->height()))) {
242 SkIRect iBounds;
243 bounds.roundOut(&iBounds);
244 commandBuffer->submit(iBounds);
245 }
egdaniel9cb63402016-06-23 08:37:05 -0700246 commandBuffer.reset();
247 }
egdaniele7d1b242016-07-01 08:06:45 -0700248 bounds.setEmpty();
bsalomon6cc90062016-07-08 11:31:22 -0700249 currentRT = fRecordedBatches[i].fBatch->renderTarget();
egdaniel9cb63402016-06-23 08:37:05 -0700250 if (currentRT) {
251 static const GrGpuCommandBuffer::LoadAndStoreInfo kBasicLoadStoreInfo
252 { GrGpuCommandBuffer::LoadOp::kLoad,GrGpuCommandBuffer::StoreOp::kStore,
253 GrColor_ILLEGAL };
254 commandBuffer.reset(fGpu->createCommandBuffer(currentRT,
255 kBasicLoadStoreInfo, // Color
256 kBasicLoadStoreInfo)); // Stencil
257 }
258 flushState->setCommandBuffer(commandBuffer);
259 }
egdaniele7d1b242016-07-01 08:06:45 -0700260 if (commandBuffer) {
bsalomon6cc90062016-07-08 11:31:22 -0700261 bounds.join(fRecordedBatches[i].fClippedBounds);
egdaniele7d1b242016-07-01 08:06:45 -0700262 }
bsalomon6dea83f2015-12-03 12:58:06 -0800263 if (fDrawBatchBounds) {
bsalomon6cc90062016-07-08 11:31:22 -0700264 const SkRect& bounds = fRecordedBatches[i].fClippedBounds;
265 SkIRect ibounds;
266 bounds.roundOut(&ibounds);
bsalomon6dea83f2015-12-03 12:58:06 -0800267 // In multi-draw buffer all the batches use the same render target and we won't need to
268 // get the batchs bounds.
bsalomon6cc90062016-07-08 11:31:22 -0700269 if (GrRenderTarget* rt = fRecordedBatches[i].fBatch->renderTarget()) {
270 fGpu->drawDebugWireRect(rt, ibounds, 0xFF000000 | random.nextU());
bsalomon6dea83f2015-12-03 12:58:06 -0800271 }
272 }
bsalomon6cc90062016-07-08 11:31:22 -0700273 fRecordedBatches[i].fBatch->draw(flushState);
bsalomon512be532015-09-10 10:42:55 -0700274 }
egdaniel9cb63402016-06-23 08:37:05 -0700275 if (commandBuffer) {
276 commandBuffer->end();
egdaniele7d1b242016-07-01 08:06:45 -0700277 if (bounds.intersect(0, 0,
278 SkIntToScalar(currentRT->width()),
279 SkIntToScalar(currentRT->height()))) {
280 SkIRect iBounds;
281 bounds.roundOut(&iBounds);
282 commandBuffer->submit(iBounds);
283 }
egdaniel9cb63402016-06-23 08:37:05 -0700284 flushState->setCommandBuffer(nullptr);
285 }
ethannicholas22793252016-01-30 09:59:10 -0800286
jvanverthd2d2eb92016-02-17 14:04:46 -0800287 fGpu->finishDrawTarget();
bsalomona73239a2015-04-28 13:35:17 -0700288}
289
bsalomon512be532015-09-10 10:42:55 -0700290void GrDrawTarget::reset() {
bsalomonfd8d0132016-08-11 11:25:33 -0700291 fLastFullClearBatch = nullptr;
bsalomon6cc90062016-07-08 11:31:22 -0700292 fRecordedBatches.reset();
csmartdaltona7f29642016-07-07 08:49:11 -0700293 if (fInstancedRendering) {
294 fInstancedRendering->endFlush();
295 }
bsalomon512be532015-09-10 10:42:55 -0700296}
297
bsalomon88cf17d2016-07-08 06:40:56 -0700298static void batch_bounds(SkRect* bounds, const GrBatch* batch) {
299 *bounds = batch->bounds();
300 if (batch->hasZeroArea()) {
301 if (batch->hasAABloat()) {
302 bounds->outset(0.5f, 0.5f);
303 } else {
304 // We don't know which way the particular GPU will snap lines or points at integer
305 // coords. So we ensure that the bounds is large enough for either snap.
306 SkRect before = *bounds;
307 bounds->roundOut(bounds);
308 if (bounds->fLeft == before.fLeft) {
309 bounds->fLeft -= 1;
310 }
311 if (bounds->fTop == before.fTop) {
312 bounds->fTop -= 1;
313 }
314 if (bounds->fRight == before.fRight) {
315 bounds->fRight += 1;
316 }
317 if (bounds->fBottom == before.fBottom) {
318 bounds->fBottom += 1;
319 }
320 }
321 }
322}
323
bsalomon6cc90062016-07-08 11:31:22 -0700324static inline bool intersect(SkRect* out, const SkRect& a, const SkRect& b) {
325 SkASSERT(a.fLeft <= a.fRight && a.fTop <= a.fBottom);
326 SkASSERT(b.fLeft <= b.fRight && b.fTop <= b.fBottom);
327 out->fLeft = SkTMax(a.fLeft, b.fLeft);
328 out->fTop = SkTMax(a.fTop, b.fTop);
329 out->fRight = SkTMin(a.fRight, b.fRight);
330 out->fBottom = SkTMin(a.fBottom, b.fBottom);
331 return (out->fLeft <= out->fRight && out->fTop <= out->fBottom);
332}
333
robertphillips391395d2016-03-02 09:26:36 -0800334void GrDrawTarget::drawBatch(const GrPipelineBuilder& pipelineBuilder,
robertphillips976f5f02016-06-03 10:59:20 -0700335 GrDrawContext* drawContext,
cdalton862cff32016-05-12 15:09:48 -0700336 const GrClip& clip,
337 GrDrawBatch* batch) {
joshualitt4d8da812015-01-28 12:53:54 -0800338 // Setup clip
cdalton862cff32016-05-12 15:09:48 -0700339 GrAppliedClip appliedClip;
bsalomon88cf17d2016-07-08 06:40:56 -0700340 SkRect bounds;
341 batch_bounds(&bounds, batch);
robertphillips59cf61a2016-07-13 09:18:21 -0700342 if (!clip.apply(fContext, drawContext, &bounds,
343 pipelineBuilder.isHWAntialias(), pipelineBuilder.hasUserStencilSettings(),
344 &appliedClip)) {
cdalton862cff32016-05-12 15:09:48 -0700345 return;
joshualitt4d8da812015-01-28 12:53:54 -0800346 }
robertphillips391395d2016-03-02 09:26:36 -0800347
robertphillips55fdccc2016-06-06 06:16:20 -0700348 // TODO: this is the only remaining usage of the AutoRestoreFragmentProcessorState - remove it
cdaltond4727922015-11-10 12:49:06 -0800349 GrPipelineBuilder::AutoRestoreFragmentProcessorState arfps;
bungeman06ca8ec2016-06-09 08:01:03 -0700350 if (appliedClip.getClipCoverageFragmentProcessor()) {
cdaltond4727922015-11-10 12:49:06 -0800351 arfps.set(&pipelineBuilder);
bungeman06ca8ec2016-06-09 08:01:03 -0700352 arfps.addCoverageFragmentProcessor(sk_ref_sp(appliedClip.getClipCoverageFragmentProcessor()));
cdaltond4727922015-11-10 12:49:06 -0800353 }
joshualitt4d8da812015-01-28 12:53:54 -0800354
bsalomonad792c12015-09-10 11:10:50 -0700355 GrPipeline::CreateArgs args;
cdalton193d9cf2016-05-12 11:52:02 -0700356 args.fPipelineBuilder = &pipelineBuilder;
robertphillips55fdccc2016-06-06 06:16:20 -0700357 args.fDrawContext = drawContext;
cdalton193d9cf2016-05-12 11:52:02 -0700358 args.fCaps = this->caps();
cdalton862cff32016-05-12 15:09:48 -0700359 args.fScissor = &appliedClip.scissorState();
360 args.fHasStencilClip = appliedClip.hasStencilClip();
361 if (pipelineBuilder.hasUserStencilSettings() || appliedClip.hasStencilClip()) {
robertphillips55fdccc2016-06-06 06:16:20 -0700362 if (!fResourceProvider->attachStencilAttachment(drawContext->accessRenderTarget())) {
cdalton17bf8202016-05-13 11:27:15 -0700363 SkDebugf("ERROR creating stencil attachment. Draw skipped.\n");
364 return;
365 }
cdalton193d9cf2016-05-12 11:52:02 -0700366 }
367 batch->getPipelineOptimizations(&args.fOpts);
368 GrScissorState finalScissor;
cdalton862cff32016-05-12 15:09:48 -0700369 if (args.fOpts.fOverrides.fUsePLSDstRead || fClipBatchToBounds) {
cdalton193d9cf2016-05-12 11:52:02 -0700370 GrGLIRect viewport;
371 viewport.fLeft = 0;
372 viewport.fBottom = 0;
robertphillips55fdccc2016-06-06 06:16:20 -0700373 viewport.fWidth = drawContext->width();
374 viewport.fHeight = drawContext->height();
cdalton193d9cf2016-05-12 11:52:02 -0700375 SkIRect ibounds;
376 ibounds.fLeft = SkTPin(SkScalarFloorToInt(batch->bounds().fLeft), viewport.fLeft,
377 viewport.fWidth);
378 ibounds.fTop = SkTPin(SkScalarFloorToInt(batch->bounds().fTop), viewport.fBottom,
379 viewport.fHeight);
380 ibounds.fRight = SkTPin(SkScalarCeilToInt(batch->bounds().fRight), viewport.fLeft,
381 viewport.fWidth);
382 ibounds.fBottom = SkTPin(SkScalarCeilToInt(batch->bounds().fBottom), viewport.fBottom,
383 viewport.fHeight);
cdalton862cff32016-05-12 15:09:48 -0700384 if (appliedClip.scissorState().enabled()) {
385 const SkIRect& scissorRect = appliedClip.scissorState().rect();
cdalton193d9cf2016-05-12 11:52:02 -0700386 if (!ibounds.intersect(scissorRect)) {
cdalton862cff32016-05-12 15:09:48 -0700387 return;
cdalton193d9cf2016-05-12 11:52:02 -0700388 }
389 }
390 finalScissor.set(ibounds);
391 args.fScissor = &finalScissor;
392 }
bungeman06ca8ec2016-06-09 08:01:03 -0700393 args.fOpts.fColorPOI.completeCalculations(
394 sk_sp_address_as_pointer_address(pipelineBuilder.fColorFragmentProcessors.begin()),
395 pipelineBuilder.numColorFragmentProcessors());
cdalton193d9cf2016-05-12 11:52:02 -0700396 args.fOpts.fCoveragePOI.completeCalculations(
bungeman06ca8ec2016-06-09 08:01:03 -0700397 sk_sp_address_as_pointer_address(pipelineBuilder.fCoverageFragmentProcessors.begin()),
398 pipelineBuilder.numCoverageFragmentProcessors());
robertphillips55fdccc2016-06-06 06:16:20 -0700399 if (!this->setupDstReadIfNecessary(pipelineBuilder, drawContext->accessRenderTarget(),
400 clip, args.fOpts,
401 &args.fDstTexture, batch->bounds())) {
cdalton193d9cf2016-05-12 11:52:02 -0700402 return;
403 }
404
405 if (!batch->installPipeline(args)) {
egdaniele36914c2015-02-13 09:00:33 -0800406 return;
407 }
bsalomonad792c12015-09-10 11:10:50 -0700408
robertphillips498d7ac2015-10-30 10:11:30 -0700409#ifdef ENABLE_MDB
410 SkASSERT(fRenderTarget);
411 batch->pipeline()->addDependenciesTo(fRenderTarget);
412#endif
bsalomon6cc90062016-07-08 11:31:22 -0700413 SkRect clippedBounds;
414 SkAssertResult(intersect(&clippedBounds, bounds, appliedClip.deviceBounds()));
415 this->recordBatch(batch, clippedBounds);
joshualitt4d8da812015-01-28 12:53:54 -0800416}
417
robertphillips59cf61a2016-07-13 09:18:21 -0700418void GrDrawTarget::stencilPath(GrDrawContext* drawContext,
cdalton862cff32016-05-12 15:09:48 -0700419 const GrClip& clip,
robertphillips59cf61a2016-07-13 09:18:21 -0700420 const GrUserStencilSettings* ss,
421 bool useHWAA,
joshualittf2384692015-09-10 11:00:51 -0700422 const SkMatrix& viewMatrix,
robertphillips59cf61a2016-07-13 09:18:21 -0700423 const GrPath* path) {
bsalomon@google.com64aef2b2012-06-11 15:36:13 +0000424 // TODO: extract portions of checkDraw that are relevant to path stenciling.
bsalomon49f085d2014-09-05 13:34:00 -0700425 SkASSERT(path);
jvanverthe9c0fc62015-04-29 11:18:05 -0700426 SkASSERT(this->caps()->shaderCaps()->pathRenderingSupport());
joshualitt2c93efe2014-11-06 12:57:13 -0800427
428 // Setup clip
cdalton862cff32016-05-12 15:09:48 -0700429 GrAppliedClip appliedClip;
robertphillips59cf61a2016-07-13 09:18:21 -0700430 if (!clip.apply(fContext, drawContext, nullptr, useHWAA, SkToBool(ss), &appliedClip)) {
joshualitt2c93efe2014-11-06 12:57:13 -0800431 return;
432 }
cdalton862cff32016-05-12 15:09:48 -0700433 // TODO: respect fClipBatchToBounds if we ever start computing bounds here.
joshualitt2c93efe2014-11-06 12:57:13 -0800434
cdalton846c0512016-05-13 10:25:00 -0700435 // Coverage AA does not make sense when rendering to the stencil buffer. The caller should never
436 // attempt this in a situation that would require coverage AA.
bungeman06ca8ec2016-06-09 08:01:03 -0700437 SkASSERT(!appliedClip.getClipCoverageFragmentProcessor());
bsalomon0ba8c242015-10-07 09:20:28 -0700438
robertphillips55fdccc2016-06-06 06:16:20 -0700439 GrStencilAttachment* stencilAttachment = fResourceProvider->attachStencilAttachment(
440 drawContext->accessRenderTarget());
cdalton17bf8202016-05-13 11:27:15 -0700441 if (!stencilAttachment) {
442 SkDebugf("ERROR creating stencil attachment. Draw skipped.\n");
443 return;
444 }
joshualitt2c93efe2014-11-06 12:57:13 -0800445
joshualittf2384692015-09-10 11:00:51 -0700446 GrBatch* batch = GrStencilPathBatch::Create(viewMatrix,
robertphillips59cf61a2016-07-13 09:18:21 -0700447 useHWAA,
448 path->getFillType(),
cdalton862cff32016-05-12 15:09:48 -0700449 appliedClip.hasStencilClip(),
cdalton93a379b2016-05-11 13:58:08 -0700450 stencilAttachment->bits(),
cdalton862cff32016-05-12 15:09:48 -0700451 appliedClip.scissorState(),
robertphillips55fdccc2016-06-06 06:16:20 -0700452 drawContext->accessRenderTarget(),
bsalomona44919e2015-08-18 13:28:19 -0700453 path);
bsalomon6cc90062016-07-08 11:31:22 -0700454 this->recordBatch(batch, appliedClip.deviceBounds());
bsalomona44919e2015-08-18 13:28:19 -0700455 batch->unref();
bsalomon@google.com64aef2b2012-06-11 15:36:13 +0000456}
457
robertphillips9199a9f2016-07-13 07:48:43 -0700458void GrDrawTarget::addBatch(sk_sp<GrBatch> batch) {
459 this->recordBatch(batch.get(), batch->bounds());
bsalomon53469832015-08-18 09:20:09 -0700460}
461
bsalomon9f129de2016-08-10 16:31:05 -0700462void GrDrawTarget::fullClear(GrRenderTarget* renderTarget, GrColor color) {
bsalomonfd8d0132016-08-11 11:25:33 -0700463 // Currently this just inserts or updates the last clear batch. However, once in MDB this can
464 // remove all the previously recorded batches and change the load op to clear with supplied
465 // color.
466 if (fLastFullClearBatch &&
467 fLastFullClearBatch->renderTargetUniqueID() == renderTarget->getUniqueID()) {
468 // As currently implemented, fLastFullClearBatch should be the last batch because we would
469 // have cleared it when another batch was recorded.
470 SkASSERT(fRecordedBatches.back().fBatch.get() == fLastFullClearBatch);
471 fLastFullClearBatch->setColor(color);
472 return;
473 }
474 sk_sp<GrClearBatch> batch(GrClearBatch::Make(SkIRect::MakeWH(renderTarget->width(),
475 renderTarget->height()),
476 color, renderTarget));
477 if (batch.get() == this->recordBatch(batch.get(), batch->bounds())) {
478 fLastFullClearBatch = batch.get();
479 }
bsalomon9f129de2016-08-10 16:31:05 -0700480}
481
bsalomon53469832015-08-18 09:20:09 -0700482void GrDrawTarget::discard(GrRenderTarget* renderTarget) {
bsalomon9f129de2016-08-10 16:31:05 -0700483 // Currently this just inserts a discard batch. However, once in MDB this can remove all the
484 // previously recorded batches and change the load op to discard.
bsalomon53469832015-08-18 09:20:09 -0700485 if (this->caps()->discardRenderTargetSupport()) {
halcanary385fe4d2015-08-26 13:07:48 -0700486 GrBatch* batch = new GrDiscardBatch(renderTarget);
bsalomon6cc90062016-07-08 11:31:22 -0700487 this->recordBatch(batch, batch->bounds());
bsalomon53469832015-08-18 09:20:09 -0700488 batch->unref();
bsalomon63b21962014-11-05 07:05:34 -0800489 }
490}
491
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000492////////////////////////////////////////////////////////////////////////////////
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000493
bsalomonb8fea972016-02-16 07:34:17 -0800494bool GrDrawTarget::copySurface(GrSurface* dst,
bsalomon@google.com116ad842013-04-09 15:38:19 +0000495 GrSurface* src,
496 const SkIRect& srcRect,
497 const SkIPoint& dstPoint) {
bsalomon872062c2015-08-18 12:12:35 -0700498 GrBatch* batch = GrCopySurfaceBatch::Create(dst, src, srcRect, dstPoint);
bsalomonb8fea972016-02-16 07:34:17 -0800499 if (!batch) {
500 return false;
501 }
robertphillips498d7ac2015-10-30 10:11:30 -0700502#ifdef ENABLE_MDB
bsalomonb8fea972016-02-16 07:34:17 -0800503 this->addDependency(src);
robertphillips498d7ac2015-10-30 10:11:30 -0700504#endif
505
bsalomon6cc90062016-07-08 11:31:22 -0700506 this->recordBatch(batch, batch->bounds());
bsalomonb8fea972016-02-16 07:34:17 -0800507 batch->unref();
508 return true;
bsalomon@google.comeb851172013-04-15 13:51:00 +0000509}
510
bsalomon6cc90062016-07-08 11:31:22 -0700511static inline bool can_reorder(const SkRect& a, const SkRect& b) {
bsalomon88cf17d2016-07-08 06:40:56 -0700512 return a.fRight <= b.fLeft || a.fBottom <= b.fTop ||
513 b.fRight <= a.fLeft || b.fBottom <= a.fTop;
514}
515
bsalomon6cc90062016-07-08 11:31:22 -0700516static void join(SkRect* out, const SkRect& a, const SkRect& b) {
517 SkASSERT(a.fLeft <= a.fRight && a.fTop <= a.fBottom);
518 SkASSERT(b.fLeft <= b.fRight && b.fTop <= b.fBottom);
519 out->fLeft = SkTMin(a.fLeft, b.fLeft);
520 out->fTop = SkTMin(a.fTop, b.fTop);
521 out->fRight = SkTMax(a.fRight, b.fRight);
522 out->fBottom = SkTMax(a.fBottom, b.fBottom);
bsalomon512be532015-09-10 10:42:55 -0700523}
524
bsalomonfd8d0132016-08-11 11:25:33 -0700525GrBatch* GrDrawTarget::recordBatch(GrBatch* batch, const SkRect& clippedBounds) {
robertphillipsa106c622015-10-16 09:07:06 -0700526 // A closed drawTarget should never receive new/more batches
robertphillips6a186652015-10-20 07:37:58 -0700527 SkASSERT(!this->isClosed());
robertphillipsa106c622015-10-16 09:07:06 -0700528
bsalomon512be532015-09-10 10:42:55 -0700529 // Check if there is a Batch Draw we can batch with by linearly searching back until we either
530 // 1) check every draw
531 // 2) intersect with something
532 // 3) find a 'blocker'
joshualittb0666ad2016-03-08 10:43:41 -0800533 GR_AUDIT_TRAIL_ADDBATCH(fAuditTrail, batch);
bsalomon512be532015-09-10 10:42:55 -0700534 GrBATCH_INFO("Re-Recording (%s, B%u)\n"
joshualitte2bcec32015-09-30 06:22:22 -0700535 "\tBounds LRTB (%f, %f, %f, %f)\n",
bsalomon512be532015-09-10 10:42:55 -0700536 batch->name(),
537 batch->uniqueID(),
538 batch->bounds().fLeft, batch->bounds().fRight,
539 batch->bounds().fTop, batch->bounds().fBottom);
540 GrBATCH_INFO(SkTabString(batch->dumpInfo(), 1).c_str());
bsalomon6cc90062016-07-08 11:31:22 -0700541 GrBATCH_INFO("\tClipped Bounds: [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n",
542 clippedBounds.fLeft, clippedBounds.fTop, clippedBounds.fRight,
543 clippedBounds.fBottom);
halcanary9d524f22016-03-29 09:03:52 -0700544 GrBATCH_INFO("\tOutcome:\n");
bsalomon6cc90062016-07-08 11:31:22 -0700545 int maxCandidates = SkTMin(fMaxBatchLookback, fRecordedBatches.count());
bsalomon512be532015-09-10 10:42:55 -0700546 if (maxCandidates) {
547 int i = 0;
548 while (true) {
bsalomon6cc90062016-07-08 11:31:22 -0700549 GrBatch* candidate = fRecordedBatches.fromBack(i).fBatch.get();
bsalomon512be532015-09-10 10:42:55 -0700550 // We cannot continue to search backwards if the render target changes
551 if (candidate->renderTargetUniqueID() != batch->renderTargetUniqueID()) {
552 GrBATCH_INFO("\t\tBreaking because of (%s, B%u) Rendertarget\n",
553 candidate->name(), candidate->uniqueID());
554 break;
555 }
556 if (candidate->combineIfPossible(batch, *this->caps())) {
557 GrBATCH_INFO("\t\tCombining with (%s, B%u)\n", candidate->name(),
558 candidate->uniqueID());
joshualittb0666ad2016-03-08 10:43:41 -0800559 GR_AUDIT_TRAIL_BATCHING_RESULT_COMBINED(fAuditTrail, candidate, batch);
bsalomon6cc90062016-07-08 11:31:22 -0700560 join(&fRecordedBatches.fromBack(i).fClippedBounds,
561 fRecordedBatches.fromBack(i).fClippedBounds, clippedBounds);
bsalomonfd8d0132016-08-11 11:25:33 -0700562 return candidate;
bsalomon512be532015-09-10 10:42:55 -0700563 }
564 // Stop going backwards if we would cause a painter's order violation.
bsalomon6cc90062016-07-08 11:31:22 -0700565 const SkRect& candidateBounds = fRecordedBatches.fromBack(i).fClippedBounds;
566 if (!can_reorder(candidateBounds, clippedBounds)) {
bsalomon512be532015-09-10 10:42:55 -0700567 GrBATCH_INFO("\t\tIntersects with (%s, B%u)\n", candidate->name(),
568 candidate->uniqueID());
569 break;
570 }
571 ++i;
572 if (i == maxCandidates) {
573 GrBATCH_INFO("\t\tReached max lookback or beginning of batch array %d\n", i);
574 break;
575 }
576 }
577 } else {
578 GrBATCH_INFO("\t\tFirstBatch\n");
579 }
joshualitt18d6b752016-02-26 08:07:50 -0800580 GR_AUDIT_TRAIL_BATCHING_RESULT_NEW(fAuditTrail, batch);
bsalomon6cc90062016-07-08 11:31:22 -0700581 fRecordedBatches.emplace_back(RecordedBatch{sk_ref_sp(batch), clippedBounds});
bsalomonfd8d0132016-08-11 11:25:33 -0700582 fLastFullClearBatch = nullptr;
583 return batch;
bsalomon512be532015-09-10 10:42:55 -0700584}
585
bsalomonaecc0182016-03-07 11:50:44 -0800586void GrDrawTarget::forwardCombine() {
bsalomon6cc90062016-07-08 11:31:22 -0700587 for (int i = 0; i < fRecordedBatches.count() - 2; ++i) {
588 GrBatch* batch = fRecordedBatches[i].fBatch.get();
589 const SkRect& batchBounds = fRecordedBatches[i].fClippedBounds;
590 int maxCandidateIdx = SkTMin(i + fMaxBatchLookahead, fRecordedBatches.count() - 1);
bsalomonaecc0182016-03-07 11:50:44 -0800591 int j = i + 1;
592 while (true) {
bsalomon6cc90062016-07-08 11:31:22 -0700593 GrBatch* candidate = fRecordedBatches[j].fBatch.get();
bsalomonaecc0182016-03-07 11:50:44 -0800594 // We cannot continue to search if the render target changes
595 if (candidate->renderTargetUniqueID() != batch->renderTargetUniqueID()) {
596 GrBATCH_INFO("\t\tBreaking because of (%s, B%u) Rendertarget\n",
597 candidate->name(), candidate->uniqueID());
598 break;
599 }
600 if (j == i +1) {
601 // We assume batch would have combined with candidate when the candidate was added
602 // via backwards combining in recordBatch.
603 SkASSERT(!batch->combineIfPossible(candidate, *this->caps()));
604 } else if (batch->combineIfPossible(candidate, *this->caps())) {
605 GrBATCH_INFO("\t\tCombining with (%s, B%u)\n", candidate->name(),
606 candidate->uniqueID());
joshualittb0666ad2016-03-08 10:43:41 -0800607 GR_AUDIT_TRAIL_BATCHING_RESULT_COMBINED(fAuditTrail, batch, candidate);
bsalomon6cc90062016-07-08 11:31:22 -0700608 fRecordedBatches[j].fBatch = std::move(fRecordedBatches[i].fBatch);
609 join(&fRecordedBatches[j].fClippedBounds, fRecordedBatches[j].fClippedBounds,
610 batchBounds);
bsalomonaecc0182016-03-07 11:50:44 -0800611 break;
612 }
613 // Stop going traversing if we would cause a painter's order violation.
bsalomon6cc90062016-07-08 11:31:22 -0700614 const SkRect& candidateBounds = fRecordedBatches[j].fClippedBounds;
615 if (!can_reorder(candidateBounds, batchBounds)) {
bsalomonaecc0182016-03-07 11:50:44 -0800616 GrBATCH_INFO("\t\tIntersects with (%s, B%u)\n", candidate->name(),
617 candidate->uniqueID());
618 break;
619 }
620 ++j;
621 if (j > maxCandidateIdx) {
622 GrBATCH_INFO("\t\tReached max lookahead or end of batch array %d\n", i);
623 break;
624 }
625 }
626 }
627}
628
egdaniele36914c2015-02-13 09:00:33 -0800629///////////////////////////////////////////////////////////////////////////////
630
bsalomonb3b9aec2015-09-10 11:16:35 -0700631void GrDrawTarget::clearStencilClip(const SkIRect& rect, bool insideClip, GrRenderTarget* rt) {
halcanary385fe4d2015-08-26 13:07:48 -0700632 GrBatch* batch = new GrClearStencilClipBatch(rect, insideClip, rt);
bsalomon6cc90062016-07-08 11:31:22 -0700633 this->recordBatch(batch, batch->bounds());
bsalomon5ea03632015-08-18 10:33:30 -0700634 batch->unref();
635}