为什么 ID3D11DeviceContext::map() 函数不起作用并返回 E_INVALIDAGR(一个或多个参数无效)

发布于 2025-01-16 12:10:31 字数 4518 浏览 6 评论 0 原文

当我想使用 DXGI Duplication API 截图时,deviceContext->map() 总是失败。它返回E_INVALIDAGR(一个或多个参数无效)。不过,我认为没有任何论据是无效的。我不知道如何解决这个问题。这是我的代码。 (所有初始化均成功,包括devicedeviceContextdxgiOutputDuplication)。

/*
this function take a screenshot and save the bmp image of the screenshot to the data pointer.
@param BYTE* data: (out) The pointer to a BYTE array where the bmp image will be saved to.
@return ULARGE_INTEGER: the size of bmp image.
*/
ULARGE_INTEGER GetFrame(BYTE* data) {

    IDXGIResource* desktopResource = nullptr;
    DXGI_OUTDUPL_FRAME_INFO FrameInfo{};
    ID3D11Texture2D* acquiredDesktopImage = nullptr;
    
    //Get new frame
    HRESULT hr = 0;
    do {
        hr = dxgiOutputDuplication->AcquireNextFrame(1000, &FrameInfo, &desktopResource);
    } while (hr != S_OK);
    

    hr = desktopResource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&acquiredDesktopImage));
    if (hr != S_OK) {
    printf("failed to query interface\n");
    }
    D3D11_MAPPED_SUBRESOURCE* resource = new D3D11_MAPPED_SUBRESOURCE();

    ID3D11Texture2D* copiedImage = nullptr;

    D3D11_TEXTURE2D_DESC desc{};

    acquiredDesktopImage->GetDesc(&desc);

    desc.Usage = D3D11_USAGE_DEFAULT;
    desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
    desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;

    hr = device->CreateTexture2D(&desc, NULL, &copiedImage);
    if (hr != S_OK) {
    printf("failed to create texture\n");
    }
    deviceContext->CopyResource(copiedImage, acquiredDesktopImage);
    
    hr = deviceContext->Map(copiedImage, 0, D3D11_MAP_READ, NULL, resource);  
    // always failed in the upper line.
    
    if (hr != S_OK) {
    printf("failed to map\n");
    }

    
    ULARGE_INTEGER length = encodeData(dxgiOutDuplDesc.ModeDesc.Width, dxgiOutDuplDesc.ModeDesc.Height, resource->RowPitch, resource->pData, data);
    // This function is to encode the data from rgb matrix to bmp format. 
    // Here is the description of this function.
    /*
    encode RGB matrix to bmp format and save it into data
    @param int width: (in) matrix width
    @param int height: (in) matrix height
    @param UINT stride: (in) the size of a line of matrix
    @param void* pixels: (in) data source pointer
    @param BYTE* data: (out) data result pointer
    @return ULARGE_INTEGER: data result length
    */

    desktopResource->Release();
    acquiredDesktopImage->Release();
    delete resource;
    return length;
}

这是初始化函数。


BOOL initDevice() {
    IDXGIDevice*            dxgiDevice = nullptr;
    IDXGIAdapter*           dxgiAdapter = nullptr;
    IDXGIOutput*            dxgiOutput = nullptr;
    IDXGIOutput1*           dxgiOutput1 = nullptr;

    D3D_FEATURE_LEVEL feature_levels[] = {
        D3D_FEATURE_LEVEL_11_0
    };

    CHECK_RESULT(D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, D3D11_CREATE_DEVICE_DEBUG, feature_levels, ARRAYSIZE(feature_levels), D3D11_SDK_VERSION, &device, NULL, &deviceContext));
    printf("successful init create d3d11 device\n");

    // Get DXGI device
    CHECK_RESULT(device->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(&dxgiDevice)));

    // Get DXGI adapter
    CHECK_RESULT(dxgiDevice->GetParent(__uuidof(IDXGIAdapter), reinterpret_cast<void**>(&dxgiAdapter)));


    // Get output
    CHECK_RESULT(dxgiAdapter->EnumOutputs(0, &dxgiOutput));


    CHECK_RESULT(dxgiOutput->GetDesc(&dxgiOutputDesc));

    // QI for Output 1
    CHECK_RESULT(dxgiOutput->QueryInterface(__uuidof(dxgiOutput1), reinterpret_cast<void**>(&dxgiOutput1)));
    

    // Create desktop duplication
    CHECK_RESULT(dxgiOutput1->DuplicateOutput(device, &dxgiOutputDuplication));

    dxgiOutputDuplication->GetDesc(&dxgiOutDuplDesc);

    dxgiDevice->Release();
    dxgiDevice = nullptr;
    dxgiAdapter->Release();
    dxgiAdapter = nullptr;
    dxgiOutput->Release();
    dxgiOutput = nullptr;
    dxgiOutput1->Release();
    dxgiOutput1 = nullptr;
    return true;
}

这是我使用的宏。

#define CHECK_RESULT(func) if ((func) != S_OK) return false

我尝试更改desc(D3D11_TEXTURE2D_DESC)的几乎所有参数,但都无法成功。另外,我搜索过这个问题,他们文章上的代码和我的一样,所以我对发生的事情感到非常困惑。有人能帮我吗?我将非常感谢你的帮助。

When I want to use DXGI Duplication API to take screenshots, the deviceContext->map() always failed. It returns E_INVALIDAGR (one or more arguments are invalid). However, I don't think there are any arguments invalid. I don't know how to solve this problem. Here's my code. (all the initialization are successes, including device, deviceContext, dxgiOutputDuplication).

/*
this function take a screenshot and save the bmp image of the screenshot to the data pointer.
@param BYTE* data: (out) The pointer to a BYTE array where the bmp image will be saved to.
@return ULARGE_INTEGER: the size of bmp image.
*/
ULARGE_INTEGER GetFrame(BYTE* data) {

    IDXGIResource* desktopResource = nullptr;
    DXGI_OUTDUPL_FRAME_INFO FrameInfo{};
    ID3D11Texture2D* acquiredDesktopImage = nullptr;
    
    //Get new frame
    HRESULT hr = 0;
    do {
        hr = dxgiOutputDuplication->AcquireNextFrame(1000, &FrameInfo, &desktopResource);
    } while (hr != S_OK);
    

    hr = desktopResource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&acquiredDesktopImage));
    if (hr != S_OK) {
    printf("failed to query interface\n");
    }
    D3D11_MAPPED_SUBRESOURCE* resource = new D3D11_MAPPED_SUBRESOURCE();

    ID3D11Texture2D* copiedImage = nullptr;

    D3D11_TEXTURE2D_DESC desc{};

    acquiredDesktopImage->GetDesc(&desc);

    desc.Usage = D3D11_USAGE_DEFAULT;
    desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
    desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;

    hr = device->CreateTexture2D(&desc, NULL, &copiedImage);
    if (hr != S_OK) {
    printf("failed to create texture\n");
    }
    deviceContext->CopyResource(copiedImage, acquiredDesktopImage);
    
    hr = deviceContext->Map(copiedImage, 0, D3D11_MAP_READ, NULL, resource);  
    // always failed in the upper line.
    
    if (hr != S_OK) {
    printf("failed to map\n");
    }

    
    ULARGE_INTEGER length = encodeData(dxgiOutDuplDesc.ModeDesc.Width, dxgiOutDuplDesc.ModeDesc.Height, resource->RowPitch, resource->pData, data);
    // This function is to encode the data from rgb matrix to bmp format. 
    // Here is the description of this function.
    /*
    encode RGB matrix to bmp format and save it into data
    @param int width: (in) matrix width
    @param int height: (in) matrix height
    @param UINT stride: (in) the size of a line of matrix
    @param void* pixels: (in) data source pointer
    @param BYTE* data: (out) data result pointer
    @return ULARGE_INTEGER: data result length
    */

    desktopResource->Release();
    acquiredDesktopImage->Release();
    delete resource;
    return length;
}

here is the initialization function.


BOOL initDevice() {
    IDXGIDevice*            dxgiDevice = nullptr;
    IDXGIAdapter*           dxgiAdapter = nullptr;
    IDXGIOutput*            dxgiOutput = nullptr;
    IDXGIOutput1*           dxgiOutput1 = nullptr;

    D3D_FEATURE_LEVEL feature_levels[] = {
        D3D_FEATURE_LEVEL_11_0
    };

    CHECK_RESULT(D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, D3D11_CREATE_DEVICE_DEBUG, feature_levels, ARRAYSIZE(feature_levels), D3D11_SDK_VERSION, &device, NULL, &deviceContext));
    printf("successful init create d3d11 device\n");

    // Get DXGI device
    CHECK_RESULT(device->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(&dxgiDevice)));

    // Get DXGI adapter
    CHECK_RESULT(dxgiDevice->GetParent(__uuidof(IDXGIAdapter), reinterpret_cast<void**>(&dxgiAdapter)));


    // Get output
    CHECK_RESULT(dxgiAdapter->EnumOutputs(0, &dxgiOutput));


    CHECK_RESULT(dxgiOutput->GetDesc(&dxgiOutputDesc));

    // QI for Output 1
    CHECK_RESULT(dxgiOutput->QueryInterface(__uuidof(dxgiOutput1), reinterpret_cast<void**>(&dxgiOutput1)));
    

    // Create desktop duplication
    CHECK_RESULT(dxgiOutput1->DuplicateOutput(device, &dxgiOutputDuplication));

    dxgiOutputDuplication->GetDesc(&dxgiOutDuplDesc);

    dxgiDevice->Release();
    dxgiDevice = nullptr;
    dxgiAdapter->Release();
    dxgiAdapter = nullptr;
    dxgiOutput->Release();
    dxgiOutput = nullptr;
    dxgiOutput1->Release();
    dxgiOutput1 = nullptr;
    return true;
}

This is the macro that I used.

#define CHECK_RESULT(func) if ((func) != S_OK) return false

I tried to change almost all of the parameters of desc(D3D11_TEXTURE2D_DESC), but none of them can succeed. Also, I have searched about this question, and the code on their articles are as the same as mine, so I am really confused about what happened. Could anyone help me with that? I'll appreciate very much for your helping.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

梦里兽 2025-01-23 12:10:31

您的“copiedImage”纹理对于映射无效:

desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;

应该类似于:

desc.Usage = D3D11_USAGE_STAGING;
desc.BindFlags = 0;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;

看看这个 ScreenGrab 代码。

您也没有释放您的 copiedImage 纹理。您应该考虑使用 COM 智能指针,例如 Microsoft::WRL::ComPtr避免资源泄漏。

请注意,对于 DirectX 11.1 或更高版本,有一个可选硬件功能支持在 D3D11_USAGE_DEFAULT 资源上调用 Map,但它只能工作如果驱动程序将 D3D11_FEATURE_DATA_D3D11_OPTIONS1.MapOnDefaultBuffers 报告为 TRUE -并且 - 您正在使用ID3D11Buffer。这对纹理永远不起作用。

Your 'copiedImage' texture is not valid for mapping:

desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;

should be something like:

desc.Usage = D3D11_USAGE_STAGING;
desc.BindFlags = 0;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;

Take a look at this ScreenGrab code on GitHub.

You also didn't release your copiedImage texture. You should consider using a COM smart-pointer like Microsoft::WRL::ComPtr to avoid resource leaks.

Note that with DirectX 11.1 or better, there is an optional hardware feature that supports calling Map on D3D11_USAGE_DEFAULT resources, but it only works if D3D11_FEATURE_DATA_D3D11_OPTIONS1.MapOnDefaultBuffers is reported as TRUE by the driver -and- you are using a ID3D11Buffer. This never works for textures.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文