diff --git a/include/vgpu_stream.h b/include/vgpu_stream.h index a6d665f..1f1adc6 100644 --- a/include/vgpu_stream.h +++ b/include/vgpu_stream.h @@ -69,6 +69,18 @@ typedef struct { uint32_t supported_formats; /* bitmask (1u<producer->full_frame_ack, req); } + +void vgpu_publish_cursor(const vgpu_region_view* rv, int32_t x, int32_t y, uint32_t visible) { + vgpu_producer_t* p = rv->producer; + /* pack: low 32 = x, high 32 = y (signed → two's-complement bits) */ + uint64_t packed = ((uint64_t)(uint32_t)y << 32) | (uint64_t)(uint32_t)x; + /* 64-bit aligned single MOV is atomic on x86_64; barrier orders it (heartbeat pattern) */ + p->cursor_pos = packed; + vgpu_store_release32(&p->cursor_visible, visible); + /* publish seq last: its release-store gates the pos/visible writes above for the host */ + vgpu_store_release32(&p->cursor_seq, p->cursor_seq + 1u); +} diff --git a/src/stream/win32/cursor.c b/src/stream/win32/cursor.c index 46f17ee..2ce60ea 100644 --- a/src/stream/win32/cursor.c +++ b/src/stream/win32/cursor.c @@ -105,6 +105,15 @@ int cursor_sample(vgpu_ctx* ctx) { return changed; } +void cursor_sample_pos(vgpu_ctx* ctx) { + vgpu_cursor_t* cur = &ctx->cursor; + CURSORINFO ci; ci.cbSize = sizeof ci; + if (!GetCursorInfo(&ci)) { cur->visible = 0; return; } + cur->visible = (ci.flags & CURSOR_SHOWING) != 0; + cur->x = ci.ptScreenPos.x; + cur->y = ci.ptScreenPos.y; +} + void cursor_draw(vgpu_ctx* ctx, uint8_t* dst, uint32_t W, uint32_t H) { vgpu_cursor_t* cur = &ctx->cursor; if (!cur->visible || cur->gw == 0) return; diff --git a/src/stream/win32/cursor.h b/src/stream/win32/cursor.h index bb9a5c3..efe52ee 100644 --- a/src/stream/win32/cursor.h +++ b/src/stream/win32/cursor.h @@ -10,6 +10,10 @@ * Returns 1 if anything changed since last sample, else 0. */ int cursor_sample(vgpu_ctx* ctx); +/* Sample only cursor position/visibility (no shape extract). Updates + * ctx->cursor.{visible,x,y}. Cheap (one GetCursorInfo); safe to call every pump tick. */ +void cursor_sample_pos(vgpu_ctx* ctx); + /* Alpha/AND-XOR compose the sampled cursor onto a tight BGRA frame. */ void cursor_draw(vgpu_ctx* ctx, uint8_t* bgra, uint32_t width, uint32_t height); diff --git a/src/stream/win32/present.c b/src/stream/win32/present.c index f07e32e..f31f3fd 100644 --- a/src/stream/win32/present.c +++ b/src/stream/win32/present.c @@ -100,6 +100,12 @@ void vgpu_present_run(vgpu_ctx* ctx) { last_beat = nowt; } + /* --- cursor position: sensor data, reported every tick independent of + * draw_cursor / compositing (host may overlay it itself) --- */ + cursor_sample_pos(ctx); + vgpu_publish_cursor(rv, (int32_t)ctx->cursor.x, (int32_t)ctx->cursor.y, + (uint32_t)(ctx->cursor.visible != 0)); + /* --- reconcile control (gen-seqlock -> apply -> ack) --- */ vgpu_control_view cv; uint32_t desired = prev_state;