Cogs.Core
EffectsCommon.cpp
1#include "EffectsCommon.h"
2#include "DefaultIOHandler.h"
3#include "Utilities.h"
4
5#include "../IBuffers.h"
6
7#include "Foundation/Logging/Logger.h"
8
9namespace
10{
11 Cogs::Logging::Log logger = Cogs::Logging::getLogger("EffectsCommon");
12}
13
14#ifdef COGSRENDERING_GFX_ANNOTATE
15Cogs::StringView Cogs::tryToName(const Cogs::StringView filename)
16{
17 size_t first = 0, t;
18 size_t last = filename.length();
19
20 t = filename.find_last_of("/\\");
21 if (t != std::string::npos) {
22 first = t;
23 }
24
25 t = filename.find_last_of('.', first);
26 if (t != std::string::npos) {
27 last = t;
28 }
29
30 if (first < last) {
31 return filename.substr(first, last - first);
32 }
33 else {
34 return "";
35 }
36}
37#endif
38
39void Cogs::EffectsCommon::initialize(IBuffers * buffers)
40{
41 if (!handler) {
42 defaultHandler = std::make_unique<DefaultIOHandler>();
43 handler = defaultHandler.get();
44 }
45 else{
46 LOG_DEBUG(logger, "Custom IOHandler set.");
47 }
48 this->buffers = buffers;
49}
50
52{
53 if (description.type == EffectDescriptionType::File) {
54 EffectDescription sourceDescription = description;
55 sourceDescription.type = EffectDescriptionType::Source;
56
57 EffectContents contents = {};
58
59 if (description.effect.size()) {
60 Utilities::readFile(handler, description.effect, contents.effect);
61 } else {
62 if (!Utilities::readFile(handler, description.vertexShader, contents.vertexShader)) {
63 LOG_WARNING(logger, "Failed to read vertex shader %s.", std::string(description.vertexShader).c_str());
65 }
66 if(!contents.vertexShader.content.size()) {
67 LOG_WARNING(logger, "Vertex shader %s is empty.", std::string(description.vertexShader).c_str());
69 }
70
71 if (description.geometryShader.size()) {
72 Utilities::readFile(handler, description.geometryShader, contents.geometryShader);
73 }
74
75 if (description.pixelShader.size()) {
76 Utilities::readFile(handler, description.pixelShader, contents.pixelShader);
77 }
78
79 if (description.hullShader.size()) {
80 Utilities::readFile(handler, description.hullShader, contents.hullShader);
81 }
82
83 if (description.domainShader.size()) {
84 Utilities::readFile(handler, description.domainShader, contents.domainShader);
85 }
86 }
87
88 return loadEffectContents(sourceDescription, contents);
89 } else {
90 return loadEffectSource(description);
91 }
92}
93
94Cogs::EffectHandle Cogs::EffectsCommon::loadEffectSource(const EffectDescription & description)
95{
97
98 EffectContents contents = {};
99
100 if (description.effect.size()) {
101 Utilities::preprocessContent(handler, description.effect, contents.effect);
102 } else {
103 Utilities::preprocessContent(handler, description.vertexShader, contents.vertexShader);
104
105 if (description.geometryShader.size()) {
106 Utilities::preprocessContent(handler, description.geometryShader, contents.geometryShader);
107 }
108
109 if (description.hullShader.size()) {
110 Utilities::preprocessContent(handler, description.hullShader, contents.hullShader);
111 }
112
113 if (description.domainShader.size()) {
114 Utilities::preprocessContent(handler, description.domainShader, contents.domainShader);
115 }
116
117 Utilities::preprocessContent(handler, description.pixelShader, contents.pixelShader);
118 }
119
120 return loadEffectContents(description, contents);
121}
122
123Cogs::EffectHandle Cogs::EffectsCommon::loadEffectContents(const EffectDescription & description, const EffectContents & contents)
124{
125 if (contents.effect.content.size()) {
126 return load(contents.effect,
127 (description.flags & EffectFlags::GeometryShader) ? contents.effect : ProcessedContent(),
128 contents.effect,
129 description.vsEntryPoint.size() ? description.vsEntryPoint.data() : "VShader",
130 description.gsEntryPoint.size() ? description.gsEntryPoint.data() : "GShader",
131 description.psEntryPoint.size() ? description.psEntryPoint.data() : "PShader",
132 description);
133 } else {
134 return load(contents.vertexShader,
135 contents.hullShader,
136 contents.domainShader,
137 contents.geometryShader,
138 contents.pixelShader,
139 description.vsEntryPoint.size() ? description.vsEntryPoint.data() : "main",
140 description.hsEntryPoint.size() ? description.hsEntryPoint.data() : "main",
141 description.dsEntryPoint.size() ? description.dsEntryPoint.data() : "main",
142 description.gsEntryPoint.size() ? description.gsEntryPoint.data() : "main",
143 description.psEntryPoint.size() ? description.psEntryPoint.data() : "main",
144 description);
145 }
146}
147
149{
150 auto e = loadEffect(fileName, PreprocessorDefinitions(), effectFlags);
151
152#ifdef COGSRENDERING_GFX_ANNOTATE
153 annotate(e, tryToName(fileName));
154#endif
155
156 return e;
157}
158
160{
161 auto e = loadEffect(vsFileName, psFileName, PreprocessorDefinitions(), effectFlags);
162
163#ifdef COGSRENDERING_GFX_ANNOTATE
164 annotateVS(e, tryToName(vsFileName));
165 annotatePS(e, tryToName(psFileName));
166#endif
167
168 return e;
169}
170
172{
174 desc.vertexShader = vsFileName;
175 desc.pixelShader = psFileName;
176 desc.definitions = defines;
177 desc.flags = effectFlags;
178 desc.type = EffectDescriptionType::File;
179
180 auto e = loadEffect(desc);
181
182#ifdef COGSRENDERING_GFX_ANNOTATE
183 annotateVS(e, tryToName(vsFileName));
184 annotatePS(e, tryToName(psFileName));
185#endif
186
187 return e;
188}
189
190Cogs::EffectHandle Cogs::EffectsCommon::loadEffectSource(const StringView & vsSource, const StringView & psSource, EffectFlags::EEffectFlags effectFlags)
191{
192 return loadEffectSource(vsSource, psSource, PreprocessorDefinitions(), effectFlags);
193}
194
195Cogs::EffectHandle Cogs::EffectsCommon::loadEffectSource(const StringView & vsSource, const StringView & psSource, const PreprocessorDefinitions & defines, EffectFlags::EEffectFlags flags)
196{
198 desc.vertexShader = vsSource;
199 desc.pixelShader = psSource;
200 desc.definitions = defines;
201 desc.flags = static_cast<EffectFlags::EEffectFlags>(flags);
203
204 return loadEffectSource(desc);
205}
206
207Cogs::EffectHandle Cogs::EffectsCommon::loadEffectSource(const StringView & vsSource, const StringView & gsSource, const StringView & psSource, EffectFlags::EEffectFlags effectFlags)
208{
209 return loadEffectSource(vsSource, gsSource, psSource, PreprocessorDefinitions(), effectFlags);
210}
211
212Cogs::EffectHandle Cogs::EffectsCommon::loadEffectSource(const StringView & vsSource, const StringView & gsSource, const StringView & psSource, const PreprocessorDefinitions & defines, EffectFlags::EEffectFlags flags)
213{
215 desc.vertexShader = vsSource;
216 desc.geometryShader = gsSource;
217 desc.pixelShader = psSource;
218 desc.definitions = defines;
219 desc.flags = static_cast<EffectFlags::EEffectFlags>(flags);
221
222 return loadEffectSource(desc);
223}
224
226{
228 desc.effect = fileName;
229 desc.definitions = defines;
230 desc.flags = flags;
231 desc.type = EffectDescriptionType::File;
232
233 auto e = loadEffect(desc);
234
235 return e;
236}
237
238Cogs::EffectHandle Cogs::EffectsCommon::load(const ProcessedContent & vsSource,
239 const ProcessedContent & psSource,
240 const StringView & vsEntryPoint,
241 const StringView & psEntryPoint,
242 const EffectDescription & desc)
243{
244 return load(vsSource, ProcessedContent(), psSource, vsEntryPoint, nullptr, psEntryPoint, desc);
245}
246
247Cogs::EffectHandle Cogs::EffectsCommon::load(const ProcessedContent & vsSource,
248 const ProcessedContent & gsSource,
249 const ProcessedContent & psSource,
250 const StringView & vsEntryPoint,
251 const StringView & gsEntryPoint,
252 const StringView & psEntryPoint,
253 const EffectDescription & desc)
254{
255 return load(vsSource,
256 ProcessedContent(),
257 ProcessedContent(),
258 gsSource,
259 psSource,
260 vsEntryPoint,
261 StringView(),
262 StringView(),
263 gsEntryPoint,
264 psEntryPoint,
265 desc);
266}
267
268namespace Cogs
269{
270 template<typename Collection>
271 uint8_t getSlot(Collection & collection, const StringView & name)
272 {
273 auto it = collection.find(Cogs::hash(name));
274
275 if (it == collection.end()) return Cogs::NoBinding;
276
277 return (uint8_t)it->second;
278 }
279
280 uint64_t encode(uint8_t vsSlot, uint8_t hsSlot, uint8_t dsSlot, uint8_t gsSlot, uint8_t psSlot)
281 {
282 if ((vsSlot == NoBinding) &&
283 (hsSlot == NoBinding) &&
284 (dsSlot == NoBinding) &&
285 (gsSlot == NoBinding) &&
286 (psSlot == NoBinding))
287 {
288 return 0;
289 }
290 else {
291 return ((static_cast<uint64_t>(vsSlot) << 0) |
292 (static_cast<uint64_t>(hsSlot) << 8) |
293 (static_cast<uint64_t>(dsSlot) << 16) |
294 (static_cast<uint64_t>(gsSlot) << 24) |
295 (static_cast<uint64_t>(psSlot) << 32) |
296 (static_cast<uint64_t>(1) << 63));
297 }
298 }
299
300 uint64_t encode(uint8_t csSlot)
301 {
302 return encode(csSlot, NoBinding, NoBinding, NoBinding, NoBinding);
303 }
304
305 template<typename Effect>
306 uint64_t getSlots(Effect & effect, const StringView & name)
307 {
308 const uint8_t vsSlot = getSlot(effect.vertexShader.reflection.slots, name);
309 const uint8_t hsSlot = getSlot(effect.hullShader.reflection.slots, name);
310 const uint8_t dsSlot = getSlot(effect.domainShader.reflection.slots, name);
311 const uint8_t gsSlot = getSlot(effect.geometryShader.reflection.slots, name);
312 const uint8_t psSlot = getSlot(effect.pixelShader.reflection.slots, name);
313
314 return encode(vsSlot, hsSlot, dsSlot, gsSlot, psSlot);
315 }
316
317 template<typename Effect>
318 int64_t getTextureSlots(Effect & effect, const StringView & name)
319 {
320 const uint8_t vsSlot = getSlot(effect.vertexShader.reflection.textures, name);
321 const uint8_t hsSlot = getSlot(effect.hullShader.reflection.textures, name);
322 const uint8_t dsSlot = getSlot(effect.domainShader.reflection.textures, name);
323 const uint8_t gsSlot = getSlot(effect.geometryShader.reflection.textures, name);
324 const uint8_t psSlot = getSlot(effect.pixelShader.reflection.textures, name);
325
326 return encode(vsSlot, hsSlot, dsSlot, gsSlot, psSlot);
327 }
328
329 template<typename Effect>
330 int64_t getSamplerSlots(Effect & effect, const StringView & name)
331 {
332 const uint8_t vsSlot = getSlot(effect.vertexShader.reflection.samplers, name);
333 const uint8_t hsSlot = getSlot(effect.hullShader.reflection.samplers, name);
334 const uint8_t dsSlot = getSlot(effect.domainShader.reflection.samplers, name);
335 const uint8_t gsSlot = getSlot(effect.geometryShader.reflection.samplers, name);
336 const uint8_t psSlot = getSlot(effect.pixelShader.reflection.samplers, name);
337
338 return encode(vsSlot, hsSlot, dsSlot, gsSlot, psSlot);
339 }
340
341 template<typename Effect>
342 int64_t getBufferUAVSlots(Effect & effect, const StringView & name)
343 {
344 const uint8_t vsSlot = getSlot(effect.vertexShader.reflection.bufferUAVs, name);
345 const uint8_t hsSlot = getSlot(effect.hullShader.reflection.bufferUAVs, name);
346 const uint8_t dsSlot = getSlot(effect.domainShader.reflection.bufferUAVs, name);
347 const uint8_t gsSlot = getSlot(effect.geometryShader.reflection.bufferUAVs, name);
348 const uint8_t psSlot = getSlot(effect.pixelShader.reflection.bufferUAVs, name);
349
350 return encode(vsSlot, hsSlot, dsSlot, gsSlot, psSlot);
351 }
352
353 template<typename Effect>
354 int64_t getBufferSRVSlots(Effect & effect, const StringView & name)
355 {
356 const uint8_t vsSlot = getSlot(effect.vertexShader.reflection.bufferSRVs, name);
357 const uint8_t hsSlot = getSlot(effect.hullShader.reflection.bufferSRVs, name);
358 const uint8_t dsSlot = getSlot(effect.domainShader.reflection.bufferSRVs, name);
359 const uint8_t gsSlot = getSlot(effect.geometryShader.reflection.bufferSRVs, name);
360 const uint8_t psSlot = getSlot(effect.pixelShader.reflection.bufferSRVs, name);
361
362 return encode(vsSlot, hsSlot, dsSlot, gsSlot, psSlot);
363 }
364}
365
367{
368 if (!HandleIsValid(effectHandle)) return EffectVariableHandle::InvalidHandle;
369
370 auto id = Cogs::hash(name);
371 auto & effect = effects[effectHandle];
372
373 auto existingEffectVariable = effect.effectVariables.find(id);
374
375 if (existingEffectVariable != effect.effectVariables.end()) {
376 return EffectVariableHandle(reinterpret_cast<int64_t>(&(existingEffectVariable->second)));
377 }
378
379 EffectVariable effectVariable;
380
381 auto addEffectVariable = [&](ShaderConstantBuffer & constantBuffer) {
382 auto cbVariable = constantBuffer.variables.find(id);
383
384 if (!HandleIsValid(constantBuffer.buffer)) {
385 constantBuffer.memoryBuffer.resize(constantBuffer.size);
386 constantBuffer.buffer = buffers->loadBuffer(nullptr, constantBuffer.size, Usage::Dynamic, AccessMode::Write, BindFlags::ConstantBuffer);
387 }
388
389 if (cbVariable != constantBuffer.variables.end()) {
390 ConstantBufferVariable variable;
391 variable.buffer = &constantBuffer;
392 variable.offset = constantBuffer.offsets[cbVariable->second];
393 variable.size = constantBuffer.sizes[cbVariable->second];
394
395 effectVariable.variables.push_back(variable);
396 }
397 };
398
399 for (auto & shader : effect.shaders) {
400 for (auto & constantBuffer : shader.reflection.constantBuffers) {
401 addEffectVariable(constantBuffer);
402 }
403 }
404
405 auto variablePointer = &(effect.effectVariables[id] = effectVariable);
406
407 return EffectVariableHandle(reinterpret_cast<int64_t>(variablePointer));
408}
409
411{
412 auto & effect = effects[effectHandle];
413
414 if (effect.computeShader.shader) {
415 return ConstantBufferBindingHandle(encode(getSlot(effect.computeShader.reflection.slots, name)));
416 } else {
417 return ConstantBufferBindingHandle(getSlots(effect, name));
418 }
419}
420
422{
423 auto & effect = this->effects[effectHandle];
424
425 if (effect.computeShader.shader) {
426 return TextureBindingHandle(encode(getSlot(effect.computeShader.reflection.textures, name)));
427 } else {
428 return TextureBindingHandle(getTextureSlots(effect, name));
429 }
430}
431
433{
434 auto & effect = this->effects[effectHandle];
435
436 if (effect.computeShader.shader) {
437 return SamplerStateBindingHandle(encode(getSlot(effect.computeShader.reflection.samplers, name)));
438 } else {
439 return SamplerStateBindingHandle(getSamplerSlots(effect, name));
440 }
441}
442
444{
445 auto & effect = this->effects[effectHandle];
446
447 if (effect.computeShader.shader) {
448 BufferBinding binding = { getSlot(effect.computeShader.reflection.bufferUAVs, name), getSlot(effect.computeShader.reflection.bufferSRVs, name) };
449
450 return bufferBindings.addResource(std::move(binding));
451 } else {
452 BufferBinding binding = { getBufferUAVSlots(effect, name), getBufferSRVSlots(effect, name) };
453
454 return bufferBindings.addResource(std::move(binding));
455 }
456}
457
459{
460 bufferBindings.removeResource(bufferBindingHandle);
461}
462
463void Cogs::Effect::buildSignature()
464{
465 signature = {};
466
467 for (size_t i = 0; i < ShaderType::NumShaderTypes; ++i) {
468 auto & shader = shaders[i];
469
470 signature.slots[SlotType::CBV].values[i] = static_cast<uint32_t>(shader.reflection.slots.size());
471 signature.slots[SlotType::SRV].values[i] = shader.reflection.srvSlots;
472 signature.slots[SlotType::Sampler].values[i] = static_cast<uint32_t>(shader.reflection.samplers.size());
473 signature.slots[SlotType::UAV].values[i] = static_cast<uint32_t>(shader.reflection.bufferUAVs.size());
474 }
475
476 const uint32_t numUAVSlotsReservedForRT = 1;
477 signature.slots[SlotType::UAV].values[ShaderType::PixelShader] += numUAVSlotsReservedForRT;
478
479 int range = 0;
480 for (size_t i = 0; i < SlotType::NumSlotTypes; ++i) {
481 for (size_t j = 0; j < ShaderType::NumShaderTypes; ++j) {
482 if (signature.slots[i].values[j]) {
483 signature.slots[i].rangeIndex[j] = range++;
484 }
485 }
486 }
487}
Log implementation class.
Definition: LogManager.h:139
Provides a weakly referenced view over the contents of a string.
Definition: StringView.h:24
size_t find_last_of(const StringView characters, size_t pos=NoPosition) const noexcept
See std::basic_string::find_last_of.
Definition: StringView.cpp:31
constexpr size_t size() const noexcept
Get the size of the string.
Definition: StringView.h:178
constexpr size_t length() const noexcept
Get the length of the string.
Definition: StringView.h:185
constexpr StringView substr(size_t offset, size_t count=NoPosition) const noexcept
Get the given sub string.
Definition: StringView.h:258
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:180
Contains all Cogs related functionality.
Definition: FieldSetter.h:23
constexpr size_t hash() noexcept
Simple getter function that returns the initial value for fnv1a hashing.
Definition: HashFunctions.h:62
std::vector< PreprocessorDefinition > PreprocessorDefinitions
A set of preprocessor definitions.
Definition: IEffects.h:13
@ Write
The buffer can be mapped and written to by the CPU after creation.
Definition: Flags.h:50
@ ConstantBuffer
The buffer can be bound as input to effects as a constant buffer.
Definition: Flags.h:72
Contains an effect description used to load a single effect.
Definition: IEffects.h:55
StringView geometryShader
Geometry shader file name or source.
Definition: IEffects.h:66
StringView effect
Effect file name or source.
Definition: IEffects.h:72
StringView domainShader
Domain shader file name or source.
Definition: IEffects.h:63
StringView vertexShader
Vertex shader file name or source.
Definition: IEffects.h:57
EffectDescriptionType type
Type of effect description. Defaults to file names.
Definition: IEffects.h:99
StringView pixelShader
Pixel shader file name or source.
Definition: IEffects.h:69
StringView hullShader
Hull shader file name or source.
Definition: IEffects.h:60
EEffectFlags
Effect source flags.
Definition: IEffects.h:20
@ GeometryShader
Effect source contains geometry shader.
Definition: IEffects.h:28
ConstantBufferBindingHandle getConstantBufferBinding(EffectHandle effectHandle, const StringView &name) override
Get a handle to a constant buffer binding, mapping how to bind a constant buffer to the given effect.
BufferBindingHandle getBufferBinding(EffectHandle effectHandle, const StringView &name) override
Get a handle to a buffer binding.
SamplerStateBindingHandle getSamplerStateBinding(EffectHandle effectHandle, const StringView &name, const unsigned int slot) override
Get a handle to a sampler state object binding, mapping how to bind the sampler state to the given ef...
void releaseBufferBinding(BufferBindingHandle bufferBindingHandle) override
Release a handle to a buffer binding.
EffectVariableHandle getEffectVariable(EffectHandle effectHandle, const StringView &name) override
Get a handle to the variable with the given name in the effect with the given effectHandle.
TextureBindingHandle getTextureBinding(EffectHandle effectHandle, const StringView &name, const unsigned int slot) override
Get a handle to a texture object binding, mapping how to bind textures to the given effect.
EffectHandle loadEffect(const EffectDescription &description) final
Load an effect from the given description.
static const Handle_t InvalidHandle
Represents an invalid handle.
Definition: Common.h:80
@ Dynamic
Buffer will be loaded and modified with some frequency.
Definition: Flags.h:30