Hello all! I got to the point where I am tired of hardcoding shaders and decided that it was now time to look into using ID3D11ShaderReflection to get data from the shader and set my shader's constant buffer using that data. I have a simple system that loads up shaders and gets it's data.
H:
enum NXDeviceShaderType
{
NXDST_VERTEX,
NXDST_PIXEL,
NXDTS_COMPUTE,
NXDST_GEOMETRY,
NXDST_DOMAIN,
NXDST_HULL,
};
struct NXShaderVariable
{
D3D11_SHADER_VARIABLE_DESC Description;
D3D11_SHADER_TYPE_DESC Type;
};
struct NXShaderConstantBuffer
{
ID3D11Buffer* Data = nullptr;
D3D11_SHADER_BUFFER_DESC Description;
vector<NXShaderVariable> Variables;
bool Create();
~NXShaderConstantBuffer()
{
if (Data)
{
Data = nullptr;
}
Variables.clear();
}
};
class NXDeviceShader
{
public:
~NXDeviceShader()
{
if (Reflection)
{
Reflection->Release();
Reflection = nullptr;
}
ConstantBuffers.clear();
};
D3D_FEATURE_LEVEL MinimumFeatureLevel;
ID3D11ShaderReflection* Reflection = nullptr;
vector<NXShaderConstantBuffer> ConstantBuffers;
bool Enabled = true;
virtual const NXDeviceShaderType Type() = 0;
virtual void Apply() = 0;
virtual void Dispose() = 0;
NXShaderVariable* GetVariableByName(string name);
/*bool Set(string constantName, DirectX::XMMATRIX& value)
{
return UpdateConstant(0, constantName, &value);
}
void Set(string constantName, int value);
void Set(string constantName, float value);
void Set(string constantName, double value);
void Set(string constantName, XMVECTOR& value);
void Set(string constantName, XMFLOAT2 value);
void Set(string constantName, XMFLOAT3 value);
void Set(string constantName, XMFLOAT4 value);
void Set(string constantName, XMMATRIX& value);*/
private:
};
class NXVertexShader : public NXDeviceShader
{
public:
const NXDeviceShaderType Type()
{
return NXDST_VERTEX;
}
void Apply();
void Dispose();
ID3D11VertexShader* Shader = nullptr;
ID3D11InputLayout* Layout = nullptr;
};
class NXPixelShader : public NXDeviceShader
{
public:
const NXDeviceShaderType Type()
{
return NXDST_PIXEL;
}
void Apply();
void Dispose();
ID3D11PixelShader* Shader = nullptr;
};
class NXComputeShader : public NXDeviceShader
{
public:
const NXDeviceShaderType Type()
{
return NXDTS_COMPUTE;
}
void Apply();
void Dispose();
ID3D11ComputeShader* Shader = nullptr;
};
class NXGeometryShader : public NXDeviceShader
{
public:
const NXDeviceShaderType Type()
{
return NXDST_GEOMETRY;
}
void Apply();
void Dispose();
ID3D11GeometryShader* Shader = nullptr;
};
class NXDomainShader : public NXDeviceShader
{
public:
const NXDeviceShaderType Type()
{
return NXDST_DOMAIN;
}
void Apply();
void Dispose();
ID3D11DomainShader* Shader = nullptr;
};
class NXHullShader : public NXDeviceShader
{
public:
const NXDeviceShaderType Type()
{
return NXDST_HULL;
}
void Apply();
void Dispose();
ID3D11HullShader* Shader = nullptr;
};
bool NXGetShaderInformation(NXDeviceShader* shader);
bool NXCreateVertexShader(string& file, NXVertexShader* shader);
bool NXCreatePixelShader(string& file, NXPixelShader* shader);
bool NXCreateComputeShader(string& file, NXComputeShader* shader);
bool NXCreateGeometryShader(string& file, NXGeometryShader* shader);
bool NXCreateDomainShader(string& file, NXDomainShader* shader);
bool NXCreateHullShader(string& file, NXHullShader* shader);
class NXShader
{
public:
NXShader(){}
NXShader(string vsFileName, string psFileName, string csFileName, string gsFileName, string dsFileName, string hsFileName);
NXShader(string vsFileName, string psFileName, string csFileName, string gsFileName, string dsFileName);
NXShader(string vsFileName, string psFileName, string csFileName, string gsFileName);
NXShader(string vsFileName, string psFileName, string csFileName);
NXShader(string vsFileName, string psFileName);
void Apply();
void Dispose();
int ID = 0;
NXVertexShader* VertexShader = nullptr;
NXPixelShader* PixelShader = nullptr;
NXComputeShader* ComputeShader = nullptr;
NXGeometryShader* GeometryShader = nullptr;
NXDomainShader* DomainShader = nullptr;
NXHullShader* HullShader = nullptr;
};
CPP:
bool NXShaderConstantBuffer::Create()
{
D3D11_BUFFER_DESC desc;
desc.ByteWidth = Description.Size;
desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
desc.MiscFlags = 0;
desc.StructureByteStride = 0;
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
if (FAILED(Core::NXGPU::CreateBuffer(&desc, 0, &Data)))
return false;
return true;
}
//----------------------------------------------------//
bool NXGetShaderInformation(NXDeviceShader* shader)
{
if (shader->Reflection == nullptr)
return false;
D3D11_SHADER_DESC shaderDesc;
shader->Reflection->GetDesc(&shaderDesc);
shader->Reflection->GetMinFeatureLevel(&shader->MinimumFeatureLevel);
/*for (UINT i = 0; i < shaderDesc.InputParameters; ++i)
{
D3D11_SIGNATURE_PARAMETER_DESC input_desc;
shader->Reflection->GetInputParameterDesc(i, &input_desc);
shader->InputParameters.push_back(input_desc);
}
for (UINT i = 0; i < shaderDesc.OutputParameters; ++i)
{
D3D11_SIGNATURE_PARAMETER_DESC output_desc;
shader->Reflection->GetInputParameterDesc(i, &output_desc);
shader->OutputParameters.push_back(output_desc);
}*/
for (UINT i = 0; i < shaderDesc.ConstantBuffers; ++i)
{
NXShaderConstantBuffer constantBuffer;
ID3D11ShaderReflectionConstantBuffer* buffer = shader->Reflection->GetConstantBufferByIndex(i);
if (FAILED(buffer->GetDesc(&constantBuffer.Description)))
return false;
for (UINT v = 0; v < constantBuffer.Description.Variables; ++v)
{
NXShaderVariable shaderVariable;
ID3D11ShaderReflectionVariable* variable = buffer->GetVariableByIndex(v);
if (FAILED(variable->GetDesc(&shaderVariable.Description)))
return false;
ID3D11ShaderReflectionType* type = variable->GetType();
if (FAILED(type->GetDesc(&shaderVariable.Type)))
return false;
constantBuffer.Variables.push_back(shaderVariable);
}
if (!constantBuffer.Create())
return false;
shader->ConstantBuffers.push_back(constantBuffer);
}
return true;
}
bool NXCreateVertexShader(string& file, NXVertexShader* shader)
{
HRESULT result;
IO::NXBinaryReader vsReader(file);
vector<uint8_t> vsCode;
if (vsReader.Exists())
{
vsReader.ReadFileToBuffer(vsCode);
result = Core::NXGPU::GetDevice()->CreateVertexShader(vsCode.data(), vsReader.GetSize(), nullptr, &shader->Shader);
if (FAILED(result))
{
vsCode.clear();
vsReader.Close();
shader->Dispose();
MessageBox(nullptr, L"Failed To Create Vertex Shader.", L"Error", MB_OK);
return false;
}
result = D3DReflect(vsCode.data(), vsReader.GetSize(), IID_ID3D11ShaderReflection, (void**) &shader->Reflection);
if (FAILED(result))
{
vsCode.clear();
vsReader.Close();
shader->Dispose();
MessageBox(nullptr, L"Failed To Create Vertex Shader Reflection.", L"Error", MB_OK);
return false;
}
}
else
{
vsReader.Close();
shader->Dispose();
MessageBox(nullptr, L"Could not find vertex shader.", L"Error", MB_OK);
return false;
}
result = Core::NXGPU::GetDevice()->CreateInputLayout(Graphics::NXVertex::InputElements, Graphics::NXVertex::InputElementCount, vsCode.data(),
vsReader.GetSize(), &shader->Layout);
vsCode.clear();
vsReader.Close();
if (FAILED(result))
{
shader->Dispose();
MessageBox(nullptr, L"Failed To Create Input Layout.", L"Error", MB_OK);
return false;
}
result = NULL;
return NXGetShaderInformation(shader);
}
bool NXCreatePixelShader(string& file, NXPixelShader* shader)
{
HRESULT result;
IO::NXBinaryReader psReader(file);
vector<uint8_t> psCode;
if (psReader.Exists())
{
psReader.ReadFileToBuffer(psCode);
result = Core::NXGPU::GetDevice()->CreatePixelShader(psCode.data(), psReader.GetSize(), nullptr, &shader->Shader);
if (FAILED(result))
{
shader->Dispose();
MessageBox(nullptr, L"Failed To Create Pixel Shader.", L"Error", MB_OK);
return false;
}
result = D3DReflect(psCode.data(), psReader.GetSize(), IID_ID3D11ShaderReflection, (void**) &shader->Reflection);
psCode.clear();
psReader.Close();
if (FAILED(result))
{
shader->Dispose();
MessageBox(nullptr, L"Failed To Create Pixel Shader Reflection.", L"Error", MB_OK);
return false;
}
}
else
{
psReader.Close();
shader->Dispose();
MessageBox(nullptr, L"Could not find pixel shader.", L"Error", MB_OK);
return false;
}
result = NULL;
return NXGetShaderInformation(shader);
}
bool NXCreateComputeShader(string& file, NXComputeShader* shader)
{
HRESULT result;
IO::NXBinaryReader csReader(file);
vector<uint8_t> csCode;
if (csReader.Exists())
{
csReader.ReadFileToBuffer(csCode);
result = Core::NXGPU::GetDevice()->CreateComputeShader(csCode.data(), csReader.GetSize(), nullptr, &shader->Shader);
if (FAILED(result))
{
shader->Dispose();
MessageBox(nullptr, L"Failed To Create Compute Shader.", L"Error", MB_OK);
return false;
}
result = D3DReflect(csCode.data(), csReader.GetSize(), IID_ID3D11ShaderReflection, (void**) &shader->Reflection);
csCode.clear();
csReader.Close();
if (FAILED(result))
{
shader->Dispose();
MessageBox(nullptr, L"Failed To Create Compute Shader Reflection.", L"Error", MB_OK);
return false;
}
}
else
{
csReader.Close();
shader->Dispose();
MessageBox(nullptr, L"Could not find compute shader.", L"Error", MB_OK);
return false;
}
result = NULL;
return NXGetShaderInformation(shader);
}
bool NXCreateGeometryShader(string& file, NXGeometryShader* shader)
{
HRESULT result;
IO::NXBinaryReader gsReader(file);
vector<uint8_t> gsCode;
if (gsReader.Exists())
{
gsReader.ReadFileToBuffer(gsCode);
result = Core::NXGPU::GetDevice()->CreateGeometryShader(gsCode.data(), gsReader.GetSize(), nullptr, &shader->Shader);
if (FAILED(result))
{
shader->Dispose();
MessageBox(nullptr, L"Failed To Create Geometry Shader.", L"Error", MB_OK);
return false;
}
result = D3DReflect(gsCode.data(), gsReader.GetSize(), IID_ID3D11ShaderReflection, (void**) &shader->Reflection);
gsCode.clear();
gsReader.Close();
if (FAILED(result))
{
shader->Dispose();
MessageBox(nullptr, L"Failed To Create Geometry Shader Reflection.", L"Error", MB_OK);
return false;
}
}
else
{
gsReader.Close();
shader->Dispose();
MessageBox(nullptr, L"Could not find geometry shader.", L"Error", MB_OK);
return false;
}
result = NULL;
return NXGetShaderInformation(shader);
}
bool NXCreateDomainShader(string& file, NXDomainShader* shader)
{
HRESULT result;
IO::NXBinaryReader dsReader(file);
vector<uint8_t> dsCode;
if (dsReader.Exists())
{
dsReader.ReadFileToBuffer(dsCode);
result = Core::NXGPU::GetDevice()->CreateDomainShader(dsCode.data(), dsReader.GetSize(), nullptr, &shader->Shader);
if (FAILED(result))
{
shader->Dispose();
MessageBox(nullptr, L"Failed To Create Domain Shader.", L"Error", MB_OK);
return false;
}
result = D3DReflect(dsCode.data(), dsReader.GetSize(), IID_ID3D11ShaderReflection, (void**) &shader->Reflection);
dsCode.clear();
dsReader.Close();
if (FAILED(result))
{
shader->Dispose();
MessageBox(nullptr, L"Failed To Create Domain Shader Reflection.", L"Error", MB_OK);
return false;
}
}
else
{
dsReader.Close();
shader->Dispose();
MessageBox(nullptr, L"Could not find domain shader.", L"Error", MB_OK);
return false;
}
result = NULL;
return NXGetShaderInformation(shader);
}
bool NXCreateHullShader(string& file, NXHullShader* shader)
{
HRESULT result;
IO::NXBinaryReader hsReader(file);
vector<uint8_t> hsCode;
if (hsReader.Exists())
{
hsReader.ReadFileToBuffer(hsCode);
result = Core::NXGPU::GetDevice()->CreateHullShader(hsCode.data(), hsReader.GetSize(), nullptr, &shader->Shader);
if (FAILED(result))
{
shader->Dispose();
MessageBox(nullptr, L"Failed To Create Hull Shader.", L"Error", MB_OK);
return false;
}
result = D3DReflect(hsCode.data(), hsReader.GetSize(), IID_ID3D11ShaderReflection, (void**) &shader->Reflection);
hsCode.clear();
hsReader.Close();
if (FAILED(result))
{
shader->Dispose();
MessageBox(nullptr, L"Failed To Create Hull Shader Reflection.", L"Error", MB_OK);
return false;
}
}
else
{
hsReader.Close();
shader->Dispose();
MessageBox(nullptr, L"Could not find hull shader.", L"Error", MB_OK);
return false;
}
return NXGetShaderInformation(shader);
}
//----------------------------------------------------//
NXShaderVariable* NXDeviceShader::GetVariableByName(string name)
{
for (unsigned int i = 0; i < ConstantBuffers.size(); ++i)
{
for (unsigned int v = 0; v < ConstantBuffers[i].Variables.size(); ++v)
{
if (ConstantBuffers[i].Variables[v].Description.Name == name)
{
return &ConstantBuffers[i].Variables[v];
}
}
}
return nullptr;
}
void NXVertexShader::Apply()
{
if (Shader && Layout && Enabled)
{
Core::NXGPU::GetDeviceContext()->IASetInputLayout(Layout);
Core::NXGPU::SetVertexShader(Shader, nullptr, 0);
}
}
void NXVertexShader::Dispose()
{
if (Layout)
{
Layout->Release();
Layout = nullptr;
}
if (Shader)
{
Shader->Release();
Shader = nullptr;
}
}
void NXDomainShader::Apply()
{
if (Shader && Enabled)
{
Core::NXGPU::SetDomainShader(Shader, nullptr, 0);
}
}
void NXDomainShader::Dispose()
{
if (Shader)
{
Shader->Release();
Shader = nullptr;
}
}
void NXHullShader::Apply()
{
if (Shader && Enabled)
{
Core::NXGPU::SetHullShader(Shader, nullptr, 0);
}
}
void NXHullShader::Dispose()
{
if (Shader)
{
Shader->Release();
Shader = nullptr;
}
}
void NXGeometryShader::Apply()
{
if (Shader && Enabled)
{
Core::NXGPU::SetGeometryShader(Shader, nullptr, 0);
}
}
void NXGeometryShader::Dispose()
{
if (Shader)
{
Shader->Release();
Shader = nullptr;
}
}
void NXPixelShader::Apply()
{
if (Shader && Enabled)
{
Core::NXGPU::SetPixelShader(Shader, nullptr, 0);
}
}
void NXPixelShader::Dispose()
{
if (Shader)
{
Shader->Release();
Shader = nullptr;
}
}
void NXComputeShader::Apply()
{
if (Shader && Enabled)
{
Core::NXGPU::SetComputeShader(Shader, nullptr, 0);
}
}
void NXComputeShader::Dispose()
{
if (Shader)
{
Shader->Release();
Shader = nullptr;
}
}
//----------------------------------------------------//
NXShader::NXShader(string vsFileName, string psFileName, string csFileName, string gsFileName, string dsFileName, string hsFileName)
{
if (vsFileName != "")
{
VertexShader = new NXVertexShader();
if (!NXCreateVertexShader(vsFileName, VertexShader))
{
Dispose();
return;
}
}
if (psFileName != "")
{
PixelShader = new NXPixelShader();
if (!NXCreatePixelShader(psFileName, PixelShader))
{
Dispose();
return;
}
}
if (csFileName != "")
{
ComputeShader = new NXComputeShader();
if (!NXCreateComputeShader(csFileName, ComputeShader))
{
Dispose();
return;
}
}
if (gsFileName != "")
{
GeometryShader = new NXGeometryShader();
if (!NXCreateGeometryShader(gsFileName, GeometryShader))
{
Dispose();
return;
}
}
if (dsFileName != "")
{
DomainShader = new NXDomainShader();
if (!NXCreateDomainShader(dsFileName, DomainShader))
{
Dispose();
return;
}
}
if (hsFileName != "")
{
HullShader = new NXHullShader();
if (!NXCreateHullShader(hsFileName, HullShader))
{
Dispose();
return;
}
}
}
NXShader::NXShader(string vsFileName, string psFileName, string csFileName, string gsFileName, string dsFileName) : NXShader(vsFileName, psFileName, csFileName, gsFileName, dsFileName, ""){}
NXShader::NXShader(string vsFileName, string psFileName, string csFileName, string gsFileName) : NXShader(vsFileName, psFileName, csFileName, gsFileName, "", ""){}
NXShader::NXShader(string vsFileName, string psFileName, string csFileName) : NXShader(vsFileName, psFileName, csFileName, "", "", ""){}
NXShader::NXShader(string vsFileName, string psFileName) : NXShader(vsFileName, psFileName, "", "", "", ""){}
void NXShader::Apply()
{
if (VertexShader)
VertexShader->Apply();
if (PixelShader)
PixelShader->Apply();
if (ComputeShader)
ComputeShader->Apply();
if (GeometryShader)
GeometryShader->Apply();
if (DomainShader)
DomainShader->Apply();
if (HullShader)
HullShader->Apply();
}
void NXShader::Dispose()
{
if (VertexShader)
{
VertexShader->Dispose();
delete VertexShader;
VertexShader = nullptr;
}
if (PixelShader)
{
PixelShader->Dispose();
delete PixelShader;
PixelShader = nullptr;
}
if (ComputeShader)
{
ComputeShader->Dispose();
delete ComputeShader;
ComputeShader = nullptr;
}
if (GeometryShader)
{
GeometryShader->Dispose();
delete GeometryShader;
GeometryShader = nullptr;
}
if (DomainShader)
{
DomainShader->Dispose();
delete DomainShader;
DomainShader = nullptr;
}
if (HullShader)
{
HullShader->Dispose();
delete HullShader;
HullShader = nullptr;
}
}
Now that I have the data, I would like to know how the correct way to upload the data to the constant buffer. I've searched on Google and couldn't find too much information on this. Any help? Thanks! :)