Friday, December 28, 2012

Shader Reflection using ID3D11ShaderReflection

Merry Christmas and a Happy New Year to all!!

It's been some time since i wrote my last blog. There's been a lot of work lately and I haven't been able to dedicate any time to my hobby engine and to this blog. Now that I'm on vacation, I got to spend some time with the engine.With my new laptop, Windows 8 with DirectX 11.1 and some work experience , I decided to rewrite my whole engine from scratch, and see if I could design a better engine.

One of the first thoughts about the old engine was that the shader system was kind of clunky. With all the hard-coded resource bindings (like constant buffers, textures etc), I was not able to get far with the existing system. So I decided to spend a little time to investigate how to manage the shader system better. After some investigation I came across "Shader Reflection" mentioned on the Microsoft site and on a few blogs. After playing around with it, I found that it's possible to analyze  the entire shader from within the engine and it was the perfect solution to the problem.

So, what is shader Reflection? According to http://msdn.microsoft.com/en-us/library/windows/desktop/ff476590(v=vs.85).aspx, "ID3D11ShaderReflection" is basically an interface to access shader information. This means that you can figure out the following:
1. Constant Buffer Information ( constants used, register bindings etc)
2. Texture Sampler Information
3. Instruction Counts for Performance measuring
4. Input Layout Generation
and a whole lot more.

Here's the line that gets the shader reflection:

HRESULT hr = D3DReflect( pBlob->GetBufferPointer(), pBlob->GetBufferSize(), IID_ID3D11ShaderReflection, (void**) &ppShaderReflection );

where pBlob is ID3DBlob* which gets loaded from a file or created during runtime by compiling a shader.

So now that I had access to this information, figuring out the details of the shader was so simple. I was able to dynamically generate the input layout and set up the constant buffer information. Now it's possible for different shaders to access the same constant buffer information, without storing separate buffer information for each one of them (from engine side). Plus, at the point of binding, I could figure out which register the constant buffer is used and then bind the information to that register itself. All this without any sort of hard-coding !!


For Input Layout Information:
http://takinginitiative.net/2011/12/11/directx-1011-basic-shader-reflection-automatic-input-layout-creation/


Here's a code snippet on how to access the constant buffer information:

D3D11_SHADER_DESC shaderDesc;
pShaderReflection->GetDesc(&shaderDesc);
HRESULT hr;
for(UINT i=0; i< shaderDesc.ConstantBuffers; i++)
{
D3D11_SHADER_BUFFER_DESC bufferDesc;
ID3D11ShaderReflectionConstantBuffer* pConstantBuffer = m_pShaderReflection->GetConstantBufferByIndex(i);
       //This has the buffer description
hr = pConstantBuffer->GetDesc(&bufferDesc);

       //Access to register binding
D3D11_SHADER_INPUT_BIND_DESC bindDesc;
hr = pShaderReflection->GetResourceBindingDescByName(bufferDesc.Name, &bindDesc);

for(UINT j=0; j< bufferDesc.Variables; j++)
{
ID3D11ShaderReflectionVariable* pVariable = pConstantBuffer->GetVariableByIndex(j);
                //Access to variable information
D3D11_SHADER_VARIABLE_DESC variableDesc;
        pVariable->GetDesc(&variableDesc);

}
}

So, when the shader is bound, all the constant buffers it uses, will get updated with the new information and they will get bound to the right register. Right now I've been playing only with the constant buffer information, but i presume that the texture samplers will also be the same. I'll keep posting on any more details about shader reflection.

So if you're looking into writing a more flexible shader system, I'd suggest you to look into this whole interface. If you have any questions regarding the design of my new engine, or this interface, feel free to post on this blog.

Following are some links that helped me out:

http://msdn.microsoft.com/en-us/library/windows/desktop/ff476590(v=vs.85).aspx
http://members.gamedev.net/JasonZ/Heiroglyph/D3D11ShaderReflection.pdf

No comments: