Shader Reflection
DirectX 11 Shader Reflection
- ID3D11ShaderReflection
-> 해당 struct를 통해 Shader Reflection 실행.
- ID3D11ShaderReflectionConstantBuffer
-> 해당 struct를 통해 ConstantBuffer Index를 기준으로 정보를 가져온다.
- D3D11_SHADER_DESC
-> 해당 struct를 통해 ID3D11ShaderReflection에서 Shader 정보를 가져온다.
- D3D11_SHADER_BUFFER_DESC
-> 해당 struct를 통해 ID3D11ShaderReflectionConstantBuffer에서 Constant Buffer 정보를 가져온다.
- D3D11_SHADER_INPUT_BIND_DESC
-> 해당 struct를 통해 Binding 된 Resource Name을 기준으로 정보를 가져온다.
Shader Reflection 이점
- 경험상 Effect11을 사용 할 때 Input Layout 실수가 너무 잦아 애를 많이 먹었었다. 하지만 해당 Shader Reflection을
통해 Input Layout을 Shader Load시 설정할 수 있어 일일히 Input Layout과 대응하는 구조체를 만들어 설정해 줄
필요가 없어진다.
- Effect 기준 해당 Constant Buffer나 Resource에 관한 Update를 일일히 함수로 지정해주어야 했는데, 그렇게 되면
Shader가 늘어날수록 Class를 일일히 설정해주는게 귀찮았다. 하지만 Shader Reflection을 통해 해당 Resource의
Bind Point(Register Slot)을 알 수 있고, 해당 Register Slot으로 Resource를 설정 해주게 되면 매번 설정할 필요가
없어진다.
ID3DBlob* shaderBlob = nullptr;
ID3D11ShaderReflection* pReflector = nullptr;
...
// Create Reflector..
D3DReflect(shaderBlob->GetBufferPointer(), shaderBlob->GetBufferSize(), IID_ID3D11ShaderReflection, (void**)&pReflector);
// Shader Refection
D3D11_SHADER_DESC shaderDesc;
pReflector->GetDesc(&shaderDesc);
/// Input Layout Reflection
// Shader Input Layout..
std::vector<D3D11_INPUT_ELEMENT_DESC> inputLayoutDesc;
for (unsigned inputIndex = 0; inputIndex < shaderDesc.InputParameters; inputIndex++)
{
D3D11_SIGNATURE_PARAMETER_DESC paramDesc;
pReflector->GetInputParameterDesc(inputIndex, ¶mDesc);
// Shader Input Data를 기반으로 생성..
D3D11_INPUT_ELEMENT_DESC elementDesc;
elementDesc.SemanticName = paramDesc.SemanticName;
elementDesc.SemanticIndex = paramDesc.SemanticIndex;
elementDesc.InputSlot = 0;
elementDesc.AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
elementDesc.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
elementDesc.InstanceDataStepRate = 0;
// Shader Data 기반으로 DXGI format 설정..
if (paramDesc.Mask == 1)
{
if (paramDesc.ComponentType == D3D_REGISTER_COMPONENT_UINT32) elementDesc.Format = DXGI_FORMAT_R32_UINT;
else if (paramDesc.ComponentType == D3D_REGISTER_COMPONENT_SINT32) elementDesc.Format = DXGI_FORMAT_R32_SINT;
else if (paramDesc.ComponentType == D3D_REGISTER_COMPONENT_FLOAT32) elementDesc.Format = DXGI_FORMAT_R32_FLOAT;
}
else if (paramDesc.Mask <= 3)
{
if (paramDesc.ComponentType == D3D_REGISTER_COMPONENT_UINT32) elementDesc.Format = DXGI_FORMAT_R32G32_UINT;
else if (paramDesc.ComponentType == D3D_REGISTER_COMPONENT_SINT32) elementDesc.Format = DXGI_FORMAT_R32G32_SINT;
else if (paramDesc.ComponentType == D3D_REGISTER_COMPONENT_FLOAT32) elementDesc.Format = DXGI_FORMAT_R32G32_FLOAT;
}
else if (paramDesc.Mask <= 7)
{
if (paramDesc.ComponentType == D3D_REGISTER_COMPONENT_UINT32) elementDesc.Format = DXGI_FORMAT_R32G32B32_UINT;
else if (paramDesc.ComponentType == D3D_REGISTER_COMPONENT_SINT32) elementDesc.Format = DXGI_FORMAT_R32G32B32_SINT;
else if (paramDesc.ComponentType == D3D_REGISTER_COMPONENT_FLOAT32) elementDesc.Format = DXGI_FORMAT_R32G32B32_FLOAT;
}
else if (paramDesc.Mask <= 15)
{
if (paramDesc.ComponentType == D3D_REGISTER_COMPONENT_UINT32) elementDesc.Format = DXGI_FORMAT_R32G32B32A32_UINT;
else if (paramDesc.ComponentType == D3D_REGISTER_COMPONENT_SINT32) elementDesc.Format = DXGI_FORMAT_R32G32B32A32_SINT;
else if (paramDesc.ComponentType == D3D_REGISTER_COMPONENT_FLOAT32) elementDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
}
// 현 InputLayout 데이터 삽입..
inputLayoutDesc.push_back(elementDesc);
}
// Shader InputLayout 생성..
HR(g_Device->CreateInputLayout(&inputLayoutDesc[0], (UINT)inputLayoutDesc.size(), shaderBlob->GetBufferPointer(), shaderBlob->GetBufferSize(), &m_InputLayout));
/// ConstantBuffer Reflection
// Pixel Shader ConstantBuffer..
for (unsigned int cbindex = 0; cbindex < shaderDesc.ConstantBuffers; cbindex++)
{
ID3D11ShaderReflectionConstantBuffer* cBuffer = pReflector->GetConstantBufferByIndex(cbindex);
D3D11_SHADER_BUFFER_DESC bufferDesc;
if (SUCCEEDED(cBuffer->GetDesc(&bufferDesc)))
{
ID3D11Buffer* cBuffer = nullptr;
CD3D11_BUFFER_DESC cBufferDesc(bufferDesc.Size, D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
D3D11_SHADER_INPUT_BIND_DESC bindDesc;
pReflector->GetResourceBindingDescByName(bufferDesc.Name, &bindDesc);
// 해당 Constant Buffer 생성..
HR(g_Device->CreateBuffer(&cBufferDesc, nullptr, &cBuffer));
// Constant Buffer Register Slot Number..
cbuffer_register_slot = bindDesc.BindPoint;
...
}
}
/// Shader Resource Reflection
// Shader Resource..
for (unsigned int rsindex = 0; rsindex < shaderDesc.BoundResources; rsindex++)
{
D3D11_SHADER_INPUT_BIND_DESC bindDesc;
pReflector->GetResourceBindingDesc(rsindex, &bindDesc);
// Resource Type에 맞는 해당 List에 삽입..
switch (bindDesc.Type)
{
case D3D_SIT_TEXTURE:
{
// Texture Resource 삽입..
}
break;
case D3D_SIT_SAMPLER:
{
// Sampler Resource 삽입..
}
break;
default:
break;
}
}
Shader Reflection을 통한 Shader Data 설정.
/// <summary>
/// ShaderBase Class
/// </summary>
///
/// - 모든 Shader Class의 Base Class
/// - Vertex, Pixel, Compute Shader의 기본적으로 사용하는 Resource를 포함한 Base Class
///
class ShaderBase : public IShader
{
public:
ShaderBase(SHADER_TYPE shaderType) : m_ShaderType(shaderType) {}
public:
virtual void LoadShader(std::string fileName, const char* entry_point, const char* shader_model, const D3D_SHADER_MACRO* pDefines) abstract;
virtual void Update() abstract;
virtual void Release();
// Shader SamplerState 설정..
void SetSamplerState(Hash_Code hash_code, ID3D11SamplerState* sampler);
// Shader ConstantBuffer Resource Update..
template<typename T>
void ConstantBufferCopy(T* cBuffer);
template<typename T>
void ConstantBufferUpdate(T* cBuffer);
// Shader ShaderResourceView 설정..
template<typename T>
void SetShaderResourceView(ID3D11ShaderResourceView* srv);
public:
// 현재 Shader Type 반환 함수..
SHADER_TYPE GetType();
protected:
void CreateShader(const wchar_t* wPath, const D3D_SHADER_MACRO* pDefines, LPCSTR entry_point, LPCSTR shader_model, ID3DBlob** ppShader);
protected:
// 연속된 메모리 공간에 있는 ConstantBuffer List..
std::vector<Microsoft::WRL::ComPtr<ID3D11Buffer>> m_ConstantBuffers;
// 연속된 메모리 공간에 있는 SamplerState List..
std::vector<Microsoft::WRL::ComPtr<ID3D11SamplerState>> m_SamplerStates;
// 연속된 메모리 공간에 있는 ShaderResourceView List..
std::vector<Microsoft::WRL::ComPtr<ID3D11ShaderResourceView>> m_ShaderResourceViews;
// PixelShader ConstantBuffer List..
std::unordered_map<Hash_Code, ConstantBuffer*> m_ConstantBufferList;
// PixelShader SamplerState List..
std::unordered_map<Hash_Code, SamplerBuffer*> m_SamplerList;
// PixelShader ShaderResourceView List..
std::unordered_map<Hash_Code, ShaderResourceBuffer*> m_SRVList;
private:
// 현재 Shader Type..
SHADER_TYPE m_ShaderType;
};
Shader Base Class를 통해 Shader Resource Update.