detbox: lazy atlas rebuild в draw (CUDA context fix)

Bug: cfc_overlay_detbox_upsert вызывался из MQTT thread который не имеет
CUDA primary context active. cuMemAlloc → CUDA_ERROR_INVALID_CONTEXT (201),
text_atlas всегда оставался 0 → подпись не рисовалась.

Fix: rebuild_label_atlas вызывается lazily из draw_detection_boxes
(main composer thread с активным CUDA context). Текст cached по
rendered_text — rebuild только при изменении label/score.

Verify (live на cfc-grid): atlas '...' успешно аллоцируется, snap
видит правильный atlas pointer.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-06-21 21:56:38 +01:00
parent 265c5c9503
commit e57999b6b8
+7 -6
View File
@@ -643,7 +643,6 @@ static void detbox_rebuild_label_atlas(detbox_data_t *d, int slot)
int w = 0, h = 0, ascent = 0; int w = 0, h = 0, ascent = 0;
if (text_measure(face, txt, &w, &h, &ascent) != 0) return; if (text_measure(face, txt, &w, &h, &ascent) != 0) return;
if (w <= 0 || h <= 0) return; if (w <= 0 || h <= 0) return;
unsigned char *cpu = calloc((size_t)w * h, 4); unsigned char *cpu = calloc((size_t)w * h, 4);
if (!cpu) return; if (!cpu) return;
/* Белый текст для контраста с pill background. */ /* Белый текст для контраста с pill background. */
@@ -811,11 +810,9 @@ int cfc_overlay_detbox_upsert(cfc_overlay_t *ov, const char *event_id,
d->entries[slot].y2 = y2; d->entries[slot].y2 = y2;
d->entries[slot].last_update_ms = now_ms(); d->entries[slot].last_update_ms = now_ms();
/* Rebuild label atlas (если label/score изменились). FT render + CUDA /* НЕ rebuild в upsert: upsert вызывается из MQTT thread который не
* upload под mutex'ом — это slow (~few ms), но upsert редкий (cooldown * имеет CUDA context (cuMemAlloc → ERR_INVALID_CONTEXT err=201). Atlas
* детектора 3s × 4 камеры × 2-3 labels ~ 3-4/sec total). Если text * lazily rebuilt в draw из main composer thread. */
* не изменился — no-op. */
detbox_rebuild_label_atlas(d, slot);
pthread_mutex_unlock(&d->mu); pthread_mutex_unlock(&d->mu);
return 0; return 0;
@@ -866,6 +863,10 @@ static int draw_detection_boxes(cfc_overlay_t *ov,
for (int i = 0; i < CFC_DETBOX_MAX; i++) { for (int i = 0; i < CFC_DETBOX_MAX; i++) {
if (!d->entries[i].event_id[0]) continue; if (!d->entries[i].event_id[0]) continue;
if (d->entries[i].last_update_ms < cutoff) continue; /* TTL expired */ if (d->entries[i].last_update_ms < cutoff) continue; /* TTL expired */
/* Lazy rebuild label atlas — выполняется в main composer thread
* где CUDA context активен (upsert thread его не имеет). No-op если
* label/score не изменились. */
detbox_rebuild_label_atlas(d, i);
snap[snap_n].x1 = d->entries[i].x1; snap[snap_n].x1 = d->entries[i].x1;
snap[snap_n].y1 = d->entries[i].y1; snap[snap_n].y1 = d->entries[i].y1;
snap[snap_n].x2 = d->entries[i].x2; snap[snap_n].x2 = d->entries[i].x2;