Cogs.Core
RenderStates.cpp
1#include "RenderStates.h"
2
3#include <functional>
4
5#include "Foundation/Logging/Logger.h"
6
7#include "Rendering/IGraphicsDevice.h"
8#include "Rendering/IRenderTargets.h"
9#include "Rendering/ITextures.h"
10#include "Rendering/IBuffers.h"
11
12#include "Resources/MaterialOptions.h"
13#include "Systems/Core/CameraSystem.h"
14#include "Resources/VertexFormats.h"
15
16namespace
17{
18 Cogs::Logging::Log logger = Cogs::Logging::getLogger("RenderStates");
19}
20
21void Cogs::Core::RenderStates::initialize(IGraphicsDevice * device)
22{
23 this->device = device;
24 auto renderTargets = device->getRenderTargets();
25 auto textures = device->getTextures();
26
28 rs.cullMode = RasterizerState::Front;
29 rs.frontCounterClockwise = false;
30 rs.noDepthClip = true;
31 getRasterizerState(rs);
32
33 rs.cullMode = RasterizerState::Front;
34 rs.frontCounterClockwise = true;
35 rs.noDepthClip = true;
36 getRasterizerState(rs);
37
38 rs.cullMode = RasterizerState::Back;
39 rs.frontCounterClockwise = false;
40 rs.noDepthClip = true;
41 getRasterizerState(rs);
42
43 rs.cullMode = RasterizerState::Back;
44 rs.frontCounterClockwise = true;
45 rs.noDepthClip = true;
46 getRasterizerState(rs);
47
48 rs.cullMode = RasterizerState::None;
49 rs.frontCounterClockwise = false;
50 rs.noDepthClip = true;
51 getRasterizerState(rs);
52
53 rs.cullMode = RasterizerState::None;
54 rs.frontCounterClockwise = true;
55 rs.noDepthClip = true;
56 getRasterizerState(rs);
57
59 rs.noDepthClip = true;
60 defaultRasterizerStateHandle = device->getRenderTargets()->loadRasterizerState(rs);
61 rs.frontCounterClockwise = true;
62 defaultCCWasterizerStateHandle = device->getRenderTargets()->loadRasterizerState(rs);
63
64 { // BlendMode::Blend
65 auto& blend = blendStates[size_t(BlendMode::Blend)];
66 blend.color.enabled = true;
67 blend.color.sourceBlend = BlendState::Blend::SourceAlpha;
68 blend.color.destinationBlend = BlendState::Blend::InverseSourceAlpha;
69 blend.color.operation = BlendState::BlendOperation::Add;
70 blend.alpha.enabled = true;
71 blend.alpha.sourceBlend = BlendState::Blend::One;
72 blend.alpha.destinationBlend = BlendState::Blend::InverseSourceAlpha;
73 blend.alpha.operation = BlendState::BlendOperation::Add;
74 blend.handle = renderTargets->loadBlendState(blend.color, blend.alpha);
75 }
76
77 { // BlendMode::Add
78 auto& blend = blendStates[size_t(BlendMode::Add)];
79 blend.color.enabled = true;
80 blend.color.sourceBlend = BlendState::Blend::SourceAlpha;
81 blend.color.destinationBlend = BlendState::Blend::One;
82 blend.color.operation = BlendState::BlendOperation::Add;
83 blend.alpha.enabled = true;
84 blend.alpha.sourceBlend = BlendState::Blend::One;
85 blend.alpha.destinationBlend = BlendState::Blend::One;
86 blend.alpha.operation = BlendState::BlendOperation::Add;
87 blend.handle = renderTargets->loadBlendState(blend.color, blend.alpha);
88 }
89
90 { // BlendMode::PremultipliedBlend
91 auto& blend = blendStates[size_t(BlendMode::PremultipliedBlend)];
92 blend.color.enabled = true;
93 blend.color.sourceBlend = BlendState::Blend::One;
94 blend.color.destinationBlend = BlendState::Blend::InverseSourceAlpha;
95 blend.color.operation = BlendState::BlendOperation::Add;
96 blend.alpha.enabled = true;
97 blend.alpha.sourceBlend = BlendState::Blend::One;
98 blend.alpha.destinationBlend = BlendState::Blend::InverseSourceAlpha;
99 blend.alpha.operation = BlendState::BlendOperation::Add;
100 blend.handle = renderTargets->loadBlendState(blend.color, blend.alpha);
101 }
102
103 { // BlendMode::AlphaToCoverage
104 auto& blend = blendStates[size_t(BlendMode::AlphaToCoverage)];
105 blend.color.enabled = false;
106 blend.alpha.enabled = false;
107 blend.handle = renderTargets->loadBlendState(blend.color, blend.alpha, Cogs::BlendFlags::AlphaToCoverage);
108 }
109
110 { // BlendMode::None
111 auto& blend = blendStates[size_t(BlendMode::None)];
112 blend.color.enabled = false;
113 blend.alpha.enabled = false;
114 blend.handle = renderTargets->loadBlendState(blend.color, blend.alpha);
115 }
116
117 { // BlendMode::Zero
118 auto& blend = blendStates[size_t(BlendMode::Zero)];
119 blend.color.enabled = true;
120 blend.color.sourceBlend = BlendState::Blend::Zero;
121 blend.color.destinationBlend = BlendState::Blend::One;
122 blend.color.operation = BlendState::BlendOperation::Add;
123 blend.alpha = blend.color;
124 blend.handle = renderTargets->loadBlendState(blend.color, blend.alpha);
125 }
126
127 { // BlendMode::One_One_Zero_InverseSourceAlpha
128 auto& blend = blendStates[size_t(BlendMode::One_One_Zero_InverseSourceAlpha)];
129 blend.color.enabled = true;
130 blend.color.sourceBlend = BlendState::Blend::One;
131 blend.color.destinationBlend = BlendState::Blend::One;
132 blend.color.operation = BlendState::BlendOperation::Add;
133 blend.alpha.enabled = true;
134 blend.alpha.sourceBlend = BlendState::Blend::Zero;
135 blend.alpha.destinationBlend = BlendState::Blend::InverseSourceAlpha;
136 blend.alpha.operation = BlendState::BlendOperation::Add;
137 blend.handle = renderTargets->loadBlendState(blend.color, blend.alpha);
138 }
139
140 { // BlendMode::InverseSourceAlpha_SourceAlpha
141 auto& blend = blendStates[size_t(BlendMode::InverseSourceAlpha_SourceAlpha)];
142 blend.color.enabled = true;
143 blend.color.sourceBlend = BlendState::Blend::InverseSourceAlpha;
144 blend.color.destinationBlend = BlendState::Blend::SourceAlpha;
145 blend.color.operation = BlendState::BlendOperation::Add;
146 blend.alpha = blend.color;
147 blend.handle = renderTargets->loadBlendState(blend.color, blend.alpha);
148 }
149
150 { // BlendMode::DestinationAlpha_InverseDestinationAlpha
151 auto& blend = blendStates[size_t(BlendMode::DestinationAlpha_InverseDestinationAlpha)];
152 blend.color.enabled = true;
153 blend.color.sourceBlend = BlendState::Blend::DestinationAlpha;
154 blend.color.destinationBlend = BlendState::Blend::InverseDestinationAlpha;
155 blend.color.operation = BlendState::BlendOperation::Add;
156 blend.alpha = blend.color;
157 blend.handle = renderTargets->loadBlendState(blend.color, blend.alpha);
158 }
159
160 setupDepthStates(device);
161 defaultSampler = textures->loadSamplerState(SamplerState::DefaultState());
162
163 SamplerState states[] = {
168 };
169
170 for (size_t i = 0; i < 4; ++i) {
171 commonSamplerStates[i] = textures->loadSamplerState(states[i]);
172 }
173
174 SamplerState shadowSamplerState{};
175 switch (device->getType()) {
178 shadowSamplerState.addressModeS = SamplerState::Wrap;
179 shadowSamplerState.addressModeT = SamplerState::Wrap;
180 shadowSamplerState.addressModeW = SamplerState::Wrap;
181 shadowSamplerState.comparisonFunction = reverseDepth ? SamplerState::GreaterEqual : SamplerState::LessEqual;
182 shadowSamplerState.filter = SamplerState::ComparisonMinMagMipLinear;
183 break;
184 default:
185 shadowSamplerState.addressModeS = SamplerState::Border;
186 shadowSamplerState.addressModeT = SamplerState::Border;
187 shadowSamplerState.addressModeW = SamplerState::Border;
188 shadowSamplerState.comparisonFunction = reverseDepth ? SamplerState::GreaterEqual : SamplerState::LessEqual;
189 shadowSamplerState.filter = SamplerState::ComparisonMinMagMipLinear;
190 for (size_t i = 0; i < 4; i++) {
191 shadowSamplerState.borderColor[i] = reverseDepth ? 0.f : 1.f;
192 }
193 break;
194 }
195 shadowSampler = textures->loadSamplerState(shadowSamplerState);
196
197 IBuffers * buffers = device->getBuffers();
198
199 const glm::vec4 fst[] =
200 {
201 {-1.0, -1.0, 0.0, 1.f},
202 { 3.0, -1.0, 0.0, 1.f},
203 {-1.0, 3.0, 0.0, 1.f},
204 };
205
206 fullScreenTriangle = buffers->loadVertexBuffer(fst, sizeof(fst) / sizeof(fst[0]), VertexFormats::Pos4f);
207}
208
209void Cogs::Core::RenderStates::setupDepthStates(IGraphicsDevice* device) {
210 auto renderTargets = device->getRenderTargets();
211 DepthStencilState defaultState = DepthStencilState::DefaultState();
212 if (reverseDepth) defaultState.depthFunction = DepthStencilState::Greater;
213 defaultDepthStencilStateHandle = renderTargets->loadDepthStencilState(defaultState);
214 commonDepthStates[(int)DepthMode::Default] = defaultDepthStencilStateHandle;
215
216 DepthStencilState depthState = { true, false, DepthStencilState::Less };
217 if (reverseDepth) depthState.depthFunction = DepthStencilState::Greater;
218 noWriteDepthStencilStateHandle = renderTargets->loadDepthStencilState(depthState);
219 commonDepthStates[(int)DepthMode::NoWrite] = noWriteDepthStencilStateHandle;
220
221 DepthStencilState noTestDepthState = { true, true, DepthStencilState::Always };
222 noTestDepthStencilStateHandle = renderTargets->loadDepthStencilState(noTestDepthState);
223 commonDepthStates[(int)DepthMode::AlwaysWrite] = noTestDepthStencilStateHandle;
224 DepthStencilState noDepthState = { false, false, DepthStencilState::Always };
225 noDepthStencilStateHandle = renderTargets->loadDepthStencilState(noDepthState);
226 commonDepthStates[(int)DepthMode::Disabled] = noDepthStencilStateHandle;
227
228 DepthStencilState leqState = { true, true, DepthStencilState::LessOrEqual };
229 if (reverseDepth) leqState.depthFunction = DepthStencilState::GreaterOrEqual;
230 leqDepthStencilStateHandle = renderTargets->loadDepthStencilState(leqState);
231
232 for (int depthMode = 0; depthMode < 4; depthMode++) {
233 for (int depthFunc = 0; depthFunc < 5; depthFunc++) {
235 switch (DepthFunc(depthFunc)) {
236 case DepthFunc::Less:
238 break;
239 case DepthFunc::Always:
241 break;
242 case DepthFunc::LessOrEqual:
244 break;
245 case DepthFunc::NotEqual:
247 break;
248 case DepthFunc::Equal:
250 break;
251 case DepthFunc::Count:
252 assert(false);
253 break;
254 }
255 DepthStencilState state = DepthStencilState::DefaultState();
256 state.depthFunction = depthFunction;
257 switch (DepthMode(depthMode)) {
259 break;
261 state = { true, false, depthFunction };
262 break;
265 break;
267 state = { false, false, depthFunction };
268 break;
269 case DepthMode::Count:
270 assert(false);
271 break;
272 }
273 commonDepthStates[depthFunc * (int)DepthMode::Count + depthMode] = renderTargets->loadDepthStencilState(state);
274 }
275 }
276}
277
278void Cogs::Core::RenderStates::cleanup()
279{
280 for (auto & d : depthStencilStates) {
281 device->getRenderTargets()->releaseDepthStencilState(d.second);
282 }
283
284 for (auto & r : rasterizerStates) {
285 device->getRenderTargets()->releaseRasterizerState(r.second.handle);
286 }
287
288 for (auto & s : samplerStates) {
289 device->getTextures()->releaseSamplerState(s.second);
290 }
291
292 depthStencilStates.clear();
293 rasterizerStates.clear();
294 samplerStates.clear();
295}
296
297namespace {
298
299 size_t getDefaultRenderPassOptionsHash() {
301 options.updateHash();
302 return options.hash;
303 }
304
305}
306
307
308uint16_t Cogs::Core::RenderStates::getRasterizerState(const Cogs::Core::RenderPassOptions& passOptions,
310 bool wireFrame,
311 bool counterClockWise)
312{
313
314 static const size_t defaultRenderPassOptionsHash = getDefaultRenderPassOptionsHash();
315 if (wireFrame || passOptions.hash != defaultRenderPassOptionsHash) {
316
317 RasterizerState rasterizerState = RasterizerState::DefaultState();
318 rasterizerState.wireFrame = wireFrame;
319 rasterizerState.cullMode = cullMode;
320 rasterizerState.frontCounterClockwise = counterClockWise;
321 rasterizerState.noDepthClip = passOptions.getFlag(RenderPassOptions::Flags::NoDepthClip);
322 rasterizerState.depthBias = passOptions.depthBias;
323 rasterizerState.slopeScaledDepthBias = passOptions.depthSlopedBias;
324 rasterizerState.depthBiasClamp = passOptions.depthBiasClamp;
325 rasterizerState.scissor = passOptions.getFlag(RenderPassOptions::Flags::ScissorTest);
326
327 return getRasterizerState(rasterizerState);
328 } else {
329 return (uint16_t)(cullMode * 2 + counterClockWise);
330 }
331}
332
333uint16_t Cogs::Core::RenderStates::getRasterizerState(const RasterizerState & rs_a)
334{
335 RasterizerState rs = rs_a;
336 if(reverseDepth){
337 rs.depthBias = -rs.depthBias;
338 rs.slopeScaledDepthBias = -rs.slopeScaledDepthBias;
339 rs.depthBiasClamp = -rs.depthBiasClamp;
340 }
341 auto it = rasterizerStates.find(rs);
342
343 if (it == rasterizerStates.end()) {
344 LOG_TRACE(logger, "Created rasterizer state %d.", int(rasterizerStates.size()));
345
346 auto rsh = device->getRenderTargets()->loadRasterizerState(rs);
347
348 auto index = static_cast<uint16_t>(rasterizerStateHandles.size());
349 rasterizerStateHandles.emplace_back(rsh);
350
351 rasterizerStates[rs] = { index, rsh };
352
353 return index;
354 } else {
355 return it->second.index;
356 }
357}
358
359Cogs::DepthStencilStateHandle Cogs::Core::RenderStates::getDepthStencilState(const DepthStencilState & ds_a)
360{
361 DepthStencilState ds = ds_a;
362 if(reverseDepth){
363 if(ds.depthFunction == DepthStencilState::Less)
364 ds.depthFunction = DepthStencilState::Greater;
365 if(ds.depthFunction == DepthStencilState::LessOrEqual)
366 ds.depthFunction = DepthStencilState::GreaterOrEqual;
367 }
368
369 auto it = depthStencilStates.find(ds);
370
371 if (it == depthStencilStates.end()) {
372 LOG_TRACE(logger, "Created depth stencil state %d.", int(rasterizerStates.size()));
373
374 auto dsh = device->getRenderTargets()->loadDepthStencilState(ds);
375
376 depthStencilStates[ds] = dsh;
377
378 return dsh;
379 } else {
380 return it->second;
381 }
382}
383
384Cogs::SamplerStateHandle Cogs::Core::RenderStates::getSamplerState(const SamplerState & ss)
385{
386 auto it = samplerStates.find(ss);
387
388 if (it == samplerStates.end()) {
389 LOG_TRACE(logger, "Created sampler state %d.", int(samplerStates.size()));
390
391 auto ssh = device->getTextures()->loadSamplerState(ss);
392
393 samplerStates[ss] = ssh;
394
395 return ssh;
396 } else {
397 return it->second;
398 }
399}
Log implementation class.
Definition: LogManager.h:140
@ Blend
Render with regular alpha blending.
@ None
No blending enabled for opaque shapes, defaults to Blend for transparent shapes.
@ AlphaToCoverage
Interpret alpha value as a coverage mask.
@ Zero
Disable all color writes.
@ Add
Render with additive blending.
DepthMode
Defines common depth stencil modes.
@ NoWrite
Depth test enabled, write disabled.
@ Default
Default, depth test & write enabled.
@ AlwaysWrite
Depth write enabled, test mode "Always". Deprecated.
@ Disabled
Depth test/write disabled.
DepthFunc
Defines common depth functions.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:181
@ OpenGLES30
Graphics device using the OpenGLES 3.0 API.
@ WebGPU
Graphics device using the WebGPU API Backend.
DepthFunction
Depth functions to apply when determining object visibility based on its depth test.
@ GreaterOrEqual
Greater or equal depth.
@ NotEqual
Depth not equal evaluates to true.
@ Always
Always evaluates to true.
@ LessOrEqual
Less or equal depth.
static DepthStencilState DefaultState()
Constructs a depth stencil state object initialized with the default values.
static RasterizerState DefaultState()
Constructs a rasterizer state initialized with the default values.
CullMode
Culling modes for triangle rasterization.
@ None
Do not perform any face culling.
@ Back
Cull back facing primitives.
@ Front
Cull front facing primitives.
static SamplerState & DefaultState()
Constructs a sampler state initialized with the default values.
Definition: SamplerState.h:85
@ Clamp
Texture coordinates are clamped to the [0, 1] range.
Definition: SamplerState.h:17
@ Border
Texture color is set to the border color when outside [0, 1] range.
Definition: SamplerState.h:23
@ Wrap
Texture coordinates automatically wrap around to [0, 1] range.
Definition: SamplerState.h:19
@ ComparisonMinMagMipLinear
Comparison filter for depth sample comparisons using linear interpolation sampling.
Definition: SamplerState.h:40
@ MinMagMipPoint
Point sampling for both minification and magnification.
Definition: SamplerState.h:33
@ MinMagMipLinear
Linear sampling for both minification and magnification.
Definition: SamplerState.h:35