void GrDrawTarget::stencilPath(const GrPipelineBuilder& pipelineBuilder, const SkMatrix& viewMatrix, const GrPath* path, GrPathRendering::FillType fill) { // TODO: extract portions of checkDraw that are relevant to path stenciling. SkASSERT(path); SkASSERT(this->caps()->shaderCaps()->pathRenderingSupport()); // Setup clip GrPipelineBuilder::AutoRestoreStencil ars; GrAppliedClip clip; if (!fClipMaskManager->setupClipping(pipelineBuilder, &ars, nullptr, &clip)) { return; } GrPipelineBuilder::AutoRestoreFragmentProcessorState arfps; if (clip.clipCoverageFragmentProcessor()) { arfps.set(&pipelineBuilder); arfps.addCoverageFragmentProcessor(clip.clipCoverageFragmentProcessor()); } // set stencil settings for path GrStencilSettings stencilSettings; GrRenderTarget* rt = pipelineBuilder.getRenderTarget(); GrStencilAttachment* sb = fResourceProvider->attachStencilAttachment(rt); this->getPathStencilSettingsForFilltype(fill, sb, &stencilSettings); GrBatch* batch = GrStencilPathBatch::Create(viewMatrix, pipelineBuilder.isHWAntialias(), stencilSettings, clip.scissorState(), pipelineBuilder.getRenderTarget(), path); this->recordBatch(batch); batch->unref(); }
void GrDrawTarget::discard(GrRenderTarget* renderTarget) { if (this->caps()->discardRenderTargetSupport()) { GrBatch* batch = new GrDiscardBatch(renderTarget); this->recordBatch(batch); batch->unref(); } }
void GrDrawTarget::copySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint) { GrBatch* batch = GrCopySurfaceBatch::Create(dst, src, srcRect, dstPoint); if (batch) { this->recordBatch(batch); batch->unref(); } }
void GrDrawTarget::recordBatch(GrBatch* batch) { // A closed drawTarget should never receive new/more batches SkASSERT(!this->isClosed()); // Check if there is a Batch Draw we can batch with by linearly searching back until we either // 1) check every draw // 2) intersect with something // 3) find a 'blocker' GR_AUDIT_TRAIL_ADDBATCH(fAuditTrail, batch); GrBATCH_INFO("Re-Recording (%s, B%u)\n" "\tBounds LRTB (%f, %f, %f, %f)\n", batch->name(), batch->uniqueID(), batch->bounds().fLeft, batch->bounds().fRight, batch->bounds().fTop, batch->bounds().fBottom); GrBATCH_INFO(SkTabString(batch->dumpInfo(), 1).c_str()); GrBATCH_INFO("\tOutcome:\n"); int maxCandidates = SkTMin(fMaxBatchLookback, fBatches.count()); if (maxCandidates) { int i = 0; while (true) { GrBatch* candidate = fBatches.fromBack(i); // We cannot continue to search backwards if the render target changes if (candidate->renderTargetUniqueID() != batch->renderTargetUniqueID()) { GrBATCH_INFO("\t\tBreaking because of (%s, B%u) Rendertarget\n", candidate->name(), candidate->uniqueID()); break; } if (candidate->combineIfPossible(batch, *this->caps())) { GrBATCH_INFO("\t\tCombining with (%s, B%u)\n", candidate->name(), candidate->uniqueID()); GR_AUDIT_TRAIL_BATCHING_RESULT_COMBINED(fAuditTrail, candidate, batch); return; } // Stop going backwards if we would cause a painter's order violation. // TODO: The bounds used here do not fully consider the clip. It may be advantageous // to clip each batch's bounds to the clip. if (intersect(candidate->bounds(), batch->bounds())) { GrBATCH_INFO("\t\tIntersects with (%s, B%u)\n", candidate->name(), candidate->uniqueID()); break; } ++i; if (i == maxCandidates) { GrBATCH_INFO("\t\tReached max lookback or beginning of batch array %d\n", i); break; } } } else { GrBATCH_INFO("\t\tFirstBatch\n"); } GR_AUDIT_TRAIL_BATCHING_RESULT_NEW(fAuditTrail, batch); fBatches.push_back().reset(SkRef(batch)); }
void GrDrawTarget::recordBatch(GrBatch* batch) { // Check if there is a Batch Draw we can batch with by linearly searching back until we either // 1) check every draw // 2) intersect with something // 3) find a 'blocker' // Experimentally we have found that most batching occurs within the first 10 comparisons. static const int kMaxLookback = 10; GrBATCH_INFO("Re-Recording (%s, B%u)\n" "\tBounds LRTB (%f, %f, %f, %f)\n", batch->name(), batch->uniqueID(), batch->bounds().fLeft, batch->bounds().fRight, batch->bounds().fTop, batch->bounds().fBottom); GrBATCH_INFO(SkTabString(batch->dumpInfo(), 1).c_str()); GrBATCH_INFO("\tOutcome:\n"); int maxCandidates = SkTMin(kMaxLookback, fBatches.count()); if (maxCandidates) { int i = 0; while (true) { GrBatch* candidate = fBatches.fromBack(i); // We cannot continue to search backwards if the render target changes if (candidate->renderTargetUniqueID() != batch->renderTargetUniqueID()) { GrBATCH_INFO("\t\tBreaking because of (%s, B%u) Rendertarget\n", candidate->name(), candidate->uniqueID()); break; } if (candidate->combineIfPossible(batch, *this->caps())) { GrBATCH_INFO("\t\tCombining with (%s, B%u)\n", candidate->name(), candidate->uniqueID()); return; } // Stop going backwards if we would cause a painter's order violation. if (intersect(candidate->bounds(), batch->bounds())) { GrBATCH_INFO("\t\tIntersects with (%s, B%u)\n", candidate->name(), candidate->uniqueID()); break; } ++i; if (i == maxCandidates) { GrBATCH_INFO("\t\tReached max lookback or beginning of batch array %d\n", i); break; } } } else { GrBATCH_INFO("\t\tFirstBatch\n"); } fBatches.push_back().reset(SkRef(batch)); if (fBatches.count() > kMaxLookback) { SkASSERT(fBatches.count() - kMaxLookback - fFirstUnpreparedBatch == 1); fBatches[fFirstUnpreparedBatch++]->prepare(&fFlushState); } }
void GrDrawTarget::recordBatch(GrBatch* batch, const SkRect& clippedBounds) { // A closed drawTarget should never receive new/more batches SkASSERT(!this->isClosed()); // Check if there is a Batch Draw we can batch with by linearly searching back until we either // 1) check every draw // 2) intersect with something // 3) find a 'blocker' GR_AUDIT_TRAIL_ADDBATCH(fAuditTrail, batch); GrBATCH_INFO("Re-Recording (%s, B%u)\n" "\tBounds LRTB (%f, %f, %f, %f)\n", batch->name(), batch->uniqueID(), batch->bounds().fLeft, batch->bounds().fRight, batch->bounds().fTop, batch->bounds().fBottom); GrBATCH_INFO(SkTabString(batch->dumpInfo(), 1).c_str()); GrBATCH_INFO("\tClipped Bounds: [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", clippedBounds.fLeft, clippedBounds.fTop, clippedBounds.fRight, clippedBounds.fBottom); GrBATCH_INFO("\tOutcome:\n"); int maxCandidates = SkTMin(fMaxBatchLookback, fRecordedBatches.count()); if (maxCandidates) { int i = 0; while (true) { GrBatch* candidate = fRecordedBatches.fromBack(i).fBatch.get(); // We cannot continue to search backwards if the render target changes if (candidate->renderTargetUniqueID() != batch->renderTargetUniqueID()) { GrBATCH_INFO("\t\tBreaking because of (%s, B%u) Rendertarget\n", candidate->name(), candidate->uniqueID()); break; } if (candidate->combineIfPossible(batch, *this->caps())) { GrBATCH_INFO("\t\tCombining with (%s, B%u)\n", candidate->name(), candidate->uniqueID()); GR_AUDIT_TRAIL_BATCHING_RESULT_COMBINED(fAuditTrail, candidate, batch); join(&fRecordedBatches.fromBack(i).fClippedBounds, fRecordedBatches.fromBack(i).fClippedBounds, clippedBounds); return; } // Stop going backwards if we would cause a painter's order violation. const SkRect& candidateBounds = fRecordedBatches.fromBack(i).fClippedBounds; if (!can_reorder(candidateBounds, clippedBounds)) { GrBATCH_INFO("\t\tIntersects with (%s, B%u)\n", candidate->name(), candidate->uniqueID()); break; } ++i; if (i == maxCandidates) { GrBATCH_INFO("\t\tReached max lookback or beginning of batch array %d\n", i); break; } } } else { GrBATCH_INFO("\t\tFirstBatch\n"); } GR_AUDIT_TRAIL_BATCHING_RESULT_NEW(fAuditTrail, batch); fRecordedBatches.emplace_back(RecordedBatch{sk_ref_sp(batch), clippedBounds}); }
void GrDrawTarget::copySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint) { GrBatch* batch = GrCopySurfaceBatch::Create(dst, src, srcRect, dstPoint); if (batch) { #ifdef ENABLE_MDB this->addDependency(src); #endif this->recordBatch(batch); batch->unref(); } }
bool GrDrawTarget::copySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint) { GrBatch* batch = GrCopySurfaceBatch::Create(dst, src, srcRect, dstPoint); if (!batch) { return false; } #ifdef ENABLE_MDB this->addDependency(src); #endif this->recordBatch(batch, batch->bounds()); batch->unref(); return true; }
void GrDrawTarget::clear(const SkIRect* rect, GrColor color, bool canIgnoreRect, GrRenderTarget* renderTarget) { SkIRect rtRect = SkIRect::MakeWH(renderTarget->width(), renderTarget->height()); SkIRect clippedRect; if (!rect || (canIgnoreRect && this->caps()->fullClearIsFree()) || rect->contains(rtRect)) { rect = &rtRect; } else { clippedRect = *rect; if (!clippedRect.intersect(rtRect)) { return; } rect = &clippedRect; } if (this->caps()->useDrawInsteadOfClear()) { // This works around a driver bug with clear by drawing a rect instead. // The driver will ignore a clear if it is the only thing rendered to a // target before the target is read. if (rect == &rtRect) { this->discard(renderTarget); } GrPipelineBuilder pipelineBuilder; pipelineBuilder.setXPFactory( GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref(); pipelineBuilder.setRenderTarget(renderTarget); SkRect scalarRect = SkRect::Make(*rect); SkAutoTUnref<GrDrawBatch> batch( GrRectBatchFactory::CreateNonAAFill(color, SkMatrix::I(), scalarRect, nullptr, nullptr)); this->drawBatch(pipelineBuilder, batch); } else { GrBatch* batch = new GrClearBatch(*rect, color, renderTarget); this->recordBatch(batch); batch->unref(); } }
void GrDrawTarget::stencilPath(const GrPipelineBuilder& pipelineBuilder, GrDrawContext* drawContext, const GrClip& clip, const SkMatrix& viewMatrix, const GrPath* path, GrPathRendering::FillType fill) { // TODO: extract portions of checkDraw that are relevant to path stenciling. SkASSERT(path); SkASSERT(this->caps()->shaderCaps()->pathRenderingSupport()); // Setup clip GrAppliedClip appliedClip; if (!clip.apply(fContext, pipelineBuilder, drawContext, nullptr, &appliedClip)) { return; } // TODO: respect fClipBatchToBounds if we ever start computing bounds here. // Coverage AA does not make sense when rendering to the stencil buffer. The caller should never // attempt this in a situation that would require coverage AA. SkASSERT(!appliedClip.getClipCoverageFragmentProcessor()); GrStencilAttachment* stencilAttachment = fResourceProvider->attachStencilAttachment( drawContext->accessRenderTarget()); if (!stencilAttachment) { SkDebugf("ERROR creating stencil attachment. Draw skipped.\n"); return; } GrBatch* batch = GrStencilPathBatch::Create(viewMatrix, pipelineBuilder.isHWAntialias(), fill, appliedClip.hasStencilClip(), stencilAttachment->bits(), appliedClip.scissorState(), drawContext->accessRenderTarget(), path); this->recordBatch(batch); batch->unref(); }
void GrDrawTarget::clearStencilClip(const SkIRect& rect, bool insideClip, GrRenderTarget* rt) { GrBatch* batch = new GrClearStencilClipBatch(rect, insideClip, rt); this->recordBatch(batch); batch->unref(); }
void GrDrawTarget::forwardCombine() { for (int i = 0; i < fBatches.count() - 2; ++i) { GrBatch* batch = fBatches[i]; int maxCandidateIdx = SkTMin(i + fMaxBatchLookahead, fBatches.count() - 1); int j = i + 1; while (true) { GrBatch* candidate = fBatches[j]; // We cannot continue to search if the render target changes if (candidate->renderTargetUniqueID() != batch->renderTargetUniqueID()) { GrBATCH_INFO("\t\tBreaking because of (%s, B%u) Rendertarget\n", candidate->name(), candidate->uniqueID()); break; } if (j == i +1) { // We assume batch would have combined with candidate when the candidate was added // via backwards combining in recordBatch. SkASSERT(!batch->combineIfPossible(candidate, *this->caps())); } else if (batch->combineIfPossible(candidate, *this->caps())) { GrBATCH_INFO("\t\tCombining with (%s, B%u)\n", candidate->name(), candidate->uniqueID()); GR_AUDIT_TRAIL_BATCHING_RESULT_COMBINED(fAuditTrail, batch, candidate); fBatches[j].reset(SkRef(batch)); fBatches[i].reset(nullptr); break; } // Stop going traversing if we would cause a painter's order violation. // TODO: The bounds used here do not fully consider the clip. It may be advantageous // to clip each batch's bounds to the clip. if (intersect(candidate->bounds(), batch->bounds())) { GrBATCH_INFO("\t\tIntersects with (%s, B%u)\n", candidate->name(), candidate->uniqueID()); break; } ++j; if (j > maxCandidateIdx) { GrBATCH_INFO("\t\tReached max lookahead or end of batch array %d\n", i); break; } } } }
void GrDrawTarget::forwardCombine() { for (int i = 0; i < fRecordedBatches.count() - 2; ++i) { GrBatch* batch = fRecordedBatches[i].fBatch.get(); const SkRect& batchBounds = fRecordedBatches[i].fClippedBounds; int maxCandidateIdx = SkTMin(i + fMaxBatchLookahead, fRecordedBatches.count() - 1); int j = i + 1; while (true) { GrBatch* candidate = fRecordedBatches[j].fBatch.get(); // We cannot continue to search if the render target changes if (candidate->renderTargetUniqueID() != batch->renderTargetUniqueID()) { GrBATCH_INFO("\t\tBreaking because of (%s, B%u) Rendertarget\n", candidate->name(), candidate->uniqueID()); break; } if (j == i +1) { // We assume batch would have combined with candidate when the candidate was added // via backwards combining in recordBatch. SkASSERT(!batch->combineIfPossible(candidate, *this->caps())); } else if (batch->combineIfPossible(candidate, *this->caps())) { GrBATCH_INFO("\t\tCombining with (%s, B%u)\n", candidate->name(), candidate->uniqueID()); GR_AUDIT_TRAIL_BATCHING_RESULT_COMBINED(fAuditTrail, batch, candidate); fRecordedBatches[j].fBatch = std::move(fRecordedBatches[i].fBatch); join(&fRecordedBatches[j].fClippedBounds, fRecordedBatches[j].fClippedBounds, batchBounds); break; } // Stop going traversing if we would cause a painter's order violation. const SkRect& candidateBounds = fRecordedBatches[j].fClippedBounds; if (!can_reorder(candidateBounds, batchBounds)) { GrBATCH_INFO("\t\tIntersects with (%s, B%u)\n", candidate->name(), candidate->uniqueID()); break; } ++j; if (j > maxCandidateIdx) { GrBATCH_INFO("\t\tReached max lookahead or end of batch array %d\n", i); break; } } } }