Commit 65c4e35c authored by Andrey Filippov's avatar Andrey Filippov

CODEX: Keep lean pose tasks on GPU

Co-authored-by: 's avatarCodex <codex@elphel.com>
parent af31ed3d
...@@ -311,6 +311,7 @@ public class CuasPoseRT { ...@@ -311,6 +311,7 @@ public class CuasPoseRT {
null, center_disparity, scene_xyz, scene_atr, scene, center_CLT); null, center_disparity, scene_xyz, scene_atr, scene, center_CLT);
final double disparity_corr = clt_parameters.imp.disparity_corr + center_CLT.getDispInfinityRef(); final double disparity_corr = clt_parameters.imp.disparity_corr + center_CLT.getDispInfinityRef();
final TpTask [][] cons_tasks; // the convert task sets, hoisted for the consolidation OOB filter // By Claude on 07/12/2026 final TpTask [][] cons_tasks; // the convert task sets, hoisted for the consolidation OOB filter // By Claude on 07/12/2026
final boolean resident_tasks; // post-offset slots stay native on the JNA MB path // By Codex on 07/15/2026
if (mb_vectors != null) { if (mb_vectors != null) {
// Motion-blur compensation (lean v2, the certified CuasRender chain): two task // Motion-blur compensation (lean v2, the certified CuasRender chain): two task
// sets, double convert (positive SET + negative shifted SUBTRACT), erase-first // sets, double convert (positive SET + negative shifted SUBTRACT), erase-first
...@@ -357,7 +358,9 @@ public class CuasPoseRT { ...@@ -357,7 +358,9 @@ public class CuasPoseRT {
clt_parameters.corr_blue, clt_parameters.corr_blue,
0, // sensor_mask_inter = 0: convert only 0, // sensor_mask_inter = 0: convert only
ImageDtt.THREADS_MAX, ImageDtt.THREADS_MAX,
debugLevel); debugLevel,
true); // keep post-offset tasks in native slots 0/1
resident_tasks = gpuQuad.supportsResidentTaskSlots();
} else { } else {
final TpTask [] tp_tasks = GpuQuad.setInterTasks( final TpTask [] tp_tasks = GpuQuad.setInterTasks(
scene.getNumSensors(), scene.getNumSensors(),
...@@ -401,6 +404,7 @@ public class CuasPoseRT { ...@@ -401,6 +404,7 @@ public class CuasPoseRT {
if (img_out != null) { if (img_out != null) {
gpuQuad.execConvertDirect(false, null, 1); gpuQuad.execConvertDirect(false, null, 1);
} }
resident_tasks = false;
} }
// 3. the consolidation bridge: GPU v1 chain (JNA backend, on-device, OOB-filtered) // 3. the consolidation bridge: GPU v1 chain (JNA backend, on-device, OOB-filtered)
// with the CPU bridge as the JCuda-backend fallback - see CuasTD.consolidateToSlot0. // with the CPU bridge as the JCuda-backend fallback - see CuasTD.consolidateToSlot0.
...@@ -414,8 +418,16 @@ public class CuasPoseRT { ...@@ -414,8 +418,16 @@ public class CuasPoseRT {
// By Claude on 07/04/2026, falsified-and-reverted per LEAN-07. // By Claude on 07/04/2026, falsified-and-reverted per LEAN-07.
// pose_corr capture: the SAME arrays after updateTasks() filled the GPU-computed // pose_corr capture: the SAME arrays after updateTasks() filled the GPU-computed
// offsets - the exact stream the consolidation flattens. By Claude on 07/13/2026. // offsets - the exact stream the consolidation flattens. By Claude on 07/13/2026.
// Export is the explicit diagnostic exception to residency: read both slots
// only when a pose_corr capture is armed. By Codex on 07/15/2026.
if (resident_tasks && PoseCorrExport.isArmed()) {
gpuQuad.updateTasks(cons_tasks[0], false, 0);
gpuQuad.updateTasks(cons_tasks[1], false, 1);
}
PoseCorrExport.iterTasksPost(scene, cons_tasks); PoseCorrExport.iterTasksPost(scene, cons_tasks);
CuasTD.consolidateToSlot0(gpuQuad, cons_tasks, // By Claude on 07/12/2026 if (resident_tasks) CuasTD.consolidateResidentToSlot0(gpuQuad, cons_tasks,
clt_parameters.curt.oob_soft, clt_parameters.curt.oob_hard);
else CuasTD.consolidateToSlot0(gpuQuad, cons_tasks, // By Claude on 07/12/2026
clt_parameters.curt.oob_soft, clt_parameters.curt.oob_hard); clt_parameters.curt.oob_soft, clt_parameters.curt.oob_hard);
// DEBUG (img_out): render the composite the correlator sees (the weighted average) // DEBUG (img_out): render the composite the correlator sees (the weighted average)
if (img_out != null) { if (img_out != null) {
......
...@@ -280,6 +280,35 @@ public class CuasTD { ...@@ -280,6 +280,35 @@ public class CuasTD {
gpuQuad.setCltData(0, avg_td, false); gpuQuad.setCltData(0, avg_td, false);
} }
/**
* Lean JNA path: consume the task streams that geometry updated in native
* slots 0/1. If that native call fails, read the slots back before using the
* ordinary host-task bridge, preserving a correct fallback. By Codex on
* 07/15/2026.
*/
public static void consolidateResidentToSlot0(
final GpuQuad gpuQuad,
final TpTask [][] tp_tasks,
final double soft_margin,
final double hard_margin) {
if (!gpuQuad.supportsResidentTaskSlots()) {
consolidateToSlot0(gpuQuad, tp_tasks, soft_margin, hard_margin);
return;
}
if (gpuQuad.execConsolidateResidentTasksTD(tp_tasks, soft_margin, hard_margin)) {
if (!gpu_bridge_reported) {
gpu_bridge_reported = true;
System.out.println("CuasTD.consolidateResidentToSlot0(): GPU consolidation active (soft/hard = "+
soft_margin+"/"+hard_margin+" px, task slots stay resident)");
}
return;
}
for (int nset = 0; nset < Math.min(2, tp_tasks.length); nset++) {
if (tp_tasks[nset] != null) gpuQuad.updateTasks(tp_tasks[nset], false, nset);
}
consolidateToSlot0(gpuQuad, tp_tasks, soft_margin, hard_margin);
}
/** /**
* Validate the consolidation against the linearity oracle: imclt is linear, so * Validate the consolidation against the linearity oracle: imclt is linear, so
* imclt(TD-average of sensors) must equal the pixel-domain average of the * imclt(TD-average of sensors) must equal the pixel-domain average of the
......
...@@ -1025,6 +1025,25 @@ public class GpuQuad{ // quad camera description ...@@ -1025,6 +1025,25 @@ public class GpuQuad{ // quad camera description
} }
} }
/**
* Upload a task stream into an explicit resident slot. The JCuda backend has
* one task buffer, so its compatibility implementation ignores {@code slot}.
* GpuQuadJna overrides this with two persistent native slots used by the lean
* motion-blur chain. By Codex on 07/15/2026.
*/
public void setTasks(
TpTask [] tile_tasks,
boolean use_aux,
boolean verify,
int slot) {
setTasks(tile_tasks, use_aux, verify);
}
/** @return true when explicit resident task slots are implemented. */
public boolean supportsResidentTaskSlots() {
return false;
}
/** /**
* Update tp_tasks from the GPU after derived coordinates are calculated * Update tp_tasks from the GPU after derived coordinates are calculated
* *
...@@ -1058,6 +1077,14 @@ public class GpuQuad{ // quad camera description ...@@ -1058,6 +1077,14 @@ public class GpuQuad{ // quad camera description
System.out.println("======updateTasks()"); System.out.println("======updateTasks()");
} }
} }
/** Read back one explicit task slot; compatibility implementation reads the live buffer. */
public void updateTasks(
TpTask [] tile_tasks,
boolean use_aux,
int slot) {
updateTasks(tile_tasks, use_aux);
}
public TpTask [] readbackTasks( public TpTask [] readbackTasks(
int num_tasks, int num_tasks,
int num_sensors, int num_sensors,
...@@ -1386,6 +1413,18 @@ public class GpuQuad{ // quad camera description ...@@ -1386,6 +1413,18 @@ public class GpuQuad{ // quad camera description
return false; // JCuda backend: not implemented (CPU bridge fallback) return false; // JCuda backend: not implemented (CPU bridge fallback)
} }
/**
* Consolidate the post-geometry task streams already held in explicit GPU
* slots. Only the JNA backend implements this; callers must fall back to the
* host-task method when false is returned. By Codex on 07/15/2026.
*/
public boolean execConsolidateResidentTasksTD(
TpTask [][] tp_tasks,
double soft_margin,
double hard_margin) {
return false;
}
public void setCltData( // for testing only public void setCltData( // for testing only
float [][] fclt, // float [][] fclt, //
boolean use_ref){ boolean use_ref){
......
...@@ -165,6 +165,32 @@ public class GpuQuadJna extends GpuQuad { ...@@ -165,6 +165,32 @@ public class GpuQuadJna extends GpuQuad {
return true; return true;
} }
// Lean-chain fast path: geometry already updated task slots 0/1 in place, so
// consolidation consumes those device buffers without rebuilding TpTask on
// the host or uploading the flattened streams again. By Codex on 07/15/2026.
@Override public boolean execConsolidateResidentTasksTD(
TpTask [][] tp_tasks, double soft_margin, double hard_margin) {
if ((tp_tasks == null) || (tp_tasks.length < 1) ||
(tp_tasks[0] == null) || (tp_tasks[0].length == 0)) return false;
final int task_size = tp_tasks[0][0].getSize();
final int slot1 = ((tp_tasks.length > 1) && (tp_tasks[1] != null)) ? 1 : -1;
final int [] stats = new int [3];
int rc = lib.tp_proc_exec_consolidate_slots(proc, 0, slot1,
tp_tasks[0].length, task_size,
(float) soft_margin, (float) hard_margin, stats);
if (rc != 0) {
System.out.println("GpuQuadJna.execConsolidateResidentTasksTD(): native rc=" + rc +
" (" + lib.tp_last_error() + ") - falling back to task readback");
return false;
}
if (stats[2] != 0) {
System.out.println("GpuQuadJna.execConsolidateResidentTasksTD(): WARNING - " + stats[2] +
" misaligned MB pairs (task slots not index-aligned), " +
stats[0] + " pairs -> " + stats[1] + " tiles");
}
return true;
}
/** Native handles for the override implementations (added incrementally). */ /** Native handles for the override implementations (added incrementally). */
protected TpJna lib() { return lib; } protected TpJna lib() { return lib; }
protected Pointer module() { return module; } protected Pointer module() { return module; }
...@@ -297,19 +323,31 @@ public class GpuQuadJna extends GpuQuad { ...@@ -297,19 +323,31 @@ public class GpuQuadJna extends GpuQuad {
// ---- tasks ---- // ---- tasks ----
@Override public void setTasks(TpTask[] tile_tasks, boolean use_aux, boolean verify) { @Override public void setTasks(TpTask[] tile_tasks, boolean use_aux, boolean verify) {
setTasks(tile_tasks, use_aux, verify, 0);
}
@Override public void setTasks(TpTask[] tile_tasks, boolean use_aux, boolean verify, int slot) {
num_task_tiles = tile_tasks.length; num_task_tiles = tile_tasks.length;
int task_size = getTaskSize(); int task_size = getTaskSize();
float[] ftasks = new float[task_size * num_task_tiles]; float[] ftasks = new float[task_size * num_task_tiles];
for (int i = 0; i < num_task_tiles; i++) { tile_tasks[i].task |= 511; tile_tasks[i].asFloatArray(ftasks, i, use_aux); } for (int i = 0; i < num_task_tiles; i++) { tile_tasks[i].task |= 511; tile_tasks[i].asFloatArray(ftasks, i, use_aux); }
lib.tp_proc_set_tasks(proc, ftasks, num_task_tiles, task_size * num_task_tiles); int rc = lib.tp_proc_set_tasks_slot(proc, ftasks, num_task_tiles, task_size * num_task_tiles, slot);
if (rc != 0) throw new IllegalStateException("tp_proc_set_tasks_slot("+slot+") rc="+rc+
" ("+lib.tp_last_error()+")");
} }
@Override public boolean supportsResidentTaskSlots() { return true; }
// Read tasks back after calculate_tiles_offsets (computed centerXY/disp_dist) -> rebuild TpTask[]. // Read tasks back after calculate_tiles_offsets (computed centerXY/disp_dist) -> rebuild TpTask[].
@Override public void updateTasks(TpTask[] tile_tasks, boolean use_aux) { @Override public void updateTasks(TpTask[] tile_tasks, boolean use_aux) {
updateTasks(tile_tasks, use_aux, 0);
}
@Override public void updateTasks(TpTask[] tile_tasks, boolean use_aux, int slot) {
num_task_tiles = tile_tasks.length; num_task_tiles = tile_tasks.length;
int task_size = getTaskSize(); int task_size = getTaskSize();
float[] ftasks = new float[task_size * num_task_tiles]; float[] ftasks = new float[task_size * num_task_tiles];
lib.tp_proc_get_tasks(proc, ftasks, task_size * num_task_tiles); int rc = lib.tp_proc_get_tasks_slot(proc, ftasks, task_size * num_task_tiles, slot);
if (rc != 0) throw new IllegalStateException("tp_proc_get_tasks_slot("+slot+") rc="+rc+
" ("+lib.tp_last_error()+")");
for (int i = 0; i < num_task_tiles; i++) for (int i = 0; i < num_task_tiles; i++)
tile_tasks[i] = new TpTask(getNumSensors(), ftasks, i, use_aux); tile_tasks[i] = new TpTask(getNumSensors(), ftasks, i, use_aux);
} }
......
...@@ -76,6 +76,9 @@ public interface TpJna extends Library { ...@@ -76,6 +76,9 @@ public interface TpJna extends Library {
int tp_proc_set_center_image(Pointer proc, float[] d); int tp_proc_set_center_image(Pointer proc, float[] d);
int tp_proc_set_tasks(Pointer proc, float[] ftasks, int ntiles, int totalFloats); int tp_proc_set_tasks(Pointer proc, float[] ftasks, int ntiles, int totalFloats);
int tp_proc_get_tasks(Pointer proc, float[] out, int totalFloats); int tp_proc_get_tasks(Pointer proc, float[] out, int totalFloats);
/** Explicit persistent task slots (0/1); the selected slot becomes the live kernel stream. */
int tp_proc_set_tasks_slot(Pointer proc, float[] ftasks, int ntiles, int totalFloats, int slot);
int tp_proc_get_tasks_slot(Pointer proc, float[] out, int totalFloats, int slot);
int tp_proc_exec_geometry(Pointer proc, int uniformGrid); int tp_proc_exec_geometry(Pointer proc, int uniformGrid);
/** convert_direct: ref_scene (0/1 -> clt vs clt_ref), erase_clt (-1/0/1), no_kernels (0/1). */ /** convert_direct: ref_scene (0/1 -> clt vs clt_ref), erase_clt (-1/0/1), no_kernels (0/1). */
int tp_proc_exec_convert_direct(Pointer proc, int refScene, int eraseClt, int noKernels); int tp_proc_exec_convert_direct(Pointer proc, int refScene, int eraseClt, int noKernels);
...@@ -91,6 +94,10 @@ public interface TpJna extends Library { ...@@ -91,6 +94,10 @@ public interface TpJna extends Library {
int tp_proc_exec_consolidate(Pointer proc, float[] ftasks0, float[] ftasks1, int tp_proc_exec_consolidate(Pointer proc, float[] ftasks0, float[] ftasks1,
int numEntries, int taskSize, int numEntries, int taskSize,
float softMargin, float hardMargin, int[] stats); float softMargin, float hardMargin, int[] stats);
/** Same consolidation chain, consuming post-geometry task slots directly; slot1 < 0 = no-MB. */
int tp_proc_exec_consolidate_slots(Pointer proc, int slot0, int slot1,
int numEntries, int taskSize,
float softMargin, float hardMargin, int[] stats);
/** Allocate imclt(RBG) + correlation buffers and store corr config. */ /** Allocate imclt(RBG) + correlation buffers and store corr config. */
int tp_proc_setup_rbg_corr(Pointer proc, int numPairs, int s0,int s1,int s2,int s3, int tp_proc_setup_rbg_corr(Pointer proc, int numPairs, int s0,int s1,int s2,int s3,
float cw0,float cw1,float cw2, int corrOutRad); float cw0,float cw1,float cw2, int corrOutRad);
......
...@@ -1323,6 +1323,40 @@ public class ImageDtt extends ImageDttCPU { ...@@ -1323,6 +1323,40 @@ public class ImageDtt extends ImageDttCPU {
final int threadsMax, // maximal number of threads to launch final int threadsMax, // maximal number of threads to launch
final int globalDebugLevel) final int globalDebugLevel)
{ {
interCorrTDMotionBlur(
imgdtt_params, erase_clt_first, tp_tasks, fcorr_td,
gpu_sigma_r, gpu_sigma_b, gpu_sigma_g, gpu_sigma_m,
gpu_sigma_rb_corr, gpu_sigma_corr, gpu_sigma_log_corr,
corr_red, corr_blue, sensor_mask_inter, threadsMax, globalDebugLevel,
false);
}
/**
* Erase-capable MB conversion with an opt-in resident-task contract. When the
* backend supports slots, geometry updates slots 0/1 in place and host task
* reconstruction is skipped; the caller must use consolidateResidentToSlot0.
* By Codex on 07/15/2026.
*/
public void interCorrTDMotionBlur(
final ImageDttParameters imgdtt_params,
final int erase_clt_first,
final TpTask[][] tp_tasks,
final float [][][][] fcorr_td,
final double gpu_sigma_r,
final double gpu_sigma_b,
final double gpu_sigma_g,
final double gpu_sigma_m,
final double gpu_sigma_rb_corr,
final double gpu_sigma_corr,
final double gpu_sigma_log_corr,
final double corr_red,
final double corr_blue,
final int sensor_mask_inter,
final int threadsMax,
final int globalDebugLevel,
final boolean keep_tasks_resident)
{
final boolean resident_tasks = keep_tasks_resident && gpuQuad.supportsResidentTaskSlots();
final int numcol = isMonochrome()?1:3; final int numcol = isMonochrome()?1:3;
final double [] col_weights= new double [numcol]; // colors are RBG final double [] col_weights= new double [numcol]; // colors are RBG
if (isMonochrome()) { if (isMonochrome()) {
...@@ -1362,7 +1396,8 @@ public class ImageDtt extends ImageDttCPU { ...@@ -1362,7 +1396,8 @@ public class ImageDtt extends ImageDttCPU {
log_flat, log_flat,
globalDebugLevel > 2); globalDebugLevel > 2);
// set primary tasks and perform direct conversion to TD // set primary tasks and perform direct conversion to TD
gpuQuad.setTasks( // copy tp_tasks to the GPU memory if (resident_tasks) gpuQuad.setTasks(tp_tasks[0], false, imgdtt_params.gpu_verify, 0);
else gpuQuad.setTasks( // copy tp_tasks to the GPU memory
tp_tasks[0], // TpTask [] tile_tasks, tp_tasks[0], // TpTask [] tile_tasks,
false, // use_aux); // boolean use_aux) false, // use_aux); // boolean use_aux)
imgdtt_params.gpu_verify); // boolean verify imgdtt_params.gpu_verify); // boolean verify
...@@ -1376,7 +1411,7 @@ public class ImageDtt extends ImageDttCPU { ...@@ -1376,7 +1411,7 @@ public class ImageDtt extends ImageDttCPU {
// Why always NON-UNIFORM grid? Already set in tp_tasks // Why always NON-UNIFORM grid? Already set in tp_tasks
gpuQuad.execSetTilesOffsets(false); // false); // prepare tiles offsets in GPU memory, using NON-UNIFORM grid (pre-calculated) gpuQuad.execSetTilesOffsets(false); // false); // prepare tiles offsets in GPU memory, using NON-UNIFORM grid (pre-calculated)
// update tp_tasks // update tp_tasks
gpuQuad.updateTasks( if (!resident_tasks) gpuQuad.updateTasks(
tp_tasks[0], tp_tasks[0],
false); // boolean use_aux // while is it in class member? - just to be able to free false); // boolean use_aux // while is it in class member? - just to be able to free
...@@ -1384,14 +1419,15 @@ public class ImageDtt extends ImageDttCPU { ...@@ -1384,14 +1419,15 @@ public class ImageDtt extends ImageDttCPU {
gpuQuad.execConvertDirect(false, null, erase_clt_first); // Convert primary image (erase per erase_clt_first; each task tile is SET as scales > 0) // By Claude on 07/05/2026 gpuQuad.execConvertDirect(false, null, erase_clt_first); // Convert primary image (erase per erase_clt_first; each task tile is SET as scales > 0) // By Claude on 07/05/2026
// set secondary tasks and perform direct conversion to TD, subtracting from the converted primary // set secondary tasks and perform direct conversion to TD, subtracting from the converted primary
gpuQuad.setTasks( // copy tp_tasks to the GPU memory if (resident_tasks) gpuQuad.setTasks(tp_tasks[1], false, imgdtt_params.gpu_verify, 1);
else gpuQuad.setTasks( // copy tp_tasks to the GPU memory
tp_tasks[1], // TpTask [] tile_tasks, tp_tasks[1], // TpTask [] tile_tasks,
false, // use_aux); // boolean use_aux) false, // use_aux); // boolean use_aux)
imgdtt_params.gpu_verify); // boolean verify imgdtt_params.gpu_verify); // boolean verify
// Why always NON-UNIFORM grid? Already set in tp_tasks // Why always NON-UNIFORM grid? Already set in tp_tasks
gpuQuad.execSetTilesOffsets(false); // false); // prepare tiles offsets in GPU memory, using NON-UNIFORM grid (pre-calculated) gpuQuad.execSetTilesOffsets(false); // false); // prepare tiles offsets in GPU memory, using NON-UNIFORM grid (pre-calculated)
// update tp_tasks // update tp_tasks
gpuQuad.updateTasks( if (!resident_tasks) gpuQuad.updateTasks(
tp_tasks[1], tp_tasks[1],
false); // boolean use_aux // while is it in class member? - just to be able to free false); // boolean use_aux // while is it in class member? - just to be able to free
gpuQuad.execConvertDirect(false, null, -1); // Convert secondary image, no erase (each tile will be SUBTRACTED as scales < 0) gpuQuad.execConvertDirect(false, null, -1); // Convert secondary image, no erase (each tile will be SUBTRACTED as scales < 0)
......
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