Commit 3b33a397 authored by Andrey Filippov's avatar Andrey Filippov

CLAUDE: item-4 step-4 - detection-input render via its CARVED green-ctx module (MAP v2)

- GpuQuadJna.renderProcPrepare(spec): lazy second module (tp_create_module2,
  explicit SM-carve spec) + render-only TpProc bound to the main proc
  (tp_proc_render_bind_source); all render* entries route to it when present.
  Bound proc destroyed FIRST on close. Optional -Dtp.green.pose carves the
  MAIN module (default unset - INIT/pre-RT phases would be confined too).
- CuasPoseRT: renderProcPrepare BEFORE the timed loop (NVRTC compile never
  lands in scene 0's slot); fail-safe = render stays on the main module.
- New saved param curt.det_render_green (default "8+8" per the ratified MAP
  v2 pose-8/render-8/rest-20): empty/"0" = R1a single-module shape (A/B).
- Native gates (tile_processor_gpu 0a0d509): carve_combo b0-b4 bind
  arrangements ALL PASS bit-exact incl. the PLAIN-pose + carved-render
  production mirror; full suite ALL PASS; sanitizer 0.
- Step-4 gate (Andrey's run): 497 Done lines byte-identical to the 07/16
  22:52 record with det_render ON + capacity re-measure.
Co-Authored-By: 's avatarClaude Fable 5 <noreply@anthropic.com>
parent 5ead4c80
......@@ -2862,6 +2862,21 @@ public class CuasPoseRT {
final ImageStack det_render_stack = (det_render_ok[0] && clt_parameters.curt.det_render_save) ?
new ImageStack(center_CLT.getGeometryCorrection().getSensorWH()[0],
center_CLT.getGeometryCorrection().getSensorWH()[1]) : null;
// item 4 step-4 (MAP v2, Andrey 07/19): move the render stage onto its OWN
// carved green-ctx module BEFORE the timed loop (the NVRTC compile must not
// land in scene 0's slot). KEY LAW: carve the AGGRESSOR - the render's
// saturating grids confined to curt.det_render_green SMs is the step-4
// byte-identity prediction. Empty spec or any failure = render stays on
// the main module (the R1a shape, one console line from GpuQuadJna).
// By Claude on 07/19/2026.
if (det_render_ok[0]) {
try {
center_CLT.getGPUQuad().renderProcPrepare(clt_parameters.curt.det_render_green);
} catch (Exception e) {
System.out.println("CuasPoseRT: renderProcPrepare failed ("+e.getMessage()+
") - detection-input render stays on the main GPU module");
}
}
final boolean [] dp_overlap_ok = {true};
// ---- Ascending per-scene loop (the RT iterator) ----
final int tilesX = center_CLT.getTilesX();
......
......@@ -3042,6 +3042,11 @@ public class GpuQuad{ // quad camera description
// pipelined one scene behind the pose service). Base = unsupported.
// By Claude on 07/19/2026. ----
public boolean supportsRenderStage() { return false; } // By Claude on 07/19/2026
/** item-4 step-4: move the render stage onto its OWN carved (green-ctx) module bound to
* this GpuQuad's proc (MAP v2 pose/render/rest partitioning). null/""/"0" spec or any
* failure = false -> render stays on the main module (the R1a path). By Claude on 07/19/2026. */
public boolean renderProcPrepare(String green_spec) {
throw new UnsupportedOperationException("renderProcPrepare: JNA backend only"); }
public boolean renderSetup(float disparity_corr,
float min_px, float max_px, float min_py, float max_py, float soft, float hard) {
throw new UnsupportedOperationException("renderSetup: JNA backend only"); }
......
......@@ -31,6 +31,14 @@ public class GpuQuadJna extends GpuQuad {
private Pointer module; // TpModule* (NVRTC kernels)
private Pointer proc; // TpProc* (persistent device buffers)
private boolean closed = false;
// item-4 step-4 (GPU partitioning, MAP v2): OPTIONAL carved render module -
// the detection-input render chain runs in its OWN green-context SM carve,
// bound to the main proc's image ring/residents (tp_proc_render_bind_source).
// null = the original single-module render path. By Claude on 07/19/2026.
private String jna_srcdir, jna_devrt; // saved for the lazy render module compile
private Pointer render_module = null; // TpModule* (carved green ctx)
private Pointer render_proc = null; // render-only TpProc* bound to proc
private String render_green = null; // active carve spec (for the console line)
/**
* Per-scene (sensor) backend.
......@@ -59,7 +67,20 @@ public class GpuQuadJna extends GpuQuad {
// num_cams=1 and kernels_hor=kern_tiles=0, so no kernel buffers are allocated.
private void initNative(String srcdir, String devrt) {
this.lib = Native.load("tileproc", TpJna.class);
this.module = lib.tp_create_module(srcdir, devrt);
this.jna_srcdir = srcdir; this.jna_devrt = devrt; // By Claude on 07/19/2026 (item-4 step-4)
// item-4 step-4: optional MAIN-module SM carve (-Dtp.green.pose=8). Default
// UNSET = plain context: this module also runs the INIT/pre-RT phases
// (ingest, FPN, calibration, template build) which a permanent 8-SM carve
// would slow ~4x - carve it only for dedicated A/B runs (MAP (B) sizing).
// By Claude on 07/19/2026.
final String pose_green = System.getProperty("tp.green.pose");
this.module = ((pose_green != null) && !pose_green.isEmpty() && !"0".equals(pose_green)) ?
lib.tp_create_module2(srcdir, devrt, pose_green) :
lib.tp_create_module(srcdir, devrt);
if ((pose_green != null) && (module != null)) {
System.out.println("GpuQuadJna: MAIN module carved to green ctx '"+pose_green+
"' (-Dtp.green.pose) - INIT/pre-RT phases are confined too");
}
if (module == null) {
throw new IllegalStateException("GpuQuadJna: tp_create_module failed: " + lib.tp_last_error());
}
......@@ -203,6 +224,10 @@ public class GpuQuadJna extends GpuQuad {
public synchronized void close() {
if (closed) return;
closed = true;
// item-4 step-4: the BOUND render proc reads the main proc's residents -
// destroy it (and its carved module) FIRST. By Claude on 07/19/2026.
if (render_proc != null) { lib.tp_proc_destroy(render_proc); render_proc = null; }
if (render_module != null) { lib.tp_destroy_module(render_module); render_module = null; }
if (proc != null) lib.tp_proc_destroy(proc);
if (module != null) lib.tp_destroy_module(module);
}
......@@ -794,11 +819,46 @@ public class GpuQuadJna extends GpuQuad {
// ---- imagej ROADMAP item 4 (combined image + LoG) rung R1: async combined-
// render stage (render_dp on a low-priority stream, one scene behind the
// pose service). By Claude on 07/19/2026. ----
// item-4 step-4: when renderProcPrepare() succeeded, all render* calls run on
// the BOUND render-only proc in its carved module (KEY LAW: carve the
// aggressor); otherwise they run on the main proc (the original R1a path).
// By Claude on 07/19/2026.
private Pointer rproc() { return (render_proc != null) ? render_proc : proc; }
@Override public boolean renderProcPrepare(final String green_spec) {
if ((green_spec == null) || green_spec.isEmpty() || "0".equals(green_spec)) return false; // legacy path
if (render_proc != null) return true; // idempotent (re-arm per sequence is renderSetup's job)
try {
final Pointer rmod = lib.tp_create_module2(jna_srcdir, jna_devrt, green_spec);
if (rmod == null) {
throw new IllegalStateException("tp_create_module2('"+green_spec+"'): "+lib.tp_last_error());
}
final Pointer rp = lib.tp_proc_create(rmod);
if (rp == null) {
lib.tp_destroy_module(rmod);
throw new IllegalStateException("tp_proc_create(render): "+lib.tp_last_error());
}
final int rc = lib.tp_proc_render_bind_source(rp, proc);
if (rc != 0) {
lib.tp_proc_destroy(rp);
lib.tp_destroy_module(rmod);
throw new IllegalStateException("tp_proc_render_bind_source rc="+rc+": "+lib.tp_last_error());
}
render_module = rmod; render_proc = rp; render_green = green_spec;
System.out.println("GpuQuadJna: render stage bound to its CARVED module (green ctx '"+
green_spec+"', item-4 step-4 MAP v2)");
return true;
} catch (Exception e) {
System.out.println("GpuQuadJna.renderProcPrepare FAILED - render stays on the main module: "+
e.getMessage());
render_module = null; render_proc = null; render_green = null;
return false;
}
}
@Override public boolean supportsRenderStage() { return !rectilinear; }
@Override public boolean renderSetup(
final float disparity_corr, final float min_px, final float max_px,
final float min_py, final float max_py, final float soft, final float hard) {
final int rc = lib.tp_proc_render_setup(proc,
final int rc = lib.tp_proc_render_setup(rproc(),
disparity_corr, min_px, max_px, min_py, max_py, soft, hard);
if (rc != 0) {
throw new IllegalStateException("GpuQuadJna.renderSetup rc="+rc+": "+lib.tp_last_error());
......@@ -809,7 +869,7 @@ public class GpuQuadJna extends GpuQuad {
if ((task_map == null) || (task_centers == null) || (task_centers.length != 3 * task_map.length)) {
throw new IllegalArgumentException("GpuQuadJna.renderTemplate: inconsistent template");
}
final int rc = lib.tp_proc_render_template(proc, task_map, task_centers, task_map.length);
final int rc = lib.tp_proc_render_template(rproc(), task_map, task_centers, task_map.length);
if (rc != 0) {
throw new IllegalStateException("GpuQuadJna.renderTemplate rc="+rc+": "+lib.tp_last_error());
}
......@@ -818,7 +878,7 @@ public class GpuQuadJna extends GpuQuad {
@Override public boolean renderCameras(final IntersceneLmaFloat.Camera reference,
final IntersceneLmaFloat.Camera scene) {
final int rc = lib.tp_proc_render_cameras(
proc,
rproc(),
(reference != null) ? poseCameraMeta(reference) : null,
(reference != null) ? reference.radial : null,
(reference != null) ? reference.rByRDist : null,
......@@ -846,7 +906,7 @@ public class GpuQuadJna extends GpuQuad {
copyPoseVector3(reference_atr, poseVectors, 3);
copyPoseVector3(scene_xyz, poseVectors, 6);
copyPoseVector3(scene_atr, poseVectors, 9);
final int rc = lib.tp_proc_render_scene(proc, poseVectors, 12,
final int rc = lib.tp_proc_render_scene(rproc(), poseVectors, 12,
(float) dx_main, (float) dy_main, (float) dx_sub, (float) dy_sub,
(float) scale_main, (float) scale_sub, task_code_main, task_code_sub, img_set, 1);
if (rc != 0) {
......@@ -855,13 +915,13 @@ public class GpuQuadJna extends GpuQuad {
return true;
}
@Override public int renderStatus(final boolean wait, final int [] stats) {
return lib.tp_proc_render_status(proc, wait ? 1 : 0, stats);
return lib.tp_proc_render_status(rproc(), wait ? 1 : 0, stats);
}
@Override public float [] renderGet() { // TEST-ONLY D2H (ruling 07/19 3.4); de-pitched like getRBG
final int out_width = getImageWidth(), out_height = getImageHeight();
final int gpu_width = out_width + GPUTileProcessor.DTT_SIZE, gpu_height = out_height + GPUTileProcessor.DTT_SIZE;
final float[] packed = new float[num_colors * gpu_width * gpu_height];
final int rc = lib.tp_proc_render_get(proc, packed);
final int rc = lib.tp_proc_render_get(rproc(), packed);
if (rc != 1) {
throw new IllegalStateException("GpuQuadJna.renderGet rc="+rc+": "+lib.tp_last_error());
}
......
......@@ -12,6 +12,10 @@ public interface TpJna extends Library {
/** NVRTC-compile the kernels in srcdir (+ getTpDefines), cuLink(libcudadevrt), load the module.
* Returns an opaque module handle, or null on failure (see tp_last_error()). */
Pointer tp_create_module(String srcdir, String libcudadevrt);
/** item-4 step-4: same as tp_create_module, with an EXPLICIT green-context SM-carve spec
* ("&lt;count&gt;" | "&lt;skip&gt;+&lt;count&gt;" | "&lt;skip&gt;+rem"; null/""/"0" = plain context).
* By Claude on 07/19/2026. */
Pointer tp_create_module2(String srcdir, String libcudadevrt, String greenSpec);
/** Number of kernel functions resolved in the module (33 expected:
* 19 base + 2 conditioning + 4 consolidation + 2 peak + pose-fx/J + 4 pose-LMA + LMA-products),
* or -1 if handle is null. */
......@@ -325,6 +329,12 @@ public interface TpJna extends Library {
/** TEST-ONLY D2H of the rendered combined image (ruling 07/19 3.4): pitched
* (imgW+8) x (imgH+8) floats, de-pitched by the caller. 1 on success. */
int tp_proc_render_get(Pointer proc, float[] out);
/** item-4 step-4: bind a FRESH render-only proc (its own - normally carved -
* module, NO tp_proc_setup) to the pose proc whose image ring and static
* residents (gc/rbr/kernels) the render chain reads cross-context. Call
* BEFORE tp_proc_render_setup on the render proc. 0 on success.
* By Claude on 07/19/2026. */
int tp_proc_render_bind_source(Pointer renderProc, Pointer srcProc);
// ---- D5 overlap (design ratified 2026-07-17): device image-set ring (D5a) +
// launch/collect split of the scene entry (D5b). By Claude on 07/17/2026. ----
......
......@@ -28,6 +28,7 @@ public class CuasRtParameters {
public boolean pose_feed16 = true; // T2 (Andrey 07/18): replace the ~9.7 GiB float preload with the in-loop 16-bit feeder - real per-scene fixed-offset TIFF reads (4 threads = the production 4xSATA sensor groups) pread straight into pinned u16 staging, GPU does byte-swap + borrowed Row/Col + conditioning in one kernel (bit-exact vs the preload, case u16_cond). fadvise keeps reruns honestly cold; paced mode also gates the DATA at 60 Hz arrival. OFF = the legacy preload. // By Claude on 07/18/2026
public boolean det_render = true; // item 4 R1 (Andrey 07/19): detection-input stage - full-frame combined virtual render at the FITTED pose (dual-MB, 16-sensor consolidated, cam0-only imclt) as ONE async chain on a LOW-PRIORITY stream, pipelined ONE SCENE BEHIND the pose service (pose keeps its own 1/60 slot; +1 frame detection latency). Fail-safe: any error disables the stage for the run, poses untouched. // By Claude on 07/19/2026
public boolean det_render_save = false; // item 4 R1 DEBUG (ruling 07/19 3.4: D2H is TEST-ONLY): blocking per-scene readback of the rendered combined image -> -CUAS-RT-DETINPUT hyperstack for the A/B vs CuasRender.renderSceneVirtual. Slows the run - measurement/A-B only. // By Claude on 07/19/2026
public String det_render_green = "8+8"; // item 4 step-4 (MAP v2 ratified 07/19: pose 8 / render 8 / rest 20): green-context SM carve spec for the render's OWN module ("<count>" | "<skip>+<count>"; "8+8" = 8 SMs disjoint from the pose-8 slot). Empty/"0" = render on the main module (the R1a shape - the wobble A/B). Prepared BEFORE the timed loop (NVRTC compile); any failure falls back to the main module with a console line. // By Claude on 07/19/2026
public boolean pose_lean = false; // phase B measurement engine: TD-average the 16 sensors (CuasTD, CPU bridge) then ONE conj-multiply vs the virtual-center TD -> FZ-normalize -> PD -> argmax+eigen (getMaxXYCmEig) -> 3-angle LMA. All existing GPU kernels. v1: NO motion-blur compensation - compare vs the NOMB baseline. // By Claude on 07/05/2026
public boolean pose_full = false; // DEBUG: use ALL strength-selected tiles (~1074) - the -POSE-RT-TILE-CALIB calibration is neither read nor written (temporary bypass of the 150-tile filter for measurement debugging). // By Claude on 07/04/2026
public boolean pose_corr_save = false; // DEBUG: save the per-scene 2D correlations vs the virtual center in the pixel domain (-POSE-RT-CORR2D: z=scenes, tile grid of 16x16 cells, last LMA cycle) - lean engine only. // By Claude on 07/04/2026
......@@ -151,6 +152,8 @@ public class CuasRtParameters {
"Item 4 R1: render the full-frame combined virtual image at each FITTED pose as an async GPU chain on a low-priority stream, one scene behind the pose service (depth-2 pipeline, pose keeps its own 1/60 slot). The frame stays GPU-resident for the LoG/detection stages. Fail-safe disables the stage for the run.");
gd.addCheckbox ("DEBUG: save detection-input renders", this.det_render_save, // By Claude on 07/19/2026
"TEST-ONLY (ruling 07/19 3.4): blocking per-scene D2H of the rendered combined image, saved as -CUAS-RT-DETINPUT (z=scenes) for the A/B vs the diagnostic CuasRender path. Slows the run.");
gd.addStringField("Render green-ctx carve (SM spec)", this.det_render_green, 8, // By Claude on 07/19/2026
"Item 4 step-4 (MAP v2): run the detection-input render in its OWN GPU module confined to this SM carve ('8+8' = 8 SMs disjoint from the pose-8 slot). Empty or '0' = render on the main module (the R1a shape). Fail-safe falls back to the main module.");
gd.addCheckbox ("Pose test lean correlation (B)", this.pose_lean, // By Claude on 07/05/2026
"Phase B measurement: TD-average the 16 sensors, then ONE conj-multiply vs the virtual-center TD -> FZ-normalize -> PD -> argmax+eigen -> 3-angle LMA. v1 has NO motion-blur compensation (compare vs the NOMB baseline).");
......@@ -370,6 +373,7 @@ public class CuasRtParameters {
this.pose_feed16 = gd.getNextBoolean(); // By Claude on 07/18/2026
this.det_render = gd.getNextBoolean(); // By Claude on 07/19/2026
this.det_render_save = gd.getNextBoolean(); // By Claude on 07/19/2026
this.det_render_green = gd.getNextString().trim();// By Claude on 07/19/2026 (item 4 step-4)
this.pose_lean = gd.getNextBoolean(); // By Claude on 07/05/2026
this.pose_full = gd.getNextBoolean(); // By Claude on 07/04/2026
this.pose_corr_save = gd.getNextBoolean(); // By Claude on 07/04/2026
......@@ -484,6 +488,7 @@ public class CuasRtParameters {
properties.setProperty(prefix+"pose_feed16", this.pose_feed16+""); // boolean // By Claude on 07/18/2026
properties.setProperty(prefix+"det_render", this.det_render+""); // boolean // By Claude on 07/19/2026
properties.setProperty(prefix+"det_render_save", this.det_render_save+"");// boolean // By Claude on 07/19/2026
properties.setProperty(prefix+"det_render_green",this.det_render_green); // String // By Claude on 07/19/2026 (item 4 step-4)
properties.setProperty(prefix+"pose_lean", this.pose_lean+""); // boolean // By Claude on 07/05/2026
properties.setProperty(prefix+"pose_full", this.pose_full+""); // boolean // By Claude on 07/04/2026
properties.setProperty(prefix+"pose_corr_save", this.pose_corr_save+""); // boolean // By Claude on 07/04/2026
......@@ -598,6 +603,7 @@ public class CuasRtParameters {
if (properties.getProperty(prefix+"pose_feed16")!=null) this.pose_feed16=Boolean.parseBoolean(properties.getProperty(prefix+"pose_feed16")); // By Claude on 07/18/2026
if (properties.getProperty(prefix+"det_render")!=null) this.det_render=Boolean.parseBoolean(properties.getProperty(prefix+"det_render")); // By Claude on 07/19/2026
if (properties.getProperty(prefix+"det_render_save")!=null) this.det_render_save=Boolean.parseBoolean(properties.getProperty(prefix+"det_render_save"));// By Claude on 07/19/2026
if (properties.getProperty(prefix+"det_render_green")!=null)this.det_render_green=properties.getProperty(prefix+"det_render_green").trim(); // By Claude on 07/19/2026 (item 4 step-4)
if (properties.getProperty(prefix+"pose_lean")!=null) this.pose_lean=Boolean.parseBoolean(properties.getProperty(prefix+"pose_lean")); // By Claude on 07/05/2026
if (properties.getProperty(prefix+"pose_full")!=null) this.pose_full=Boolean.parseBoolean(properties.getProperty(prefix+"pose_full")); // By Claude on 07/04/2026
if (properties.getProperty(prefix+"pose_corr_save")!=null) this.pose_corr_save=Boolean.parseBoolean(properties.getProperty(prefix+"pose_corr_save")); // By Claude on 07/04/2026
......@@ -715,6 +721,7 @@ public class CuasRtParameters {
cp.pose_feed16 = this.pose_feed16; // By Claude on 07/18/2026
cp.det_render = this.det_render; // By Claude on 07/19/2026
cp.det_render_save = this.det_render_save; // By Claude on 07/19/2026
cp.det_render_green = this.det_render_green; // By Claude on 07/19/2026 (item 4 step-4)
cp.pose_lean = this.pose_lean;
cp.pose_full = this.pose_full; // By Claude on 07/04/2026
cp.pose_corr_save = this.pose_corr_save; // By Claude on 07/04/2026
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment