SleakEngine 1.0.0
C++23 multi-backend game engine
Loading...
Searching...
No Matches
DirectX11Shader.cpp
Go to the documentation of this file.
2
3#include <d3d11.h>
4#include <d3d11shader.h>
5#include <d3dcompiler.h>
6#include <wrl/client.h>
7
8#include <Core/Logger.hpp>
9#include <stdexcept>
10#include <string>
11
12namespace Sleak {
13namespace RenderEngine {
14
15DirectX11Shader::DirectX11Shader(ID3D11Device* device) : m_device(device) {
16 assert(m_device != nullptr); // Ensure the device is valid
17 m_device->GetImmediateContext(m_deviceContext.GetAddressOf());
18}
19
21 // Resources are automatically released by ComPtr
22}
23
24bool DirectX11Shader::compile(const std::string& shaderPath) {
25 // Compile vertex shader
26 if (!compileShader(shaderPath, "VS_Main", "vs_5_0", m_vertexShader,
27 m_vertexShaderBlob)) {
28 SLEAK_ERROR("Failed to compile vertex shader!");
29 return false;
30 }
31
32 // Compile pixel shader
33 if (!compileShader(shaderPath, "PS_Main", "ps_5_0", m_pixelShader,
34 m_pixelShaderBlob)) {
35 SLEAK_ERROR("Failed to compile pixel shader!");
36 return false;
37 }
38
39 return true;
40}
41
42bool DirectX11Shader::compile(const std::string& vertPath,
43 const std::string& fragPath) {
44 // Compile vertex shader
45 if (!compileShader(vertPath, "Main", "vs_5_0", m_vertexShader,
46 m_vertexShaderBlob)) {
47 SLEAK_ERROR("Failed to compile vertex shader!");
48 return false;
49 }
50
51 // Compile pixel shader
52 if (!compileShader(fragPath, "Main", "ps_5_0", m_pixelShader,
53 m_pixelShaderBlob)) {
54 SLEAK_ERROR("Failed to compile pixel shader!");
55 return false;
56 }
57
58 return true;
59}
60
62 if (!m_vertexShader || !m_pixelShader) {
63 throw std::runtime_error("Shaders are not compiled!");
64 }
65
66 m_deviceContext->VSSetShader(m_vertexShader.Get(), nullptr, 0);
67 m_deviceContext->PSSetShader(m_pixelShader.Get(), nullptr, 0);
68 if (Layout)
69 m_deviceContext->IASetInputLayout(Layout.Get());
70}
71
73 return m_vertexShaderBlob.Get();
74}
75
77 // Check via reflection if the shader uses BLENDINDICES (skinned shader)
78 bool isSkinned = false;
79 Microsoft::WRL::ComPtr<ID3D11ShaderReflection> reflector;
80 HRESULT hr = D3DReflect(m_vertexShaderBlob->GetBufferPointer(),
81 m_vertexShaderBlob->GetBufferSize(),
82 IID_ID3D11ShaderReflection,
83 reinterpret_cast<void**>(reflector.GetAddressOf()));
84 if (SUCCEEDED(hr)) {
85 D3D11_SHADER_DESC shaderDesc;
86 reflector->GetDesc(&shaderDesc);
87 for (UINT p = 0; p < shaderDesc.InputParameters; ++p) {
88 D3D11_SIGNATURE_PARAMETER_DESC paramDesc;
89 reflector->GetInputParameterDesc(p, &paramDesc);
90 if (strcmp(paramDesc.SemanticName, "BLENDINDICES") == 0) {
91 isSkinned = true;
92 break;
93 }
94 }
95 }
96
97 D3D11_INPUT_ELEMENT_DESC* layoutDesc = isSkinned ? SkinnedLayout : DefaultLayout;
98 UINT layoutCount = isSkinned ? ARRAYSIZE(SkinnedLayout) : ARRAYSIZE(DefaultLayout);
99
100 ID3D11InputLayout* inputLayout = nullptr;
101 hr = m_device->CreateInputLayout(
102 layoutDesc, layoutCount,
103 m_vertexShaderBlob->GetBufferPointer(),
104 m_vertexShaderBlob->GetBufferSize(), &inputLayout);
105
106 if (FAILED(hr)) {
107 SLEAK_ERROR("Failed to create input layout: 0x{:08X}", hr);
108 return nullptr;
109 }
110
111 // Store per-shader so bind() can set it
112 Layout.Attach(inputLayout);
113 inputLayout->AddRef(); // Keep a ref for the caller too
114
115 return inputLayout;
116}
117
118/// Compiles a shader stage from an HLSL file and creates the matching D3D11 shader object.
119template <typename T>
120bool DirectX11Shader::compileShader(const std::string& filePath,
121 const std::string& entryPoint,
122 const std::string& profile,
123 Microsoft::WRL::ComPtr<T>& shader,
124 Microsoft::WRL::ComPtr<ID3DBlob>& blob) {
125 Microsoft::WRL::ComPtr<ID3DBlob> errorBlob;
126 HRESULT hr = D3DCompileFromFile(
127 std::wstring(filePath.begin(), filePath.end()).c_str(), // File path
128 nullptr, // Defines
129 D3D_COMPILE_STANDARD_FILE_INCLUDE, // Includes
130 entryPoint.c_str(), // Entry point
131 profile.c_str(), // Shader profile (e.g., "vs_5_0")
132 D3DCOMPILE_DEBUG, // Flags
133 0, // Flags 2
134 &blob, // Output blob
135 &errorBlob // Error blob
136 );
137
138 if (FAILED(hr)) {
139 if (errorBlob) {
140 SLEAK_ERROR("Shader compilation error: {}",
141 (char*)errorBlob->GetBufferPointer());
142 }
143 return false;
144 }
145
146 // Create the shader object
147 if constexpr (std::is_same_v<T, ID3D11VertexShader>) {
148 hr = m_device->CreateVertexShader(
149 blob->GetBufferPointer(), blob->GetBufferSize(), nullptr,
150 reinterpret_cast<ID3D11VertexShader**>(shader.GetAddressOf()));
151 } else if constexpr (std::is_same_v<T, ID3D11PixelShader>) {
152 hr = m_device->CreatePixelShader(
153 blob->GetBufferPointer(), blob->GetBufferSize(), nullptr,
154 reinterpret_cast<ID3D11PixelShader**>(shader.GetAddressOf()));
155 }
156
157 return SUCCEEDED(hr);
158}
159
160} // namespace RenderEngine
161} // namespace Sleak
#define SLEAK_ERROR(...)
Definition Logger.hpp:22
ID3D11InputLayout * createInputLayout()
Builds the input layout matching DefaultLayout or SkinnedLayout from the vertex shader bytecode.
bool compile(const std::string &shaderPath) override
Compiles the combined-path convention (vs_main/ps_main entry points) from a single HLSL file.
void bind() override
Binds this program as the active shader for subsequent draws.
Backend-facing rendering layer shared by the four graphics backends.
Root namespace for everything the engine exposes.
Definition Camera.hpp:10