Merge adjacent GrOpsTasks with same target together
This allows the ops tasks to make one render pass instead of multiple. The only case where this merging is needed is as a result of reordering (reduceOpsTaskSplitting). Bug: skia:10877 Change-Id: Ia967ead6efc43f7d2c1da58f770d3987da690cda Reviewed-on: https://skia-review.googlesource.com/c/skia/+/353656 Reviewed-by: Robert Phillips <robertphillips@google.com> Commit-Queue: Adlai Holler <adlai@google.com>
This commit is contained in:
parent
eeeaae9a02
commit
3b5b7d1178
@ -424,17 +424,20 @@ void GrDrawingManager::sortTasks() {
|
||||
}
|
||||
|
||||
// Reorder the array to match the llist without reffing & unreffing sk_sp's.
|
||||
// Both args must contain the same objects.
|
||||
// The llist must contain a subset of the entries in the array.
|
||||
// This is basically a shim because clustering uses LList but the rest of drawmgr uses array.
|
||||
// Pointers in the array are not dereferenced.
|
||||
template <typename T>
|
||||
static void reorder_array_by_llist(const SkTInternalLList<T>& llist, SkTArray<sk_sp<T>>* array) {
|
||||
for (sk_sp<T>& t : *array) {
|
||||
[[maybe_unused]] T* old = t.release();
|
||||
}
|
||||
int i = 0;
|
||||
for (T* t : llist) {
|
||||
// Release the pointer that used to live here so it doesn't get unreffed.
|
||||
[[maybe_unused]] T* old = array->at(i).release();
|
||||
array->at(i++).reset(t);
|
||||
}
|
||||
SkASSERT(i == array->count());
|
||||
SkASSERT(i <= array->count());
|
||||
array->resize_back(i);
|
||||
}
|
||||
|
||||
void GrDrawingManager::reorderTasks() {
|
||||
@ -446,6 +449,30 @@ void GrDrawingManager::reorderTasks() {
|
||||
}
|
||||
// TODO: Handle case where proposed order would blow our memory budget.
|
||||
// Such cases are currently pathological, so we could just return here and keep current order.
|
||||
|
||||
// Merge adjacent ops tasks. Note: We remove (future) tasks from the list during iteration.
|
||||
// This works out, however, because when we access the next element in llist it will be valid.
|
||||
for (auto task : llist) {
|
||||
auto opsTask = task->asOpsTask();
|
||||
if (!opsTask) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int removedCount = opsTask->mergeFromLList();
|
||||
auto removedTask = opsTask->fNext;
|
||||
for (int i = 0; i < removedCount; i++) {
|
||||
auto next = removedTask->fNext;
|
||||
llist.remove(removedTask);
|
||||
|
||||
// After this unref, there will be a dangling sk_sp to this task in fDAG somewhere.
|
||||
// That dangling pointer will be removed in reorder_array_by_llist.
|
||||
removedTask->disown(this);
|
||||
removedTask->unref();
|
||||
|
||||
removedTask = next;
|
||||
}
|
||||
}
|
||||
|
||||
reorder_array_by_llist(llist, &fDAG);
|
||||
}
|
||||
|
||||
|
@ -429,7 +429,7 @@ void GrOpsTask::addDrawOp(GrDrawingManager* drawingMgr, GrOp::Owner op,
|
||||
void GrOpsTask::endFlush(GrDrawingManager* drawingMgr) {
|
||||
fLastClipStackGenID = SK_InvalidUniqueID;
|
||||
this->deleteOps();
|
||||
fClipAllocator.reset();
|
||||
fClipAllocators.reset();
|
||||
|
||||
fDeferredProxies.reset();
|
||||
fSampledProxies.reset();
|
||||
@ -677,6 +677,50 @@ void GrOpsTask::setColorLoadOp(GrLoadOp op, std::array<float, 4> color) {
|
||||
}
|
||||
}
|
||||
|
||||
int GrOpsTask::mergeFromLList() {
|
||||
GrOpsTask* last = this;
|
||||
int addlProxyCount = 0;
|
||||
int addlOpChainCount = 0;
|
||||
int mergedCount = 0;
|
||||
for (GrRenderTask* task = fNext; task; task = task->fNext) {
|
||||
auto opsTask = task->asOpsTask();
|
||||
if (!opsTask || opsTask->target(0) != this->target(0)) {
|
||||
break;
|
||||
}
|
||||
SkASSERT(fTargetSwizzle == opsTask->fTargetSwizzle);
|
||||
SkASSERT(fTargetOrigin == opsTask->fTargetOrigin);
|
||||
mergedCount += 1;
|
||||
addlProxyCount += opsTask->fSampledProxies.count();
|
||||
addlOpChainCount += opsTask->fOpChains.count();
|
||||
fClippedContentBounds.join(opsTask->fClippedContentBounds);
|
||||
fTotalBounds.join(opsTask->fTotalBounds);
|
||||
fRenderPassXferBarriers |= opsTask->fRenderPassXferBarriers;
|
||||
SkDEBUGCODE(fNumClips += opsTask->fNumClips);
|
||||
last = opsTask;
|
||||
}
|
||||
if (last == this) {
|
||||
return 0;
|
||||
}
|
||||
fLastClipStackGenID = SK_InvalidUniqueID;
|
||||
fSampledProxies.reserve_back(addlProxyCount);
|
||||
fOpChains.reserve_back(addlOpChainCount);
|
||||
fClipAllocators.reserve_back(mergedCount);
|
||||
for (auto task = fNext; task != last->fNext; task = task->fNext) {
|
||||
auto opsTask = reinterpret_cast<GrOpsTask*>(task);
|
||||
fSampledProxies.move_back_n(opsTask->fSampledProxies.count(),
|
||||
opsTask->fSampledProxies.data());
|
||||
fOpChains.move_back_n(opsTask->fOpChains.count(),
|
||||
opsTask->fOpChains.data());
|
||||
SkASSERT(1 == opsTask->fClipAllocators.count());
|
||||
fClipAllocators.push_back(std::move(opsTask->fClipAllocators[0]));
|
||||
opsTask->fClipAllocators.reset();
|
||||
opsTask->fSampledProxies.reset();
|
||||
opsTask->fOpChains.reset();
|
||||
}
|
||||
fMustPreserveStencil = last->fMustPreserveStencil;
|
||||
return mergedCount;
|
||||
}
|
||||
|
||||
bool GrOpsTask::resetForFullscreenClear(CanDiscardPreviousOps canDiscardPreviousOps) {
|
||||
if (CanDiscardPreviousOps::kYes == canDiscardPreviousOps || this->isEmpty()) {
|
||||
this->deleteOps();
|
||||
@ -918,7 +962,7 @@ void GrOpsTask::recordOp(
|
||||
GrOP_INFO("\t\tBackward: FirstOp\n");
|
||||
}
|
||||
if (clip) {
|
||||
clip = fClipAllocator.make<GrAppliedClip>(std::move(*clip));
|
||||
clip = fClipAllocators[0].make<GrAppliedClip>(std::move(*clip));
|
||||
SkDEBUGCODE(fNumClips++;)
|
||||
}
|
||||
fOpChains.emplace_back(std::move(op), processorAnalysis, clip, dstProxyView);
|
||||
|
@ -54,7 +54,7 @@ public:
|
||||
void onPrePrepare(GrRecordingContext*) override;
|
||||
/**
|
||||
* Together these two functions flush all queued up draws to GrCommandBuffer. The return value
|
||||
* of executeOps() indicates whether any commands were actually issued to the GPU.
|
||||
* of onExecute() indicates whether any commands were actually issued to the GPU.
|
||||
*/
|
||||
void onPrepare(GrOpFlushState* flushState) override;
|
||||
bool onExecute(GrOpFlushState* flushState) override;
|
||||
@ -89,6 +89,10 @@ public:
|
||||
// Must only be called if native color buffer clearing is enabled.
|
||||
void setColorLoadOp(GrLoadOp op, std::array<float, 4> color = {0, 0, 0, 0});
|
||||
|
||||
// Merge opsTasks after 'this' starting from 'fNext' into 'this'. They should all be
|
||||
// renderPass compatible. Return the number of tasks merged into 'this'.
|
||||
int mergeFromLList();
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
int numClips() const override { return fNumClips; }
|
||||
void visitProxies_debugOnly(const GrOp::VisitProxyFunc&) const override;
|
||||
@ -270,7 +274,8 @@ private:
|
||||
|
||||
// MDB TODO: 4096 for the first allocation of the clip space will be huge overkill.
|
||||
// Gather statistics to determine the correct size.
|
||||
SkArenaAllocWithReset fClipAllocator{4096};
|
||||
// TODO: Move the clips onto the recordTimeAllocator after CCPR is removed.
|
||||
SkSTArray<1, SkArenaAlloc> fClipAllocators = { SkArenaAlloc(4096) };
|
||||
SkDEBUGCODE(int fNumClips;)
|
||||
|
||||
// TODO: We could look into this being a set if we find we're adding a lot of duplicates that is
|
||||
|
Loading…
Reference in New Issue
Block a user