From 46724ca841a679545694011258589d052afed11f Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 22 Jan 2025 19:17:20 +1100 Subject: [PATCH] Fix #105164: Blender exits when QuadriFlow solver fails Replace calls to exit(..) with an error return value. --- extern/quadriflow/patches/blender.patch | 150 ++++++++++++++++++++++++ extern/quadriflow/src/main.cpp | 5 +- extern/quadriflow/src/parametrizer.cpp | 19 ++- extern/quadriflow/src/parametrizer.hpp | 3 +- extern/quadriflow/src/subdivide.cpp | 11 +- extern/quadriflow/src/subdivide.hpp | 3 +- intern/quadriflow/quadriflow_capi.cpp | 7 +- 7 files changed, 182 insertions(+), 16 deletions(-) diff --git a/extern/quadriflow/patches/blender.patch b/extern/quadriflow/patches/blender.patch index cc7a21adaa8..d74bd09f22f 100644 --- a/extern/quadriflow/patches/blender.patch +++ b/extern/quadriflow/patches/blender.patch @@ -375,6 +375,88 @@ index ab4a01c..a77f7ae 100644 }; class NetworkSimplexFlowHelper : public MaxFlowHelper { +diff --git a/extern/quadriflow/src/main.cpp b/extern/quadriflow/src/main.cpp +index 18bc4063c42..63c9e61b8c9 100644 +--- a/extern/quadriflow/src/main.cpp ++++ b/extern/quadriflow/src/main.cpp +@@ -110,7 +110,10 @@ int main(int argc, char** argv) { + printf("Use %lf seconds\n", (t2 - t1) * 1e-3); + t1 = GetCurrentTime64(); + printf("Solve index map...\n"); +- field.ComputeIndexMap(); ++ if (!field.ComputeIndexMap()) { ++ fprintf(stderr, "Failed to solve result, exiting!\n"); ++ return 1; ++ } + t2 = GetCurrentTime64(); + printf("Indexmap Use %lf seconds\n", (t2 - t1) * 1e-3); + printf("Writing the file...\n"); +diff --git a/extern/quadriflow/src/parametrizer.cpp b/extern/quadriflow/src/parametrizer.cpp +index b85383566c9..3dbdc386eca 100644 +--- a/extern/quadriflow/src/parametrizer.cpp ++++ b/extern/quadriflow/src/parametrizer.cpp +@@ -18,7 +18,7 @@ + + namespace qflow { + +-void Parametrizer::ComputeIndexMap(int with_scale) { ++bool Parametrizer::ComputeIndexMap(int with_scale) { + // build edge info + auto& V = hierarchy.mV[0]; + auto& F = hierarchy.mF; +@@ -80,9 +80,12 @@ void Parametrizer::ComputeIndexMap(int with_scale) { + #ifdef LOG_OUTPUT + printf("subdivide...\n"); + #endif +- subdivide_edgeDiff(F, V, N, Q, O, &hierarchy.mS[0], V2E, hierarchy.mE2E, boundary, nonManifold, +- edge_diff, edge_values, face_edgeOrients, face_edgeIds, sharp_edges, +- singularities, 1); ++ if (!subdivide_edgeDiff(F, V, N, Q, O, &hierarchy.mS[0], V2E, hierarchy.mE2E, boundary, nonManifold, ++ edge_diff, edge_values, face_edgeOrients, face_edgeIds, sharp_edges, ++ singularities, 1)) ++ { ++ return false; ++ } + + allow_changes.clear(); + allow_changes.resize(edge_diff.size() * 2, 1); +@@ -99,9 +102,12 @@ void Parametrizer::ComputeIndexMap(int with_scale) { + int t1 = GetCurrentTime64(); + #endif + FixFlipHierarchy(); +- subdivide_edgeDiff(F, V, N, Q, O, &hierarchy.mS[0], V2E, hierarchy.mE2E, boundary, nonManifold, ++ if (!subdivide_edgeDiff(F, V, N, Q, O, &hierarchy.mS[0], V2E, hierarchy.mE2E, boundary, nonManifold, + edge_diff, edge_values, face_edgeOrients, face_edgeIds, sharp_edges, +- singularities, 1); ++ singularities, 1)) ++ { ++ return false; ++ } + FixFlipSat(); + + #ifdef LOG_OUTPUT +@@ -242,6 +248,7 @@ void Parametrizer::ComputeIndexMap(int with_scale) { + // E2E_compact, + // V, N, Q, O, F, V2E, hierarchy.mE2E, disajoint_tree, + // hierarchy.mScale, false); ++ return true; + } + + } // namespace qflow +diff --git a/extern/quadriflow/src/parametrizer.hpp b/extern/quadriflow/src/parametrizer.hpp +index 1f4a02be6c2..9703ebbfff6 100644 +--- a/extern/quadriflow/src/parametrizer.hpp ++++ b/extern/quadriflow/src/parametrizer.hpp +@@ -54,7 +54,8 @@ class Parametrizer { + void ComputePositionSingularities(); + + // Integer Grid Map Pipeline +- void ComputeIndexMap(int with_scale = 0); ++ // Return false when the solver fails. ++ bool ComputeIndexMap(int with_scale = 0); + void BuildEdgeInfo(); + void ComputeMaxFlow(); + void MarkInteger(); diff --git a/extern/quadriflow/src/post-solver.cpp b/extern/quadriflow/src/post-solver.cpp index 6027ddd..ccefd15 100644 --- a/extern/quadriflow/src/post-solver.cpp @@ -389,3 +471,71 @@ index 6027ddd..ccefd15 100644 #include #include #include +diff --git a/extern/quadriflow/src/subdivide.cpp b/extern/quadriflow/src/subdivide.cpp +index c408bbc6394..babff96ccb4 100644 +--- a/extern/quadriflow/src/subdivide.cpp ++++ b/extern/quadriflow/src/subdivide.cpp +@@ -145,7 +145,7 @@ void subdivide(MatrixXi &F, MatrixXd &V, VectorXd& rho, VectorXi &V2E, VectorXi + E2E.conservativeResize(nF * 3); + } + +-void subdivide_edgeDiff(MatrixXi &F, MatrixXd &V, MatrixXd &N, MatrixXd &Q, MatrixXd &O, MatrixXd* S, ++bool subdivide_edgeDiff(MatrixXi &F, MatrixXd &V, MatrixXd &N, MatrixXd &Q, MatrixXd &O, MatrixXd* S, + VectorXi &V2E, VectorXi &E2E, VectorXi &boundary, VectorXi &nonmanifold, + std::vector &edge_diff, std::vector &edge_values, + std::vector &face_edgeOrients, std::vector &face_edgeIds, +@@ -500,17 +500,18 @@ void subdivide_edgeDiff(MatrixXi &F, MatrixXd &V, MatrixXd &N, MatrixXd &Q, Matr + for (int j = 0; j < 3; ++j) { + auto diff = edge_diff[face_edgeIds[i][j]]; + if (abs(diff[0]) > 1 || abs(diff[1]) > 1) { +- printf("wrong init %d %d!\n", face_edgeIds[i][j], i * 3 + j); +- exit(0); ++ fprintf(stderr, "wrong init %d %d!\n", face_edgeIds[i][j], i * 3 + j); ++ return false; + } + } + } + for (int i = 0; i < edge_diff.size(); ++i) { + if (abs(edge_diff[i][0]) > 1 || abs(edge_diff[i][1]) > 1) { +- printf("wrong...\n"); +- exit(0); ++ fprintf(stderr, "wrong...\n"); ++ return false; + } + } ++ return true; + } + + } // namespace qflow +diff --git a/extern/quadriflow/src/subdivide.hpp b/extern/quadriflow/src/subdivide.hpp +index a93c58ac2a7..8c682b6d9f2 100644 +--- a/extern/quadriflow/src/subdivide.hpp ++++ b/extern/quadriflow/src/subdivide.hpp +@@ -9,7 +9,8 @@ namespace qflow { + void subdivide(MatrixXi &F, MatrixXd &V, VectorXd& rho, VectorXi &V2E, VectorXi &E2E, VectorXi &boundary, + VectorXi &nonmanifold, double maxLength); + +-void subdivide_edgeDiff(MatrixXi &F, MatrixXd &V, MatrixXd &N, MatrixXd &Q, MatrixXd &O, MatrixXd* S, ++// Return false when solving fails. ++bool subdivide_edgeDiff(MatrixXi &F, MatrixXd &V, MatrixXd &N, MatrixXd &Q, MatrixXd &O, MatrixXd* S, + VectorXi &V2E, VectorXi &E2E, VectorXi &boundary, VectorXi &nonmanifold, + std::vector &edge_diff, std::vector &edge_values, + std::vector &face_edgeOrients, std::vector &face_edgeIds, +diff --git a/intern/quadriflow/quadriflow_capi.cpp b/intern/quadriflow/quadriflow_capi.cpp +index fad604f679a..014ac2a5613 100644 +--- a/intern/quadriflow/quadriflow_capi.cpp ++++ b/intern/quadriflow/quadriflow_capi.cpp +@@ -190,8 +190,11 @@ void QFLOW_quadriflow_remesh(QuadriflowRemeshData *qrd, + return; + } + +- /* Compute the final quad geomtry using a maxflow solver */ +- field.ComputeIndexMap(); ++ /* Compute the final quad geometry using a maxflow solver */ ++ if (!field.ComputeIndexMap()) { ++ /* Error computing the result. */ ++ return; ++ } + + if (check_if_canceled(0.9f, update_cb, update_cb_data)) { + return; diff --git a/extern/quadriflow/src/main.cpp b/extern/quadriflow/src/main.cpp index 18bc4063c42..63c9e61b8c9 100644 --- a/extern/quadriflow/src/main.cpp +++ b/extern/quadriflow/src/main.cpp @@ -110,7 +110,10 @@ int main(int argc, char** argv) { printf("Use %lf seconds\n", (t2 - t1) * 1e-3); t1 = GetCurrentTime64(); printf("Solve index map...\n"); - field.ComputeIndexMap(); + if (!field.ComputeIndexMap()) { + fprintf(stderr, "Failed to solve result, exiting!\n"); + return 1; + } t2 = GetCurrentTime64(); printf("Indexmap Use %lf seconds\n", (t2 - t1) * 1e-3); printf("Writing the file...\n"); diff --git a/extern/quadriflow/src/parametrizer.cpp b/extern/quadriflow/src/parametrizer.cpp index b85383566c9..3dbdc386eca 100644 --- a/extern/quadriflow/src/parametrizer.cpp +++ b/extern/quadriflow/src/parametrizer.cpp @@ -18,7 +18,7 @@ namespace qflow { -void Parametrizer::ComputeIndexMap(int with_scale) { +bool Parametrizer::ComputeIndexMap(int with_scale) { // build edge info auto& V = hierarchy.mV[0]; auto& F = hierarchy.mF; @@ -80,9 +80,12 @@ void Parametrizer::ComputeIndexMap(int with_scale) { #ifdef LOG_OUTPUT printf("subdivide...\n"); #endif - subdivide_edgeDiff(F, V, N, Q, O, &hierarchy.mS[0], V2E, hierarchy.mE2E, boundary, nonManifold, - edge_diff, edge_values, face_edgeOrients, face_edgeIds, sharp_edges, - singularities, 1); + if (!subdivide_edgeDiff(F, V, N, Q, O, &hierarchy.mS[0], V2E, hierarchy.mE2E, boundary, nonManifold, + edge_diff, edge_values, face_edgeOrients, face_edgeIds, sharp_edges, + singularities, 1)) + { + return false; + } allow_changes.clear(); allow_changes.resize(edge_diff.size() * 2, 1); @@ -99,9 +102,12 @@ void Parametrizer::ComputeIndexMap(int with_scale) { int t1 = GetCurrentTime64(); #endif FixFlipHierarchy(); - subdivide_edgeDiff(F, V, N, Q, O, &hierarchy.mS[0], V2E, hierarchy.mE2E, boundary, nonManifold, + if (!subdivide_edgeDiff(F, V, N, Q, O, &hierarchy.mS[0], V2E, hierarchy.mE2E, boundary, nonManifold, edge_diff, edge_values, face_edgeOrients, face_edgeIds, sharp_edges, - singularities, 1); + singularities, 1)) + { + return false; + } FixFlipSat(); #ifdef LOG_OUTPUT @@ -242,6 +248,7 @@ void Parametrizer::ComputeIndexMap(int with_scale) { // E2E_compact, // V, N, Q, O, F, V2E, hierarchy.mE2E, disajoint_tree, // hierarchy.mScale, false); + return true; } } // namespace qflow diff --git a/extern/quadriflow/src/parametrizer.hpp b/extern/quadriflow/src/parametrizer.hpp index 1f4a02be6c2..9703ebbfff6 100644 --- a/extern/quadriflow/src/parametrizer.hpp +++ b/extern/quadriflow/src/parametrizer.hpp @@ -54,7 +54,8 @@ class Parametrizer { void ComputePositionSingularities(); // Integer Grid Map Pipeline - void ComputeIndexMap(int with_scale = 0); + // Return false when the solver fails. + bool ComputeIndexMap(int with_scale = 0); void BuildEdgeInfo(); void ComputeMaxFlow(); void MarkInteger(); diff --git a/extern/quadriflow/src/subdivide.cpp b/extern/quadriflow/src/subdivide.cpp index c408bbc6394..babff96ccb4 100644 --- a/extern/quadriflow/src/subdivide.cpp +++ b/extern/quadriflow/src/subdivide.cpp @@ -145,7 +145,7 @@ void subdivide(MatrixXi &F, MatrixXd &V, VectorXd& rho, VectorXi &V2E, VectorXi E2E.conservativeResize(nF * 3); } -void subdivide_edgeDiff(MatrixXi &F, MatrixXd &V, MatrixXd &N, MatrixXd &Q, MatrixXd &O, MatrixXd* S, +bool subdivide_edgeDiff(MatrixXi &F, MatrixXd &V, MatrixXd &N, MatrixXd &Q, MatrixXd &O, MatrixXd* S, VectorXi &V2E, VectorXi &E2E, VectorXi &boundary, VectorXi &nonmanifold, std::vector &edge_diff, std::vector &edge_values, std::vector &face_edgeOrients, std::vector &face_edgeIds, @@ -500,17 +500,18 @@ void subdivide_edgeDiff(MatrixXi &F, MatrixXd &V, MatrixXd &N, MatrixXd &Q, Matr for (int j = 0; j < 3; ++j) { auto diff = edge_diff[face_edgeIds[i][j]]; if (abs(diff[0]) > 1 || abs(diff[1]) > 1) { - printf("wrong init %d %d!\n", face_edgeIds[i][j], i * 3 + j); - exit(0); + fprintf(stderr, "wrong init %d %d!\n", face_edgeIds[i][j], i * 3 + j); + return false; } } } for (int i = 0; i < edge_diff.size(); ++i) { if (abs(edge_diff[i][0]) > 1 || abs(edge_diff[i][1]) > 1) { - printf("wrong...\n"); - exit(0); + fprintf(stderr, "wrong...\n"); + return false; } } + return true; } } // namespace qflow diff --git a/extern/quadriflow/src/subdivide.hpp b/extern/quadriflow/src/subdivide.hpp index a93c58ac2a7..8c682b6d9f2 100644 --- a/extern/quadriflow/src/subdivide.hpp +++ b/extern/quadriflow/src/subdivide.hpp @@ -9,7 +9,8 @@ namespace qflow { void subdivide(MatrixXi &F, MatrixXd &V, VectorXd& rho, VectorXi &V2E, VectorXi &E2E, VectorXi &boundary, VectorXi &nonmanifold, double maxLength); -void subdivide_edgeDiff(MatrixXi &F, MatrixXd &V, MatrixXd &N, MatrixXd &Q, MatrixXd &O, MatrixXd* S, +// Return false when solving fails. +bool subdivide_edgeDiff(MatrixXi &F, MatrixXd &V, MatrixXd &N, MatrixXd &Q, MatrixXd &O, MatrixXd* S, VectorXi &V2E, VectorXi &E2E, VectorXi &boundary, VectorXi &nonmanifold, std::vector &edge_diff, std::vector &edge_values, std::vector &face_edgeOrients, std::vector &face_edgeIds, diff --git a/intern/quadriflow/quadriflow_capi.cpp b/intern/quadriflow/quadriflow_capi.cpp index fad604f679a..014ac2a5613 100644 --- a/intern/quadriflow/quadriflow_capi.cpp +++ b/intern/quadriflow/quadriflow_capi.cpp @@ -190,8 +190,11 @@ void QFLOW_quadriflow_remesh(QuadriflowRemeshData *qrd, return; } - /* Compute the final quad geomtry using a maxflow solver */ - field.ComputeIndexMap(); + /* Compute the final quad geometry using a maxflow solver */ + if (!field.ComputeIndexMap()) { + /* Error computing the result. */ + return; + } if (check_if_canceled(0.9f, update_cb, update_cb_data)) { return;