Change UnrefDDLTask to just be the DDLTask (take 2)
This includes:
https://skia-review.googlesource.com/c/skia/+/333576 (Fix UMR (valgrind) bug in GrDrawingManager)
Change-Id: I162aba033e75b47a96b4dfdd840ba2cb1f70e42c
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/334422
Reviewed-by: Adlai Holler <adlai@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
diff --git a/src/core/SkDeferredDisplayListPriv.h b/src/core/SkDeferredDisplayListPriv.h
index a8954c4..fc84970 100644
--- a/src/core/SkDeferredDisplayListPriv.h
+++ b/src/core/SkDeferredDisplayListPriv.h
@@ -33,6 +33,10 @@
const SkTArray<GrRecordingContext::ProgramData>& programData() const {
return fDDL->programData();
}
+
+ const SkTArray<sk_sp<GrRenderTask>>& renderTasks() const {
+ return fDDL->fRenderTasks;
+ }
#endif
private:
diff --git a/src/gpu/GrDDLTask.cpp b/src/gpu/GrDDLTask.cpp
new file mode 100644
index 0000000..7f3bef2
--- /dev/null
+++ b/src/gpu/GrDDLTask.cpp
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2020 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "src/gpu/GrDDLTask.h"
+
+#include "include/core/SkDeferredDisplayList.h"
+#include "src/core/SkDeferredDisplayListPriv.h"
+#include "src/gpu/GrResourceAllocator.h"
+
+GrDDLTask::GrDDLTask(GrDrawingManager* drawingMgr,
+ sk_sp<GrRenderTargetProxy> ddlTarget,
+ sk_sp<const SkDeferredDisplayList> ddl)
+ : fDDL(std::move(ddl))
+ , fDDLTarget(std::move(ddlTarget)) {
+
+ for (const sk_sp<GrRenderTask>& task : fDDL->priv().renderTasks()) {
+ SkASSERT(task->isClosed());
+
+ for (int i = 0; i < task->numTargets(); ++i) {
+ drawingMgr->setLastRenderTask(task->target(i).proxy(), task.get());
+ }
+ }
+
+ // The DDL task never accepts additional tasks
+ this->setFlag(kClosed_Flag);
+}
+
+GrDDLTask::~GrDDLTask() { }
+
+void GrDDLTask::endFlush(GrDrawingManager* drawingManager) {
+ for (auto& task : fDDL->priv().renderTasks()) {
+ task->endFlush(drawingManager);
+ }
+
+ INHERITED::endFlush(drawingManager);
+}
+
+void GrDDLTask::disown(GrDrawingManager* drawingManager) {
+ for (auto& task : fDDL->priv().renderTasks()) {
+ task->disown(drawingManager);
+ }
+
+ INHERITED::disown(drawingManager);
+}
+
+bool GrDDLTask::onIsUsed(GrSurfaceProxy* proxy) const {
+ for (auto& task : fDDL->priv().renderTasks()) {
+ if (task->isUsed(proxy)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void GrDDLTask::handleInternalAllocationFailure() {
+ for (auto& task : fDDL->priv().renderTasks()) {
+ task->handleInternalAllocationFailure();
+ }
+}
+
+void GrDDLTask::gatherProxyIntervals(GrResourceAllocator* alloc) const {
+ // We don't have any proxies, but the resource allocator will still bark
+ // if a task doesn't claim any op indices, so we oblige it.
+ alloc->incOps();
+
+ for (auto& task : fDDL->priv().renderTasks()) {
+ task->gatherProxyIntervals(alloc);
+ }
+}
+
+GrRenderTask::ExpectedOutcome GrDDLTask::onMakeClosed(const GrCaps& caps,
+ SkIRect* targetUpdateBounds) {
+ SkASSERT(0);
+ return ExpectedOutcome::kTargetUnchanged;
+}
+
+void GrDDLTask::gatherIDs(SkSTArray<8, uint32_t, true>* idArray) const {
+ for (auto& task : fDDL->priv().renderTasks()) {
+ task->gatherIDs(idArray);
+ }
+}
+
+void GrDDLTask::onPrepare(GrOpFlushState* flushState) {
+ for (auto& task : fDDL->priv().renderTasks()) {
+ task->prepare(flushState);
+ }
+}
+
+bool GrDDLTask::onExecute(GrOpFlushState* flushState) {
+ bool anyCommandsIssued = false;
+ for (auto& task : fDDL->priv().renderTasks()) {
+ if (task->execute(flushState)) {
+ anyCommandsIssued = true;
+ }
+ }
+
+ return anyCommandsIssued;
+}
diff --git a/src/gpu/GrDDLTask.h b/src/gpu/GrDDLTask.h
new file mode 100644
index 0000000..3c129ac
--- /dev/null
+++ b/src/gpu/GrDDLTask.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2020 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrDDLTask_DEFINED
+#define GrDDLTask_DEFINED
+
+#include "src/gpu/GrRenderTask.h"
+
+class GrRenderTargetProxy;
+
+/**
+ * This render task isolates the DDL's tasks from the rest of the DAG. This means that
+ * the DDL's tasks cannot be reordered by the topological sort and are always executed
+ * as a single block.
+ * It almost entirely just forwards calls down to the DDL's render tasks.
+ */
+class GrDDLTask final : public GrRenderTask {
+public:
+ GrDDLTask(GrDrawingManager*,
+ sk_sp<GrRenderTargetProxy> ddlTarget,
+ sk_sp<const SkDeferredDisplayList>);
+
+ ~GrDDLTask() override;
+
+ // The render tasks w/in the DDL don't appear in the DAG so need explicit notification
+ // when they can free their contents.
+ bool requiresExplicitCleanup() const override { return true; }
+
+ void endFlush(GrDrawingManager*) override;
+
+ void disown(GrDrawingManager*) override;
+
+private:
+ bool onIsUsed(GrSurfaceProxy* proxy) const override;
+
+ void handleInternalAllocationFailure() override;
+
+ void gatherProxyIntervals(GrResourceAllocator*) const override;
+
+ ExpectedOutcome onMakeClosed(const GrCaps&, SkIRect* targetUpdateBounds) override;
+
+ void gatherIDs(SkSTArray<8, uint32_t, true>* idArray) const override;
+
+ void onPrePrepare(GrRecordingContext*) override {
+ // This entry point is only called when a DDL is snapped off of a recorder.
+ // Since DDL tasks should never recursively appear within a DDL this should never
+ // be called.
+ SkASSERT(0);
+ }
+
+ void onPrepare(GrOpFlushState*) override;
+
+ bool onExecute(GrOpFlushState*) override;
+
+#if GR_TEST_UTILS
+ const char* name() const final { return "DDL"; }
+#endif
+#ifdef SK_DEBUG
+ void visitProxies_debugOnly(const GrOp::VisitProxyFunc& fn) const override {}
+#endif
+
+ sk_sp<const SkDeferredDisplayList> fDDL;
+ sk_sp<GrRenderTargetProxy> fDDLTarget;
+
+ typedef GrRenderTask INHERITED;
+};
+
+#endif
diff --git a/src/gpu/GrDirectContextPriv.cpp b/src/gpu/GrDirectContextPriv.cpp
index 1459461..5238e23 100644
--- a/src/gpu/GrDirectContextPriv.cpp
+++ b/src/gpu/GrDirectContextPriv.cpp
@@ -66,9 +66,9 @@
return fContext->drawingManager()->flushSurfaces(proxies, access, info, newState);
}
-void GrDirectContextPriv::copyRenderTasksFromDDL(sk_sp<const SkDeferredDisplayList> ddl,
- GrRenderTargetProxy* newDest) {
- fContext->drawingManager()->copyRenderTasksFromDDL(std::move(ddl), newDest);
+void GrDirectContextPriv::createDDLTask(sk_sp<const SkDeferredDisplayList> ddl,
+ GrRenderTargetProxy* newDest) {
+ fContext->drawingManager()->createDDLTask(std::move(ddl), newDest);
}
bool GrDirectContextPriv::compile(const GrProgramDesc& desc, const GrProgramInfo& info) {
diff --git a/src/gpu/GrDirectContextPriv.h b/src/gpu/GrDirectContextPriv.h
index d96030e..5f52317 100644
--- a/src/gpu/GrDirectContextPriv.h
+++ b/src/gpu/GrDirectContextPriv.h
@@ -131,7 +131,7 @@
return fContext->onGetSmallPathAtlasMgr();
}
- void copyRenderTasksFromDDL(sk_sp<const SkDeferredDisplayList>, GrRenderTargetProxy* newDest);
+ void createDDLTask(sk_sp<const SkDeferredDisplayList>, GrRenderTargetProxy* newDest);
bool compile(const GrProgramDesc&, const GrProgramInfo&);
diff --git a/src/gpu/GrDrawingManager.cpp b/src/gpu/GrDrawingManager.cpp
index 68b4690..5961715 100644
--- a/src/gpu/GrDrawingManager.cpp
+++ b/src/gpu/GrDrawingManager.cpp
@@ -19,6 +19,7 @@
#include "src/gpu/GrAuditTrail.h"
#include "src/gpu/GrClientMappedBufferManager.h"
#include "src/gpu/GrCopyRenderTask.h"
+#include "src/gpu/GrDDLTask.h"
#include "src/gpu/GrDirectContextPriv.h"
#include "src/gpu/GrGpu.h"
#include "src/gpu/GrMemoryPool.h"
@@ -38,7 +39,6 @@
#include "src/gpu/GrTextureResolveRenderTask.h"
#include "src/gpu/GrTracing.h"
#include "src/gpu/GrTransferFromRenderTask.h"
-#include "src/gpu/GrUnrefDDLTask.h"
#include "src/gpu/GrWaitRenderTask.h"
#include "src/gpu/ccpr/GrCoverageCountingPathRenderer.h"
#include "src/gpu/text/GrSDFTOptions.h"
@@ -149,10 +149,10 @@
// Prepare any onFlush op lists (e.g. atlases).
if (!fOnFlushCBObjects.empty()) {
- fFlushingRenderTaskIDs.reset(fDAG.count());
- for (int i = 0; i < fDAG.count(); i++) {
- if (fDAG[i]) {
- fFlushingRenderTaskIDs[i] = fDAG[i]->uniqueID();
+ fFlushingRenderTaskIDs.reserve_back(fDAG.count());
+ for (const auto& task : fDAG) {
+ if (task) {
+ task->gatherIDs(&fFlushingRenderTaskIDs);
}
}
@@ -376,8 +376,10 @@
if (!task) {
continue;
}
- if (!task->unique()) {
- // TODO: Eventually this should be guaranteed unique: http://skbug.com/7111
+ if (!task->unique() || task->requiresExplicitCleanup()) {
+ // TODO: Eventually uniqueness should be guaranteed: http://skbug.com/7111.
+ // DDLs, however, will always require an explicit notification for when they
+ // can clean up resources.
task->endFlush(this);
}
task->disown(this);
@@ -535,8 +537,8 @@
void GrDrawingManager::setLastRenderTask(const GrSurfaceProxy* proxy, GrRenderTask* task) {
#ifdef SK_DEBUG
- if (GrRenderTask* prior = this->getLastRenderTask(proxy)) {
- SkASSERT(prior->isClosed());
+ if (auto prior = this->getLastRenderTask(proxy)) {
+ SkASSERT(prior->isClosed() || prior == task);
}
#endif
uint32_t key = proxy->uniqueID().asUInt();
@@ -565,6 +567,8 @@
this->closeAllTasks();
fActiveOpsTask = nullptr;
+ this->sortTasks();
+
fDAG.swap(ddl->fRenderTasks);
SkASSERT(fDAG.empty());
@@ -586,8 +590,8 @@
SkDEBUGCODE(this->validate());
}
-void GrDrawingManager::copyRenderTasksFromDDL(sk_sp<const SkDeferredDisplayList> ddl,
- GrRenderTargetProxy* newDest) {
+void GrDrawingManager::createDDLTask(sk_sp<const SkDeferredDisplayList> ddl,
+ GrRenderTargetProxy* newDest) {
SkDEBUGCODE(this->validate());
if (fActiveOpsTask) {
@@ -599,7 +603,7 @@
fActiveOpsTask = nullptr;
}
- // Propagate the DDL proxy's state information to the replaying DDL.
+ // Propagate the DDL proxy's state information to the replay target.
if (ddl->priv().targetProxy()->isMSAADirty()) {
newDest->markMSAADirty(ddl->priv().targetProxy()->msaaDirtyRect(),
ddl->characterization().origin());
@@ -612,7 +616,7 @@
this->addDDLTarget(newDest, ddl->priv().targetProxy());
// Here we jam the proxy that backs the current replay SkSurface into the LazyProxyData.
- // The lazy proxy that references it (in the copied opsTasks) will steal its GrTexture.
+ // The lazy proxy that references it (in the DDL opsTasks) will then steal its GrTexture.
ddl->fLazyProxyData->fReplayDest = newDest;
if (ddl->fPendingPaths.size()) {
@@ -621,11 +625,11 @@
ccpr->mergePendingPaths(ddl->fPendingPaths);
}
- this->appendTasks(ddl->fRenderTasks);
-
- // Add a task to unref the DDL after flush.
- GrRenderTask* unrefTask = this->appendTask(sk_make_sp<GrUnrefDDLTask>(std::move(ddl)));
- unrefTask->makeClosed(*fContext->priv().caps());
+ // Add a task to handle drawing and lifetime management of the DDL.
+ SkDEBUGCODE(auto ddlTask =) this->appendTask(sk_make_sp<GrDDLTask>(this,
+ sk_ref_sp(newDest),
+ std::move(ddl)));
+ SkASSERT(ddlTask->isClosed());
SkDEBUGCODE(this->validate());
}
@@ -917,4 +921,3 @@
resourceCache->purgeAsNeeded();
}
}
-
diff --git a/src/gpu/GrDrawingManager.h b/src/gpu/GrDrawingManager.h
index 14cbb20..7281d2b 100644
--- a/src/gpu/GrDrawingManager.h
+++ b/src/gpu/GrDrawingManager.h
@@ -117,7 +117,7 @@
void setLastRenderTask(const GrSurfaceProxy*, GrRenderTask*);
void moveRenderTasksToDDL(SkDeferredDisplayList* ddl);
- void copyRenderTasksFromDDL(sk_sp<const SkDeferredDisplayList>, GrRenderTargetProxy* newDest);
+ void createDDLTask(sk_sp<const SkDeferredDisplayList>, GrRenderTargetProxy* newDest);
private:
GrDrawingManager(GrRecordingContext*,
@@ -172,7 +172,8 @@
SkTArray<sk_sp<GrRenderTask>> fDAG;
GrOpsTask* fActiveOpsTask = nullptr;
- // These are the IDs of the opsTask currently being flushed (in internalFlush)
+ // These are the IDs of the opsTask currently being flushed (in internalFlush). They are
+ // only stored here to prevent memory thrashing.
SkSTArray<8, uint32_t, true> fFlushingRenderTaskIDs;
// These are the new renderTasks generated by the onFlush CBs
SkSTArray<4, sk_sp<GrRenderTask>> fOnFlushRenderTasks;
diff --git a/src/gpu/GrOpsTask.cpp b/src/gpu/GrOpsTask.cpp
index c6ca456..562bafb 100644
--- a/src/gpu/GrOpsTask.cpp
+++ b/src/gpu/GrOpsTask.cpp
@@ -875,8 +875,8 @@
}
}
-GrRenderTask::ExpectedOutcome GrOpsTask::onMakeClosed(
- const GrCaps& caps, SkIRect* targetUpdateBounds) {
+GrRenderTask::ExpectedOutcome GrOpsTask::onMakeClosed(const GrCaps& caps,
+ SkIRect* targetUpdateBounds) {
this->forwardCombine(caps);
if (!this->isNoOp()) {
GrSurfaceProxy* proxy = this->target(0).proxy();
diff --git a/src/gpu/GrRenderTask.cpp b/src/gpu/GrRenderTask.cpp
index 2a0e915..460454a 100644
--- a/src/gpu/GrRenderTask.cpp
+++ b/src/gpu/GrRenderTask.cpp
@@ -257,19 +257,16 @@
}
bool GrRenderTask::isInstantiated() const {
- // Some renderTasks (e.g. GrTransferFromRenderTask) don't have any targets.
- if (0 == this->numTargets()) {
- return true;
- }
- GrSurfaceProxy* proxy = this->target(0).proxy();
+ for (const GrSurfaceProxyView& target : fTargets) {
+ GrSurfaceProxy* proxy = target.proxy();
+ if (!proxy->isInstantiated()) {
+ return false;
+ }
- if (!proxy->isInstantiated()) {
- return false;
- }
-
- GrSurface* surface = proxy->peekSurface();
- if (surface->wasDestroyed()) {
- return false;
+ GrSurface* surface = proxy->peekSurface();
+ if (surface->wasDestroyed()) {
+ return false;
+ }
}
return true;
@@ -291,10 +288,9 @@
if (!fTargets.empty()) {
SkDebugf("Targets: \n");
- for (int i = 0; i < fTargets.count(); ++i) {
- GrSurfaceProxy* proxy = fTargets[i].proxy();
- SkDebugf("[%d]: proxyID: %d - surfaceID: %d\n",
- i,
+ for (const GrSurfaceProxyView& target : fTargets) {
+ GrSurfaceProxy* proxy = target.proxy();
+ SkDebugf("proxyID: %d - surfaceID: %d\n",
proxy ? proxy->uniqueID().asUInt() : -1,
proxy && proxy->peekSurface()
? proxy->peekSurface()->uniqueID().asUInt()
diff --git a/src/gpu/GrRenderTask.h b/src/gpu/GrRenderTask.h
index cdd3641..85ded83 100644
--- a/src/gpu/GrRenderTask.h
+++ b/src/gpu/GrRenderTask.h
@@ -37,6 +37,8 @@
void prepare(GrOpFlushState* flushState);
bool execute(GrOpFlushState* flushState) { return this->onExecute(flushState); }
+ virtual bool requiresExplicitCleanup() const { return false; }
+
// Called when this class will survive a flush and needs to truncate its ops and start over.
// TODO: ultimately it should be invalid for an op list to survive a flush.
// https://bugs.chromium.org/p/skia/issues/detail?id=7111
@@ -66,8 +68,11 @@
*/
bool dependsOn(const GrRenderTask* dependedOn) const;
+ virtual void gatherIDs(SkSTArray<8, uint32_t, true>* idArray) const {
+ idArray->push_back(fUniqueID);
+ }
uint32_t uniqueID() const { return fUniqueID; }
- int numTargets() const { return fTargets.count(); }
+ virtual int numTargets() const { return fTargets.count(); }
const GrSurfaceProxyView& target(int i) const { return fTargets[i]; }
/*
@@ -90,12 +95,22 @@
void visitTargetAndSrcProxies_debugOnly(const GrOp::VisitProxyFunc& fn) const {
this->visitProxies_debugOnly(fn);
- for (int i = 0; i < this->numTargets(); ++i) {
- fn(this->target(i).proxy(), GrMipmapped::kNo);
+ for (const GrSurfaceProxyView& target : fTargets) {
+ fn(target.proxy(), GrMipmapped::kNo);
}
}
#endif
+ bool isUsed(GrSurfaceProxy* proxy) const {
+ for (const GrSurfaceProxyView& target : fTargets) {
+ if (target.proxy() == proxy) {
+ return true;
+ }
+ }
+
+ return this->onIsUsed(proxy);
+ }
+
protected:
// In addition to just the GrSurface being allocated, has the stencil buffer been allocated (if
// it is required)?
@@ -129,6 +144,8 @@
private:
// for resetFlag, TopoSortTraits, gatherProxyIntervals, handleInternalAllocationFailure
friend class GrDrawingManager;
+ friend class GrDDLTask; // for handleInternalAllocationFailure, gatherProxyIntervals, Flags
+
// Drops any pending operations that reference proxies that are not instantiated.
// NOTE: Derived classes don't need to check targets. That is handled when the
@@ -139,16 +156,6 @@
// GrRenderTask itself will handle checking the target proxies.
virtual bool onIsUsed(GrSurfaceProxy*) const = 0;
- bool isUsed(GrSurfaceProxy* proxy) const {
- for (const GrSurfaceProxyView& target : fTargets) {
- if (target.proxy() == proxy) {
- return true;
- }
- }
-
- return this->onIsUsed(proxy);
- }
-
void addDependency(GrRenderTask* dependedOn);
void addDependent(GrRenderTask* dependent);
SkDEBUGCODE(bool isDependedent(const GrRenderTask* dependent) const;)
@@ -204,9 +211,9 @@
}
};
- // Only the GrOpsTask currently overrides this virtual
- virtual void onPrePrepare(GrRecordingContext*) {}
- virtual void onPrepare(GrOpFlushState*) {} // Only the GrOpsTask overrides this virtual
+
+ virtual void onPrePrepare(GrRecordingContext*) {} // Only the GrOpsTask currently overrides this
+ virtual void onPrepare(GrOpFlushState*) {} // Only GrOpsTask and GrDDLTask override this virtual
virtual bool onExecute(GrOpFlushState* flushState) = 0;
const uint32_t fUniqueID;
diff --git a/src/gpu/GrUnrefDDLTask.h b/src/gpu/GrUnrefDDLTask.h
deleted file mode 100644
index 41a6bba..0000000
--- a/src/gpu/GrUnrefDDLTask.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2020 Google LLC
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef GrUnrefDDLTask_DEFINED
-#define GrUnrefDDLTask_DEFINED
-
-#include "src/gpu/GrRenderTask.h"
-
-/** When a DDL is played back, the drawing manager refs the DDL and adds one
- * of these to the DAG to release it after the flush. Thus the user is free
- * to unref the DDL at their leisure without messing us up.
- */
-class GrUnrefDDLTask final : public GrRenderTask {
-public:
- GrUnrefDDLTask(sk_sp<const SkDeferredDisplayList> ddl)
- : GrRenderTask()
- , fDDL(std::move(ddl)) {}
-
- // We actually do the unreffing in dtor instead of onExecute, so that we maintain the invariant
- // that DDLs are always the last owners of their render tasks (because those tasks depend on
- // memory owned by the DDL.) If we had this in onExecute, the tasks would still be alive in
- // the drawing manager although it would already have executed them.
- ~GrUnrefDDLTask() override {
- fDDL.reset();
- }
-
-private:
- bool onIsUsed(GrSurfaceProxy* proxy) const override { return false; }
- void handleInternalAllocationFailure() override {}
- void gatherProxyIntervals(GrResourceAllocator* alloc) const override {
- // We don't have any proxies, but the resource allocator will still bark
- // if a task doesn't claim any op indices, so we oblige it.
- alloc->incOps();
- }
-
- ExpectedOutcome onMakeClosed(const GrCaps&, SkIRect*) override {
- return ExpectedOutcome::kTargetUnchanged;
- }
-
- bool onExecute(GrOpFlushState*) override { return true; }
-
-#if GR_TEST_UTILS
- const char* name() const final { return "UnrefDDL"; }
-#endif
-#ifdef SK_DEBUG
- void visitProxies_debugOnly(const GrOp::VisitProxyFunc& fn) const override {}
-#endif
-
- sk_sp<const SkDeferredDisplayList> fDDL;
-};
-
-#endif
diff --git a/src/gpu/vk/GrVkSecondaryCBDrawContext.cpp b/src/gpu/vk/GrVkSecondaryCBDrawContext.cpp
index 40f1944..605b6b1 100644
--- a/src/gpu/vk/GrVkSecondaryCBDrawContext.cpp
+++ b/src/gpu/vk/GrVkSecondaryCBDrawContext.cpp
@@ -181,7 +181,7 @@
return false;
}
- direct->priv().copyRenderTasksFromDDL(std::move(ddl), rtc->asRenderTargetProxy());
+ direct->priv().createDDLTask(std::move(ddl), rtc->asRenderTargetProxy());
return true;
}
diff --git a/src/image/SkSurface_Gpu.cpp b/src/image/SkSurface_Gpu.cpp
index 22d82fd..8109b9f 100644
--- a/src/image/SkSurface_Gpu.cpp
+++ b/src/image/SkSurface_Gpu.cpp
@@ -382,7 +382,7 @@
return false;
}
- direct->priv().copyRenderTasksFromDDL(std::move(ddl), rtc->asRenderTargetProxy());
+ direct->priv().createDDLTask(std::move(ddl), rtc->asRenderTargetProxy());
return true;
}