gpt4 book ai didi

c++ - 如何填充常量着色器以避免 E_INVALIDARG?

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:15:38 25 4
gpt4 key购买 nike

我正在调查一个 E_INVALIDARG 异常,当我尝试创建第二个常量缓冲区来存储我的灯光信息时抛出该异常:

    // create matrix stack early
CD3D11_BUFFER_DESC constantMatrixBufferDesc(sizeof(ModelViewProjectionConstantBuffer), D3D11_BIND_CONSTANT_BUFFER);
DX::ThrowIfFailed(
m_d3dDevice->CreateBuffer(
&constantMatrixBufferDesc,
nullptr,
&m_constantMatrixBuffer
)
);

DX::ThrowIfFailed(
m_matrixStack.Initialize(m_d3dContext, m_constantMatrixBuffer, &m_constantMatrixBufferData)
);

// also create the light buffer early, we must create it now but we will later
// update it with the light information that we parsed from the model
CD3D11_BUFFER_DESC constantLightBufferDesc(sizeof(LightConstantBuffer), D3D11_BIND_CONSTANT_BUFFER);

/* !!!!---- AN E_INVALIDARG IS THROWN BY THE FOLLOWING LINE ----!!!! */
DX::ThrowIfFailed(
m_d3dDevice->CreateBuffer(
&constantLightBufferDesc,
nullptr,
&m_constantLightBuffer
)
);

此时,似乎传递到 Light 的 CreateBuffer 调用的参数与 Matrix 的状态相同!问题似乎与缓冲区描述中存储的字节数有关。

缓冲区在模块中是这样定义的:

// a constant buffer that contains the 3 matrices needed to
// transform points so that they're rendered correctly
struct ModelViewProjectionConstantBuffer
{
DirectX::XMFLOAT4X4 model;
DirectX::XMFLOAT4X4 view;
DirectX::XMFLOAT4X4 projection;
};

// a constant buffer that contains up to 4 directional or point lights
struct LightConstantBuffer
{
DirectX::XMFLOAT3 ambient[4];
DirectX::XMFLOAT3 diffuse[4];
DirectX::XMFLOAT3 specular[4];

// the first spot in the array is the constant attenuation term,
// the second is the linear term, and the third is quadradic
DirectX::XMFLOAT3 attenuation[4];

// the position and direction of the light
DirectX::XMFLOAT3 position[4];
DirectX::XMFLOAT3 direction[4];

// the type of light that we're working with, defined in lights.h
UINT type[4];

// a number from 0 to 4 that tells us how many lights there are
UINT num;
};

因此在顶点着色器 (.hlsl) 中:

cbuffer ModelViewProjectionConstantBuffer : register (b0)
{
matrix model;
matrix view;
matrix projection;
};

cbuffer LightConstantBuffer : register (b1)
{
float3 ambient[4];
float3 diffuse[4];
float3 specular[4];

// the first spot in the array is the constant attenuation term,
// the second is the linear term, and the third is quadradic
float3 attenuation[4];

// the position and direction of the light
float3 position[4];
float3 direction[4];

// the type of light that we're working with, defined in lights.h
uint type[4];

// a number from 0 to 4 that tells us how many lights there are
uint num;
}

为了找出造成这种情况的原因,我在 MSDN HLSL 着色器文档 (http://msdn.microsoft.com/en-us/library/windows/desktop/ff476898(v=vs.85).aspx) 中偶然发现了这一行:

Each element stores a 1-to-4 component constant, determined by the format of the data stored.

这是什么意思,是这个异常的原因吗?我注意到在 Visual Studio 3D 初学者工具包 ( http://code.msdn.microsoft.com/wpapps/Visual-Studio-3D-Starter-455a15f1 ) 中,缓冲区有额外的 float 填充它们:

///////////////////////////////////////////////////////////////////////////////////////////
//
// Constant buffer structures
//
// These structs use padding and different data types in places to adhere
// to the shader constant's alignment.
//
struct MaterialConstants
{
MaterialConstants()
{
Ambient = DirectX::XMFLOAT4(0.0f,0.0f,0.0f,1.0f);
Diffuse = DirectX::XMFLOAT4(1.0f,1.0f,1.0f,1.0f);
Specular = DirectX::XMFLOAT4(0.0f, 0.0f, 0.0f, 0.0f);
Emissive = DirectX::XMFLOAT4(0.0f, 0.0f, 0.0f, 0.0f);
SpecularPower = 1.0f;
Padding0 = 0.0f;
Padding1 = 0.0f;
Padding2 = 0.0f;
}

DirectX::XMFLOAT4 Ambient;
DirectX::XMFLOAT4 Diffuse;
DirectX::XMFLOAT4 Specular;
DirectX::XMFLOAT4 Emissive;
float SpecularPower;
float Padding0;
float Padding1;
float Padding2;
};

struct LightConstants
{
LightConstants()
{
ZeroMemory(this, sizeof(LightConstants));
Ambient = DirectX::XMFLOAT4(1.0f,1.0f,1.0f,1.0f);
}

DirectX::XMFLOAT4 Ambient;
DirectX::XMFLOAT4 LightColor[4];
DirectX::XMFLOAT4 LightAttenuation[4];
DirectX::XMFLOAT4 LightDirection[4];
DirectX::XMFLOAT4 LightSpecularIntensity[4];
UINT IsPointLight[4*4];
UINT ActiveLights;
float Padding0;
float Padding1;
float Padding2;
};

... // and there's even more where that came from

那么我只是没有正确填充这些东西吗?如果是这样,我应该如何填充它们?还是我缺少的是完全不同的东西?

非常感谢您阅读本文并尝试提供帮助。

最佳答案

由于缺少重要信息,很难解决您的问题,但让我们试一试。

显然,“E_INVALIDARG”表示传递给函数的参数无效。现在我们必须弄清楚哪个参数是错误的。 ID3D11Device::CreateBuffer方法接受 3 个参数:D3D11_BUFFER_DESC , D3D11_SUBRESOURCE_DATA ID3D11Buffer ** 本身。

然后您向它提供 &constantLightBufferDescnullptr&m_constantLightBuffer。现在您必须仔细阅读所有 4 篇 MSDN 文章以找出问题所在。

  1. constantLightBuffer 这不是问题,只要检查它是否具有 ID3D11Buffer 指针类型即可。
  2. nullptr这不太可能是个问题, 但据我所知,它不是 C++ 标准关键字,所以在这里简单的 '0' 可能会更好。 实际上,它是 C++11 以来的标准
  3. 很遗憾,您没有提供您的 constantLightBufferDesc 定义,这可能会成为一个问题:正如您所说,可能存在缓冲区对齐错误:如果您的 constantLightBufferDesc.BindFlags 具有 D3D11_BIND_CONSTANT_BUFFER 标志和 constantLightBufferDesc.ByteWidth is not a multiple of 16 , 缓冲区创建失败。但这只是一个猜测。您可以在这里有任何其他不匹配,因此,您可以无限地猜测。

幸运的是,还有另一种诊断方法:如果您创建 ID3D11DeviceD3D11_CREATE_DEVICE_DEBUG标志,在 Visual Studio 输出窗口中,您将根据 D3D11 看到所有警告和错误。例如,如果未对齐,您将看到:

D3D11 ERROR: ID3D11Device::CreateBuffer: The Dimensions are invalid. For ConstantBuffers, marked with the D3D11_BIND_CONSTANT_BUFFER BindFlag, the ByteWidth (value = 10) must be a multiple of 16. ByteWidth must also be less than or equal to 65536 on the current driver. [ STATE_CREATION ERROR #66: CREATEBUFFER_INVALIDDIMENSIONS]

因此,如果 CreateBuffer() 由于错误的缓冲区大小而失败,有几种方法可以处理此问题:

  1. 调整结构的大小:添加填充成员,使总的 sizeof() 成为 16 的倍数。
  2. 将您的结构声明为 16 位对齐。据我所知,只有特定于编译器的方法可以做到这一点:例如 #pragma pack对于 MSVC。
  3. 分配给 ByteWidth 的不是实际结构大小,而是四舍五入为 16 的下一个倍数:link

调试愉快! =)

关于c++ - 如何填充常量着色器以避免 E_INVALIDARG?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17035891/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com