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
212 for (int depthMode = 0; depthMode < 4; depthMode++) {
213 for (int depthFunc = 0; depthFunc < 5; depthFunc++) {
215 switch (DepthFunc(depthFunc)) {
216 case DepthFunc::Less:
218 break;
219 case DepthFunc::Always:
221 break;
222 case DepthFunc::LessOrEqual:
224 break;
225 case DepthFunc::NotEqual:
227 break;
228 case DepthFunc::Equal:
230 break;
231 case DepthFunc::Count:
232 assert(false);
233 break;
234 }
235 DepthStencilState state = DepthStencilState::DefaultState();
236 state.depthFunction = depthFunction;
237 switch (DepthMode(depthMode)) {
239 break;
241 state = { true, false, depthFunction };
242 break;
245 break;
247 state = { false, false, depthFunction };
248 break;
249 case DepthMode::Count:
250 assert(false);
251 break;
252 }
253 commonDepthStates[getDepthState(DepthMode(depthMode), DepthFunc(depthFunc))] = renderTargets->loadDepthStencilState(state);
254 }
255 }
256}
257
258void Cogs::Core::RenderStates::cleanup()
259{
260 for (auto & d : depthStencilStates) {
261 device->getRenderTargets()->releaseDepthStencilState(d.second);
262 }
263
264 for (auto & r : rasterizerStates) {
265 device->getRenderTargets()->releaseRasterizerState(r.second.handle);
266 }
267
268 for (auto & s : samplerStates) {
269 device->getTextures()->releaseSamplerState(s.second);
270 }
271
272 depthStencilStates.clear();
273 rasterizerStates.clear();
274 samplerStates.clear();
275}
276
277namespace {
278
279 size_t getDefaultRenderPassOptionsHash() {
281 options.updateHash();
282 return options.hash;
283 }
284
285}
286
287
288uint16_t Cogs::Core::RenderStates::getRasterizerState(const Cogs::Core::RenderPassOptions& passOptions,
290 bool wireFrame,
291 bool counterClockWise)
292{
293
294 static const size_t defaultRenderPassOptionsHash = getDefaultRenderPassOptionsHash();
295 if (wireFrame || passOptions.hash != defaultRenderPassOptionsHash) {
296
297 RasterizerState rasterizerState = RasterizerState::DefaultState();
298 rasterizerState.wireFrame = wireFrame;
299 rasterizerState.cullMode = cullMode;
300 rasterizerState.frontCounterClockwise = counterClockWise;
301 rasterizerState.noDepthClip = passOptions.getFlag(RenderPassOptions::Flags::NoDepthClip);
302 rasterizerState.depthBias = passOptions.depthBias;
303 rasterizerState.slopeScaledDepthBias = passOptions.depthSlopedBias;
304 rasterizerState.depthBiasClamp = passOptions.depthBiasClamp;
305 rasterizerState.scissor = passOptions.getFlag(RenderPassOptions::Flags::ScissorTest);
306
307 return getRasterizerState(rasterizerState);
308 } else {
309 return (uint16_t)(cullMode * 2 + counterClockWise);
310 }
311}
312
313uint16_t Cogs::Core::RenderStates::getRasterizerState(const RasterizerState & rs_a)
314{
315 RasterizerState rs = rs_a;
316 if(reverseDepth){
317 rs.depthBias = -rs.depthBias;
318 rs.slopeScaledDepthBias = -rs.slopeScaledDepthBias;
319 rs.depthBiasClamp = -rs.depthBiasClamp;
320 }
321 auto it = rasterizerStates.find(rs);
322
323 if (it == rasterizerStates.end()) {
324 LOG_TRACE(logger, "Created rasterizer state %d.", int(rasterizerStates.size()));
325
326 auto rsh = device->getRenderTargets()->loadRasterizerState(rs);
327
328 auto index = static_cast<uint16_t>(rasterizerStateHandles.size());
329 rasterizerStateHandles.emplace_back(rsh);
330
331 rasterizerStates[rs] = { index, rsh };
332
333 return index;
334 } else {
335 return it->second.index;
336 }
337}
338
339Cogs::DepthStencilStateHandle Cogs::Core::RenderStates::getDepthStencilState(const DepthStencilState & ds_a)
340{
341 DepthStencilState ds = ds_a;
342 if(reverseDepth){
343 if(ds.depthFunction == DepthStencilState::Less)
344 ds.depthFunction = DepthStencilState::Greater;
345 if(ds.depthFunction == DepthStencilState::LessOrEqual)
346 ds.depthFunction = DepthStencilState::GreaterOrEqual;
347 }
348
349 auto it = depthStencilStates.find(ds);
350
351 if (it == depthStencilStates.end()) {
352 LOG_TRACE(logger, "Created depth stencil state %d.", int(rasterizerStates.size()));
353
354 auto dsh = device->getRenderTargets()->loadDepthStencilState(ds);
355
356 depthStencilStates[ds] = dsh;
357
358 return dsh;
359 } else {
360 return it->second;
361 }
362}
363
364Cogs::SamplerStateHandle Cogs::Core::RenderStates::getSamplerState(const SamplerState & ss)
365{
366 auto it = samplerStates.find(ss);
367
368 if (it == samplerStates.end()) {
369 LOG_TRACE(logger, "Created sampler state %d.", int(samplerStates.size()));
370
371 auto ssh = device->getTextures()->loadSamplerState(ss);
372
373 samplerStates[ss] = ssh;
374
375 return ssh;
376 } else {
377 return it->second;
378 }
379}
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