mirror of
https://dev.lirent.ru/Vatrog/vm-automation-signaling.git
synced 2026-07-11 17:46:37 +03:00
feat(vgpu): coherent sub-rect capture in perception
Persistent capture window over a fixed sub-rectangle of the captured surface. open() allocates a stable buffer once; sync() re-fills it all-or-nothing from the current latest frame under one seqlock window (byte-exact, never torn). Pull only - no poll/thread inside; the caller drives. FLAT/ROWS layouts and BGRA/RGB24 formats chosen at open, orthogonal. Strict skip when the rect does not fit the current frame; no frame_id dedup. Extract read_field into perception-internal.h as vgpup_read_field to share the producer-field read between sample.c and capture.c. Bump version to 0.3.14.
This commit is contained in:
@@ -234,6 +234,84 @@ int vgpup_read_status(vgpup_region* r, vmie_mem* m, vgpup_status* out);
|
||||
* value; it holds no reset policy (what to reset is the caller's decision). */
|
||||
uint32_t vgpup_run_epoch(const vgpup_region* r);
|
||||
|
||||
/* ---- region capture: coherent pull of a sub-rectangle of the CURRENT frame -- *
|
||||
* A persistent window over a fixed sub-rectangle of the captured surface. Open
|
||||
* allocates a STABLE buffer once (address fixed across syncs); each sync re-fills
|
||||
* it, all-or-nothing, from the CURRENT latest frame under one seqlock window
|
||||
* (byte-exact, never torn — pixels may carry encrypted structures). Pull only: no
|
||||
* poll / sleep / thread inside; the caller drives. NOT zero-copy: the rect crosses
|
||||
* pages and must survive a seqlock re-check, so it is copied via gva_read (zero-copy
|
||||
* would be live, hence non-coherent). Unlike vgpup_sample_frame there is NO frame_id
|
||||
* dedup: each sync yields the coherent rect of the current frame even if frame_id is
|
||||
* unchanged (info reports frame_id so the caller may dedup itself). */
|
||||
|
||||
/* Rectangle in captured-surface pixels; (0,0) = top-left; bounds are validated at
|
||||
* sync time against the CURRENT frame's desc.width/height. No geometry translation. */
|
||||
typedef struct { uint32_t x, y, w, h; } vgpup_rect;
|
||||
|
||||
/* Destination layout (chosen at open, orthogonal to format). */
|
||||
enum { VGPUP_LAYOUT_FLAT = 0, /* one contiguous block, rows back-to-back */
|
||||
VGPUP_LAYOUT_ROWS = 1 }; /* H separate row blocks; rows[] points at each */
|
||||
|
||||
/* Destination pixel format (chosen at open, orthogonal to layout). Source is ABI
|
||||
* VGPU_FMT_BGRA8888 (4 bpp, memory order B,G,R,A, stride == width*4). */
|
||||
enum { VGPUP_PX_BGRA = 0, /* 4 bpp, verbatim B,G,R,A from source */
|
||||
VGPUP_PX_RGB24 = 1 }; /* 3 bpp, BGRA->RGB: drop A, out byte order R,G,B */
|
||||
|
||||
/* Opaque capture window; owns the stable buffer(s). Heap-owned by the core. */
|
||||
typedef struct vgpup_capture vgpup_capture;
|
||||
|
||||
/* Per-sync metadata. desc mirrors the current frame; bytes is the TOTAL coherent
|
||||
* payload size: for FLAT == rect.w*rect.h*out_bpp; for ROWS == rect.h*row_bytes
|
||||
* (the sum of the row payloads, padding excluded). out_bpp / row_bytes are also
|
||||
* available via the accessors below. */
|
||||
typedef struct {
|
||||
vgpup_frame_desc desc; /* descriptor of the frame this rect was taken from */
|
||||
uint64_t frame_id; /* == desc.frame_id; surfaced for caller-side dedup */
|
||||
size_t bytes; /* total coherent payload bytes (see above) */
|
||||
} vgpup_capture_info;
|
||||
|
||||
/* Open a capture window over region handle r for sub-rectangle `rect`, with the
|
||||
* given layout (VGPUP_LAYOUT_*) and format (VGPUP_PX_*). r MUST outlive the window
|
||||
* (open caches proc_cr3 + ring_gva from r; sync does not take r). rect.w/h must be
|
||||
* > 0 and rect.x+rect.w / rect.y+rect.h must not exceed the ABI ceilings
|
||||
* (VGPU_MAX_WIDTH / VGPU_MAX_HEIGHT) — per-frame fit is checked at sync. Returns a
|
||||
* heap-owned window, or NULL on bad args / bad enum / allocation failure.
|
||||
*
|
||||
* If a later sync returns <0 (producer restarted), the old window is invalid: the
|
||||
* caller re-discovers (vgpup_close + vgpup_open) and must vgpup_capture_close this
|
||||
* window and re-open a fresh one on the new region handle. */
|
||||
vgpup_capture* vgpup_capture_open(vgpup_region* r, vgpup_rect rect,
|
||||
int layout, int format);
|
||||
|
||||
/* Coherently re-fill the stable buffer from the CURRENT latest frame, under one
|
||||
* seqlock window (fill, then re-check seq unchanged & even; changed -> retry up to
|
||||
* VGPUP_SEQLOCK_RETRIES). m is BORROWED (== vmie_win32_mem(v)). Returns:
|
||||
* 1 = stable buffer now holds the COHERENT rect (info filled);
|
||||
* 0 = no frame yet / writer busy past the retry limit / rect does not fit the
|
||||
* current frame (lossy SKIP — buffer is INVALID, do not consume, as with
|
||||
* vgpup_sample_frame partial writes);
|
||||
* <0 = hard read error (producer restarted -> caller re-discovers).
|
||||
* NO frame_id dedup: a repeat sync of the same frame returns 1 again. */
|
||||
int vgpup_capture_sync(vgpup_capture* c, vmie_mem* m, vgpup_capture_info* info);
|
||||
|
||||
/* Buffer geometry, fixed at open (do not change across syncs). */
|
||||
uint32_t vgpup_capture_out_bpp(const vgpup_capture* c); /* 4 (BGRA) | 3 (RGB24) */
|
||||
uint32_t vgpup_capture_row_bytes(const vgpup_capture* c); /* rect.w * out_bpp */
|
||||
uint32_t vgpup_capture_row_count(const vgpup_capture* c); /* rect.h */
|
||||
|
||||
/* FLAT accessors: one contiguous block, rows back-to-back, sub-stride == row_bytes,
|
||||
* pixel (x,y) at mem[(y*rect.w + x) * out_bpp]. NULL/0 if the window is ROWS. */
|
||||
const uint8_t* vgpup_capture_mem(const vgpup_capture* c);
|
||||
size_t vgpup_capture_bytes(const vgpup_capture* c); /* row_bytes*row_count */
|
||||
|
||||
/* ROWS accessors: an array of row_count pointers, each at a row_bytes block. The
|
||||
* pointer array and the blocks are stable across syncs. NULL if the window is FLAT. */
|
||||
const uint8_t* const* vgpup_capture_rows(const vgpup_capture* c);
|
||||
|
||||
/* Release the window and its buffer(s). Does NOT touch r / m. Safe on NULL. */
|
||||
void vgpup_capture_close(vgpup_capture* c);
|
||||
|
||||
/* ---- control-write — SEAM ONLY (this never writes) ------------------------ */
|
||||
|
||||
/* Desired control-block value (host-RW fields). The caller builds it and later
|
||||
|
||||
Reference in New Issue
Block a user