From e7dc3a9a9bc2aa2cc8069c64e61062c2d0566ef3 Mon Sep 17 00:00:00 2001 From: Abhishek Gola Date: Tue, 7 Jul 2026 18:59:39 +0530 Subject: [PATCH] added support check --- modules/dnn/src/net_impl2.cpp | 50 ++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/modules/dnn/src/net_impl2.cpp b/modules/dnn/src/net_impl2.cpp index b9c526a915..4f88f1bbf4 100644 --- a/modules/dnn/src/net_impl2.cpp +++ b/modules/dnn/src/net_impl2.cpp @@ -585,6 +585,32 @@ void Net::Impl::finalizeGraph(const Ptr& graph, bool useCUDA) g->exec_.assign(nops, Ptr()); g->execBackend_.assign(nops, DNN_BACKEND_OPENCV); +#ifdef HAVE_CUDA + // Whole-graph CUDA gate: run on CUDA only if *every* op has a CUDA executor; if any op is + // unsupported (or the graph has control-flow subgraphs) run the entire graph on CPU. This + // avoids partial CPU<->CUDA execution and its host/device coherence hazards for now. + std::vector > cudaExecs; + bool graphOnCuda = false; + if (useCUDA && cudaInfo) { + graphOnCuda = true; + cudaExecs.assign(nops, Ptr()); + for (i = 0; i < nops; i++) { + const Ptr& op = prog[i]; + if (!op) + continue; + if (op->subgraphs()) { graphOnCuda = false; break; } // control-flow bodies stay on CPU + Ptr e = LayerFactory::createExec(op->type, DNN_BACKEND_CUDA, op, &cudaInfo->context); + if (!e) { graphOnCuda = false; break; } + cudaExecs[i] = e; + } + if (!graphOnCuda) { + cudaExecs.clear(); + CV_LOG_INFO(NULL, cv::format("DNN/NewEngine: graph '%s' has layer(s) without CUDA support; " + "running the whole graph on CPU", graph->name().c_str())); + } + } +#endif + for (i = 0; i < nops; i++) { const Ptr& op = prog[i]; if (!op) @@ -600,13 +626,10 @@ void Net::Impl::finalizeGraph(const Ptr& graph, bool useCUDA) Ptr exec; int backend = DNN_BACKEND_OPENCV; #ifdef HAVE_CUDA - // Try the optimized backend first; its create() returns null if the op is unsupported. - if (useCUDA && cudaInfo && !subs) { - exec = LayerFactory::createExec(op->type, DNN_BACKEND_CUDA, op, &cudaInfo->context); - if (exec) { - exec->preferableTarget = preferableTarget; - backend = DNN_BACKEND_CUDA; - } + if (graphOnCuda && cudaExecs[i]) { + exec = cudaExecs[i]; + exec->preferableTarget = preferableTarget; + backend = DNN_BACKEND_CUDA; } #endif if (!exec) { @@ -1390,15 +1413,24 @@ void Net::Impl::forwardGraph(Ptr& graph, InputArrayOfArrays inputs_, for (i = 0; i < n_gr_inputs; i++) { Mat m = inputs_.getMat((int)i); setGraphInput(graph, i, m); + } + } #ifdef HAVE_CUDA + // Graph inputs are host-authoritative and may be updated between forward() calls + // (setInput writes them outside this function, so the loop above is skipped when + // forward() is called with no explicit inputs). Mark their device copies stale each + // forward so the current input is re-uploaded; otherwise a second forward with a + // changed input would read the previous forward's stale device data. + if (cudaInfo) { + for (i = 0; i < n_gr_inputs; i++) { Arg ginp = gr_inputs[i]; - if (ginp.idx < (int)argWrappers.size()) { + if (ginp.idx >= 0 && ginp.idx < (int)argWrappers.size()) { Ptr cw = argWrappers[ginp.idx].dynamicCast(); if (cw) cw->setHostDirty(); } -#endif } } +#endif for (size_t opidx = 0; opidx < nops; opidx++) { const Ptr& op = prog.at(opidx);