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.
38static const int kDefaultMaxBatchLookback = 10;
39
40GrDrawTarget::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
63GrDrawTarget::~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
74void 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
85void 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
103void 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
125bool 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(), &copyRect);
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
187void 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
200void 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
220void GrDrawTarget::reset() {
221    fBatches.reset();
222}
223
224void 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
250static 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
259static 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
268void 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
285void 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
321void 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
356void 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
399void 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
409bool 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
426template <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
432void 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
487bool 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
537void 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