1
2 /*
3 * Copyright 2010 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9 #include "GrDrawTarget.h"
10
11 #include "GrAuditTrail.h"
12 #include "GrCaps.h"
13 #include "GrGpu.h"
14 #include "GrPath.h"
15 #include "GrPipeline.h"
16 #include "GrMemoryPool.h"
17 #include "GrRenderTarget.h"
18 #include "GrResourceProvider.h"
19 #include "GrRenderTargetPriv.h"
20 #include "GrSurfacePriv.h"
21 #include "GrTexture.h"
22 #include "GrVertexBuffer.h"
23 #include "gl/GrGLRenderTarget.h"
24
25 #include "SkStrokeRec.h"
26
27 #include "batches/GrClearBatch.h"
28 #include "batches/GrCopySurfaceBatch.h"
29 #include "batches/GrDiscardBatch.h"
30 #include "batches/GrDrawBatch.h"
31 #include "batches/GrDrawPathBatch.h"
32 #include "batches/GrRectBatchFactory.h"
33 #include "batches/GrStencilPathBatch.h"
34
35 ////////////////////////////////////////////////////////////////////////////////
36
37 // Experimentally we have found that most batching occurs within the first 10 comparisons.
38 static const int kDefaultMaxBatchLookback = 10;
39
GrDrawTarget(GrRenderTarget * rt,GrGpu * gpu,GrResourceProvider * resourceProvider,GrAuditTrail * auditTrail,const Options & options)40 GrDrawTarget::GrDrawTarget(GrRenderTarget* rt, GrGpu* gpu, GrResourceProvider* resourceProvider,
41 GrAuditTrail* auditTrail, const Options& options)
42 : fGpu(SkRef(gpu))
43 , fResourceProvider(resourceProvider)
44 , fAuditTrail(auditTrail)
45 , fFlags(0)
46 , fRenderTarget(rt) {
47 // TODO: Stop extracting the context (currently needed by GrClipMaskManager)
48 fContext = fGpu->getContext();
49 fClipMaskManager.reset(new GrClipMaskManager(this, options.fClipBatchToBounds));
50
51 fDrawBatchBounds = options.fDrawBatchBounds;
52 fMaxBatchLookback = (options.fMaxBatchLookback < 0) ? kDefaultMaxBatchLookback :
53 options.fMaxBatchLookback;
54
55 rt->setLastDrawTarget(this);
56
57 #ifdef SK_DEBUG
58 static int debugID = 0;
59 fDebugID = debugID++;
60 #endif
61 }
62
~GrDrawTarget()63 GrDrawTarget::~GrDrawTarget() {
64 if (fRenderTarget && this == fRenderTarget->getLastDrawTarget()) {
65 fRenderTarget->setLastDrawTarget(nullptr);
66 }
67
68 fGpu->unref();
69 }
70
71 ////////////////////////////////////////////////////////////////////////////////
72
73 // Add a GrDrawTarget-based dependency
addDependency(GrDrawTarget * dependedOn)74 void GrDrawTarget::addDependency(GrDrawTarget* dependedOn) {
75 SkASSERT(!dependedOn->dependsOn(this)); // loops are bad
76
77 if (this->dependsOn(dependedOn)) {
78 return; // don't add duplicate dependencies
79 }
80
81 *fDependencies.push() = dependedOn;
82 }
83
84 // Convert from a GrSurface-based dependency to a GrDrawTarget one
addDependency(GrSurface * dependedOn)85 void GrDrawTarget::addDependency(GrSurface* dependedOn) {
86 if (dependedOn->asRenderTarget() && dependedOn->asRenderTarget()->getLastDrawTarget()) {
87 // If it is still receiving dependencies, this DT shouldn't be closed
88 SkASSERT(!this->isClosed());
89
90 GrDrawTarget* dt = dependedOn->asRenderTarget()->getLastDrawTarget();
91 if (dt == this) {
92 // self-read - presumably for dst reads
93 } else {
94 this->addDependency(dt);
95
96 // Can't make it closed in the self-read case
97 dt->makeClosed();
98 }
99 }
100 }
101
102 #ifdef SK_DEBUG
dump() const103 void GrDrawTarget::dump() const {
104 SkDebugf("--------------------------------------------------------------\n");
105 SkDebugf("node: %d -> RT: %d\n", fDebugID, fRenderTarget ? fRenderTarget->getUniqueID() : -1);
106 SkDebugf("relies On (%d): ", fDependencies.count());
107 for (int i = 0; i < fDependencies.count(); ++i) {
108 SkDebugf("%d, ", fDependencies[i]->fDebugID);
109 }
110 SkDebugf("\n");
111 SkDebugf("batches (%d):\n", fBatches.count());
112 for (int i = 0; i < fBatches.count(); ++i) {
113 #if 0
114 SkDebugf("*******************************\n");
115 #endif
116 SkDebugf("%d: %s\n", i, fBatches[i]->name());
117 #if 0
118 SkString str = fBatches[i]->dumpInfo();
119 SkDebugf("%s\n", str.c_str());
120 #endif
121 }
122 }
123 #endif
124
setupDstReadIfNecessary(const GrPipelineBuilder & pipelineBuilder,const GrPipelineOptimizations & optimizations,GrXferProcessor::DstTexture * dstTexture,const SkRect & batchBounds)125 bool GrDrawTarget::setupDstReadIfNecessary(const GrPipelineBuilder& pipelineBuilder,
126 const GrPipelineOptimizations& optimizations,
127 GrXferProcessor::DstTexture* dstTexture,
128 const SkRect& batchBounds) {
129 SkRect bounds = batchBounds;
130 bounds.outset(0.5f, 0.5f);
131
132 if (!pipelineBuilder.willXPNeedDstTexture(*this->caps(), optimizations)) {
133 return true;
134 }
135
136 GrRenderTarget* rt = pipelineBuilder.getRenderTarget();
137
138 if (this->caps()->textureBarrierSupport()) {
139 if (GrTexture* rtTex = rt->asTexture()) {
140 // The render target is a texture, so we can read from it directly in the shader. The XP
141 // will be responsible to detect this situation and request a texture barrier.
142 dstTexture->setTexture(rtTex);
143 dstTexture->setOffset(0, 0);
144 return true;
145 }
146 }
147
148 SkIRect copyRect;
149 pipelineBuilder.clip().getConservativeBounds(rt->width(), rt->height(), ©Rect);
150
151 SkIRect drawIBounds;
152 bounds.roundOut(&drawIBounds);
153 if (!copyRect.intersect(drawIBounds)) {
154 #ifdef SK_DEBUG
155 GrCapsDebugf(this->caps(), "Missed an early reject. "
156 "Bailing on draw from setupDstReadIfNecessary.\n");
157 #endif
158 return false;
159 }
160
161 // MSAA consideration: When there is support for reading MSAA samples in the shader we could
162 // have per-sample dst values by making the copy multisampled.
163 GrSurfaceDesc desc;
164 if (!fGpu->initCopySurfaceDstDesc(rt, &desc)) {
165 desc.fOrigin = kDefault_GrSurfaceOrigin;
166 desc.fFlags = kRenderTarget_GrSurfaceFlag;
167 desc.fConfig = rt->config();
168 }
169
170 desc.fWidth = copyRect.width();
171 desc.fHeight = copyRect.height();
172
173 static const uint32_t kFlags = 0;
174 SkAutoTUnref<GrTexture> copy(fResourceProvider->createApproxTexture(desc, kFlags));
175
176 if (!copy) {
177 SkDebugf("Failed to create temporary copy of destination texture.\n");
178 return false;
179 }
180 SkIPoint dstPoint = {0, 0};
181 this->copySurface(copy, rt, copyRect, dstPoint);
182 dstTexture->setTexture(copy);
183 dstTexture->setOffset(copyRect.fLeft, copyRect.fTop);
184 return true;
185 }
186
prepareBatches(GrBatchFlushState * flushState)187 void GrDrawTarget::prepareBatches(GrBatchFlushState* flushState) {
188 // Semi-usually the drawTargets are already closed at this point, but sometimes Ganesh
189 // needs to flush mid-draw. In that case, the SkGpuDevice's drawTargets won't be closed
190 // but need to be flushed anyway. Closing such drawTargets here will mean new
191 // drawTargets will be created to replace them if the SkGpuDevice(s) write to them again.
192 this->makeClosed();
193
194 // Loop over the batches that haven't yet generated their geometry
195 for (int i = 0; i < fBatches.count(); ++i) {
196 fBatches[i]->prepare(flushState);
197 }
198 }
199
drawBatches(GrBatchFlushState * flushState)200 void GrDrawTarget::drawBatches(GrBatchFlushState* flushState) {
201 // Draw all the generated geometry.
202 SkRandom random;
203 for (int i = 0; i < fBatches.count(); ++i) {
204 if (fDrawBatchBounds) {
205 const SkRect& bounds = fBatches[i]->bounds();
206 SkIRect ibounds;
207 bounds.roundOut(&ibounds);
208 // In multi-draw buffer all the batches use the same render target and we won't need to
209 // get the batchs bounds.
210 if (GrRenderTarget* rt = fBatches[i]->renderTarget()) {
211 fGpu->drawDebugWireRect(rt, ibounds, 0xFF000000 | random.nextU());
212 }
213 }
214 fBatches[i]->draw(flushState);
215 }
216
217 fGpu->finishDrawTarget();
218 }
219
reset()220 void GrDrawTarget::reset() {
221 fBatches.reset();
222 }
223
drawBatch(const GrPipelineBuilder & pipelineBuilder,GrDrawBatch * batch)224 void GrDrawTarget::drawBatch(const GrPipelineBuilder& pipelineBuilder, GrDrawBatch* batch) {
225 // Setup clip
226 GrPipelineBuilder::AutoRestoreStencil ars;
227 GrAppliedClip clip;
228 if (!fClipMaskManager->setupClipping(pipelineBuilder, &ars, &batch->bounds(), &clip)) {
229 return;
230 }
231 GrPipelineBuilder::AutoRestoreFragmentProcessorState arfps;
232 if (clip.clipCoverageFragmentProcessor()) {
233 arfps.set(&pipelineBuilder);
234 arfps.addCoverageFragmentProcessor(clip.clipCoverageFragmentProcessor());
235 }
236
237 GrPipeline::CreateArgs args;
238 if (!this->installPipelineInDrawBatch(&pipelineBuilder, &clip.scissorState(), batch)) {
239 return;
240 }
241
242 #ifdef ENABLE_MDB
243 SkASSERT(fRenderTarget);
244 batch->pipeline()->addDependenciesTo(fRenderTarget);
245 #endif
246
247 this->recordBatch(batch);
248 }
249
winding_path_stencil_settings()250 static const GrStencilSettings& winding_path_stencil_settings() {
251 GR_STATIC_CONST_SAME_STENCIL_STRUCT(gSettings,
252 kIncClamp_StencilOp,
253 kIncClamp_StencilOp,
254 kAlwaysIfInClip_StencilFunc,
255 0xFFFF, 0xFFFF, 0xFFFF);
256 return *GR_CONST_STENCIL_SETTINGS_PTR_FROM_STRUCT_PTR(&gSettings);
257 }
258
even_odd_path_stencil_settings()259 static const GrStencilSettings& even_odd_path_stencil_settings() {
260 GR_STATIC_CONST_SAME_STENCIL_STRUCT(gSettings,
261 kInvert_StencilOp,
262 kInvert_StencilOp,
263 kAlwaysIfInClip_StencilFunc,
264 0xFFFF, 0xFFFF, 0xFFFF);
265 return *GR_CONST_STENCIL_SETTINGS_PTR_FROM_STRUCT_PTR(&gSettings);
266 }
267
getPathStencilSettingsForFilltype(GrPathRendering::FillType fill,const GrStencilAttachment * sb,GrStencilSettings * outStencilSettings)268 void GrDrawTarget::getPathStencilSettingsForFilltype(GrPathRendering::FillType fill,
269 const GrStencilAttachment* sb,
270 GrStencilSettings* outStencilSettings) {
271
272 switch (fill) {
273 default:
274 SkFAIL("Unexpected path fill.");
275 case GrPathRendering::kWinding_FillType:
276 *outStencilSettings = winding_path_stencil_settings();
277 break;
278 case GrPathRendering::kEvenOdd_FillType:
279 *outStencilSettings = even_odd_path_stencil_settings();
280 break;
281 }
282 fClipMaskManager->adjustPathStencilParams(sb, outStencilSettings);
283 }
284
stencilPath(const GrPipelineBuilder & pipelineBuilder,const SkMatrix & viewMatrix,const GrPath * path,GrPathRendering::FillType fill)285 void GrDrawTarget::stencilPath(const GrPipelineBuilder& pipelineBuilder,
286 const SkMatrix& viewMatrix,
287 const GrPath* path,
288 GrPathRendering::FillType fill) {
289 // TODO: extract portions of checkDraw that are relevant to path stenciling.
290 SkASSERT(path);
291 SkASSERT(this->caps()->shaderCaps()->pathRenderingSupport());
292
293 // Setup clip
294 GrPipelineBuilder::AutoRestoreStencil ars;
295 GrAppliedClip clip;
296 if (!fClipMaskManager->setupClipping(pipelineBuilder, &ars, nullptr, &clip)) {
297 return;
298 }
299
300 GrPipelineBuilder::AutoRestoreFragmentProcessorState arfps;
301 if (clip.clipCoverageFragmentProcessor()) {
302 arfps.set(&pipelineBuilder);
303 arfps.addCoverageFragmentProcessor(clip.clipCoverageFragmentProcessor());
304 }
305
306 // set stencil settings for path
307 GrStencilSettings stencilSettings;
308 GrRenderTarget* rt = pipelineBuilder.getRenderTarget();
309 GrStencilAttachment* sb = fResourceProvider->attachStencilAttachment(rt);
310 this->getPathStencilSettingsForFilltype(fill, sb, &stencilSettings);
311
312 GrBatch* batch = GrStencilPathBatch::Create(viewMatrix,
313 pipelineBuilder.isHWAntialias(),
314 stencilSettings, clip.scissorState(),
315 pipelineBuilder.getRenderTarget(),
316 path);
317 this->recordBatch(batch);
318 batch->unref();
319 }
320
drawPathBatch(const GrPipelineBuilder & pipelineBuilder,GrDrawPathBatchBase * batch)321 void GrDrawTarget::drawPathBatch(const GrPipelineBuilder& pipelineBuilder,
322 GrDrawPathBatchBase* batch) {
323 // This looks like drawBatch() but there is an added wrinkle that stencil settings get inserted
324 // after setting up clipping but before onDrawBatch(). TODO: Figure out a better model for
325 // handling stencil settings WRT interactions between pipeline(builder), clipmaskmanager, and
326 // batches.
327 SkASSERT(this->caps()->shaderCaps()->pathRenderingSupport());
328
329 GrPipelineBuilder::AutoRestoreStencil ars;
330 GrAppliedClip clip;
331 if (!fClipMaskManager->setupClipping(pipelineBuilder, &ars, &batch->bounds(), &clip)) {
332 return;
333 }
334
335 GrPipelineBuilder::AutoRestoreFragmentProcessorState arfps;
336 if (clip.clipCoverageFragmentProcessor()) {
337 arfps.set(&pipelineBuilder);
338 arfps.addCoverageFragmentProcessor(clip.clipCoverageFragmentProcessor());
339 }
340
341 // Ensure the render target has a stencil buffer and get the stencil settings.
342 GrStencilSettings stencilSettings;
343 GrRenderTarget* rt = pipelineBuilder.getRenderTarget();
344 GrStencilAttachment* sb = fResourceProvider->attachStencilAttachment(rt);
345 this->getPathStencilSettingsForFilltype(batch->fillType(), sb, &stencilSettings);
346 batch->setStencilSettings(stencilSettings);
347
348 GrPipeline::CreateArgs args;
349 if (!this->installPipelineInDrawBatch(&pipelineBuilder, &clip.scissorState(), batch)) {
350 return;
351 }
352
353 this->recordBatch(batch);
354 }
355
clear(const SkIRect * rect,GrColor color,bool canIgnoreRect,GrRenderTarget * renderTarget)356 void GrDrawTarget::clear(const SkIRect* rect,
357 GrColor color,
358 bool canIgnoreRect,
359 GrRenderTarget* renderTarget) {
360 SkIRect rtRect = SkIRect::MakeWH(renderTarget->width(), renderTarget->height());
361 SkIRect clippedRect;
362 if (!rect ||
363 (canIgnoreRect && this->caps()->fullClearIsFree()) ||
364 rect->contains(rtRect)) {
365 rect = &rtRect;
366 } else {
367 clippedRect = *rect;
368 if (!clippedRect.intersect(rtRect)) {
369 return;
370 }
371 rect = &clippedRect;
372 }
373
374 if (this->caps()->useDrawInsteadOfClear()) {
375 // This works around a driver bug with clear by drawing a rect instead.
376 // The driver will ignore a clear if it is the only thing rendered to a
377 // target before the target is read.
378 if (rect == &rtRect) {
379 this->discard(renderTarget);
380 }
381
382 GrPipelineBuilder pipelineBuilder;
383 pipelineBuilder.setXPFactory(
384 GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref();
385 pipelineBuilder.setRenderTarget(renderTarget);
386
387 SkRect scalarRect = SkRect::Make(*rect);
388 SkAutoTUnref<GrDrawBatch> batch(
389 GrRectBatchFactory::CreateNonAAFill(color, SkMatrix::I(), scalarRect,
390 nullptr, nullptr));
391 this->drawBatch(pipelineBuilder, batch);
392 } else {
393 GrBatch* batch = new GrClearBatch(*rect, color, renderTarget);
394 this->recordBatch(batch);
395 batch->unref();
396 }
397 }
398
discard(GrRenderTarget * renderTarget)399 void GrDrawTarget::discard(GrRenderTarget* renderTarget) {
400 if (this->caps()->discardRenderTargetSupport()) {
401 GrBatch* batch = new GrDiscardBatch(renderTarget);
402 this->recordBatch(batch);
403 batch->unref();
404 }
405 }
406
407 ////////////////////////////////////////////////////////////////////////////////
408
copySurface(GrSurface * dst,GrSurface * src,const SkIRect & srcRect,const SkIPoint & dstPoint)409 bool GrDrawTarget::copySurface(GrSurface* dst,
410 GrSurface* src,
411 const SkIRect& srcRect,
412 const SkIPoint& dstPoint) {
413 GrBatch* batch = GrCopySurfaceBatch::Create(dst, src, srcRect, dstPoint);
414 if (!batch) {
415 return false;
416 }
417 #ifdef ENABLE_MDB
418 this->addDependency(src);
419 #endif
420
421 this->recordBatch(batch);
422 batch->unref();
423 return true;
424 }
425
intersect(const Left & a,const Right & b)426 template <class Left, class Right> static bool intersect(const Left& a, const Right& b) {
427 SkASSERT(a.fLeft <= a.fRight && a.fTop <= a.fBottom &&
428 b.fLeft <= b.fRight && b.fTop <= b.fBottom);
429 return a.fLeft < b.fRight && b.fLeft < a.fRight && a.fTop < b.fBottom && b.fTop < a.fBottom;
430 }
431
recordBatch(GrBatch * batch)432 void GrDrawTarget::recordBatch(GrBatch* batch) {
433 // A closed drawTarget should never receive new/more batches
434 SkASSERT(!this->isClosed());
435
436 // Check if there is a Batch Draw we can batch with by linearly searching back until we either
437 // 1) check every draw
438 // 2) intersect with something
439 // 3) find a 'blocker'
440 GR_AUDIT_TRAIL_ADDBATCH(fAuditTrail, batch->name(), batch->bounds());
441 GrBATCH_INFO("Re-Recording (%s, B%u)\n"
442 "\tBounds LRTB (%f, %f, %f, %f)\n",
443 batch->name(),
444 batch->uniqueID(),
445 batch->bounds().fLeft, batch->bounds().fRight,
446 batch->bounds().fTop, batch->bounds().fBottom);
447 GrBATCH_INFO(SkTabString(batch->dumpInfo(), 1).c_str());
448 GrBATCH_INFO("\tOutcome:\n");
449 int maxCandidates = SkTMin(fMaxBatchLookback, fBatches.count());
450 if (maxCandidates) {
451 int i = 0;
452 while (true) {
453 GrBatch* candidate = fBatches.fromBack(i);
454 // We cannot continue to search backwards if the render target changes
455 if (candidate->renderTargetUniqueID() != batch->renderTargetUniqueID()) {
456 GrBATCH_INFO("\t\tBreaking because of (%s, B%u) Rendertarget\n",
457 candidate->name(), candidate->uniqueID());
458 break;
459 }
460 if (candidate->combineIfPossible(batch, *this->caps())) {
461 GrBATCH_INFO("\t\tCombining with (%s, B%u)\n", candidate->name(),
462 candidate->uniqueID());
463 return;
464 }
465 // Stop going backwards if we would cause a painter's order violation.
466 // TODO: The bounds used here do not fully consider the clip. It may be advantageous
467 // to clip each batch's bounds to the clip.
468 if (intersect(candidate->bounds(), batch->bounds())) {
469 GrBATCH_INFO("\t\tIntersects with (%s, B%u)\n", candidate->name(),
470 candidate->uniqueID());
471 break;
472 }
473 ++i;
474 if (i == maxCandidates) {
475 GrBATCH_INFO("\t\tReached max lookback or beginning of batch array %d\n", i);
476 break;
477 }
478 }
479 } else {
480 GrBATCH_INFO("\t\tFirstBatch\n");
481 }
482 fBatches.push_back().reset(SkRef(batch));
483 }
484
485 ///////////////////////////////////////////////////////////////////////////////
486
installPipelineInDrawBatch(const GrPipelineBuilder * pipelineBuilder,const GrScissorState * scissor,GrDrawBatch * batch)487 bool GrDrawTarget::installPipelineInDrawBatch(const GrPipelineBuilder* pipelineBuilder,
488 const GrScissorState* scissor,
489 GrDrawBatch* batch) {
490 GrPipeline::CreateArgs args;
491 args.fPipelineBuilder = pipelineBuilder;
492 args.fCaps = this->caps();
493 args.fScissor = scissor;
494 batch->getPipelineOptimizations(&args.fOpts);
495 GrScissorState finalScissor;
496 if (args.fOpts.fOverrides.fUsePLSDstRead) {
497 GrRenderTarget* rt = pipelineBuilder->getRenderTarget();
498 GrGLIRect viewport;
499 viewport.fLeft = 0;
500 viewport.fBottom = 0;
501 viewport.fWidth = rt->width();
502 viewport.fHeight = rt->height();
503 SkIRect ibounds;
504 ibounds.fLeft = SkTPin(SkScalarFloorToInt(batch->bounds().fLeft), viewport.fLeft,
505 viewport.fWidth);
506 ibounds.fTop = SkTPin(SkScalarFloorToInt(batch->bounds().fTop), viewport.fBottom,
507 viewport.fHeight);
508 ibounds.fRight = SkTPin(SkScalarCeilToInt(batch->bounds().fRight), viewport.fLeft,
509 viewport.fWidth);
510 ibounds.fBottom = SkTPin(SkScalarCeilToInt(batch->bounds().fBottom), viewport.fBottom,
511 viewport.fHeight);
512 if (scissor != nullptr && scissor->enabled()) {
513 if (!ibounds.intersect(scissor->rect())) {
514 ibounds = scissor->rect();
515 }
516 }
517 finalScissor.set(ibounds);
518 args.fScissor = &finalScissor;
519 }
520 args.fOpts.fColorPOI.completeCalculations(pipelineBuilder->fColorFragmentProcessors.begin(),
521 pipelineBuilder->numColorFragmentProcessors());
522 args.fOpts.fCoveragePOI.completeCalculations(
523 pipelineBuilder->fCoverageFragmentProcessors.begin(),
524 pipelineBuilder->numCoverageFragmentProcessors());
525 if (!this->setupDstReadIfNecessary(*pipelineBuilder, args.fOpts, &args.fDstTexture,
526 batch->bounds())) {
527 return false;
528 }
529
530 if (!batch->installPipeline(args)) {
531 return false;
532 }
533
534 return true;
535 }
536
clearStencilClip(const SkIRect & rect,bool insideClip,GrRenderTarget * rt)537 void GrDrawTarget::clearStencilClip(const SkIRect& rect, bool insideClip, GrRenderTarget* rt) {
538 GrBatch* batch = new GrClearStencilClipBatch(rect, insideClip, rt);
539 this->recordBatch(batch);
540 batch->unref();
541 }
542