【问题标题】:DirectX-11 Instance Buffer returns E_INVALID_ARGSDirectX-11 实例缓冲区返回 E_INVALID_ARGS
【发布时间】:2017-12-04 03:28:26
【问题描述】:

伙计们。我正处于开始向我的游戏引擎添加实例化的地步。这是我制作的通用函数,因此我可以传入实例缓冲区指针和一些矩阵,以及要绘制的实例列表。但是,在它的第一个循环中,缓冲区为 NULL,因此它尝试对其进行初始化,但失败并显示 HR = E_INVALID_ARGS。我不确定参数的哪一部分是无效的。

目标是每个实例以 XMFLOAT4X4 的形式传递两个 4X4 矩阵。

“sizeofXMFLOAT4X4”变量只是一个健全性检查,以查看它读取的字节数为 (64, 4bytes * 4floats/vec * 4 vec = 64)。

如果有人能发现这里可能出了什么问题并指出来,我将不胜感激。如果您需要更多信息,请告诉我。谢谢。

void StaticSceneryListClass::UpdateInstanceBuffer(ID3D11Buffer *pInstanceBuffer, XMFLOAT4X4 VPMat, XMFLOAT4X4 tileMat,  vector<StaticSceneryStruct> culledInstanceList)
{
//Pass this the buffer you want to update, the VPMat for the frame, and a list of instances to draw and it will fill the buffer with the stuff and things. 
//If the buffer is not initialized yet, it will be initialized too.

//first, create the data needed.
vector<XMFLOAT4X4> instanceMats;

for (int i = 0; i < culledInstanceList.size(); i++)
{
    XMFLOAT4X4 WorldMat = xmCon->MatTranspose(xmCon->MatMultiply(culledInstanceList[i].worldMat, tileMat));
    XMFLOAT4X4 WVP = xmCon->MatTranspose(xmCon->MatMultiply(WorldMat, VPMat));
    instanceMats.push_back(WVP);
    instanceMats.push_back(WorldMat);
}

if (pInstanceBuffer == NULL)
{
    //buffer not initialized yet, initialize it.
    D3D11_BUFFER_DESC instBuffDesc;
    ZeroMemory(&instBuffDesc, sizeof(instBuffDesc));
    sizeofXMFLOAT4X4 = sizeof(XMFLOAT4X4);
    instBuffDesc.Usage = D3D11_USAGE_DYNAMIC;
    instBuffDesc.ByteWidth = sizeofXMFLOAT4X4 * 2 * culledInstanceList.size();
    instBuffDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
    instBuffDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
    instBuffDesc.MiscFlags = 0;

    D3D11_SUBRESOURCE_DATA instData;
    ZeroMemory(&instData, sizeof(instData));

    instData.pSysMem = &instanceMats[0];
    HRESULT hr = graphicsPointers.pdev->CreateBuffer(&instBuffDesc, &instData, &pInstanceBuffer);

    if (FAILED(hr))
    {
        //Fails here with E_INVALID_ARG
        MessageBox(NULL, "Failed to create instance buffer!", "StaticSceneryList", MB_OK);
    }
}
else
{
    //buffer already initialized, need to use resource may and unmap.
    D3D11_MAPPED_SUBRESOURCE mappedResource;
    ZeroMemory(&mappedResource, sizeof(D3D11_MAPPED_SUBRESOURCE));

    //  Disable GPU access to the vertex buffer data.
    graphicsPointers.pdevcon->Map(pInstanceBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
    //  Update the vertex buffer here.
    memcpy(mappedResource.pData, &instanceMats[0], sizeof(XMFLOAT4X4) * 2 * culledInstanceList.size());
    //  Reenable GPU access to the vertex buffer data.
    graphicsPointers.pdevcon->Unmap(pInstanceBuffer, 0);
}

更新 1:2017 年 12 月 2 日 2:02 CST 今天早上我一直在运行各种调试测试,结果很有趣。我尝试隔离问题,发现为数据传入 null 或为缓冲区传入一个新的本地指针什么也没做。我打开了调试层,它没有给我创建缓冲区语句的输出。我尝试使用缓冲区描述的参数来查看它会做什么,这些给了我一个错误。如果剔除列表的大小为 0 并且即使它不是 16 的倍数,我添加了一个捕获。这让它偶尔通过,但它实际上从未产生过工作缓冲区。事实上,它通常仍然失败... S_OK?? FAILED(hr) 以 S_OK 的 HR 下降,这没有多大意义。当我查看缓冲区指针的内存值时,它从 null 变为有地址,但它没有被“如果不是 null,则释放并设置为 null”块捕获。

这个有趣的副作用是它会导致各种巨大的内存泄漏。进程内存在大约 10 秒内以接近线性的速度攀升至超过 3gb(我此时关闭程序,它仍然非常灵敏)。

当然,我似乎也偶尔获得通过,然后似乎永远不会坚持,因为缓冲区是否已初始化的代码尚未触发。

这是当前更新的代码:

void StaticSceneryListClass::UpdateInstanceBuffer(ID3D11Buffer *pInstanceBuffer, XMFLOAT4X4 VPMat, XMFLOAT4X4 tileMat, vector<StaticSceneryStruct> culledInstanceList)
{
//Pass this the buffer you want to update, the VPMat for the frame, and a list of instances to draw and it will fill the buffer with the stuff and things. 
//If the buffer is not initialized yet, it will be initialized too.

//Skip this process if there aren't any instances to draw
if (culledInstanceList.size() > 0)
{
    //first, create the data needed.
    vector<XMFLOAT4X4> instanceMats;
    for (int i = 0; i < culledInstanceList.size(); i++)
    {
        XMFLOAT4X4 WorldMat = xmCon->MatTranspose(xmCon->MatMultiply(culledInstanceList[i].worldMat, tileMat));
        XMFLOAT4X4 WVP = xmCon->MatTranspose(xmCon->MatMultiply(WorldMat, VPMat));
        instanceMats.push_back(WVP);
        instanceMats.push_back(WorldMat);
    }

    if (pInstanceBuffer == NULL)
    {
        //buffer not initialized yet, initialize it.
        D3D11_BUFFER_DESC instBuffDesc;
        ZeroMemory(&instBuffDesc, sizeof(instBuffDesc));
        bytewidth = sizeof(XMFLOAT4X4) * 2 * culledInstanceList.size();
        if (bytewidth % 16 != 0)
        {
            //hasn't fallen into here yet, which makes sense.
            MessageBox(NULL, "Instance Buffer Byte Width Not a multiple of 16", "StaticSceneryList", MB_OK);
        }

        instBuffDesc.Usage = D3D11_USAGE_DYNAMIC;
        instBuffDesc.ByteWidth =  bytewidth;
        instBuffDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
        instBuffDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
        instBuffDesc.MiscFlags = 0;

        D3D11_SUBRESOURCE_DATA instData;
        ZeroMemory(&instData, sizeof(instData));

        instData.pSysMem = &instanceMats[0];

        HRESULT hr = graphicsPointers.pdev->CreateBuffer(&instBuffDesc, &instData, &pInstanceBuffer);
        //HRESULT hr = graphicsPointers.pdev->CreateBuffer(&instBuffDesc, &instData, &debugInstanceBuffer); //DEBUG
        if (FAILED(hr))
        {
            //Fails here with S_OK lulwut
            MessageBox(NULL, "Failed to create instance buffer!", "StaticSceneryList", MB_OK);
            if (pInstanceBuffer != NULL)
            {
               //This doesn't seem to trigger even though the address is not 0x0000etc
                pInstanceBuffer->Release();
                pInstanceBuffer = NULL;
            }
        }
        else
        {
            //occasionally gets here but it doesn't seem to stick
            MessageBox(NULL, "Successfully created instance buffer.", "StaticSceneryList", MB_OK);
        }
    }
    else
    {
        //never seems to get to here.
        //buffer already initialized, need to use resource may and unmap.
        D3D11_MAPPED_SUBRESOURCE mappedResource;
        ZeroMemory(&mappedResource, sizeof(D3D11_MAPPED_SUBRESOURCE));

        //  Disable GPU access to the vertex buffer data.
        graphicsPointers.pdevcon->Map(pInstanceBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
        //  Update the vertex buffer here.
        memcpy(mappedResource.pData, &instanceMats[0], sizeof(XMFLOAT4X4) * 2 * culledInstanceList.size());
        //  Reenable GPU access to the vertex buffer data.
        graphicsPointers.pdevcon->Unmap(pInstanceBuffer, 0);
    }
}//if there is anything to draw

【问题讨论】:

  • 打开debug device 并寻找诊断输出。
  • @Chuck Walbourn 嗨,查克。请查看已编辑的主帖,谢谢。

标签: directx-11


【解决方案1】:

因此,在没有运气的情况下进行了更多测试后,我将代码移到调用此函数的位置,并直接而不是间接地根据对象编写它,并且我让它工作,至少使用默认缓冲区。我不知道为什么,但是指针的传递发生了一些奇怪的事情,这会导致它在退出函数调用时最终为 null。

另外,请注意,当您在输入布局中声明四个 R32B32G32A32_FLOAT 向量系列,然后在顶点着色器中将它们作为四个 float4 拉入,然后使用 float4x4(vec1, vec2, vec3, vec4) 组合它们时,您在将 XMFLOAT4X4 放入缓冲区数据之前不要转置它!

【讨论】:

  • 你的意思是你通过循环遍历你的列表将对象写入内存缓冲区吗?此外,您可以将矩阵设置为行专业以避免转置(我假设您使用的是列专业)
  • 嗨,厄尼。我遍历“实例结构”列表以获取每个的本地空间矩阵。我将局部空间矩阵乘以瓦片空间矩阵以生成世界空间矩阵。我保存了世界矩阵,但也用它来生成 WVP 矩阵。然后我将 WVP 矩阵和世界矩阵存储在一个向量中。在循环结束时,向量包含每个实例的 WVP 和世界矩阵。然后我将向量设置为实例缓冲区的数据。当我说直接与间接时,我的意思是我一直在将实例缓冲区指针传递给一个函数,现在
  • 我直接从包含它的结构中操作指针。我当前的设置似乎运行良好。现在世界变得越来越神奇,因为我在远平面所能看到的范围内拥有森林和灌木/草桩。
  • 是的。类似于我一直在做的事情。想知道您的标准向量列表是否引起了问题,但检查了从元素 0 开始的连续内存。Gl.
猜你喜欢
  • 1970-01-01
  • 2013-08-29
  • 1970-01-01
  • 1970-01-01
  • 2015-08-23
  • 1970-01-01
  • 1970-01-01
  • 2016-03-05
  • 1970-01-01
相关资源
最近更新 更多