Cogs.Core
PostProcessTask.cpp
1#include "PostProcessTask.h"
2#include "Resources/VertexFormats.h"
3
4#include "Context.h"
5#include "Renderer/Renderer.h"
6#include "Renderer/RenderTarget.h"
7#include "Systems/Core/CameraSystem.h"
8
9#include "Rendering/IBuffers.h"
10#include "Rendering/ICapabilities.h"
11#include "Rendering/IContext.h"
12#include "Rendering/IGraphicsDevice.h"
13
14#include "Resources/ShaderBuilderPostProcess.h"
15
16#include <glm/gtc/type_ptr.hpp>
17
18#include "Foundation/Logging/Logger.h"
19
20#include <cassert>
21
22using namespace Cogs;
23
24namespace
25{
26 const char * names[] = {
27 "linearSampler",
28 "linearClampSampler",
29 "pointSampler",
30 "pointClampSampler",
31 };
32
33 Cogs::Logging::Log logger = Cogs::Logging::getLogger("PostProcessTask");
34}
35
36void Cogs::Core::PostProcessTask::initialize(RenderTaskContext* context)
37{
38 ProcessTask::initialize(context);
39}
40
41void Cogs::Core::PostProcessTask::initialize(RenderTaskContext * context, const RenderTaskDefinition& taskDefinition)
42{
43 ProcessTask::initialize(context, taskDefinition);
44
45 EffectDescription desc = createEffectDesc(context);
46 desc.vs = "Engine/FullscreenV3T2VS.hlsl";
47
48 for (auto & p : effectParameter.values) {
49 if (p.key == "definitions") {
50 for (auto & d : p.values) {
51 desc.definitions.push_back({ d.key, d.value });
52 }
53 }
54 else if (p.key == "source") {
55 desc.ps = p.value;
56 }
57 else if (p.key == "useVariables") {
58 // Handled in RenderTaskFactory.cpp
59 }
60 else if (p.key == "setVariables") {
61 // Handled in RenderTaskFactory.cpp
62 }
63 else if (p.key == "useComponentFields") {
64 // Handled in RenderTaskFactory.cpp
65 }
66 else if (p.key == "properties") {
67 // Handled in RenderTaskFactory.cpp
68 }
69 else if (p.key == "groups" && p.values.size() == 3) {
70 // Handled in RenderTaskFactory.cpp
71 }
72 else if (p.key == "options") {
73 // Handled in RenderTaskFactory.cpp
74 }
75 else{
76 LOG_WARNING(logger, "Unknown post process task pipeline section \"%s\"", p.key.c_str());
77 }
78 }
79
80 {
81 Cogs::GraphicsDeviceType graphicsDeviceType = context->renderer->getDevice()->getType();
82 bool success;
83 switch (graphicsDeviceType)
84 {
86 success = Cogs::Core::buildPostProcessEffectES3(context, desc, this);
87 break;
89 success = buildPostProcessEffectWebGPU(context, desc, this);
90 break;
91 default:
92 success = buildPostProcessEffect(context, desc, this);
93 break;
94 }
95 if (!success) {
96 LOG_ERROR(logger, "Failed to build post processing shader source");
97 }
98 }
99
100 effect = context->renderer->getEffectCache().loadEffect(context, desc);
101}
102
104{
105 IEffects* effects = context->device->getEffects();
106
107 Cogs::ResourceStatus status = HandleIsValid(effect->handle) ? effects->checkEffect(effect->handle) : Cogs::ResourceStatus::Error;
108
109 if (status == Cogs::ResourceStatus::Ready && effectStatus != Cogs::ResourceStatus::Ready) {
110 IBuffers* buffers = context->device->getBuffers();
111 inputLayout = buffers->loadInputLayout(&VertexFormats::Pos4f, 1, effect->handle);
112 for (size_t i = 0; i < 4; ++i) {
113 SamplerStateBindingHandle binding = effects->getSamplerStateBinding(effect->handle, names[i], 0);
114 if (HandleIsValid(binding)) {
115 samplerStateBindings[i] = binding;
116 samplerStates[i] = context->states->commonSamplerStates[i];
117 } else {
118 samplerStateBindings[i] = SamplerStateBindingHandle::NoHandle;
119 }
120 }
121 }
122
123 effectStatus = status;
124 return effectStatus;
125}
126
127void Cogs::Core::PostProcessTask::apply(RenderTaskContext * context)
128{
129 assert(effectStatus == Cogs::ResourceStatus::Ready);
130
131 if (scopeName.empty()) {
132 scopeName = std::string("PostProcessTask<") + name + ">::apply";
133 }
134
135 DynamicRenderInstrumentationScope(context->device->getImmediateContext(), SCOPE_RENDERING, "PostProcessTask", scopeName.c_str());
136
137 RenderTarget* renderTarget = output.get(RenderResourceType::RenderTarget)->renderTarget;
138
139 if (!renderTarget) {
140 return;
141 }
142
143 auto deviceContext = context->device->getImmediateContext();
144 deviceContext->setEffect(effect->handle);
145
146 if(context->device->getCapabilities()->getDeviceCapabilities().RenderPass){
147 RenderPassInfo info;
148 info.renderTargetHandle = renderTarget->renderTargetHandle;
149 info.depthStencilHandle = renderTarget->depthTargetHandle;
150 {
151 uint32_t i = 0;
152 info.loadOp[i] = clearColor ? LoadOp::Clear : LoadOp::Load;
153 // info.storeOp[i] = writeColor ? StoreOp::Store : StoreOp::Discard;
154 info.storeOp[i] = StoreOp::Store; // We can't really do a discard even if we don't write the color cause that may mangle previous writes to the target.
155 glm::vec4 color;
156 if (clearToDefault) {
157 color = context->renderer->getBackgroundColor();
158 }
159 else{
160 color = renderTarget->getClearColor();
161 }
162 info.clearValue[i][0] = color[0];
163 info.clearValue[i][1] = color[1];
164 info.clearValue[i][2] = color[2];
165 info.clearValue[i][3] = color[3];
166 }
167 info.depthLoadOp = clearDepth ? LoadOp::Clear : LoadOp::Load;
168 info.depthStoreOp = writeDepth ? StoreOp::Store : StoreOp::Discard;
169 info.depthClearValue = context->renderer->getClearDepth();
170 // info.depthReadOnly = !writeDepth;
171 deviceContext->beginRenderPass(info);
172 }
173 else{
174 deviceContext->setRenderTarget(renderTarget->renderTargetHandle, renderTarget->depthTargetHandle);
175 if (clearColor) {
176 if (clearToDefault) {
177 deviceContext->clearRenderTarget(glm::value_ptr(context->renderer->getBackgroundColor()));
178 } else {
179 deviceContext->clearRenderTarget(glm::value_ptr(renderTarget->getClearColor()));
180 }
181 }
182 if (clearDepth) {
183 if (HandleIsValid(renderTarget->depthTargetHandle) || !HandleIsValid(renderTarget->renderTargetHandle)) {
184 deviceContext->clearDepth(context->renderer->getClearDepth());
185 }
186 }
187 }
188
189 if (viewportFromTarget) {
190 deviceContext->setViewport(0.0f, 0.0f, static_cast<float>(renderTarget->width), static_cast<float>(renderTarget->height));
191 }
192 else {
193 // Note: context->cameraData is set when updating engine buffers, so its value is from the last invocation.
194 deviceContext->setViewport(
195 context->cameraData->viewportOrigin.x, context->cameraData->viewportOrigin.y,
196 context->cameraData->viewportSize.x, context->cameraData->viewportSize.y
197 );
198 }
199
200 if (writeDepth && depthTest) {
201 deviceContext->setDepthStencilState(context->states->commonDepthStates[RenderStates::leqDepthStencilState]);
202 } else if (writeDepth && !depthTest) {
203 deviceContext->setDepthStencilState(context->states->commonDepthStates[RenderStates::noTestDepthStencilState]);
204 }
205 else if (!writeDepth && depthTest) {
206 deviceContext->setDepthStencilState(context->states->commonDepthStates[RenderStates::noWriteDepthStencilState]);
207 }
208 else {
209 deviceContext->setDepthStencilState(context->states->commonDepthStates[RenderStates::noDepthStencilState]);
210 }
211
212 deviceContext->setRasterizerState(context->states->defaultRasterizerStateHandle);
213
214 for (size_t i = 0; i < 4; ++i) {
215 if (HandleIsValid(samplerStateBindings[i])) {
216 deviceContext->setSamplerState(samplerStateBindings[i], samplerStates[i]);
217 }
218 }
219
220 setProperties(context);
221
222 if (!writeColor){
223 deviceContext->setBlendState(context->states->blendStates[size_t(BlendMode::Zero)].handle);
224 }
225
226 deviceContext->setVertexBuffers(&context->states->fullScreenTriangle, 1);
227 deviceContext->setIndexBuffer(IndexBufferHandle::NoHandle);
228 deviceContext->setInputLayout(inputLayout);
229 deviceContext->draw(PrimitiveType::TriangleList, 0, 3);
230
231 if(context->device->getCapabilities()->getDeviceCapabilities().RenderPass){
232 deviceContext->endRenderPass();
233 }
234}
glm::vec4 getBackgroundColor() const override
Get the reference to the background color.
Definition: Renderer.h:43
float getClearDepth() override
Get adjusted clear depth used to render.
Definition: Renderer.cpp:581
virtual IEffects * getEffects()=0
Get a pointer to the effect management interface.
virtual ICapabilities * getCapabilities()=0
Get a pointer to the capability management interface used to query the graphics device capability fla...
virtual IContext * getImmediateContext()=0
Get a pointer to the immediate context used to issue commands to the graphics device.
virtual IBuffers * getBuffers()=0
Get a pointer to the buffer management interface.
Log implementation class.
Definition: LogManager.h:140
bool HandleIsValid(const ResourceHandle_t< T > &handle)
Check if the given resource is valid, that is not equal to NoHandle or InvalidHandle.
@ Zero
Disable all color writes.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:181
Contains all Cogs related functionality.
Definition: FieldSetter.h:23
GraphicsDeviceType
Contains types of graphics devices that may be supported.
Definition: Base.h:48
@ OpenGLES30
Graphics device using the OpenGLES 3.0 API.
@ WebGPU
Graphics device using the WebGPU API Backend.
ResourceStatus
Status of an asynchronously loaded resource, such as an effect or a pipeline.
Definition: Common.h:198
@ Error
The resource failed to load.
@ Ready
The resource has loaded successfully and is ready for use.
@ TriangleList
List of triangles.
Cogs::ResourceStatus checkReady(RenderTaskContext *context) override
Check if the task is ready to be applied, e.g.
Contains an effect description used to load a single effect.
Definition: IEffects.h:62
static const Handle_t NoHandle
Represents a handle to nothing.
Definition: Common.h:78
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 const GraphicsDeviceCapabilities & getDeviceCapabilities() const
Gets the device capabilities in a structure.
virtual void setEffect(EffectHandle handle)=0
Set the current effect.
Provides effects and shader management functionality.
Definition: IEffects.h:158
virtual SamplerStateBindingHandle getSamplerStateBinding(EffectHandle effectHandle, const StringView &name, const unsigned int slot)=0
Get a handle to a sampler state object binding, mapping how to bind the sampler state to the given ef...
virtual ResourceStatus checkEffect(EffectHandle effectHandle)=0
Check the load status of the effect with the given effectHandle.