directx-11vertex-attributes

optional vertexbufferobjects in directx11


I have some models (geometries) which have some vertexinformation. For example position, normal, color, texcoord each of this information has its own vertexbuffer. But some of these models have texture coordinates some not... To manage these differences I wrote a vertexshader which is checking, if the flag inside the constantbuffer "hasTextureCoordinates" is == 1. And if so it uses the texcoord parameter or not. But Directx does not realy like this workaround and prints out:

D3D11 INFO: ID3D11DeviceContext::Draw: Element [3] in the current Input Layout's declaration references input slot 3, but there is no Buffer bound to this slot. This is OK, as reads from an empty slot are defined to return 0. It is also possible the developer knows the data will not be used anyway. This is only a problem if the developer actually intended to bind an input Buffer here. [ EXECUTION INFO #348: DEVICE_DRAW_VERTEX_BUFFER_NOT_SET]

I'm not sure if every hardware handles this correctly, also it's not nice to see inside the output this "warnings" every frame... I know i could write two shaders, one with and one without texcoods, but the problem is that this is not the only maybe missing parameter... some has color other not, some has color and texturecoordinates and so on. And to write a shader for each combination of vertexbuffer inputs is extremly redundant. this is extremly bad, because if we change one shader, we have to change all other too. There is also the possibility of put parts of the shader to different files and include them, but it's confusing.

Is there a way to say directx that the specific vertexbuffer is optional? Or does someone knows a better solution for this problem?


Solution

  • You can suppress this specific message programmatically. As it's an INFO rather than an ERROR or CORRUPTION message, it's safe to ignore.

    #include <wrl/client.h>
    
    using Microsoft::WRL::ComPtr;
    
    ComPtr<ID3D11Debug> d3dDebug;
    if ( SUCCEEDED( device.As(&d3dDebug) ) )
    {
        ComPtr<ID3D11InfoQueue> d3dInfoQueue;
        if ( SUCCEEDED( d3dDebug.As(&d3dInfoQueue) ) )
        {
    #ifdef _DEBUG
            d3dInfoQueue->SetBreakOnSeverity( D3D11_MESSAGE_SEVERITY_CORRUPTION, true );
            d3dInfoQueue->SetBreakOnSeverity( D3D11_MESSAGE_SEVERITY_ERROR, true );
    #endif
            D3D11_MESSAGE_ID hide[] =
            {
                D3D11_MESSAGE_ID_SETPRIVATEDATA_CHANGINGPARAMS,
                D3D11_MESSAGE_ID_DEVICE_DRAW_VERTEX_BUFFER_NOT_SET, // <--- Your message here!
                // Add more message IDs here as needed 
            };
            D3D11_INFO_QUEUE_FILTER filter = {};
            filter.DenyList.NumIDs = _countof(hide);
            filter.DenyList.pIDList = hide;
            d3dInfoQueue->AddStorageFilterEntries( &filter );
        }
    }
    

    In addition to suppressing 'noise' messages, in debug builds this also causes the debug layer to generate a break-point if you do hit a ERROR or CORRUPTION message as those really need to be fixed.

    See Direct3D SDK Debug Layer Tricks

    Note I'm using ComPtr here to simplify the QueryInterface chain, and I assume you are keeping your device as a ComPtr<ID3D11Device> device as I do in in Anatomy of Direct3D 11 Create Device

    I also assume you are using VS 2013 or later so that D3D11_INFO_QUEUE_FILTER filter = {}; is sufficient to zero-fill the structure.