Cogs.Core
EffectCache.cpp
1#include "EffectCache.h"
2#include "Context.h"
3
4#include "Resources/ResourceStore.h"
5#include "Tasks/RenderTask.h"
6#include "Services/Variables.h"
7
8#include "Foundation/HashSequence.h"
9#include "Foundation/Platform/FileSystemWatcher.h"
10#include "Foundation/Platform/IO.h"
11
12namespace Cogs::Core
13{
14 size_t getCode(EffectDescription & desc)
15 {
16 size_t hashValue = hashSequence(desc.vs, desc.ps, desc.cs);
17
18 for (const auto & def : desc.definitions) {
19 hashValue = Cogs::hash(def.first, hashValue);
20 hashValue = Cogs::hash(def.second, hashValue);
21 }
22 return hashValue;
23 }
24
25 void changeSuffix(std::string& dst, const std::string& from, const std::string& to)
26 {
27 auto pos = dst.find(from);
28 if (pos == std::string::npos) return;
29 dst.replace(pos, to.length(), to);
30 }
31
32}
33
34void Cogs::Core::EffectCache::reload(RenderTaskContext * context)
35{
36 for (auto & p : effects) {
37 reload(context, &p.second);
38 }
39}
40
41void Cogs::Core::EffectCache::reload(RenderTaskContext * context, CachedEffect * effect)
42{
43 auto device = context->renderer->getDevice();
44
45 if (HandleIsValid(effect->handle)) {
46 device->getEffects()->releaseEffect(effect->handle);
47 }
48
49 context->context->resourceStore->purge("Shaders/" + effect->description.vs);
50 context->context->resourceStore->purge("Shaders/" + effect->description.ps);
51
52 effect->handle = device->getEffects()->loadEffect(effect->description.vs, effect->description.ps);
53}
54
55Cogs::Core::CachedEffect * Cogs::Core::EffectCache::loadEffect(RenderTaskContext * context, EffectDescription & desc)
56{
57 const size_t code = getCode(desc);
58
59 auto it = effects.find(code);
60
61 if (it != effects.end() && it->second.usage) {
62 assert(it->second.description.vs == desc.vs);
63 assert(it->second.description.cs == desc.cs);
64 assert(it->second.description.ps == desc.ps);
65 ++it->second.usage;
66 return &it->second;
67 }
68
69 Cogs::EffectHandle handle;
70 if (!desc.cs.empty()) {
71 std::string cs = desc.cs;
72 switch (context->renderer->getDevice()->getType()) {
74 changeSuffix(cs, ".hlsl", ".wgsl");
75 break;
76 default:
77 break;
78 }
79 handle = context->renderer->getDevice()->getEffects()->loadComputeEffect(cs, desc.definitions);
80 } else {
81 std::string vs, ps; // must be alive until loadEffect returns.
82
83 auto name = IO::stem(desc.ps);
84
85 Cogs::EffectDescription effectDesc = {};
86 effectDesc.flags = context->renderer->getEffectFlags();
87 switch (context->renderer->getDevice()->getType()) {
89 vs = desc.vs;
90 ps = desc.ps;
91 changeSuffix(vs, ".hlsl", ".es30.glsl");
92 changeSuffix(ps, ".hlsl", ".es30.glsl");
93 effectDesc.vertexShader = vs;
94 effectDesc.pixelShader = ps;
95 effectDesc.flags = static_cast<EffectFlags::EEffectFlags>(effectDesc.flags | EffectFlags::GLSL);
96 break;
98 vs = desc.vs;
99 ps = desc.ps;
100 changeSuffix(vs, ".hlsl", ".wgsl");
101 changeSuffix(ps, ".hlsl", ".wgsl");
102 effectDesc.vertexShader = vs;
103 effectDesc.pixelShader = ps;
104 effectDesc.flags = static_cast<EffectFlags::EEffectFlags>(effectDesc.flags | EffectFlags::WGSL);
105 break;
106 default:
107 effectDesc.vertexShader = desc.vs;
108 effectDesc.pixelShader = desc.ps;
109 break;
110 }
111 effectDesc.name = name;
112 effectDesc.definitions = desc.definitions;
113
114 handle = context->renderer->getDevice()->getEffects()->loadEffect(effectDesc);
115 }
116
117 CachedEffect effect = { desc, handle, 1 };
118 auto & cached = effects[code] = effect;
119
120 if (context->context->variables->get("resources.effects.autoReload", false)) {
121 if (desc.vs.size()) {
122 context->context->watcher->watchFile(desc.vs, [&](const FileSystemWatcher::Event&) { reload(context, &cached); });
123
124 if (desc.ps.size()) {
125 context->context->watcher->watchFile(desc.ps, [&](const FileSystemWatcher::Event&) { reload(context, &cached); });
126 }
127 }
128 }
129
130 return &cached;
131}
132
133void Cogs::Core::EffectCache::release(RenderTaskContext * context, CachedEffect * effect)
134{
135 assert(effect->usage && "Effect already released.");
136
137 if (--effect->usage == 0) {
138 if (HandleIsValid(effect->handle)) {
139 context->renderer->getDevice()->getEffects()->releaseEffect(effect->handle);
140 effect->handle = Cogs::EffectHandle::NoHandle;
141 }
142 }
143}
144
145Cogs::Core::CachedEffect * Cogs::Core::EffectCache::loadEffect(RenderTaskContext * context, StringView cs)
146{
147 EffectDescription desc{};
148 desc.cs = cs.to_string();
149 return loadEffect(context, desc);
150}
151
152
153Cogs::Core::CachedEffect * Cogs::Core::EffectCache::loadEffect(RenderTaskContext * context, StringView vs, StringView ps)
154{
155 EffectDescription desc{};
156 desc.vs = vs.to_string();
157 desc.ps = ps.to_string();
158
159 return loadEffect(context, desc);
160}
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
bool HandleIsValid(const ResourceHandle_t< T > &handle)
Check if the given resource is valid, that is not equal to NoHandle or InvalidHandle.
@ OpenGLES30
Graphics device using the OpenGLES 3.0 API.
@ WebGPU
Graphics device using the WebGPU API Backend.
constexpr size_t hash() noexcept
Simple getter function that returns the initial value for fnv1a hashing.
Definition: HashFunctions.h:62
constexpr size_t hashSequence(const T &t, const U &u)
Hash the last two items in a sequence of objects.
Definition: HashSequence.h:8
Contains an effect description used to load a single effect.
Definition: IEffects.h:55
EffectFlags::EEffectFlags flags
Effect loading flags.
Definition: IEffects.h:96
PreprocessorDefinitions definitions
Definitions.
Definition: IEffects.h:93
StringView vertexShader
Vertex shader file name or source.
Definition: IEffects.h:57
StringView name
Name of the effect. Used for tracking purposes, like naming shader dumps.
Definition: IEffects.h:90
StringView pixelShader
Pixel shader file name or source.
Definition: IEffects.h:69
EEffectFlags
Effect source flags.
Definition: IEffects.h:20
@ WGSL
Effect source is WGSL.
Definition: IEffects.h:36
@ GLSL
Effect source is GLSL.
Definition: IEffects.h:26
static const Handle_t NoHandle
Represents a handle to nothing.
Definition: Common.h:77