jjzjj

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

coder 2024-02-10 原文

我正在调查一个 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/

有关c++ - 如何填充常量着色器以避免 E_INVALIDARG?的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  4. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  5. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  6. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  7. ruby-on-rails - 未初始化的常量 Psych::Syck (NameError) - 2

    在我的gem中,我需要yaml并且在我的本地计算机上运行良好。但是在将我的gem推送到ruby​​gems.org之后,当我尝试使用我的gem时,我收到一条错误消息=>"uninitializedconstantPsych::Syck(NameError)"谁能帮我解决这个问题?附言RubyVersion=>ruby1.9.2,GemVersion=>1.6.2,Bundlerversion=>1.0.15 最佳答案 经过几个小时的研究,我发现=>“YAML使用未维护的Syck库,而Psych使用现代的LibYAML”因此,为了解决

  8. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  9. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  10. ruby - 如何每月在 Heroku 运行一次 Scheduler 插件? - 2

    在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/

随机推荐