DirectX-11 实例缓冲区 returns E_INVALID_ARGS
DirectX-11 Instance Buffer returns E_INVALID_ARGS
伙计们。我正处于开始向我的游戏引擎添加实例化的地步。这是我创建的一个通用函数,因此我可以传入一个实例缓冲区指针和一些矩阵,以及要绘制的实例列表。但是,在它的第一个循环中,缓冲区为 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 的倍数,我也添加了一个 catch。它偶尔会通过,但它实际上从未产生过工作缓冲区。事实上,它仍然经常失败... S_OK?? FAILED(hr) 正在下降,HR 为 S_OK,这没有多大意义。当我查看缓冲区指针的内存值时,它从 null 变为具有地址,但它没有被 "if not null, release and set to 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
因此,在经过多次测试但没有成功之后,我将代码移到了调用此函数的位置,并直接根据对象而不是间接地编写了它,并且我让它工作了,至少在默认情况下是这样缓冲。我不知道为什么,但是指针的传递发生了一些奇怪的事情,这会导致它在从函数调用中返回时以 null 结尾。
此外,请注意,当您在输入布局中声明四个 R32B32G32A32_FLOAT 向量系列,然后在顶点着色器中将它们作为四个 float4 拉入,然后使用 float4x4(vec1, vec2, vec3, vec4), 在将 XMFLOAT4X4 放入缓冲区数据之前不要转置它!
伙计们。我正处于开始向我的游戏引擎添加实例化的地步。这是我创建的一个通用函数,因此我可以传入一个实例缓冲区指针和一些矩阵,以及要绘制的实例列表。但是,在它的第一个循环中,缓冲区为 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 的倍数,我也添加了一个 catch。它偶尔会通过,但它实际上从未产生过工作缓冲区。事实上,它仍然经常失败... S_OK?? FAILED(hr) 正在下降,HR 为 S_OK,这没有多大意义。当我查看缓冲区指针的内存值时,它从 null 变为具有地址,但它没有被 "if not null, release and set to 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
因此,在经过多次测试但没有成功之后,我将代码移到了调用此函数的位置,并直接根据对象而不是间接地编写了它,并且我让它工作了,至少在默认情况下是这样缓冲。我不知道为什么,但是指针的传递发生了一些奇怪的事情,这会导致它在从函数调用中返回时以 null 结尾。
此外,请注意,当您在输入布局中声明四个 R32B32G32A32_FLOAT 向量系列,然后在顶点着色器中将它们作为四个 float4 拉入,然后使用 float4x4(vec1, vec2, vec3, vec4), 在将 XMFLOAT4X4 放入缓冲区数据之前不要转置它!