-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathShaderInjectionSystem.hpp
176 lines (152 loc) · 5.29 KB
/
ShaderInjectionSystem.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
#pragma once
#include <d3d11.h>
#include <d3dcompiler.h>
#include <string>
#include <unordered_map>
#include <memory>
#include <filesystem>
#include <functional>
class ShaderInjectionSystem {
public:
// Shader modification callback type
using ShaderModifierFn = std::function<std::string(const std::string&)>;
struct InjectionPoint {
std::string marker; // Marker in shader code
std::string injectedCode; // Code to inject
bool enabled = true;
};
struct ShaderVariant {
std::string name;
std::vector<std::string> defines;
std::vector<InjectionPoint> injectionPoints;
bool enabled = true;
};
ShaderInjectionSystem(ID3D11Device* device) : m_device(device) {
// Register default injectors
RegisterInjector("DEBUG", [](const std::string& code) {
return "#define DEBUG 1\n" + code;
});
RegisterInjector("PROFILING", [](const std::string& code) {
return "#define PROFILING 1\n"
"#define START_PROFILE(name) ProfileBlock profile##__LINE__(name)\n" +
code;
});
}
// Register a new shader modifier
void RegisterInjector(const std::string& name, ShaderModifierFn modifier) {
m_modifiers[name] = modifier;
}
// Add injection point
void AddInjectionPoint(const std::string& shaderName, const InjectionPoint& point) {
m_injectionPoints[shaderName].push_back(point);
}
// Create shader variant
void CreateVariant(const std::string& baseName, const ShaderVariant& variant) {
m_variants[baseName + ":" + variant.name] = variant;
}
// Load and compile shader with injections
ID3D11VertexShader* CompileVertexShader(
const std::string& shaderPath,
const std::string& variantName = "") {
std::string processedCode = LoadAndProcessShader(shaderPath, variantName);
// Compile shader
ComPtr<ID3DBlob> shaderBlob;
ComPtr<ID3DBlob> errorBlob;
HRESULT hr = D3DCompile(
processedCode.c_str(),
processedCode.length(),
shaderPath.c_str(),
nullptr,
D3D_COMPILE_STANDARD_FILE_INCLUDE,
"main",
"vs_5_0",
D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION,
0,
&shaderBlob,
&errorBlob
);
if (FAILED(hr)) {
if (errorBlob) {
// Log error
OutputDebugStringA(static_cast<char*>(errorBlob->GetBufferPointer()));
}
return nullptr;
}
// Create shader
ID3D11VertexShader* shader;
hr = m_device->CreateVertexShader(
shaderBlob->GetBufferPointer(),
shaderBlob->GetBufferSize(),
nullptr,
&shader
);
if (FAILED(hr)) {
return nullptr;
}
return shader;
}
// Dynamic shader patching at runtime
bool PatchShader(const std::string& shaderName,
const std::string& markerName,
const std::string& newCode) {
auto& points = m_injectionPoints[shaderName];
for (auto& point : points) {
if (point.marker == markerName) {
point.injectedCode = newCode;
return true;
}
}
return false;
}
// Enable/disable injection points
void SetInjectionPointEnabled(const std::string& shaderName,
const std::string& markerName,
bool enabled) {
auto& points = m_injectionPoints[shaderName];
for (auto& point : points) {
if (point.marker == markerName) {
point.enabled = enabled;
break;
}
}
}
private:
ID3D11Device* m_device;
std::unordered_map<std::string, ShaderModifierFn> m_modifiers;
std::unordered_map<std::string, std::vector<InjectionPoint>> m_injectionPoints;
std::unordered_map<std::string, ShaderVariant> m_variants;
std::string LoadAndProcessShader(const std::string& path,
const std::string& variantName) {
// Load shader file
std::ifstream file(path);
if (!file.is_open()) {
return "";
}
std::stringstream buffer;
buffer << file.rdbuf();
std::string code = buffer.str();
// Apply variant defines if specified
if (!variantName.empty()) {
if (auto it = m_variants.find(variantName); it != m_variants.end()) {
for (const auto& define : it->second.defines) {
code = "#define " + define + "\n" + code;
}
}
}
// Apply active injections
auto& points = m_injectionPoints[path];
for (const auto& point : points) {
if (point.enabled) {
size_t pos = code.find(point.marker);
if (pos != std::string::npos) {
code.insert(pos + point.marker.length(), "\n" + point.injectedCode);
}
}
}
// Apply modifiers
for (const auto& [name, modifier] : m_modifiers) {
code = modifier(code);
}
return code;
}
};