Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

Alright, I'm currently making the transition from DirectX 10 to DirectX 11 (with very little help from the MSDN documention) and recently ran into a snag with updating a shader's constant buffer.

My application at the moment simply draws a rectangle in screen space and I've attached a float to the pixel shader so that I can quickly determine if the constant buffer is being updated by looking at the rectangle color.

I've used two methods presented in the MSDN tutorial (pDeviceContext->UpdateSubresource()) and the D3D11 sample code (pDeviceContext->Map()), both yielded the same results which leads me to wonder if maybe I missed an important flag earlier in the engine while initializing the D3D device or compiling the shaders. Also is anyone aware of any important trade offs between the two techniques?

Here is the relevant code...

struct UIShaderBuffer {
    XMMATRIX scale,
            rotation,
            translation;
    float temp; // Used to change the rectangle's color.
};

// Initialize the shader buffer and interface
bool UIRectangle::StartUpShaderBuffer() {
    UIShaderBuffer _shaderBuffer;
    ZeroMemory(&_shaderBuffer, sizeof(UIShaderBuffer));

    D3D11_BUFFER_DESC _bd;
    ZeroMemory(&_bd, sizeof(D3D11_BUFFER_DESC) );
    _bd.Usage                       = D3D11_USAGE_DYNAMIC;
    _bd.ByteWidth                   = sizeof(UIShaderBuffer);
    _bd.BindFlags                   = D3D11_BIND_CONSTANT_BUFFER;
    _bd.CPUAccessFlags      = 0;
    _bd.MiscFlags                   = 0;
    _bd.StructureByteStride = 0;

    D3D11_SUBRESOURCE_DATA _subResData;
    ZeroMemory(&_subResData, sizeof(D3D11_SUBRESOURCE_DATA));
    _subResData.pSysMem             = &_shaderBuffer;
    _subResData.SysMemPitch         = 0;
    _subResData.SysMemSlicePitch = 0;

    if(FAILED(pDevice->CreateBuffer(&_bd, &_subResData, &pShaderBuffer))) {
            MessageBox(0, TEXT("UIRectangle: Failed to bind shader constant buffer.\0"), 0, 0);
            return false;
    }
    return true;
}

// Update the buffer. Call before rendering.
void UIRectangle::UpdateShaderBuffer(XMMATRIX &_rScale, XMMATRIX &_rRotation, XMMATRIX &_rTranslation) {
    static UIShaderBuffer _updatedBuffer;
    _updatedBuffer.scale            = _rScale;
    _updatedBuffer.rotation         = _rRotation;
    _updatedBuffer.translation  = _rTranslation;
    _updatedBuffer.temp = 1.0f; // Used to affect rectangle color in order to see if buffer is getting updated.

    pDeviceContext->UpdateSubresource(pShaderBuffer, 0 , 0, &_updatedBuffer, 0, 0);
    pDeviceContext->VSSetConstantBuffers(0, 1, &pShaderBuffer);
    pDeviceContext->PSSetConstantBuffers(0, 1, &pShaderBuffer);

    /* Alternative method used in D3D11 sample code.
    D3D11_MAPPED_SUBRESOURCE mappedResource;
    UIShaderBuffer* bufPtr = 0;
    if (FAILED(pDeviceContext->Map(pShaderBufferAddr, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource)))
            MessageBox(0, TEXT("UIRectangle: Failed to map shader buffer.\0"), 0, 0);
    bufPtr = (UIShaderBuffer*) mappedResource.pData;
    bufPtr->scale           = _rScale;
    bufPtr->rotation        = _rRotation;
    bufPtr->translation = _rTranslation;
    bufPtr->temp = pos;
    pDeviceContext->Unmap(pShaderBufferAddr, 0);

    pDeviceContext->VSSetConstantBuffers(0, 1, &pShaderBufferAddr);
    pDeviceContext->PSSetConstantBuffers(0, 1, &pShaderBufferAddr);
    */
}

// Render
bool UIRectangle::Render() {
    static XMMATRIX _scale          = XMMatrixTranspose(XMMatrixScaling(1.0f, 1.0f, 1.0f)),
                            _rotation       = XMMatrixTranspose(XMMatrixIdentity()),
                            _translation = XMMatrixTranspose(XMMatrixTranslation(-0.5f, 0.0f, 0.0f));

    UpdateShaderBuffer(_scale, _rotation, _translation);    
    return Mesh<V_Pos>::Render();
}

template <class V>
bool Mesh<V>::Render() {
pDeviceContext->IASetInputLayout(pVertexLayout);
pDeviceContext->IASetPrimitiveTopology(topologyType);
pDeviceContext->VSSetShader(pVShader, 0, 0);
pDeviceContext->PSSetShader(pPShader, 0, 0);
pDeviceContext->Draw(bufSize, 0);

return true;
}

Shader code....

cbuffer ConstantBuffer : register( b0 ) {
    matrix scale;
    matrix rotation;
    matrix translation;
    float temp;
};

float4 VS( float4 _pos : POSITION ) : SV_POSITION {
    //return mul(translation, _pos);
    return _pos;
}

float4 PS( float4 Pos : SV_POSITION ) : SV_Target {
    return float4( temp, temp, temp, 1.0f );
}

Forgot to mention that I noticed this in the D3D11 debug output.

D3D11: INFO: ID3D11DeviceContext::Draw: Constant Buffer expected at slot 0 of the Pixel Shader unit (with size at least 208 bytes) but none is bound. This is OK, as reads of an unbound Constant Buffer are defined to return 0. It is also posible the developer knows the data will not be used anyway. This is only a problem if the developer actually intended to bind a Constant Buffer here.  [ EXECUTION INFO #350: DEVICE_DRAW_CONSTANT_BUFFER_NOT_SET ]

I'm assuming that this is the problem however I don't understand it! Playing with the slot parameter of the SetConstantBuffers() call doesn't change anything, and I have no idea where else I need to bind the buffer. Is there some kind of resource dispute between the pixel and vertex shaders over the constant buffer? Or is this a data packing and alignment issue?

Other questions...

Are there any advantages to using XMMatrices over D3DMatrices? (Other than having to transpose one)

"XMMATRIX is SSE2 optimized and the code inlined, which as far as I know, isn't true of D3DXMATRIX. So it's definitely faster than D3DX, and in addition, it's more portable (has an Xbox 360 port)." - DeadMG

I've mirrored this question here http://www.gamedev.net/topic/605347-updating-shader-buffers/

Edit 1

Jumped the gun, thought I found the solution. Same issue and warning remains.

Here is the shader initialization code

Vertex Shader

 bool VShader::StartUp(const character *_id, const void *_pDevice, LPCWSTR _pFileName, const char *_pFuncName, const char *_pShadModel) {
// Id used to reference the shader from the shader manager subsystem's hash table.
    // Replace with Int hash value!!!!
if ( !id.StartUp(GAME_OBJECT_STRLEN) ) {
    MessageBox(0, TEXT("VShader: Failed to start up shader id.\0"), 0, 0);
    return false;
}

if (!id.SetString(_id)) {
    MessageBox(0, TEXT("VShader: Failed to set shader id.\0"), 0, 0);
    return false;
}

// I'm under the impression that these are the correct flags since MSDN documentation referenced typedefs and enums that didn't exist.
unsigned int _shaderFlags = D3D10_SHADER_ENABLE_STRICTNESS;

// Debug flag
#if defined(_DEBUG)
    _shaderFlags |= D3D10_SHADER_DEBUG | D3D10_SHADER_SKIP_OPTIMIZATION;
#endif

ID3D10Blob* _pErrorBlob = 0;
bool _hasFailed = false;

// Create the vertex shader
if(FAILED(D3DX11CompileFromFile(_pFileName, 0, 0, _pFuncName, _pShadModel, _shaderFlags, 0, 0, &pVSBlob, &_pErrorBlob, 0)))
    _hasFailed = true;

if (_pErrorBlob || _hasFailed) {
    if (_pErrorBlob != 0)
        MessageBoxA(0, (LPCSTR)_pErrorBlob->GetBufferPointer(), 0, 0);
    else {
        SString _error(ERROR_STRING_SIZE);
        _error.SetString(TEXT("VShader: Unable to find \"\0"));
        _error.Append(_pFileName);
        _error.Append(TEXT("\". (\0"));
        _error.Append(id.GetStringPtr());
        _error.Append(TEXT(")\0"));

        MessageBox(0, _error.GetStringPtr(), 0, 0);
        _error.ShutDown();
    }
    return false;
}

if (FAILED(((ID3D11Device*)_pDevice)->CreateVertexShader(pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), 0, &pVShader))) {
    SString _error(ERROR_STRING_SIZE);
    _error.SetString(TEXT("VShader: Failed to create pixel shader.\0"));
    _error.Append(_pFileName);
    _error.Append(TEXT(")\0"));

    MessageBox(0, _error.GetStringPtr(), 0, 0);
    _error.ShutDown();
    return false;
} else return true;
}

Pixel Shader.

bool PShader::StartUp(const character *_id, const void *_pDevice, LPCWSTR _pFileName, const char *_pFuncName, const char *_pShadModel) {
if ( !id.StartUp(GAME_OBJECT_STRLEN) ) {
    MessageBox(0, TEXT("PShader: Failed to start up shader id.\0"), 0, 0);
    return false;
}

if (!id.SetString(_id)) {
    MessageBox(0, TEXT("PShader: Failed to set shader id.\0"), 0, 0);
    return false;
}

unsigned int _shaderFlags = D3D10_SHADER_ENABLE_STRICTNESS;

// Debug flag
#if defined(_DEBUG)
    _shaderFlags |= D3D10_SHADER_DEBUG | D3D10_SHADER_SKIP_OPTIMIZATION;
#endif

ID3D10Blob* _pErrorBlob = 0;
bool _hasFailed = false;

// Create the pixel shader.
if(FAILED(D3DX11CompileFromFile(_pFileName, 0, 0, _pFuncName, _pShadModel, _shaderFlags, 0, 0, &pPSBlob, &_pErrorBlob, 0)))
    _hasFailed = true;

if (_pErrorBlob || _hasFailed) {
    if (_pErrorBlob != 0)
        MessageBoxA(0, (LPCSTR)_pErrorBlob->GetBufferPointer(), 0, 0);
    else {
        SString _error(ERROR_STRING_SIZE);
        _error.SetString(TEXT("PShader: Unable to find \"\0"));
        _error.Append(_pFileName);
        _error.Append(TEXT("\". (\0"));
        _error.Append(id.GetStringPtr());
        _error.Append(TEXT(")\0"));

        MessageBox(0, _error.GetStringPtr(), 0, 0);
        _error.ShutDown();
    }
    return false;
}

if (FAILED(((ID3D11Device*)_pDevice)->CreatePixelShader(pPSBlob->GetBufferPointer(), pPSBlob->GetBufferSize(), 0, &pPShader))) {
    SString _error(ERROR_STRING_SIZE);
    _error.SetString(TEXT("PShader: Failed to create pixel shader. (\0"));
    _error.Append(id.GetStringPtr());
    _error.Append(TEXT(")\0"));

    MessageBox(0, (LPCWSTR)_error.GetStringPtr(), 0, 0);
    _error.ShutDown();
    return false;
} else return true;
}

Edit 2

I'm starting to think it's an issue with my draw call sequence and by extension the design of my Mesh superclass and UIRectangle subclass. Didn't originally include the Mesh.Render() function with the code I posted but I added it to the bottom of the first code block. Could someone validate it?

Voting to delete. I solved the problem while rearranging my architecture and it was an inheritance issue! (kicks self) Don't believe this question can help anyone.

share|improve this question

migrated from stackoverflow.com Jul 4 '11 at 10:15

This question came from our site for professional and enthusiast programmers.

closed as too localized by Tetrad Jul 11 '11 at 23:29

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.If this question can be reworded to fit the rules in the help center, please edit the question.

    
Please, one question per question. –  user744 Jul 4 '11 at 13:42

2 Answers 2

You need to set the constant buffer on the shader after you've updated it. After this

pDeviceContext->UpdateSubresource(pShaderBuffer, 0 , 0, &_updatedBuffer, 0, 0);

you need to call

this->_context->PSSetConstantBuffers(0, 1, &pShaderBuffer);

This way you set the values on your struct instance, and then use UpdateSubresource to update the D3D11_BUFFER with the new values, once that's done, you need to send the updated buffer to the GPU with PSSetConstantBuffers (in order to set it onto the pixel shader slot).

The way you are creating you D3D11_BUFFER looks a little convoluted to me too, this is the way I set up most of my constant buffers:

D3D11_BUFFER_DESC bd;
ZeroMemory(&bd, sizeof(bd));
bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
bd.ByteWidth = sizeof(cb_perObject);
bd.Usage = D3D11_USAGE_DEFAULT;
if (FAILED(this->_device->CreateBuffer(&bd, 0, &this->_perObjectBuffer)))
    return false;

and this is how I update it:

this->_perObject.wvp = XMMatrixTranspose(this->_model.getWorldMatrix() * this->_camera.getViewMatrix() * this->_projection);
this->_perObject.world = XMMatrixTranspose(this->_model.getWorldMatrix());
this->_context->UpdateSubresource(this->_perObjectBuffer, 0, 0, &this->_perObject, 0, 0);
this->_context->PSSetConstantBuffers(0, 1, &this->_perObjectBuffer);

It might not be the best way to do it, but it works for me.

The XNAMATH data types such as XMMATRIX are 16 bytes aligned and use SSE/SSE2 instructions (SIMD) and therefore faster than the older D3DXMATRIX. Depending on the alignment you are using, they can be a bit of a pain to work with and you will need to use the XMFLOAT3, XMFLOAT4, XMFLOAT4X3, XMFLOAT4X4 and load/unload them into XMMATRIX/XMVECTOR types.

share|improve this answer
    
Hmmm, rearranging the calls didn't make a difference. (I also still get the same D3D11 warning) Also you sure it isn't important to label the buffer as cpu write only? Also does it not give any performance optimizations by specifying a dynamic usage flag? The cpu will only be writing, the gpu will only be reading. Updated the code to reflect your changes too. –  Joel Jul 7 '11 at 15:53
    
If you are not using the Map function you don't need to make the buffer dynamic, and you can also create it with no sub resource data. –  dotminic Jul 7 '11 at 22:52
    
Ah ok, thanks! Is the map function faster or slower since it has to get a mutex lock (I'm assuming) on the buffer and update the entire struct and then release the lock, as opposed to just flushing a whole struct of data to the GPU? Also playing with these suggestions still doesn't fix the problem and the D3D11 warning remains. –  Joel Jul 7 '11 at 23:47
    
I'm not sure if Map is faster/slower, but I know the flag passed to the Map function may have an effect on performance, in any case, with the Map or UpdateSubresource, the data will have to be transferred from the CPU back to the GPU. This link will shed some light: msdn.microsoft.com/en-us/library/ff476486%28v=vs.85%29.aspx. As for the problem, I have no idea, it basicaly means you have no buffer set on the shader, did you not forget to set the pixel shader or anything else that may cause the problem ? You could also comment the code step by step until you isolate the problem source. –  dotminic Jul 8 '11 at 0:29
    
I set the pixel and vertex shader buffers right after updating the buffer and right before drawing. I've been rummaging around the MSDN documentation for awhile and I haven't found any discrepancies. So I'm guessing it might be something else earlier in the code so I'm going to post the shader compilation code too. While I dissect and comment out lines. –  Joel Jul 8 '11 at 0:40

XMMATRIX is SSE2 optimized and the code inlined, which as far as I know, isn't true of D3DXMATRIX. So it's definitely faster than D3DX, and in addition, it's more portable (has an Xbox 360 port).

share|improve this answer
    
Awesome! Thanks! –  Joel Smith Jul 3 '11 at 17:34

Not the answer you're looking for? Browse other questions tagged or ask your own question.