diff --git a/Overlord-Client/cmd/agent/capture/h264_encoder_x264.go b/Overlord-Client/cmd/agent/capture/h264_encoder_x264.go index 4f0f99e..0c2bb0b 100644 --- a/Overlord-Client/cmd/agent/capture/h264_encoder_x264.go +++ b/Overlord-Client/cmd/agent/capture/h264_encoder_x264.go @@ -66,13 +66,15 @@ func ensureH264EncoderLocked(width, height int) error { closeH264EncoderLocked() opts := &x264.Options{ - Width: width, - Height: height, - FrameRate: 25, - Tune: "zerolatency", - Preset: "ultrafast", - Profile: "baseline", - LogLevel: x264.LogError, + Width: width, + Height: height, + FrameRate: 120, + Tune: "zerolatency,fastdecode", + Preset: "ultrafast", + Profile: "baseline", + RateControl: "crf", + RateConstant: 30, + LogLevel: x264.LogError, } enc, err := x264.NewEncoder(&h264Buf, opts) diff --git a/Overlord-Client/cmd/agent/capture/win_duplication.go b/Overlord-Client/cmd/agent/capture/win_duplication.go index 8511da3..2d737f9 100644 --- a/Overlord-Client/cmd/agent/capture/win_duplication.go +++ b/Overlord-Client/cmd/agent/capture/win_duplication.go @@ -686,7 +686,7 @@ func (s *duplicationState) capture(display int) (*image.RGBA, error) { var info dxgiOutDuplFrameInfo var resource *iunknown - hr := s.dup.AcquireNextFrame(50, &info, &resource) + hr := s.dup.AcquireNextFrame(5, &info, &resource) if hr == dxgiErrorWaitTimeout { if s.lastBase != nil { img := s.composeFrame(s.lastBase) @@ -756,14 +756,27 @@ func (s *duplicationState) composeFrame(base *image.RGBA) *image.RGBA { if base == nil { return nil } - img := cloneRGBA(base) + userScale := captureScale() + withCursor := cursorCaptureEnabled.Load() + + // Fast path: no cursor overlay and no scaling means we can reuse the raw + // frame without an extra clone/copy. + if !withCursor && userScale == 1 { + return base + } + + img := base + if withCursor { + img = cloneRGBA(base) + } bounds := s.bounds if bounds.Dx() != int(s.desc.ModeDesc.Width) || bounds.Dy() != int(s.desc.ModeDesc.Height) { bounds = image.Rect(bounds.Min.X, bounds.Min.Y, bounds.Min.X+int(s.desc.ModeDesc.Width), bounds.Min.Y+int(s.desc.ModeDesc.Height)) } - drawCursorRotated(img, s.cursorBounds, bounds, s.desc.Rotation) + if withCursor { + drawCursorRotated(img, s.cursorBounds, bounds, s.desc.Rotation) + } - userScale := captureScale() rotW := img.Bounds().Dx() rotH := img.Bounds().Dy() dstW := int(float64(rotW) * userScale) @@ -1108,16 +1121,6 @@ func drawCursorRotated(img *image.RGBA, cursorBounds, captureBounds image.Rectan curX := ci.ptScreenPos.x curY := ci.ptScreenPos.y - var icon iconInfo - ret, _, _ = procGetIconInfo.Call(ci.hCursor, uintptr(unsafe.Pointer(&icon))) - if ret != 0 { - if icon.hbmMask != 0 { - defer deleteObject(icon.hbmMask) - } - if icon.hbmColor != 0 { - defer deleteObject(icon.hbmColor) - } - } if cursorBounds.Empty() { cursorBounds = captureBounds } @@ -1151,9 +1154,10 @@ func drawCursorRotated(img *image.RGBA, cursorBounds, captureBounds image.Rectan ry = localY } rotBounds := image.Rect(0, 0, img.Bounds().Dx(), img.Bounds().Dy()) - if !drawRealCursorOnImage(img, ci.hCursor, int32(rx), int32(ry), int32(icon.xHotspot), int32(icon.yHotspot)) { - drawCursor(img, int32(rx), int32(ry), rotBounds) - } + + // Performance-first cursor overlay for duplication path: avoid per-frame + // icon extraction/DC composition and draw a lightweight software cursor. + drawCursor(img, int32(rx), int32(ry), rotBounds) } func drawRealCursorOnImage(img *image.RGBA, hCursor uintptr, hotX, hotY, xHotspot, yHotspot int32) bool {