36static const int kMaxOpMergeDistance = 10;
37static const int kMaxOpChainDistance = 10;
50 const std::array<float, 4>& loadClearColor,
72 stencilLoadAndStoreInfo, sampledProxies, renderPassXferBarriers);
82 : fHead(
std::move(op)), fTail(fHead.
get()) {
89 fHead = std::move(that.fHead);
96inline GrOp::Owner OpsTask::OpChain::List::popHead() {
98 auto temp = fHead->cutChain();
110 while (
head->prevInChain()) {
head =
head->prevInChain(); }
116 return this->popHead();
118 auto temp =
prev->cutChain();
119 if (
auto next = temp->cutChain()) {
129inline void OpsTask::OpChain::List::pushHead(
GrOp::Owner op) {
134 op->chainConcat(std::move(fHead));
135 fHead = std::move(op);
137 fHead = std::move(op);
142inline void OpsTask::OpChain::List::pushTail(
GrOp::Owner op) {
144 fTail->chainConcat(std::move(op));
145 fTail = fTail->nextInChain();
148inline void OpsTask::OpChain::List::validate()
const {
152 fHead->validateChain(fTail);
161 : fList{
std::move(op)}
162 , fProcessorAnalysis(processorAnalysis)
163 , fAppliedClip(appliedClip) {
164 if (fProcessorAnalysis.requiresDstTexture()) {
166 fDstProxyView = *dstProxyView;
168 fBounds = fList.head()->bounds();
176 op.visitProxies(func);
178 if (fDstProxyView.proxy()) {
182 fAppliedClip->visitProxies(func);
186void OpsTask::OpChain::deleteOps() {
187 while (!fList.empty()) {
208 GrOp* origATail = chainA.tail();
211 int numMergeChecks = 0;
213 bool noSkip = (origATail == chainA.tail());
215 bool canBackwardMerge = noSkip || can_reorder(chainB.head()->bounds(), skipBounds);
216 SkRect forwardMergeBounds = skipBounds;
219 bool canForwardMerge =
220 (
a == chainA.tail()) || can_reorder(
a->bounds(), forwardMergeBounds);
221 if (canForwardMerge || canBackwardMerge) {
222 auto result =
a->combineIfPossible(chainB.head(), opsTaskArena, caps);
225 GrOP_INFO(
"\t\t: (%s opID: %u) -> Combining with (%s, opID: %u)\n",
226 chainB.head()->name(), chainB.head()->uniqueID(),
a->name(),
231 if (canBackwardMerge) {
238 if (
a == origATail) {
239 origATail =
a->prevInChain();
244 chainB.pushHead(std::move(detachedA));
245 if (chainA.empty()) {
252 if (++numMergeChecks == kMaxOpMergeDistance) {
257 canBackwardMerge && can_reorder(chainB.head()->bounds(),
a->bounds());
258 a =
a->prevInChain();
264 chainA.pushTail(chainB.popHead());
267 }
while (!chainB.empty());
273bool OpsTask::OpChain::tryConcat(
279 SkASSERT(fProcessorAnalysis.requiresDstTexture() ==
SkToBool(fDstProxyView.proxy()));
282 if (fList.head()->classID() != list->head()->classID() ||
284 (fAppliedClip && *fAppliedClip != *appliedClip) ||
285 (fProcessorAnalysis.requiresNonOverlappingDraws() !=
287 (fProcessorAnalysis.requiresNonOverlappingDraws() &&
292 (fProcessorAnalysis.requiresDstTexture() != processorAnalysis.
requiresDstTexture()) ||
293 (fProcessorAnalysis.requiresDstTexture() && fDstProxyView != dstProxyView)) {
299 switch (fList.tail()->combineIfPossible(list->head(), opsTaskArena, caps))
309 fList = DoConcat(std::move(fList), std::exchange(*list,
List()), caps, opsTaskArena,
316 GrOP_INFO(
"\t\t: (%s opID: %u) -> Combining with (%s, opID: %u)\n",
317 list->tail()->name(), list->tail()->uniqueID(), list->head()->name(),
318 list->head()->uniqueID());
326 }
while (!list->empty());
333bool OpsTask::OpChain::prependChain(OpChain* that,
const GrCaps& caps,
SkArenaAlloc* opsTaskArena,
335 if (!that->tryConcat(&fList, fProcessorAnalysis, fDstProxyView, fAppliedClip,
fBounds, caps,
336 opsTaskArena, auditTrail)) {
344 fList = std::move(that->fList);
347 that->fDstProxyView.setProxyView({});
348 if (that->fAppliedClip && that->fAppliedClip->hasCoverageFragmentProcessor()) {
350 that->fAppliedClip->detachCoverageFragmentProcessor();
362 dstProxyView = &noDstProxyView;
364 SkASSERT(op->isChainHead() && op->isChainTail());
365 SkRect opBounds = op->bounds();
366 List chain(std::move(op));
367 if (!this->tryConcat(&chain, processorAnalysis, *dstProxyView, appliedClip, opBounds, caps,
368 opsTaskArena, auditTrail)) {
371 return chain.popHead();
379inline void OpsTask::OpChain::validate()
const {
397 , fAuditTrail(auditTrail)
398 , fUsesMSAASurface(view.asRenderTargetProxy()->numSamples() > 1)
399 , fTargetSwizzle(view.swizzle())
400 , fTargetOrigin(view.origin())
401 , fArenas{
std::move(arenas)}
406void OpsTask::deleteOps() {
407 for (
auto& chain : fOpChains) {
420 this->
addDependency(drawingMgr,
p, mipmapped, textureResolveManager, caps);
435 this->
addDependency(drawingMgr,
p, mipmapped, textureResolveManager, caps);
440 if (dstProxyView.
proxy()) {
456 this->
recordOp(std::move(op), usesMSAA, processorAnalysis,
clip.doesClip() ? &
clip :
nullptr,
457 &dstProxyView, caps);
465 fSampledProxies.clear();
466 fAuditTrail =
nullptr;
477 if (this->isColorNoOp() ||
484 for (
const auto& chain : fOpChains) {
485 if (chain.shouldExecute()) {
486 chain.head()->prePrepare(context,
489 chain.dstProxyView(),
490 fRenderPassXferBarriers,
503 if (this->isColorNoOp() ||
512 for (
const auto& chain : fOpChains) {
513 if (chain.shouldExecute()) {
518 chain.dstProxyView(),
519 fRenderPassXferBarriers,
530 chain.head()->prepare(flushState);
546 if (this->isColorNoOp() || fClippedContentBounds.
isEmpty()) {
564 SkDebugf(
"WARNING: failed to attach a stencil buffer. Rendering will be skipped.\n");
571 switch (fInitialStencilContent) {
617 fClippedContentBounds,
623 fRenderPassXferBarriers);
634 for (
const auto& chain : fOpChains) {
635 if (!chain.shouldExecute()) {
643 chain.dstProxyView(),
644 fRenderPassXferBarriers,
648 chain.head()->execute(flushState, chain.bounds());
661 fLoadClearColor =
color;
669void OpsTask::reset() {
671 fSampledProxies.clear();
680 fArenas == opsTask->fArenas &&
681 !opsTask->fCannotMergeBackward;
687 auto opsTask = task->asOpsTask();
688 if (!opsTask || !this->
canMerge(opsTask)) {
691 SkASSERT(fTargetSwizzle == opsTask->fTargetSwizzle);
692 SkASSERT(fTargetOrigin == opsTask->fTargetOrigin);
700 if (0 == mergedCount) {
706 int addlDeferredProxyCount = 0;
707 int addlProxyCount = 0;
708 int addlOpChainCount = 0;
709 for (
const auto& toMerge : mergingNodes) {
710 addlDeferredProxyCount += toMerge->fDeferredProxies.size();
711 addlProxyCount += toMerge->fSampledProxies.size();
712 addlOpChainCount += toMerge->fOpChains.size();
713 fClippedContentBounds.
join(toMerge->fClippedContentBounds);
714 fTotalBounds.
join(toMerge->fTotalBounds);
715 fRenderPassXferBarriers |= toMerge->fRenderPassXferBarriers;
726 fInitialStencilContent = toMerge->fInitialStencilContent;
728 fUsesMSAASurface |= toMerge->fUsesMSAASurface;
734 fSampledProxies.reserve_exact(fSampledProxies.size() + addlProxyCount);
735 fOpChains.reserve_exact(fOpChains.size() + addlOpChainCount);
736 for (
const auto& toMerge : mergingNodes) {
738 renderTask->replaceDependency(toMerge.get(),
this);
741 renderTask->replaceDependent(toMerge.get(),
this);
744 toMerge->fDeferredProxies.data());
745 fSampledProxies.move_back_n(toMerge->fSampledProxies.size(),
746 toMerge->fSampledProxies.data());
747 fOpChains.move_back_n(toMerge->fOpChains.size(),
748 toMerge->fOpChains.data());
749 toMerge->fDeferredProxies.clear();
750 toMerge->fSampledProxies.clear();
751 toMerge->fOpChains.clear();
753 fMustPreserveStencil = mergingNodes.
back()->fMustPreserveStencil;
761 fSampledProxies.clear();
785#if defined(GR_TEST_UTILS)
788 bool printDependencies,
793 switch (fColorLoadOp) {
798 SkDebugf(
"kClear {%g, %g, %g, %g}\n",
810 switch (fInitialStencilContent) {
823 for (
int i = 0;
i < fOpChains.size(); ++
i) {
824 SkDebugf(
"%s*******************************\n", indent.
c_str());
825 if (!fOpChains[
i].
head()) {
826 SkDebugf(
"%s%d: <combined forward or failed instantiation>\n", indent.
c_str(),
i);
828 SkDebugf(
"%s%d: %s\n", indent.
c_str(),
i, fOpChains[
i].head()->name());
830 SkDebugf(
"%sClippedBounds: [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n",
837 SkDebugf(
"%s\tClippedBounds: [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n",
845 SkDebugf(
"%s--------------------------------------------------------------\n\n",
854 func(tex, mipmapped);
857 for (
const OpChain& chain : fOpChains) {
858 chain.visitProxies(textureFunc);
866void OpsTask::onMakeSkippable() {
876 if (proxy == proxyToCheck) {
882 bool usedSlow =
false;
884 if (
p == proxyToCheck) {
888 this->visitProxies_debugOnly(visit);
897 if (this->isColorNoOp()) {
917 if (!fOpChains.empty()) {
918 unsigned int cur = alloc->
curOp();
920 alloc->
addInterval(targetProxy, cur, cur + fOpChains.size() - 1,
946 for (
const OpChain& recordedOp : fOpChains) {
947 recordedOp.visitProxies(
gather);
971 if (!op->bounds().isFinite()) {
975 fUsesMSAASurface |= usesMSAA;
979 fTotalBounds.
join(op->bounds());
986 GrOP_INFO(
"opsTask: %d Recording (%s, opID: %u)\n"
987 "\tBounds [L: %.2f, T: %.2f R: %.2f B: %.2f]\n",
991 op->bounds().fLeft, op->bounds().fTop,
992 op->bounds().fRight, op->bounds().fBottom);
995 int maxCandidates =
std::min(kMaxOpChainDistance, fOpChains.size());
999 OpChain& candidate = fOpChains.fromBack(
i);
1000 op = candidate.appendOp(std::move(op), processorAnalysis, dstProxyView,
clip, caps,
1006 if (!can_reorder(candidate.bounds(), op->bounds())) {
1007 GrOP_INFO(
"\t\tBackward: Intersects with chain (%s, head opID: %u)\n",
1008 candidate.head()->name(), candidate.head()->uniqueID());
1011 if (++
i == maxCandidates) {
1012 GrOP_INFO(
"\t\tBackward: Reached max lookback or beginning of op array %d\n",
i);
1023 fOpChains.emplace_back(std::move(op), processorAnalysis,
clip, dstProxyView);
1026void OpsTask::forwardCombine(
const GrCaps& caps) {
1028 GrOP_INFO(
"opsTask: %d ForwardCombine %d ops:\n", this->
uniqueID(), fOpChains.size());
1030 for (
int i = 0;
i < fOpChains.size() - 1; ++
i) {
1031 OpChain& chain = fOpChains[
i];
1032 int maxCandidateIdx =
std::min(
i + kMaxOpChainDistance, fOpChains.size() - 1);
1035 OpChain& candidate = fOpChains[j];
1036 if (candidate.prependChain(&chain, caps, fArenas->
arenaAlloc(), fAuditTrail)) {
1040 if (!can_reorder(chain.bounds(), candidate.bounds())) {
1042 "\t\t%d: chain (%s head opID: %u) -> "
1043 "Intersects with chain (%s, head opID: %u)\n",
1044 i, chain.head()->name(), chain.head()->uniqueID(), candidate.head()->name(),
1045 candidate.head()->uniqueID());
1048 if (++j > maxCandidateIdx) {
1049 GrOP_INFO(
"\t\t%d: chain (%s opID: %u) -> Reached max lookahead or end of array\n",
1050 i, chain.head()->name(), chain.head()->uniqueID());
1058 SkIRect* targetUpdateBounds) {
1059 this->forwardCombine(*rContext->
priv().
caps());
1060 if (!this->isColorNoOp()) {
1067 if (clippedContentBounds.
intersect(fTotalBounds)) {
1068 clippedContentBounds.
roundOut(&fClippedContentBounds);
1072 fClippedContentBounds);
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
#define GR_AUDIT_TRAIL_OPS_RESULT_COMBINED(audit_trail, combineWith, op)
#define GR_AUDIT_TRAIL_ADD_OP(audit_trail, op, proxy_id)
static bool GrRectsOverlap(const SkRect &a, const SkRect &b)
static bool GrRectsTouchOrOverlap(const SkRect &a, const SkRect &b)
std::function< void(GrSurfaceProxy *, skgpu::Mipmapped)> GrVisitProxyFunc
@ kRequiresTextureBarrier
static float next(float f)
static float prev(float f)
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
SkIDChangeListener::List List
static SkPath clip(const SkPath &path, const SkHalfPlane &plane)
sk_sp< T > sk_ref_sp(T *obj)
void swap(sk_sp< T > &a, sk_sp< T > &b)
#define SK_AT_SCOPE_EXIT(stmt)
SkString SkTabString(const SkString &string, int tabCnt)
SkDEBUGCODE(SK_SPI) SkThreadID SkGetThreadID()
constexpr size_t SkToSizeT(S x)
static constexpr bool SkToBool(const T &x)
#define TRACE_EVENT0_ALWAYS(category_group, name)
static constexpr uint32_t SK_InvalidUniqueID
static void dump(const float m[20], SkYUVColorSpace cs, bool rgb2yuv)
SkArenaAlloc * arenaAlloc()
bool hasPerformedInitialClear() const
void markHasPerformedInitialClear()
const GrCaps * caps() const
bool discardStencilValuesAfterRenderPass() const
bool supportsDynamicMSAA(const GrRenderTargetProxy *) const
bool performColorClearsAsDraws() const
bool performStencilClearsAsDraws() const
GrDstSampleFlags dstSampleFlags() const
const SkIPoint & offset() const
GrSurfaceProxy * proxy() const
const GrCaps * caps() const
virtual void submit(GrOpsRenderPass *)=0
GrOpsRenderPass * getOpsRenderPass(GrRenderTarget *renderTarget, bool useMSAASurface, GrAttachment *stencil, GrSurfaceOrigin, const SkIRect &bounds, const GrOpsRenderPass::LoadAndStoreInfo &, const GrOpsRenderPass::StencilLoadAndStoreInfo &, const skia_private::TArray< GrSurfaceProxy *, true > &sampledProxies, GrXferBarrierFlags renderPassXferBarriers)
void setOpArgs(OpArgs *opArgs)
void setOpsRenderPass(GrOpsRenderPass *renderPass)
void setSampledProxyArray(skia_private::TArray< GrSurfaceProxy *, true > *sampledProxies)
GrResourceProvider * resourceProvider() const final
GrOp * prevInChain() const
std::unique_ptr< GrOp > Owner
bool requiresNonOverlappingDraws() const
bool usesNonCoherentHWBlending() const
bool requiresDstTexture() const
static constexpr Analysis EmptySetAnalysis()
GrRecordingContextPriv priv()
bool wrapsVkSecondaryCB() const
bool canUseStencil(const GrCaps &caps) const
GrAttachment * getStencilAttachment(bool useMSAASurface) const
GrSurfaceProxy * target(int i) const
SkSpan< GrRenderTask * > dependencies()
bool isInstantiated() const
void addDependency(GrDrawingManager *, GrSurfaceProxy *dependedOn, skgpu::Mipmapped, GrTextureResolveManager, const GrCaps &caps)
void addTarget(GrDrawingManager *dm, const GrSurfaceProxyView &view)
SkDEBUGCODE(~GrRenderTask() override;) void makeClosed(GrRecordingContext *)
SkSpan< GrRenderTask * > dependents()
virtual void endFlush(GrDrawingManager *)
skia_private::TArray< GrTextureProxy *, true > fDeferredProxies
uint32_t uniqueID() const
void addInterval(GrSurfaceProxy *, unsigned int start, unsigned int end, ActualUse actualUse, AllowRecycling SkDEBUGCODE(, bool isDirectDstRead=false))
unsigned int curOp() const
bool attachStencilAttachment(GrRenderTarget *rt, bool useMSAASurface)
sk_sp< GrSurfaceProxy > detachProxy()
virtual GrRenderTargetProxy * asRenderTargetProxy()
SkRect backingStoreBoundsRect() const
UniqueID uniqueID() const
GrRenderTarget * peekRenderTarget() const
auto make(Ctor &&ctor) -> decltype(ctor(nullptr))
static constexpr SkRect MakeLargestInverted()
constexpr T & back() const
const char * c_str() const
void onPrepare(GrOpFlushState *flushState) override
void recordOp(GrOp::Owner, bool usesMSAA, GrProcessorSet::Analysis, GrAppliedClip *, const GrDstProxyView *, const GrCaps &)
void setColorLoadOp(GrLoadOp op, std::array< float, 4 > color={0, 0, 0, 0})
bool canMerge(const OpsTask *) const
int mergeFrom(SkSpan< const sk_sp< GrRenderTask > > tasks)
bool resetForFullscreenClear(CanDiscardPreviousOps)
bool onExecute(GrOpFlushState *flushState) override
void onPrePrepare(GrRecordingContext *) override
void endFlush(GrDrawingManager *) override
void addOp(GrDrawingManager *, GrOp::Owner, GrTextureResolveManager, const GrCaps &)
ExpectedOutcome onMakeClosed(GrRecordingContext *, SkIRect *targetUpdateBounds) override
void addDrawOp(GrDrawingManager *, GrOp::Owner, bool usesMSAA, const GrProcessorSet::Analysis &, GrAppliedClip &&, const GrDstProxyView &, GrTextureResolveManager, const GrCaps &)
void addSampledTexture(GrSurfaceProxy *proxy)
T * move_back_n(int n, T *t)
void reserve_exact(int n)
static float min(float r, float g, float b)
SI T gather(const T *p, U32 ix)
Optional< SkRect > bounds
const myers::Point & get(const myers::Segment &)
static SkIRect MakeIRectRelativeTo(GrSurfaceOrigin origin, int rtHeight, SkIRect devRect)
void join(const SkIRect &r)
static constexpr SkIRect MakeEmpty()
static constexpr SkRect MakeEmpty()
SkScalar fBottom
larger y-axis bounds
void joinNonEmptyArg(const SkRect &r)
void joinPossiblyEmptyRect(const SkRect &r)
bool intersect(const SkRect &r)
SkScalar fLeft
smaller x-axis bounds
SkScalar fRight
larger x-axis bounds
void roundOut(SkIRect *dst) const
void join(const SkRect &r)
SkScalar fTop
smaller y-axis bounds
#define TRACE_EVENT0(category_group, name)