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
20using namespace Cogs;
21
22namespace
23{
24 const char * names[] = {
25 "linearSampler",
26 "linearClampSampler",
27 "pointSampler",
28 "pointClampSampler",
29 };
30
31 Cogs::Logging::Log logger = Cogs::Logging::getLogger("PostProcessTask");
32}
33
34void Cogs::Core::PostProcessTask::initialize(RenderTaskContext* context)
35{
36 ProcessTask::initialize(context);
37}
38
39void Cogs::Core::PostProcessTask::initialize(RenderTaskContext * context, const RenderTaskDefinition& taskDefinition)
40{
41 ProcessTask::initialize(context, taskDefinition);
42
43 auto effects = context->device->getEffects();
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 if (p.key == "source") {
55 desc.ps = p.value;
56 }
57 }
58
59 {
60 Cogs::GraphicsDeviceType graphicsDeviceType = context->renderer->getDevice()->getType();
61 bool success;
62 switch (graphicsDeviceType)
63 {
65 success = Cogs::Core::buildPostProcessEffectES3(context, desc, this);
66 break;
68 success = buildPostProcessEffectWebGPU(context, desc, this);
69 break;
70 default:
71 success = buildPostProcessEffect(context, desc, this);
72 break;
73 }
74 if (!success) {
75 LOG_ERROR(logger, "Failed to build post processing shader source");
76 }
77 }
78
79 effect = context->renderer->getEffectCache().loadEffect(context, desc);
80
81 if (!HandleIsValid(effect->handle)) {
82 return;
83 }
84 auto * buffers = context->device->getBuffers();
85 inputLayout = buffers->loadInputLayout(&VertexFormats::Pos4f, 1, effect->handle);
86
87 for (size_t i = 0; i < 4; ++i) {
88 auto binding = effects->getSamplerStateBinding(effect->handle, names[i], 0);
89
90 if (HandleIsValid(binding)) {
91 samplerStateBindings[i] = binding;
92 samplerStates[i] = context->states->commonSamplerStates[i];
93 } else {
94 samplerStateBindings[i] = SamplerStateBindingHandle::NoHandle;
95 }
96 }
97}
98
99void Cogs::Core::PostProcessTask::apply(RenderTaskContext * context)
100{
101 if (scopeName.empty()) {
102 scopeName = std::string("PostProcessTask<") + name + ">::apply";
103 }
104
105 DynamicRenderInstrumentationScope(context->device->getImmediateContext(), SCOPE_RENDERING, "PostProcessTask", scopeName.c_str());
106
107 RenderTarget* renderTarget = output.get(RenderResourceType::RenderTarget)->renderTarget;
108
109 if (!renderTarget) {
110 return;
111 }
112
113 if (!HandleIsValid(effect->handle)) {
114 return;
115 }
116
117 auto deviceContext = context->device->getImmediateContext();
118 deviceContext->setEffect(effect->handle);
119
120 if(context->device->getCapabilities()->getDeviceCapabilities().RenderPass){
121 RenderPassInfo info;
122 info.renderTargetHandle = renderTarget->renderTargetHandle;
123 info.depthStencilHandle = renderTarget->depthTargetHandle;
124 {
125 uint32_t i = 0;
126 info.loadOp[i] = clearColor ? LoadOp::Clear : LoadOp::Load;
127 // info.storeOp[i] = writeColor ? StoreOp::Store : StoreOp::Discard;
128 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.
129 glm::vec4 color;
130 if (clearToDefault) {
131 color = context->renderer->getBackgroundColor();
132 }
133 else{
134 color = renderTarget->getClearColor();
135 }
136 info.clearValue[i][0] = color[0];
137 info.clearValue[i][1] = color[1];
138 info.clearValue[i][2] = color[2];
139 info.clearValue[i][3] = color[3];
140 }
141 info.depthLoadOp = clearDepth ? LoadOp::Clear : LoadOp::Load;
142 info.depthStoreOp = writeDepth ? StoreOp::Store : StoreOp::Discard;
143 info.depthClearValue = context->renderer->getClearDepth();
144 // info.depthReadOnly = !writeDepth;
145 deviceContext->beginRenderPass(info);
146 }
147 else{
148 deviceContext->setRenderTarget(renderTarget->renderTargetHandle, renderTarget->depthTargetHandle);
149 if (clearColor) {
150 if (clearToDefault) {
151 deviceContext->clearRenderTarget(glm::value_ptr(context->renderer->getBackgroundColor()));
152 } else {
153 deviceContext->clearRenderTarget(glm::value_ptr(renderTarget->getClearColor()));
154 }
155 }
156 if (clearDepth) {
157 if (HandleIsValid(renderTarget->depthTargetHandle) || !HandleIsValid(renderTarget->renderTargetHandle)) {
158 deviceContext->clearDepth(context->renderer->getClearDepth());
159 }
160 }
161 }
162
163 if (viewportFromTarget) {
164 deviceContext->setViewport(0.0f, 0.0f, static_cast<float>(renderTarget->width), static_cast<float>(renderTarget->height));
165 }
166 else {
167 // Note: context->cameraData is set when updating engine buffers, so its value is from the last invocation.
168 deviceContext->setViewport(
169 context->cameraData->viewportOrigin.x, context->cameraData->viewportOrigin.y,
170 context->cameraData->viewportSize.x, context->cameraData->viewportSize.y
171 );
172 }
173
174 if (writeDepth && depthTest) {
175 deviceContext->setDepthStencilState(context->states->leqDepthStencilStateHandle);
176 } else if (writeDepth && !depthTest) {
177 deviceContext->setDepthStencilState(context->states->noTestDepthStencilStateHandle);
178 }
179 else if (!writeDepth && depthTest) {
180 deviceContext->setDepthStencilState(context->states->noWriteDepthStencilStateHandle);
181 }
182 else {
183 deviceContext->setDepthStencilState(context->states->noDepthStencilStateHandle);
184 }
185
186 deviceContext->setRasterizerState(context->states->defaultRasterizerStateHandle);
187
188 for (size_t i = 0; i < 4; ++i) {
189 if (HandleIsValid(samplerStateBindings[i])) {
190 deviceContext->setSamplerState(samplerStateBindings[i], samplerStates[i]);
191 }
192 }
193
194 setProperties(context);
195
196 if (!writeColor){
197 deviceContext->setBlendState(context->states->blendStates[size_t(BlendMode::Zero)].handle);
198 }
199
200 deviceContext->setVertexBuffers(&context->states->fullScreenTriangle, 1);
201 deviceContext->setIndexBuffer(IndexBufferHandle::NoHandle);
202 deviceContext->setInputLayout(inputLayout);
203 deviceContext->draw(PrimitiveType::TriangleList, 0, 3);
204
205 if(context->device->getCapabilities()->getDeviceCapabilities().RenderPass){
206 deviceContext->endRenderPass();
207 }
208}
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.
@ TriangleList
List of triangles.
Contains an effect description used to load a single effect.
Definition: IEffects.h:55
static const Handle_t NoHandle
Represents a handle to nothing.
Definition: Common.h:78