Cogs.Core
RenderEffect.cpp
1#include "RenderEffect.h"
2
3#include "Rendering/IGraphicsDevice.h"
4#include "Rendering/IEffects.h"
5#include "Rendering/IBuffers.h"
6
7#include "Foundation/Logging/Logger.h"
8
9#include "Context.h"
10
11#include "Services/Variables.h"
12#include "Services/TaskManager.h"
13
14#include "Resources/Material.h"
15
16#include "Renderer.h"
17#include "RenderResources.h"
18
19namespace
20{
21 using namespace Cogs::Core;
22
23 Cogs::Logging::Log logger = Cogs::Logging::getLogger("RenderEffect");
24
25 bool checkAndLogEffectLoad(Effect* effect, Cogs::EffectHandle effectHandle, Cogs::InputLayoutHandle inputHandle)
26 {
27 bool success = true;
28 if (!HandleIsValid(effectHandle)) {
29 LOG_ERROR(logger, "Error loading effect %s, definition:", effect->getName().data());
30 success = false;
31 }
32
33 if (success && !HandleIsValid(inputHandle)) { // Input layout will always fail if effect is invalid, no point in reporting
34 LOG_WARNING(logger, "Could not create input layout for %.*s, definition:", StringViewFormat(effect->getName()));
35 success = false;
36 }
37
38 if(!success) {
39 effect->definition.streamsLayout.logLayout(logger);
40 for (const Cogs::PreprocessorDefinition& d : effect->definition.definitions) {
41 LOG_DEBUG(logger, "+- #define %s %s", d.first.c_str(), d.second.c_str());
42 }
43 if (effect->definition.definitions.empty()) {
44 LOG_DEBUG(logger, "+- No #define's");
45 }
46 const ShaderDefinition& vs = effect->definition.vertexShader;
47 for (const ShaderInterfaceMemberDefinition& i : vs.shaderInterface.members) {
48 LOG_DEBUG(logger, " +- Vertex shader input semantic %.*s", StringViewFormat(ShaderInterfaceMemberDefinition::semanticNameString(i.semantic.name)));
49 }
50 if (effect->definition.vertexShader.shaderInterface.members.empty()) {
51 LOG_DEBUG(logger, "+- No vertex shader input semantics");
52 }
53 }
54
55 return success;
56 }
57
58
59}
60
61Cogs::Core::ActivationResult Cogs::Core::RenderEffect::update(Effect * effect, IGraphicsDevice * device, RenderResources * resources)
62{
63 if (effect->delayLoad) {
64 setDelayed();
65
67 }
68
69 Context* context = resources->getContext();
70 Renderer* renderer = resources->getRenderer();
71
72 const bool updateAsync = context->variables->get("resources.effects.updateAsync", false);
73
74 IEffects* effects = device->getEffects();
75 IBuffers* buffers = device->getBuffers();
76
77 if (haveQueued) {
78 effectHandle = queuedEffectHandle;
79 queuedEffectHandle = Cogs::EffectHandle::NoHandle;
80
81 inputHandle = queuedInputHandle;
82 queuedInputHandle = Cogs::InputLayoutHandle::NoHandle;
83
84 task = NoTask;
85 haveQueued = false;
86
87 if (!checkAndLogEffectLoad(effect, effectHandle, inputHandle)) {
88
89 if (effect->material) {
90 effect->material->setChanged();
91 }
92
93 setFailed();
94
96 }
97
98 if (effect->material) {
99 effect->material->setChanged();
100 }
101
102 incrementGeneration();
103 setActive();
104
106 }
107
108 if (updateAsync) {
109 if (!task.isValid()) {
110 Cogs::EffectDescription description = {};
111 description.flags = renderer->getEffectFlags();
112 description.vertexShader = effect->definition.vertexShader.loadPath;
113 description.hullShader = effect->definition.hullShader.loadPath;
114 description.domainShader = effect->definition.domainShader.loadPath;
115 description.geometryShader = effect->definition.geometryShader.loadPath;
116 description.pixelShader = effect->definition.pixelShader.loadPath;
117 description.definitions = effect->definition.definitions;
118
119 task = context->taskManager->enqueue(TaskManager::ResourceQueue, [this, effects, description, buffers, effect]()
120 {
121 queuedEffectHandle = effects->loadEffect(description);
122 queuedInputHandle = queuedEffectHandle
123 ? buffers->loadInputLayout(effect->definition.streamsLayout.vertexFormats,
124 effect->definition.streamsLayout.numStreams,
125 queuedEffectHandle)
127
128 haveQueued = true;
129 });
130
131 setDelayed();
132 }
133
135 }
136 else {
137 Cogs::EffectDescription description = {};
138 description.flags = renderer->getEffectFlags();
139 description.name = effect->getName();
140 description.vertexShader = effect->definition.vertexShader.loadPath;
141 description.hullShader = effect->definition.hullShader.loadPath;
142 description.domainShader = effect->definition.domainShader.loadPath;
143 description.geometryShader = effect->definition.geometryShader.loadPath;
144 description.pixelShader = effect->definition.pixelShader.loadPath;
145 description.definitions = effect->definition.definitions;
146
147 if (description.vertexShader.find("glsl") != StringView::NoPosition) {
148 description.flags = static_cast<EffectFlags::EEffectFlags>(description.flags | EffectFlags::GLSL);
149 }
150
151 effectHandle = effects->loadEffect(description);
152 inputHandle = effectHandle
153 ? buffers->loadInputLayout(effect->definition.streamsLayout.vertexFormats,
154 effect->definition.streamsLayout.numStreams,
155 effectHandle)
157
158 if (!checkAndLogEffectLoad(effect, effectHandle, inputHandle)) {
159 LOG_ERROR(logger, "Error loading effect %s.", effect->getName().data());
160
161 if (effect->material) {
162 effect->material->setChanged();
163 }
164
165 setFailed();
166
168 }
169
170 if (effect->material) {
171 effect->material->setChanged();
172 }
173
174 // Let dependent resources know the effect has been (re)loaded.
175 ++generation;
176
177 setActive();
178
180 }
181}
182
183void Cogs::Core::RenderEffect::release(Renderer * renderer)
184{
185 IGraphicsDevice* device = renderer->getDevice();
186 IEffects* effects = device->getEffects();
187 IBuffers* buffers = device->getBuffers();
188
189 if (HandleIsValid(effectHandle)) {
190 effects->releaseEffect(effectHandle);
191 effectHandle = Cogs::EffectHandle::NoHandle;
192 }
193 if (HandleIsValid(inputHandle)) {
194 buffers->releaseInputLayout(inputHandle);
196 }
197
198 setReleased();
199}
200
201void Cogs::Core::RenderEffect::requestLoad()
202{
203 getResource()->delayLoad = false;
204 getResource()->setChanged();
205}
A Context instance contains all the services, systems and runtime components needed to use Cogs.
Definition: Context.h:83
std::unique_ptr< class TaskManager > taskManager
TaskManager service instance.
Definition: Context.h:186
std::unique_ptr< class Variables > variables
Variables service instance.
Definition: Context.h:180
Contains render resources used by the renderer.
Core renderer system.
Definition: Renderer.h:28
IGraphicsDevice * getDevice() override
Get the graphics device used by the renderer.
Definition: Renderer.h:45
EffectFlags::EEffectFlags getEffectFlags() const override
Get the EffectFlags.
Definition: Renderer.h:69
static constexpr TaskQueueId ResourceQueue
Resource task queue.
Definition: TaskManager.h:232
Represents a graphics device used to manage graphics resources and issue drawing commands.
virtual IEffects * getEffects()=0
Get a pointer to the effect management interface.
virtual IBuffers * getBuffers()=0
Get a pointer to the buffer management interface.
Log implementation class.
Definition: LogManager.h:139
constexpr const char * data() const noexcept
Get the sequence of characters referenced by the string view.
Definition: StringView.h:171
static constexpr size_t NoPosition
No position.
Definition: StringView.h:43
size_t find(const StringView &other, size_t offset=0) const noexcept
Find the given string segment inside the string.
Definition: StringView.cpp:18
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
ActivationResult
Defines results for resource activation.
Definition: ResourceBase.h:14
@ Success
Resource activated successfully.
@ Delayed
Delayed activation.
@ Postponed
Resource activation postponed, retry later.
@ Failure
Resource activation failed.
bool HandleIsValid(const ResourceHandle_t< T > &handle)
Check if the given resource is valid, that is not equal to NoHandle or InvalidHandle.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:180
std::pair< std::string, std::string > PreprocessorDefinition
Preprocessor definition.
Definition: IEffects.h:10
MeshStreamsLayout streamsLayout
The vertex layout this effect expects.
PreprocessorDefinitions definitions
Preprocessor definitions.
Effect resources contain data to control the shader stages of the GPU pipeline.
Definition: Effect.h:24
bool delayLoad
If the effect should be loaded or delayed.
Definition: Effect.h:40
struct Material * material
Owning material resource.
Definition: Effect.h:37
VertexFormatHandle vertexFormats[maxStreams]
void logLayout(Cogs::Logging::Log &logger) const
StringView getName() const
Get the name of the resource.
Definition: ResourceBase.h:307
bool isValid() const
Check if the task id is valid.
Definition: TaskManager.h:29
Contains an effect description used to load a single effect.
Definition: IEffects.h:55
EffectFlags::EEffectFlags flags
Effect loading flags.
Definition: IEffects.h:96
StringView geometryShader
Geometry shader file name or source.
Definition: IEffects.h:66
StringView domainShader
Domain shader file name or source.
Definition: IEffects.h:63
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
StringView hullShader
Hull shader file name or source.
Definition: IEffects.h:60
EEffectFlags
Effect source flags.
Definition: IEffects.h:20
@ GLSL
Effect source is GLSL.
Definition: IEffects.h:26
static const Handle_t NoHandle
Represents a handle to nothing.
Definition: Common.h:77
Provides buffer management functionality.
Definition: IBuffers.h:13
virtual InputLayoutHandle loadInputLayout(const VertexFormatHandle *vertexFormats, const size_t count, EffectHandle effectHandle)=0
Loads a new input layout to map vertex flow between vertex buffers with the given vertexFormats to ef...
virtual void releaseInputLayout(InputLayoutHandle inputLayoutHandle)=0
Releases the input layout with the given inputLayoutHandle.
Provides effects and shader management functionality.
Definition: IEffects.h:148
virtual void releaseEffect(EffectHandle effectHandle)=0
Release the effect with the given handle, freeing all resources generated during program loading.
virtual EffectHandle loadEffect(const EffectDescription &description)=0
Load an effect from the given description.