为什么 Map() 在默认纹理上失败,尽管使用了 UnifiedMemoryArchitecture 和 MapOnDefaultTextures

问题描述 投票:0回答:2

文档建议,默认使用纹理可以映射到 UMA 架构上,例如具有 Direct3D 11.3 的英特尔集成显卡。

我试图实现这一目标,但

Map()
总是失败,并出现
E_INVALIDARG

我对 C++ 和 DirectX 很陌生,但下面是我认为的最小测试用例。请毫不犹豫地指出我犯下的任何愚蠢行为。

我在装有 Windows 10 1809、Intel Skylake i5-6300U 和 HD Graphics 520 的笔记本上运行此程序。

#include "pch.h"
#include <iostream>
#include <dxgi1_6.h>
#include <d3d.h>
#include <d3d11_4.h>
#include <assert.h>

int main()
{
    HRESULT res = S_OK;
    ID3D11Device *Dev = nullptr;
    ID3D11DeviceContext *Ctx = nullptr;
    D3D_FEATURE_LEVEL Fl;
    D3D_FEATURE_LEVEL fls[1] = { D3D_FEATURE_LEVEL_11_1 };

    res = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, D3D11_CREATE_DEVICE_DEBUG | D3D11_CREATE_DEVICE_BGRA_SUPPORT, fls, 1, D3D11_SDK_VERSION, &Dev, &Fl, &Ctx);
    assert(res == S_OK);
    assert(Fl == D3D_FEATURE_LEVEL_11_1);

    ID3D11Device5 *Dev5 = nullptr;
    res = Dev->QueryInterface<ID3D11Device5>(&Dev5);
    assert(res == S_OK);
    Dev->Release();
    Dev = nullptr;

    ID3D11DeviceContext4 *Ctx4;
    res = Ctx->QueryInterface<ID3D11DeviceContext4>(&Ctx4);
    assert(res == S_OK);
    Ctx->Release();
    Ctx = nullptr;

    D3D11_FEATURE_DATA_D3D11_OPTIONS2 opts2;
    res = Dev5->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS2, &opts2, sizeof(opts2));
    assert(res == S_OK);
    assert(opts2.MapOnDefaultTextures);
    assert(opts2.UnifiedMemoryArchitecture);

    D3D11_TEXTURE2D_DESC1 texDesc = { 0 };
    texDesc.ArraySize = 1;
    texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS;
    texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
    texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    texDesc.Height = 256;
    texDesc.Width = 256;
    texDesc.MipLevels = 1;
    texDesc.MiscFlags = 0;
    texDesc.SampleDesc.Count = 1;
    texDesc.SampleDesc.Quality = 0;
    texDesc.TextureLayout = D3D11_TEXTURE_LAYOUT_UNDEFINED;
    texDesc.Usage = D3D11_USAGE_DEFAULT;

    byte mem[256 * 256 * 4];
    ZeroMemory(mem, 256 * 256 * 4);

    D3D11_SUBRESOURCE_DATA data = { 0 };
    data.pSysMem = mem;
    data.SysMemPitch = 256 * 4;

    ID3D11Texture2D1 *tex2d;
    res = Dev5->CreateTexture2D1(&texDesc, &data, &tex2d);
    assert(res == S_OK);

    D3D11_MAPPED_SUBRESOURCE map = { 0 };
    // I believe at least one of these should succeed, but all fail
    res = Ctx4->Map(tex2d, 0, D3D11_MAP_READ, 0, &map);
    //res = Ctx4->Map(tex2d, 0, D3D11_MAP_WRITE, 0, &map);
    //res = Ctx4->Map(tex2d, 0, D3D11_MAP_READ_WRITE, 0, &map);
    assert(res == S_OK); // E_INVALIDARG
}

我相信 Map() 调用应该成功,但它失败并显示 E_INVALIDARG。

编辑:我也尝试了

D3D11_TEXTURE_LAYOUT_ROW_MAJOR
D3D11_TEXTURE_LAYOUT_64K_STANDARD_SWIZZLE
,但随后
CreateTexture2D1()
因E_INVALIDARG而失败。也许我的硬件不支持这些模式?

c++ directx directx-11 direct3d11
2个回答
0
投票

我认为问题已在文档中描述:

在默认纹理上设置CPU访问标志而不将TextureLayout设置为D3D11_TEXTURE_LAYOUT_UNDEFINED以外的值是非法的。


0
投票

此方法可能会解决您的问题在文档中

当提供使用 D3D11_USAGE_DEFAULT 创建的纹理并且在直接上下文上调用 API 时,pMappedResource 参数可能为 NULL。这允许映射默认纹理,即使它是使用 D3D11_TEXTURE_LAYOUT_UNDEFINED 创建的。在此 API 调用之后,可以使用 ID3D11DeviceContext3::WriteToSubresource 和/或 ID3D11DeviceContext3::ReadFromSubresource 访问纹理。

像这样的伪代码:

deviceContext->Map(defaultWithCPUAccesssTexture, 0, D3D11_MAP_WRITE, 0, NULL);
device3->WriteSubResource(defaultWithCPUAccesssTexture, 0, NULL, pData, rowPitch, depthPitch);
deviceContext->UnMap(defaultWithCPUAccesssTexture, 0);

从默认纹理读取的方式与写入相同。

© www.soinside.com 2019 - 2024. All rights reserved.