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 setupDepthStates(device);
151 defaultSampler = textures->loadSamplerState(SamplerState::DefaultState());
152
153 SamplerState states[] = {
158 };
159
160 for (size_t i = 0; i < 4; ++i) {
161 commonSamplerStates[i] = textures->loadSamplerState(states[i]);
162 }
163
164 SamplerState shadowSamplerState{};
165 switch (device->getType()) {
167 shadowSamplerState.addressModeS = SamplerState::Wrap;
168 shadowSamplerState.addressModeT = SamplerState::Wrap;
169 shadowSamplerState.addressModeW = SamplerState::Wrap;
170 shadowSamplerState.comparisonFunction = reverseDepth ? SamplerState::GreaterEqual : SamplerState::LessEqual;
171 shadowSamplerState.filter = SamplerState::ComparisonMinMagMipLinear;
172 break;
173 default:
174 shadowSamplerState.addressModeS = SamplerState::Border;
175 shadowSamplerState.addressModeT = SamplerState::Border;
176 shadowSamplerState.addressModeW = SamplerState::Border;
177 shadowSamplerState.comparisonFunction = reverseDepth ? SamplerState::GreaterEqual : SamplerState::LessEqual;
178 shadowSamplerState.filter = SamplerState::ComparisonMinMagMipLinear;
179 for (size_t i = 0; i < 4; i++) {
180 shadowSamplerState.borderColor[i] = reverseDepth ? 0.f : 1.f;
181 }
182 break;
183 }
184 shadowSampler = textures->loadSamplerState(shadowSamplerState);
185
186 IBuffers * buffers = device->getBuffers();
187
188 const glm::vec4 fst[] =
189 {
190 {-1.0, -1.0, 0.0, 1.f},
191 { 3.0, -1.0, 0.0, 1.f},
192 {-1.0, 3.0, 0.0, 1.f},
193 };
194
195 fullScreenTriangle = buffers->loadVertexBuffer(fst, sizeof(fst) / sizeof(fst[0]), VertexFormats::Pos4f);
196}
197
198void Cogs::Core::RenderStates::setupDepthStates(IGraphicsDevice* device) {
199 auto renderTargets = device->getRenderTargets();
200 DepthStencilState defaultState = DepthStencilState::DefaultState();
201 if (reverseDepth) defaultState.depthFunction = DepthStencilState::Greater;
202 defaultDepthStencilStateHandle = renderTargets->loadDepthStencilState(defaultState);
203 commonDepthStates[(int)DepthMode::Default] = defaultDepthStencilStateHandle;
204
205 DepthStencilState depthState = { true, false, DepthStencilState::Less };
206 if (reverseDepth) depthState.depthFunction = DepthStencilState::Greater;
207 noWriteDepthStencilStateHandle = renderTargets->loadDepthStencilState(depthState);
208 commonDepthStates[(int)DepthMode::NoWrite] = noWriteDepthStencilStateHandle;
209
210 DepthStencilState noTestDepthState = { true, true, DepthStencilState::Always };
211 noTestDepthStencilStateHandle = renderTargets->loadDepthStencilState(noTestDepthState);
212 commonDepthStates[(int)DepthMode::AlwaysWrite] = noTestDepthStencilStateHandle;
213 DepthStencilState noDepthState = { false, false, DepthStencilState::Always };
214 noDepthStencilStateHandle = renderTargets->loadDepthStencilState(noDepthState);
215 commonDepthStates[(int)DepthMode::Disabled] = noDepthStencilStateHandle;
216
217 for (int depthMode = 0; depthMode < 4; depthMode++) {
218 for (int depthFunc = 0; depthFunc < 5; depthFunc++) {
220 switch (DepthFunc(depthFunc)) {
221 case DepthFunc::Less:
223 break;
224 case DepthFunc::Always:
226 break;
227 case DepthFunc::LessOrEqual:
229 break;
230 case DepthFunc::NotEqual:
232 break;
233 case DepthFunc::Equal:
235 break;
236 case DepthFunc::Count:
237 assert(false);
238 break;
239 }
240 DepthStencilState state = DepthStencilState::DefaultState();
241 state.depthFunction = depthFunction;
242 switch (DepthMode(depthMode)) {
244 break;
246 state = { true, false, depthFunction };
247 break;
250 break;
252 state = { false, false, depthFunction };
253 break;
254 case DepthMode::Count:
255 assert(false);
256 break;
257 }
258 commonDepthStates[depthFunc * (int)DepthMode::Count + depthMode] = renderTargets->loadDepthStencilState(state);
259 }
260 }
261}
262
263void Cogs::Core::RenderStates::cleanup()
264{
265 for (auto & d : depthStencilStates) {
266 device->getRenderTargets()->releaseDepthStencilState(d.second);
267 }
268
269 for (auto & r : rasterizerStates) {
270 device->getRenderTargets()->releaseRasterizerState(r.second.handle);
271 }
272
273 for (auto & s : samplerStates) {
274 device->getTextures()->releaseSamplerState(s.second);
275 }
276
277 depthStencilStates.clear();
278 rasterizerStates.clear();
279 samplerStates.clear();
280}
281
282namespace {
283
284 size_t getDefaultRenderPassOptionsHash() {
286 options.updateHash();
287 return options.hash;
288 }
289
290}
291
292
293uint16_t Cogs::Core::RenderStates::getRasterizerState(const Cogs::Core::RenderPassOptions& passOptions,
295 bool wireFrame,
296 bool counterClockWise)
297{
298
299 static const size_t defaultRenderPassOptionsHash = getDefaultRenderPassOptionsHash();
300 if (wireFrame || passOptions.hash != defaultRenderPassOptionsHash) {
301
302 RasterizerState rasterizerState = RasterizerState::DefaultState();
303 rasterizerState.wireFrame = wireFrame;
304 rasterizerState.cullMode = cullMode;
305 rasterizerState.frontCounterClockwise = counterClockWise;
306 rasterizerState.noDepthClip = passOptions.getFlag(RenderPassOptions::Flags::NoDepthClip);
307 rasterizerState.depthBias = passOptions.depthBias;
308 rasterizerState.slopeScaledDepthBias = passOptions.depthSlopedBias;
309 rasterizerState.depthBiasClamp = passOptions.depthBiasClamp;
310 rasterizerState.scissor = passOptions.getFlag(RenderPassOptions::Flags::ScissorTest);
311
312 return getRasterizerState(rasterizerState);
313 } else {
314 return (uint16_t)(cullMode * 2 + counterClockWise);
315 }
316}
317
318uint16_t Cogs::Core::RenderStates::getRasterizerState(const RasterizerState & rs_a)
319{
320 RasterizerState rs = rs_a;
321 if(reverseDepth){
322 rs.depthBias = -rs.depthBias;
323 rs.slopeScaledDepthBias = -rs.slopeScaledDepthBias;
324 rs.depthBiasClamp = -rs.depthBiasClamp;
325 }
326 auto it = rasterizerStates.find(rs);
327
328 if (it == rasterizerStates.end()) {
329 LOG_TRACE(logger, "Created rasterizer state %d.", int(rasterizerStates.size()));
330
331 auto rsh = device->getRenderTargets()->loadRasterizerState(rs);
332
333 auto index = static_cast<uint16_t>(rasterizerStateHandles.size());
334 rasterizerStateHandles.emplace_back(rsh);
335
336 rasterizerStates[rs] = { index, rsh };
337
338 return index;
339 } else {
340 return it->second.index;
341 }
342}
343
344Cogs::DepthStencilStateHandle Cogs::Core::RenderStates::getDepthStencilState(const DepthStencilState & ds_a)
345{
346 DepthStencilState ds = ds_a;
347 if(reverseDepth){
348 if(ds.depthFunction == DepthStencilState::Less)
349 ds.depthFunction = DepthStencilState::Greater;
350 if(ds.depthFunction == DepthStencilState::LessOrEqual)
351 ds.depthFunction = DepthStencilState::GreaterOrEqual;
352 }
353
354 auto it = depthStencilStates.find(ds);
355
356 if (it == depthStencilStates.end()) {
357 LOG_TRACE(logger, "Created depth stencil state %d.", int(rasterizerStates.size()));
358
359 auto dsh = device->getRenderTargets()->loadDepthStencilState(ds);
360
361 depthStencilStates[ds] = dsh;
362
363 return dsh;
364 } else {
365 return it->second;
366 }
367}
368
369Cogs::SamplerStateHandle Cogs::Core::RenderStates::getSamplerState(const SamplerState & ss)
370{
371 auto it = samplerStates.find(ss);
372
373 if (it == samplerStates.end()) {
374 LOG_TRACE(logger, "Created sampler state %d.", int(samplerStates.size()));
375
376 auto ssh = device->getTextures()->loadSamplerState(ss);
377
378 samplerStates[ss] = ssh;
379
380 return ssh;
381 } else {
382 return it->second;
383 }
384}
Log implementation class.
Definition: LogManager.h:139
@ 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:180
@ OpenGLES30
Graphics device using the OpenGLES 3.0 API.
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