0

I am fiddling with recording the screen of Windows Sandbox based on https://github.com/mika-f/dotnet-window-capture :

var hr = _duplication.TryAcquireNextFrame(100, out _, out var desktopResourceOut);
if (hr.Failure)
    return null;

using var desktopTexture = desktopResourceOut.QueryInterface<Texture2D>();
var texture2dDescription = new Texture2DDescription {
    ArraySize = 1,
    BindFlags = BindFlags.ShaderResource | BindFlags.RenderTarget,
    CpuAccessFlags = CpuAccessFlags.None,
    Format = Format.B8G8R8A8_UNorm,
    Height = desktopTexture.Description.Height,
    MipLevels = 1,
    SampleDescription = new SampleDescription(1, 0),
    Usage = ResourceUsage.Default,
    Width = desktopTexture.Description.Width
};
var texture2d = new Texture2D(device, texture2dDescription);
device.ImmediateContext.CopyResource(desktopTexture, texture2d);

// release resources
desktopResourceOut.Dispose();
_duplication.ReleaseFrame();

return texture2d;

Problem is from the start the code works on my own machine and also via RDP. But inside the Windows Sandbox all I get is a blank window.

Now I searched around, and found a few "deficiencies" in the above sample, namely:

  1. All failures of TryAcquireNextFrame are ignored silently.
  2. OutputDuplicateFrameInformation is ignored. Specifically, it never checks LastPresentTime which must be checked according to this SO thread (although that contradicts When AcquireNextFrame returns successfully, the calling application can access the desktop image that AcquireNextFrame returns in the variable at ppDesktopResource from MSDN).

So after fiddling with error handling and OutputDuplicateFrameInformation all I am getting from Windows Sandbox is:

  1. As long as I move mouse around, TryAcquireNextFrame mostly succeeds, however OutputDuplicateFrameInformation.LastPresentTime is always 0.
  2. The only error code I get in simple tests is 0x887A0027 aka timeout, which just indicates the need to wait more as there was no picture update.
  3. If I ignore LastPresentTime == 0, the texture2d comes out black.
  4. I also tried to copy some Texture2DDescription parameters directly from desktopTexture in attempt to avoid potential silent failure of CopyResource as suggested in this SO thread, but that had no visible effect.
  5. I enumerated Adapters and their associated Outputs, and there's only one Output in the system.

The final modification that still exhibits the blank texture2d behavior is

var hr = _duplication.TryAcquireNextFrame(100, out var frameInfo, out var desktopResourceOut);
if (hr.Failure) {
    if (hr.Code == unchecked((int)0x887A0027)) return null; // no changes
    hr.CheckError();
    return null;
}

try {
    //if (frameInfo.LastPresentTime == 0) {
    //    return null; // in Sandbox all frames go here
    //}

    using var desktopTexture = desktopResourceOut.QueryInterface<Texture2D>();
    var texture2dDescription = new Texture2DDescription {
        ArraySize = desktopTexture.Description.ArraySize,
        BindFlags = BindFlags.ShaderResource | BindFlags.RenderTarget,
        CpuAccessFlags = CpuAccessFlags.None,
        Format = desktopTexture.Description.Format,
        Height = desktopTexture.Description.Height,
        MipLevels = 1,
        SampleDescription = new SampleDescription(1, 0),
        Usage = ResourceUsage.Default,
        Width = desktopTexture.Description.Width
    };
    var texture2d = new Texture2D(device, texture2dDescription);
    device.ImmediateContext.CopyResource(desktopTexture, texture2d);

    return texture2d;
} finally {
    // release resources
    desktopResourceOut.Dispose();
    _duplication.ReleaseFrame();
}

P.S. As alternative I also tried WinRT's IGraphicsCaptureItemInterop::CreateForMonitor(hmon, new Guid("79C3F95B-31F7-4EC2-A464-632EF5D30760")) but this one fails with 0x80040154 REGDB_E_CLASSNOTREG.

LOST
  • 2,956
  • 3
  • 25
  • 40
  • 1
    The Win32.DesktopDuplication sample works fine for me in the sandbox, as well as the official Microsoft sample https://github.com/microsoft/Windows-classic-samples/tree/main/Samples/DXGIDesktopDuplication – Simon Mourier Feb 23 '23 at 07:46
  • @SimonMourier what GPU do you use, and what is your OS version? I have tried on 2 separate machines with build 22621.1265 one with Titan V + iGPU and the other is 2x3090 and they both show blank screen in both samples (the C++ one also draws mouse pointer, but that's it) inside the sandbox, but work fine on the host. – LOST Feb 23 '23 at 17:58
  • 1
    I've tested on a Windows 10 compiled as x64 (AMD Radeon RX 5600 XT) and on a Windows 11 Surface Pro X compiled as ARM64 (SQL2 Adreno 690 GPU) but the sandbox uses a remote display adapter by default https://i.imgur.com/kI7riZt.png https://i.imgur.com/iAOkv03.png I don't think the problem is from the code, but more from your hardware/drivers – Simon Mourier Feb 23 '23 at 18:59
  • @SimonMourier yeah, Sandbox has supported graphics acceleration for some time now. I guess yours is off either due to old version of Windows, or due to GPU WDDM version (WDDM 2.5+ is required). – LOST Feb 23 '23 at 22:14
  • 1
    I don't have "old version of Windows" they're all up to date and it does the same with sandbox GPU acceleration enabled https://stackoverflow.com/questions/70553527/windows-sandbox-enable-gpu-acceleration – Simon Mourier Feb 24 '23 at 06:39
  • In your screenshot Device Manager inside Sandbox shows only the remote display adapter, but on my machines it also shows my GPUs, so it looked like your GPU acceleration was not enabled or not working for some reason. But you were right, I found another machine, and the issue does not reproduce there. – LOST Feb 24 '23 at 16:56

0 Answers0