run another check against the duplication api. Also fix mac building with CGO enabled.
This commit is contained in:
@@ -92,6 +92,8 @@ WORKDIR /app
|
||||
|
||||
# openssl/ca-certificates: TLS cert generation + HTTPS validation.
|
||||
# wget/tar/unzip/xz-utils: required by toolchain-manager for on-demand downloads.
|
||||
# clang: fallback C compiler for darwin/CGO agent builds (no toolchain mapping in
|
||||
# toolchain-manager.ts, so build-process.ts falls back to the default `cc`).
|
||||
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||||
--mount=type=cache,target=/var/lib/apt,sharing=locked \
|
||||
apt-get update && apt-get install -y --no-install-recommends \
|
||||
@@ -102,6 +104,7 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||||
unzip \
|
||||
xz-utils \
|
||||
git \
|
||||
clang \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Reuse Go + garble from the builder so we don't re-download.
|
||||
|
||||
@@ -304,9 +304,10 @@ func safeActiveDisplays() int {
|
||||
}
|
||||
|
||||
func safeCaptureDisplay(display int) (*image.RGBA, error) {
|
||||
defer func() {
|
||||
_ = recover()
|
||||
}()
|
||||
// Log panics with a stack trace so the actual culprit is captured in the
|
||||
// crash log instead of being silently swallowed (returns nil image, which
|
||||
// the caller treats as a transient capture failure).
|
||||
defer recoverAndLog("safeCaptureDisplay", nil)
|
||||
img, err := captureDisplayFn(display)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -701,12 +701,18 @@ func (s *duplicationState) capture(display int) (*image.RGBA, error) {
|
||||
}
|
||||
if s.lastBase != nil {
|
||||
img := s.composeFrame(s.lastBase, int(s.desc.ModeDesc.Width), int(s.desc.ModeDesc.Height))
|
||||
s.lastFrame = img
|
||||
// composeFrame may return s.lastBase or s.cursorScratch directly;
|
||||
// both are reused across captures, so the caller's PutRGBA would
|
||||
// hand them to the pool and a subsequent capture would race.
|
||||
if img == s.lastBase || img == s.cursorScratch {
|
||||
img = cloneRGBA(img)
|
||||
}
|
||||
s.lastFrame = cloneRGBA(img)
|
||||
s.lastFrameAt = time.Now()
|
||||
return img, nil
|
||||
}
|
||||
if s.lastFrame != nil {
|
||||
return s.lastFrame, nil
|
||||
return cloneRGBA(s.lastFrame), nil
|
||||
}
|
||||
if waitMs >= 50 {
|
||||
return nil, errors.New("dxgi: frame timeout")
|
||||
@@ -749,22 +755,25 @@ func (s *duplicationState) capture(display int) (*image.RGBA, error) {
|
||||
_ = s.dup.ReleaseFrame()
|
||||
return nil, fmt.Errorf("dxgi: map desktop surface failed 0x%x", hr)
|
||||
}
|
||||
// Unmap and release the frame on every exit, including a panic in
|
||||
// the conversion code below. Leaving the surface mapped wedges the
|
||||
// duplication object until the device is fully closed.
|
||||
dup := s.dup
|
||||
defer func() {
|
||||
_ = dup.UnMapDesktopSurface()
|
||||
_ = dup.ReleaseFrame()
|
||||
}()
|
||||
|
||||
if mapped.Pitch <= 0 || mapped.Bits == nil {
|
||||
_ = s.dup.UnMapDesktopSurface()
|
||||
_ = s.dup.ReleaseFrame()
|
||||
return nil, errors.New("dxgi: invalid mapped surface")
|
||||
}
|
||||
|
||||
pitch := int(mapped.Pitch)
|
||||
if pitch < width*4 {
|
||||
_ = s.dup.UnMapDesktopSurface()
|
||||
_ = s.dup.ReleaseFrame()
|
||||
return nil, fmt.Errorf("dxgi: pitch %d too small for width %d", pitch, width)
|
||||
}
|
||||
totalBytes := pitch * height
|
||||
if totalBytes/height != pitch {
|
||||
_ = s.dup.UnMapDesktopSurface()
|
||||
_ = s.dup.ReleaseFrame()
|
||||
return nil, fmt.Errorf("dxgi: pitch*height overflow (%d * %d)", pitch, height)
|
||||
}
|
||||
src := unsafe.Slice(mapped.Bits, totalBytes)
|
||||
@@ -774,8 +783,6 @@ func (s *duplicationState) capture(display int) (*image.RGBA, error) {
|
||||
if img == nil {
|
||||
img = convertBGRA(src, pitch, width, height, s.desc.Rotation)
|
||||
}
|
||||
_ = s.dup.UnMapDesktopSurface()
|
||||
_ = s.dup.ReleaseFrame()
|
||||
if img == nil {
|
||||
return nil, errors.New("dxgi: pixel conversion failed (buffer too small)")
|
||||
}
|
||||
@@ -788,9 +795,17 @@ func (s *duplicationState) capture(display int) (*image.RGBA, error) {
|
||||
}
|
||||
}
|
||||
|
||||
s.lastBase = img
|
||||
// Cache an independent clone so the timeout path (which serves the cached
|
||||
// frame back to callers) doesn't alias a buffer the caller will return to
|
||||
// the RGBA pool via PutRGBA.
|
||||
s.lastBase = cloneRGBA(img)
|
||||
img = s.composeFrame(img, width, height)
|
||||
s.lastFrame = img
|
||||
if img == s.cursorScratch {
|
||||
// cursorScratch is reused across captures; clone before returning so
|
||||
// the next compose doesn't write into a buffer the caller has pooled.
|
||||
img = cloneRGBA(img)
|
||||
}
|
||||
s.lastFrame = cloneRGBA(img)
|
||||
s.lastFrameAt = time.Now()
|
||||
|
||||
return img, nil
|
||||
|
||||
Reference in New Issue
Block a user