Commit 6ec3ea29 authored by Andrey Filippov's avatar Andrey Filippov

CLAUDE: item-4 R2 - GPU LoG + gated subtract-avg in the RT loop; render ARM pre-loop; enqueue shave

R2 (rulings 3.1/3.3/3.4): CuasPoseRT arms the LoG+subtract-average stage with
the render - taps from the static getLoGKenel (psf_radius/n_sigma, the same
params detection uses); curt.det_avg_file (prior-run raw-domain average)
LoG'd in Java DOUBLE at arm = the post-LoG base; gated EMA refresh
(det_ema_rate 0.02 / det_ema_gate 10.0 placeholder dial, ungated = loud
warning); detection frame (LoG - avg) stays GPU-resident. Post-loop saves
-CUAS-RT-AVG (NaN-aware run average + count = the next run's prior file,
skipped if the stage disabled mid-run) and the -CUAS-RT-LOG debug stack
(det_log_save, ruling 3.4 test-only). New saved params det_log/det_log_save/
det_avg_file/det_avg_save/det_ema_rate/det_ema_gate (all 5 touch-points).

Fold-in 1 (Session-54 close): the whole render ARM (renderSetup allocs +
template + reference camera + R2 arm) hoisted PRE-LOOP next to
renderProcPrepare - the scene-0 101/108 ms alloc-class outlier is gone;
content-neutral (cv static per sequence; pXpYD_center + setReferenceGPU
precede the arm). In-loop lazy arm removed (armed assertion, same fail-safe).

Fold-in 2: GpuQuadJna.renderCameras static-table latch - first scene uploads
radial/rByRDist once, then per-scene calls pass null and the native fast
path sends meta+ERS pinned+async (renderSetup resets the latch per sequence).

GpuQuad/GpuQuadJna/TpJna: renderLogSetup/renderLogGet surface. Stage0
EXPECTED_KERNELS 42 -> 45 (42 was stale - the render_dp bump to 43 was
missed) and Stage0 passes 45/45. mvn package + test PASS; native gates in
tile_processor_gpu 8840db8 (case log_pipe ALL PASS, sanitizer 0).
Co-Authored-By: 's avatarClaude Fable 5 <noreply@anthropic.com>
parent 3b33a397
......@@ -3064,6 +3064,16 @@ public class GpuQuad{ // quad camera description
throw new UnsupportedOperationException("renderStatus: JNA backend only"); }
public float [] renderGet() {
throw new UnsupportedOperationException("renderGet: JNA backend only"); }
/** item-4 R2 (07/19/2026): arm the GPU pixel-LoG + post-LoG subtract-average stage on the
* resident render frame (all alloc-class work at arm time). avg_init = post-LoG base
* (prior-run average LoG'd in Java double) or null (NaN start). By Claude on 07/19/2026. */
public boolean renderLogSetup(float [] taps, int krad, float [] avg_init,
double ema_k, double gate_abs, boolean accum, boolean want_raw) {
throw new UnsupportedOperationException("renderLogSetup: JNA backend only"); }
/** item-4 R2: D2H of an R2 buffer (debug/eval + end-of-run average save; never per-scene
* in production). which: 0=diff, 1=avg, 2=raw LoG, 3=accum sum, 4=accum count. */
public float [] renderLogGet(int which) {
throw new UnsupportedOperationException("renderLogGet: JNA backend only"); }
/** Store the per-scene measure-cycle descriptor (union of the fixed chain's stage args). */
public boolean setPoseCycleConfig(
int num_tasks, int task_size,
......
......@@ -863,6 +863,7 @@ public class GpuQuadJna extends GpuQuad {
if (rc != 0) {
throw new IllegalStateException("GpuQuadJna.renderSetup rc="+rc+": "+lib.tp_last_error());
}
render_scene_static_uploaded = false; // per-sequence: next scene camera re-uploads radial/rbr // By Claude on 07/19/2026
return true;
}
@Override public boolean renderTemplate(final int [] task_map, final float [] task_centers) {
......@@ -875,8 +876,16 @@ public class GpuQuadJna extends GpuQuad {
}
return true;
}
// item-4 R2 enqueue shave (07/19/2026): the scene camera's radial/rByRDist
// are per-sequence calibration constants (same physical camera every
// scene) - upload them ONCE (first scene, full blocking path), then pass
// null so the native fast path sends only meta+ERS, packed pinned + async
// on the render stream (no stream-sync, no 20 KB JNA marshal per scene).
// renderSetup() resets the latch (per-sequence re-arm, rerun == fresh).
private boolean render_scene_static_uploaded = false;
@Override public boolean renderCameras(final IntersceneLmaFloat.Camera reference,
final IntersceneLmaFloat.Camera scene) {
final boolean scene_fast = (scene != null) && (reference == null) && render_scene_static_uploaded;
final int rc = lib.tp_proc_render_cameras(
rproc(),
(reference != null) ? poseCameraMeta(reference) : null,
......@@ -886,14 +895,15 @@ public class GpuQuadJna extends GpuQuad {
(reference != null) ? reference.ers : null,
(reference != null) ? reference.ers.length : 0,
(scene != null) ? poseCameraMeta(scene) : null,
(scene != null) ? scene.radial : null,
(scene != null) ? scene.rByRDist : null,
(scene != null) ? scene.rByRDist.length : 0,
(scene != null) ? (scene_fast ? null : scene.radial) : null,
(scene != null) ? (scene_fast ? null : scene.rByRDist) : null,
(scene != null) ? (scene_fast ? 0 : scene.rByRDist.length) : 0,
(scene != null) ? scene.ers : null,
(scene != null) ? scene.ers.length : 0);
if (rc != 0) {
throw new IllegalStateException("GpuQuadJna.renderCameras rc="+rc+": "+lib.tp_last_error());
}
if ((scene != null) && !scene_fast) render_scene_static_uploaded = true;
return true;
}
@Override public boolean renderScene(final float [] reference_xyz, final float [] reference_atr,
......@@ -931,6 +941,27 @@ public class GpuQuadJna extends GpuQuad {
System.arraycopy(packed, tl + gpu_width * nrow, fimg, out_width * nrow, out_width);
return fimg;
}
// ---- item-4 R2 (07/19/2026): GPU pixel-LoG + post-LoG subtract-average on
// the resident render frame (kernels enqueued by renderScene after the
// render_dp chain; sensor-window packed). By Claude on 07/19/2026. ----
@Override public boolean renderLogSetup(final float [] taps, final int krad, final float [] avg_init,
final double ema_k, final double gate_abs, final boolean accum, final boolean want_raw) {
final int rc = lib.tp_proc_render_log_setup(rproc(), taps, krad,
avg_init, (avg_init != null) ? avg_init.length : 0,
(float) ema_k, (float) gate_abs, accum ? 1 : 0, want_raw ? 1 : 0);
if (rc != 0) {
throw new IllegalStateException("GpuQuadJna.renderLogSetup rc="+rc+": "+lib.tp_last_error());
}
return true;
}
@Override public float [] renderLogGet(final int which) { // blocking D2H (debug/eval + avg save)
final float [] out = new float [getImageWidth() * getImageHeight()];
final int rc = lib.tp_proc_render_log_get(rproc(), which, out);
if (rc != 1) {
throw new IllegalStateException("GpuQuadJna.renderLogGet("+which+") rc="+rc+": "+lib.tp_last_error());
}
return out;
}
// ---- 3-B rung B3: single measure-chain entry (design 2026-07-16) ---- // By Claude on 07/16/2026
@Override public boolean supportsPoseMeasureCycle() { return !rectilinear; }
......
......@@ -10,7 +10,7 @@ import com.sun.jna.Pointer;
* com.elphel.imagej.gpu.jna.Stage0 [kernel_src_dir] [libcudadevrt.a]
*/
public class Stage0 {
private static final int EXPECTED_KERNELS = 42; // 41 (through margin rung M1) + condition_lwir_u16 (T2 16-bit feeder) // By Claude on 07/18/2026
private static final int EXPECTED_KERNELS = 45; // 42 (through T2) + render_dp (item-4 R1a, missed bump) + render_pix_log + render_avg_accum (item-4 R2) // By Claude on 07/19/2026
public static void main(String[] args) {
String srcdir = (args.length > 0) ? args[0] : "/home/elphel/git/tile_processor_gpu/src";
String devrt = (args.length > 1) ? args[1] : "/usr/local/cuda/targets/x86_64-linux/lib/libcudadevrt.a";
......
......@@ -335,6 +335,22 @@ public interface TpJna extends Library {
* 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);
// ---- item-4 R2 (07/19/2026): pixel-LoG + post-LoG subtract-average on the
// resident render frame, enqueued after render_dp on the render stream. ----
/** Arm the LoG/subtract-avg stage (ALL allocations happen here - the
* standing no-alloc-in-loop rule). taps = (2*krad+1)^2 LoG taps; avgInit =
* post-LoG-domain base (prior-run average file LoG'd in Java double) of
* imgW*imgH floats or null (NaN start: EMA seeds from the first frame;
* emaK=0 keeps the diff NaN there). Re-call per sequence resets avg +
* accumulators (rerun == fresh). 0 on success. By Claude on 07/19/2026. */
int tp_proc_render_log_setup(Pointer proc, float[] taps, int krad,
float[] avgInit, int avgLen,
float emaK, float gateAbs, int accumEnable, int wantRaw);
/** D2H of an R2 buffer (debug/eval + the end-of-run average save; never
* per-scene in production). which: 0=diff (detection frame), 1=avg
* (post-LoG), 2=raw LoG, 3=accum sum, 4=accum count. Blocking; out =
* imgW*imgH floats (sensor window, packed). 1 on success. */
int tp_proc_render_log_get(Pointer proc, int which, float[] out);
// ---- 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. ----
......
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