Bug: Windows.Graphics.Capture on HoloLens 2 yields E_INVALIDARG error without further explanation

David Mórász 1 Reputation point
2021-12-06T22:54:00.307+00:00

This issue has been redirected from https://github.com/MicrosoftDocs/winrt-api/issues/2108 as it was posted on the wrong place originally.:

Description:

I'm trying to use the Windows.Graphics.Capture WinRT API from C++ on HoloLens 2 hardware. winrt::Windows::Graphics::Capture::GraphicsCaptureSession::IsSupported() returns true and I'm doing my best to set up permissions correctly however that might be the problem here. Anyway I'm using Graphics::Capture::GraphicsCapturePicker to retrieve a capture item. Its UI works and it indeed returns a capture item. However after I set up my Direct3D11CaptureFramePool and the session for the capture item, I get an "Invalid Parameter" exception when calling StartCapture(). It works fine on my desktop PC equivalent.

Symptoms:

After everything is set up calling winrt::Windows::Graphics::Capture::GraphicsCaptureSession::StartCapture() throws "Invalid Parameter" exception on HoloLens 2 instead of starting the capturing session.

Environment / Setup:

I'm working with C++ inside Unreal Engine, therefore I already have a D3D11 device set up by the engine. On D3D12 I set up my own D3D11 device and do texture sharing interop between Unreal's D3D12 renderer and my intermediate D3D11 boilerplate. This works fine on desktop. I also enable D3D debug mode for both the engine device and for my intermediate D3D11 device, but that doesn't give me extra log as it usually does on incorrect graphics code.

Here's the code I set up the Picker with:

Cpp
    try
    {
        Graphics::Capture::GraphicsCapturePicker picker;
        auto pickOp{picker.PickSingleItemAsync()};
        AsyncTask(ENamedThreads::AnyThread, [=]
        {
            result->SetValue(MakeShareable(new FCaptureItem(pickOp.get(), targetTexture)));
        });
    }
    catch (winrt::hresult_error const& ex)
    {
        // this works fine
        // [...]
    }

Here's how I set up the session:

Cpp
    try
    {
        FramePool = Graphics::Capture::Direct3D11CaptureFramePool::Create(
            RtD3D11Device,      // got the device earlier
            format.Format,      // determined the correct format for the capture earlier
            FramePoolBuffersNum,    // constant set to 2
            LastSize        // initially not 0 but {128, 128}, it crashed on me when I had it at 0 on desktop PC
        );

        // if format is invalid then exception is thrown at Create immediately
        // Graphics::Capture::GraphicsCaptureItem item; it's created by window picker

        Session = FramePool.CreateCaptureSession(item);
        FrameArrivedRevoker = FramePool.FrameArrived(
            winrt::auto_revoke,
            { this, &FCaptureFrameHandlerBase::OnFrameArrivedInternal }
        );
        Session.StartCapture(); // This is where exception is thrown
        WindowFormat = format;
    }
    catch (winrt::hresult_error const& ex)
    {
        // error handling
    }

Further exploration

I've already ruled out incorrect format input as when pixel format is invalid exception is thrown immediately on Graphics::Capture::Direct3D11CaptureFramePool::Create. My current suspects are incorrectly set up capabilities or somehow incorrectly set up D3D11 device.

Incorrect capabilities

I understand this feature needs <uap6:Capability Name = "graphicsCapture" /> capability however makeappx was complaining that it didn't know the uap6 namespace, even when I added manually to the AppManifest.xml. Doing <DeviceCapability Name = "graphicsCapture" /> doesn't freak out makeappx but I'm not 100% trusting that.

Incorrect D3D11 device

When I use my own device I create a pretty standard one. So if anything is wrong with it, it didn't struck me. I'm pasting it here for reference:

Cpp
D3D_FEATURE_LEVEL FeatureLevels[4] = {
    D3D_FEATURE_LEVEL_11_1,
    D3D_FEATURE_LEVEL_11_0,
    D3D_FEATURE_LEVEL_10_1,
    D3D_FEATURE_LEVEL_10_0
};

winrt::check_hresult(
    D3D11CreateDevice(
        /* pAdapter, */          nullptr,
        /* DriverType, */        D3D_DRIVER_TYPE_HARDWARE,
        /* Software, */          nullptr,
        /* Flags, */             D3D11_CREATE_DEVICE_BGRA_SUPPORT | (ShouldCreateWithD3DDebug() ? D3D11_CREATE_DEVICE_DEBUG : 0),
        /* pFeatureLevels, */    &FeatureLevels[0],
        /* FeatureLevels, */     4,
        /* SDKVersion, */        D3D11_SDK_VERSION,
        /* ppDevice, */          Resources.D3D11Device.put(),
        /* pFeatureLevel, */     nullptr,
        /* ppImmediateContext */ Resources.D3D11Context.put()
    )
);

I hope it's enough info for anyone who might concern. Thanks in advance for looking into it!

C++
C++
A high-level, general-purpose programming language, created as an extension of the C programming language, that has object-oriented, generic, and functional features in addition to facilities for low-level memory manipulation.
3,634 questions
HoloLens Development
HoloLens Development
HoloLens: A family of Microsoft self-contained, holographic devices that enable engagement with digital content and interaction with holograms in the surrounding environment.Development: The process of researching, productizing, and refining new or existing technologies.
390 questions
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. Hernando Ren 2,171 Reputation points
    2021-12-07T09:35:13.297+00:00

    Hello, Welcome to Microsoft Q&A,

    D3D11 device initialization should be okay from the code snippets. However, from the source code of ManifestGenerator for HoloLens by Unreal, the uap6 graphicsCapture manifest is not supported for HoloLens platform:ManifestGenerator.cs, therefore, Capability could turn out to be the culprit.

    In addition to this, if your need is to take a mixed reality capture (MRC) photo(the behave similar to screenshots ), please refer to this doc:Mixed reality capture with Unreal

    ----
    If the response is helpful, please click "Accept Answer" and upvote it.
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    1 person found this answer helpful.