Skip to content

Fix review findings: crashes, USDZ export, performance, deps and CI - #7

Merged
lanxinger merged 7 commits into
mainfrom
claude/review-fixes
Oct 30, 2026
Merged

lanxinger merged 7 commits into
mainfrom
claude/review-fixes

Conversation

@lanxinger

Copy link
Copy Markdown
Owner

Fixes the bugs, USDZ export issues, performance problems, dependency and CI items from a full code review. Each commit is one area and builds on its own.

Bugs fixed

  • ModelIO buffer overrun: float3 attributes were read and written as 16-byte SIMD3<Float>, which clobbered the next attribute (normal.x / UV.u) and wrote past packed buffers.
  • CLI crashes: faceless meshes segfaulted; a bad --export-precision aborted; zero-extent meshes divided by zero. The C bridge now catches C++ exceptions.
  • Option files: indented or tab-separated lines were silently ignored and missing keys fell back to Lambda 10 / OuterIterations 5. Unknown keys and malformed values are now errors; omitted keys keep the tuned defaults.
  • Validation: NaN/Inf parameters were accepted and produced a collapsed mesh with exit 0.
  • Split vertices: flat-shaded triangle soups failed outright and UV/normal seams acted as open boundaries. CLI and kit now filter a welded copy and copy results back (output keeps the input's vertices and faces).
  • USD import: node transforms are applied (the README already claimed this); face indices are bounds-checked.
  • Cancellation: now polled between solver iterations, so the default single outer iteration can be cancelled.
  • Native backend: Float accumulation inflated lambda by 22% at 360K faces (now Double); isGPUAvailable reflects whether the Metal pipeline was created; latent non-power-of-two reduction bug.

USDZ export

  • Root layer taken from the first archive entry (USDZ spec), not the alphabetically first file.
  • Meshes matched to the USDA by position, not order; non-mesh points (curves) are left alone.
  • primvars:normals recomputed (vertex / faceVarying / uniform, indexed or not) while keeping authored hard edges.
  • Meshes stored in sublayers/references are patched via a flattened stage.
  • USDA parsed as bytes for large files.

Performance

  • C++ reference: peak memory 1.80 → 1.51 GB on a 327K-face mesh with byte-identical output; parallel neighbor search and guidance pass under OpenMP (2.35 s vs 3.7 s serial, identical output).
  • Native CPU filter 5.6× faster; vertex update 4–8× faster (Jacobi-preconditioned, warm-started 3-column CG); GPU path peak memory roughly halved.
  • Fewer per-vertex/per-face allocations in the Swift kit and preprocessor.

Dependencies and CI

  • Eigen 3.4.1 → 5.0.1 (identical output on the 327K-face mesh).
  • OpenMesh tarball pinned with URL_HASH, linked statically; deprecated FetchContent_Populate removed.
  • -march=native is opt-in (MESHDENOISER_NATIVE_ARCH), so release binaries run on any CPU.
  • Workflow token is read-only; a separate release job has contents: write. Actions bumped to current majors.
  • .gitignore no longer hides cmake/*.cmake; unused vcpkg.json removed.

Behaviour changes

  • Option files with unknown keys now fail; partial files get the tuned defaults instead of the old class defaults.
  • Assets with split vertices at seams are now smoothed across seams.
  • md_denoise gained a cancel callback (internal target, no public product change).
  • --export-precision accepts 1–17.

Verification (macOS, Apple Silicon)

  • CLI suite (ctest) 14/14 with AppleClang, with AppleClang + libomp (OpenMP, CHOLMOD auto-detected), and against Eigen 5.0.1.
  • Swift package: 92/92 tests.
  • Not run locally: Linux GCC and Windows MSVC builds. This PR's CI covers them.

Not changed: the MeshUpdateDisplacementEps 0.1 default still stops the mesh update after one iteration. Changing it alters the tuned output and the golden fixture, so it needs a separate decision.

- Reject faceless meshes, zero-extent meshes and invalid --export-precision
  instead of segfaulting or aborting; catch exceptions in main.
- Parse option files on any whitespace (indent, tabs, CRLF), reject unknown
  keys and malformed values, and keep the tuned defaults for omitted keys.
- Reject NaN/Inf parameters; accept MeshUpdateDisplacementEps <= 0 as
  documented (disables early stop).
- Merge coincident vertices for filtering (seams, triangle soups) and copy
  results back to the input's vertices.
- Apply USD node world transforms and bounds-check face indices.
- Poll a cancellation hook between solver iterations.
- Print mesh-update parameters; fix a vector<bool> data race under OpenMP.
- Cut memory: 32-bit neighborhood indices, drop an unused matrix copy,
  parallel order-preserving neighbor search and guidance-normal pass,
  array-backed glTF vertex cache. Output is unchanged.
- Read and write ModelIO float3 attributes as three floats; SIMD3<Float>
  is 16 bytes and clobbered the next attribute or ran past the buffer.
  Keep mapped buffers alive while their pointers are used.
- Denoise a position-welded copy so seams and flat-shaded assets are not
  open boundaries; fall back to the input topology if welding fails.
- Cancel between solver iterations via a new md_cancel_fn; catch C++
  exceptions at the C boundary; reject zero-extent meshes.
- USDZ export: take the root layer from the first archive entry, match
  meshes by position instead of order, recompute primvars:normals (vertex,
  faceVarying, uniform, indexed) while keeping authored hard edges, patch
  a flattened stage when meshes live in other layers, and parse USDA as
  bytes for large files.
- Remove per-vertex/per-face allocations in coincident-vertex averaging
  and MeshPreprocessor; avoid Int64 traps on extreme coordinates.
- Locate test executables next to the test bundle.
- Accumulate area, distance and displacement sums in Double; Float sums
  inflated the rescaled lambda by 22% at 360K faces.
- isGPUAvailable reports whether the Metal pipeline was actually created.
- Parallel, deterministic CPU filter over exact-size CSR rows (5.6x at
  89K faces).
- Vertex update: one three-column Jacobi-preconditioned CG solve with warm
  start and reused buffers (4-8x).
- GPU: write rows and weights straight into Metal buffers (peak memory
  roughly halved) and round the reduction width to a power of two.
…ries

- Pin the OpenMesh 11.0 tarball with URL_HASH and replace the deprecated
  FetchContent_Populate/CMP0169 OLD setup with FetchContent_MakeAvailable.
- Link OpenMesh statically (with OM_STATIC_BUILD) so the CLI is a single
  self-contained executable; CI verifies it has no OpenMesh dylib.
- Make -march=native opt-in (MESHDENOISER_NATIVE_ARCH) so released
  binaries run on any CPU of the target architecture.
- Read-only workflow token; only a separate release job can write.
- Update actions to checkout v7, setup-python v7, upload-artifact v7,
  download-artifact v8 and action-gh-release v3; drop unneeded installs.
- Stop ignoring cmake/*.cmake; remove the unused vcpkg.json.
The CLI output on a 327K-face mesh is byte-identical to Eigen 3.4.1 and all
CLI and Swift package tests pass.
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-30T12:35:49.750128Z 454bb17 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 454bb177e3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

A mesh whose points were a subset of another prim's could claim that prim when ModelIO listed it first, leaving both prims with the wrong geometry. Every point referenced by the prim's faces must now receive a result; coincident USD points share one.
@lanxinger
lanxinger merged commit fdb49af into main Oct 30, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant