Search code examples
c++directxdirectx-10

Updating vertex buffer in Directx10 and 11


I use Directx10 in my program. When I try to change vertexes' positions I get an error:

Exception thrown at 0x558CA083 (d3d10core.dll) in NBodyProblemDebug.exe: 0xC0000005: Access violation reading location 0x00000000.

It happens during the execution of the next code during the run-time:

    D3D10_MAPPED_TEXTURE3D resourse;        
    ZeroMemory(&resourse, sizeof(D3D10_MAPPED_TEXTURE3D));
    g_pVertexBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &resourse.pData); //exception is thrown here
    memcpy(resourse.pData, positions, 4 * n_bodies * sizeof(float));
    g_pVertexBuffer->Unmap();

where the veкtex buffer is initialized as follows:

    float * positions;
    ID3D10Buffer*  g_pVertexBuffer = nullptr;
    D3D10_BUFFER_DESC bd;
    ZeroMemory( &bd, sizeof(bd) );
    bd.Usage = D3D10_USAGE_DYNAMIC;
    bd.ByteWidth = sizeof( SimpleVertex ) * bodies;
    bd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
    bd.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
    D3D10_SUBRESOURCE_DATA InitData;
    ZeroMemory( &InitData, sizeof(InitData) );
    InitData.pSysMem = positions;
    result = m_device->CreateBuffer( &bd, &InitData, &g_pVertexBuffer );

What one should do to fix it? Is this code an apt equivalent to the one used in Directx11:

 D3D11_MAPPED_SUBRESOURCE resourse;
 ZeroMemory(&resourse, sizeof(D3D11_MAPPED_SUBRESOURCE));
 g_pImmediateContext->Map(g_pVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &resourse);
 memcpy(resourse.pData, positions, 4 * bodies * sizeof(float));     
 g_pImmediateContext->Unmap(g_pVertexBuffer, 0);

Solution

  • Your code is not doing any error checking. Whenever a COM API returns a HRESULT, you must check it for failure. If it was safe to ignore the return value, then it would return void. You should use the SUCCEEDED or FAILED macros to check the results, or adopt something like ThrowIfFailed.

    D3D11_MAPPED_SUBRESOURCE resource = {};
    if ( SUCCEEDED(
        g_pImmediateContext->Map(g_pVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD,
           0, &resource) )
    {
        memcpy(resourse.pData, positions, 4 * bodies * sizeof(float));     
        g_pImmediateContext->Unmap(g_pVertexBuffer, 0);
    }
    

    If as you note the exception is thrown on the line with Map, then likely you are missing a failed HRESULT earlier in the program that resulted in g_pImmediateContext still being nullptr.

    Note that ZeroMemory is very old-school. You only need it if you are using a version of Visual C++ prior to VS 2013. With VS 2013 or later, C++11 uniform initialization rules means D3D11_MAPPED_SUBRESOURCE resource = {}; is guaranteed to be filling the structure with zeros.

    If once you have checked all the HRESULTs where appropriate, the second step for debugging a DirectX application is to enable the DEBUG device. This will then provide additional details about any failures in the debug output window which will help you pinpoint the failure case in your program. See Anatomy of Direct3D 11 Create Device and Direct3D SDK Debug Layer Tricks

    BTW, based on your style you are using raw pointers for your COM interfaces. You should consider adopting a smart-pointer like ComPtr.

    There's no reason at all to continue to use DirectX 10. All supported platforms that can run DirectX 10 can run DirectX 11. DirectX 11 supports more hardware, has better utility library support, better tool support, and is the current 'mainstream' version of DirectX. Don't use DirectX 10. The porting from DirectX 10 to DirectX 11 is very straight-forward. See MSDN, Living without D3DX, and Direct3D 11 Deployment for Game Developers