Overte C++ Documentation
State.h
1 //
2 // State
3 // libraries/gpu/src/gpu
4 //
5 // Created by Sam Gateau on 3/8/2015.
6 // Copyright 2014 High Fidelity, Inc.
7 //
8 // Distributed under the Apache License, Version 2.0.
9 // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10 //
11 #ifndef hifi_gpu_State_h
12 #define hifi_gpu_State_h
13 
14 #include "Format.h"
15 
16 #include <memory>
17 #include <sstream>
18 #include <vector>
19 #include <unordered_map>
20 #include <bitset>
21 #include <QString>
22 
23 // Why a macro and not a fancy template you will ask me ?
24 // Because some of the fields are bool packed tightly in the State::Cache class
25 // and it s just not good anymore for template T& variable manipulation...
26 #define SET_FIELD(FIELD, PATH, value) \
27  { \
28  _values.PATH = value; \
29  if (value == DEFAULT.PATH) { \
30  _signature.reset(FIELD); \
31  } else { \
32  _signature.set(FIELD); \
33  } \
34  _stamp++; \
35  }
36 
37 namespace gpu {
38 
39 class GPUObject;
40 
41 class State {
42 public:
43  State();
44  State(const State& state) : _values(state._values), _signature(state._signature), _stamp(state._stamp) {}
45  virtual ~State();
46 
47  Stamp getStamp() const { return _stamp; }
48 
49  typedef ::gpu::ComparisonFunction ComparisonFunction;
50 
51  enum FillMode
52  {
53  FILL_POINT = 0,
54  FILL_LINE,
55  FILL_FACE,
56 
57  NUM_FILL_MODES,
58  };
59 
60  enum CullMode
61  {
62  CULL_NONE = 0,
63  CULL_FRONT,
64  CULL_BACK,
65 
66  NUM_CULL_MODES,
67  };
68 
69  enum StencilOp
70  {
71  STENCIL_OP_KEEP = 0,
72  STENCIL_OP_ZERO,
73  STENCIL_OP_REPLACE,
74  STENCIL_OP_INCR_SAT,
75  STENCIL_OP_DECR_SAT,
76  STENCIL_OP_INVERT,
77  STENCIL_OP_INCR,
78  STENCIL_OP_DECR,
79 
80  NUM_STENCIL_OPS,
81  };
82 
83  enum BlendArg
84  {
85  ZERO = 0,
86  ONE,
87  SRC_COLOR,
88  INV_SRC_COLOR,
89  SRC_ALPHA,
90  INV_SRC_ALPHA,
91  DEST_ALPHA,
92  INV_DEST_ALPHA,
93  DEST_COLOR,
94  INV_DEST_COLOR,
95  SRC_ALPHA_SAT,
96  FACTOR_COLOR,
97  INV_FACTOR_COLOR,
98  FACTOR_ALPHA,
99  INV_FACTOR_ALPHA,
100 
101  NUM_BLEND_ARGS,
102  };
103 
104  enum BlendOp
105  {
106  BLEND_OP_ADD = 0,
107  BLEND_OP_SUBTRACT,
108  BLEND_OP_REV_SUBTRACT,
109  BLEND_OP_MIN,
110  BLEND_OP_MAX,
111 
112  NUM_BLEND_OPS,
113  };
114 
115  enum ColorMask
116  {
117  WRITE_NONE = 0,
118  WRITE_RED = 1,
119  WRITE_GREEN = 2,
120  WRITE_BLUE = 4,
121  WRITE_ALPHA = 8,
122  WRITE_ALL = (WRITE_RED | WRITE_GREEN | WRITE_BLUE | WRITE_ALPHA),
123  };
124 
125  class DepthTest {
126  public:
127  uint8 writeMask{ true };
128  uint8 enabled{ false };
129  ComparisonFunction function{ LESS };
130 
131  public:
132  DepthTest(bool enabled = false, bool writeMask = true, ComparisonFunction func = LESS) :
133  writeMask(writeMask), enabled(enabled), function(func) {}
134 
135  bool isEnabled() const { return enabled != 0; }
136  ComparisonFunction getFunction() const { return function; }
137  uint8 getWriteMask() const { return writeMask; }
138 
139  bool operator==(const DepthTest& right) const {
140  return
141  writeMask == right.writeMask &&
142  enabled == right.enabled &&
143  function == right.function;
144  }
145 
146  bool operator!=(const DepthTest& right) const {
147  return !(*this == right);
148  }
149 
150  operator QString() const {
151  return QString("{ writeMask = %1, enabled = %2, function = %3 }").arg(writeMask).arg(enabled).arg(function);
152  }
153  };
154 
155  struct StencilTest {
156  ComparisonFunction function;
157  StencilOp failOp;
158  StencilOp depthFailOp;
159  StencilOp passOp;
160  int8 reference{ 0 };
161  uint8 readMask{ 0xff };
162 
163  public:
164  StencilTest(int8 reference = 0,
165  uint8 readMask = 0xFF,
166  ComparisonFunction func = ALWAYS,
167  StencilOp failOp = STENCIL_OP_KEEP,
168  StencilOp depthFailOp = STENCIL_OP_KEEP,
169  StencilOp passOp = STENCIL_OP_KEEP) :
170  function(func),
171  failOp(failOp), depthFailOp(depthFailOp), passOp(passOp), reference(reference), readMask(readMask) {}
172 
173  ComparisonFunction getFunction() const { return function; }
174  StencilOp getFailOp() const { return failOp; }
175  StencilOp getDepthFailOp() const { return depthFailOp; }
176  StencilOp getPassOp() const { return passOp; }
177 
178  int8 getReference() const { return reference; }
179  uint8 getReadMask() const { return readMask; }
180 
181  bool operator==(const StencilTest& right) const {
182  return
183  function == right.function &&
184  failOp == right.failOp &&
185  depthFailOp == right.depthFailOp &&
186  passOp == right.passOp &&
187  reference == right.reference &&
188  readMask == right.readMask;
189 
190  }
191 
192  bool operator!=(const StencilTest &right) const { return !(right==*this); }
193  };
194 
195  StencilTest stencilTestFront;
196 
197  struct StencilActivation {
198  uint8 frontWriteMask = 0xFF;
199  uint8 backWriteMask = 0xFF;
200  bool enabled;
201 
202  public:
203  StencilActivation(bool enabled = false, uint8 frontWriteMask = 0xFF, uint8 backWriteMask = 0xFF) :
204  frontWriteMask(frontWriteMask), backWriteMask(backWriteMask), enabled(enabled) {}
205 
206  bool isEnabled() const { return enabled; }
207  uint8 getWriteMaskFront() const { return frontWriteMask; }
208  uint8 getWriteMaskBack() const { return backWriteMask; }
209 
210  bool operator==(const StencilActivation& right) const {
211  return
212  frontWriteMask == right.frontWriteMask &&
213  backWriteMask == right.backWriteMask &&
214  enabled == right.enabled;
215  }
216 
217  bool operator!=(const StencilActivation& right) const {
218  return !(*this == right);
219  }
220  };
221 
222  struct BlendFunction {
223  // Using uint8 here will make the structure as a whole not align to 32 bits
224  uint16 enabled;
225  BlendArg sourceColor;
226  BlendArg sourceAlpha;
227  BlendArg destColor;
228  BlendArg destAlpha;
229  BlendOp opColor;
230  BlendOp opAlpha;
231 
232  public:
233  BlendFunction(bool enabled,
234  BlendArg sourceColor,
235  BlendOp operationColor,
236  BlendArg destinationColor,
237  BlendArg sourceAlpha,
238  BlendOp operationAlpha,
239  BlendArg destinationAlpha) :
240  enabled(enabled),
241  sourceColor(sourceColor), sourceAlpha(sourceAlpha),
242  destColor(destinationColor), destAlpha(destinationAlpha),
243  opColor(operationColor), opAlpha(operationAlpha) {}
244 
245  BlendFunction(bool enabled = false, BlendArg source = ONE, BlendOp operation = BLEND_OP_ADD, BlendArg destination = ZERO) :
246  BlendFunction(enabled, source, operation, destination, source, operation, destination) {}
247 
248  bool isEnabled() const { return (enabled != 0); }
249 
250  BlendArg getSourceColor() const { return sourceColor; }
251  BlendArg getDestinationColor() const { return destColor; }
252  BlendOp getOperationColor() const { return opColor; }
253 
254  BlendArg getSourceAlpha() const { return sourceAlpha; }
255  BlendArg getDestinationAlpha() const { return destAlpha; }
256  BlendOp getOperationAlpha() const { return opAlpha; }
257 
258  bool operator==(const BlendFunction& right) const {
259  return
260  enabled == right.enabled &&
261  sourceColor == right.sourceColor &&
262  sourceAlpha == right.sourceAlpha &&
263  destColor == right.destColor &&
264  destAlpha == right.destAlpha &&
265  opColor == right.opColor &&
266  opAlpha == right.opAlpha;
267 
268  }
269 
270  bool operator!=(const BlendFunction& right) const {
271  return !(*this == right);
272  }
273  };
274 
275  struct Flags {
276  Flags() :
277  frontFaceClockwise(false), depthClampEnable(false), scissorEnable(false), multisampleEnable(true),
278  antialisedLineEnable(true), alphaToCoverageEnable(false) {}
279  bool frontFaceClockwise;
280  bool depthClampEnable;
281  bool scissorEnable;
282  bool multisampleEnable;
283  bool antialisedLineEnable;
284  bool alphaToCoverageEnable;
285 
286 
287  bool operator==(const Flags& right) const {
288  return
289  frontFaceClockwise == right.frontFaceClockwise &&
290  depthClampEnable == right.depthClampEnable &&
291  scissorEnable == right.scissorEnable &&
292  multisampleEnable == right.multisampleEnable &&
293  antialisedLineEnable == right.antialisedLineEnable &&
294  alphaToCoverageEnable == right.alphaToCoverageEnable;
295 
296  }
297 
298  bool operator!=(const Flags& right) const {
299  return !(*this == right);
300  }
301  };
302 
303  // The Data class is the full explicit description of the State class fields value.
304  // Useful for having one const static called Default for reference or for the gpu::Backend to keep track of the current value
305  class Data {
306  public:
307  float depthBias = 0.0f;
308  float depthBiasSlopeScale = 0.0f;
309 
310  DepthTest depthTest;
311  StencilActivation stencilActivation;
312  StencilTest stencilTestFront;
313  StencilTest stencilTestBack;
314  uint32 sampleMask = 0xFFFFFFFF;
315  BlendFunction blendFunction;
316  FillMode fillMode{ FILL_FACE };
317  CullMode cullMode{ CULL_NONE };
318  ColorMask colorWriteMask{ WRITE_ALL };
319 
320  Flags flags;
321  };
322 
323  // The unique default values for all the fields
324  static const Data DEFAULT;
325  void setFillMode(FillMode fill) { SET_FIELD(FILL_MODE, fillMode, fill); }
326  FillMode getFillMode() const { return _values.fillMode; }
327 
328  void setCullMode(CullMode cull) { SET_FIELD(CULL_MODE, cullMode, cull); }
329  CullMode getCullMode() const { return _values.cullMode; }
330 
331  const Flags& getFlags() const { return _values.flags; }
332 
333  void setFrontFaceClockwise(bool isClockwise) { SET_FIELD(FRONT_FACE_CLOCKWISE, flags.frontFaceClockwise, isClockwise); }
334  bool isFrontFaceClockwise() const { return _values.flags.frontFaceClockwise; }
335 
336  void setDepthClampEnable(bool enable) { SET_FIELD(DEPTH_CLAMP_ENABLE, flags.depthClampEnable, enable); }
337  bool isDepthClampEnable() const { return _values.flags.depthClampEnable; }
338 
339  void setScissorEnable(bool enable) { SET_FIELD(SCISSOR_ENABLE, flags.scissorEnable, enable); }
340  bool isScissorEnable() const { return _values.flags.scissorEnable; }
341 
342  void setMultisampleEnable(bool enable) { SET_FIELD(MULTISAMPLE_ENABLE, flags.multisampleEnable, enable); }
343  bool isMultisampleEnable() const { return _values.flags.multisampleEnable; }
344 
345  void setAntialiasedLineEnable(bool enable) { SET_FIELD(ANTIALISED_LINE_ENABLE, flags.antialisedLineEnable, enable); }
346  bool isAntialiasedLineEnable() const { return _values.flags.antialisedLineEnable; }
347 
348  // Depth Bias
349  void setDepthBias(float bias) { SET_FIELD(DEPTH_BIAS, depthBias, bias); }
350  float getDepthBias() const { return _values.depthBias; }
351 
352  void setDepthBiasSlopeScale(float scale) { SET_FIELD(DEPTH_BIAS_SLOPE_SCALE, depthBiasSlopeScale, scale); }
353  float getDepthBiasSlopeScale() const { return _values.depthBiasSlopeScale; }
354 
355  // Depth Test
356  void setDepthTest(DepthTest newDepthTest) { SET_FIELD(DEPTH_TEST, depthTest, newDepthTest); }
357  void setDepthTest(bool enable, bool writeMask, ComparisonFunction func) {
358  setDepthTest(DepthTest(enable, writeMask, func));
359  }
360  DepthTest getDepthTest() const { return _values.depthTest; }
361 
362  bool isDepthTestEnabled() const { return getDepthTest().isEnabled(); }
363  uint8 getDepthTestWriteMask() const { return getDepthTest().getWriteMask(); }
364  ComparisonFunction getDepthTestFunc() const { return getDepthTest().getFunction(); }
365 
366  // Stencil test
367  void setStencilTest(bool enabled, uint8 frontWriteMask, StencilTest frontTest, uint8 backWriteMask, StencilTest backTest) {
368  SET_FIELD(STENCIL_ACTIVATION, stencilActivation, StencilActivation(enabled, frontWriteMask, backWriteMask));
369  SET_FIELD(STENCIL_TEST_FRONT, stencilTestFront, frontTest);
370  SET_FIELD(STENCIL_TEST_BACK, stencilTestBack, backTest);
371  }
372 
373  void setStencilTest(bool enabled, uint8 frontWriteMask, StencilTest frontTest) {
374  setStencilTest(enabled, frontWriteMask, frontTest, frontWriteMask, frontTest);
375  }
376 
377  StencilActivation getStencilActivation() const { return _values.stencilActivation; }
378  StencilTest getStencilTestFront() const { return _values.stencilTestFront; }
379  StencilTest getStencilTestBack() const { return _values.stencilTestBack; }
380 
381  bool isStencilEnabled() const { return getStencilActivation().isEnabled(); }
382  uint8 getStencilWriteMaskFront() const { return getStencilActivation().getWriteMaskFront(); }
383  uint8 getStencilWriteMaskBack() const { return getStencilActivation().getWriteMaskBack(); }
384 
385  // Alpha to coverage
386  void setAlphaToCoverageEnable(bool enable) { SET_FIELD(ALPHA_TO_COVERAGE_ENABLE, flags.alphaToCoverageEnable, enable); }
387  bool isAlphaToCoverageEnabled() const { return _values.flags.alphaToCoverageEnable; }
388 
389  // Sample mask
390  void setSampleMask(uint32 mask) { SET_FIELD(SAMPLE_MASK, sampleMask, mask); }
391  uint32 getSampleMask() const { return _values.sampleMask; }
392 
393  // Blend Function
394  void setBlendFunction(BlendFunction function) { SET_FIELD(BLEND_FUNCTION, blendFunction, function); }
395  const BlendFunction& getBlendFunction() const { return _values.blendFunction; }
396 
397  void setBlendFunction(bool enabled,
398  BlendArg sourceColor,
399  BlendOp operationColor,
400  BlendArg destinationColor,
401  BlendArg sourceAlpha,
402  BlendOp operationAlpha,
403  BlendArg destinationAlpha) {
404  setBlendFunction(BlendFunction(enabled, sourceColor, operationColor, destinationColor, sourceAlpha, operationAlpha,
405  destinationAlpha));
406  }
407  void setBlendFunction(bool enabled, BlendArg source, BlendOp operation, BlendArg destination) {
408  setBlendFunction(BlendFunction(enabled, source, operation, destination));
409  }
410 
411  bool isBlendEnabled() const { return getBlendFunction().isEnabled(); }
412 
413  // Color write mask
414  void setColorWriteMask(ColorMask mask) { SET_FIELD(COLOR_WRITE_MASK, colorWriteMask, mask); }
415  void setColorWriteMask(bool red, bool green, bool blue, bool alpha) {
416  ColorMask value = (ColorMask)((WRITE_RED * red) | (WRITE_GREEN * green) | (WRITE_BLUE * blue) | (WRITE_ALPHA * alpha));
417  SET_FIELD(COLOR_WRITE_MASK, colorWriteMask, value);
418  }
419  ColorMask getColorWriteMask() const { return _values.colorWriteMask; }
420 
421  // All the possible fields
422  // NOTE: If you change this, you must update GLBackend::GLState::_resetStateCommands
423  enum Field
424  {
425  FILL_MODE,
426  CULL_MODE,
427  FRONT_FACE_CLOCKWISE,
428  DEPTH_CLAMP_ENABLE,
429  SCISSOR_ENABLE,
430  MULTISAMPLE_ENABLE,
431  ANTIALISED_LINE_ENABLE,
432 
433  DEPTH_BIAS,
434  DEPTH_BIAS_SLOPE_SCALE,
435 
436  DEPTH_TEST,
437 
438  STENCIL_ACTIVATION,
439  STENCIL_TEST_FRONT,
440  STENCIL_TEST_BACK,
441 
442  SAMPLE_MASK,
443 
444  ALPHA_TO_COVERAGE_ENABLE,
445 
446  BLEND_FUNCTION,
447 
448  COLOR_WRITE_MASK,
449 
450  NUM_FIELDS, // not a valid field, just the count
451  };
452 
453  // The signature of the state tells which fields of the state are not default
454  // this way during rendering the Backend can compare it's current state and try to minimize the job to do
455  typedef std::bitset<NUM_FIELDS> Signature;
456 
457  Signature getSignature() const { return _signature; }
458 
459  static Signature evalSignature(const Data& state);
460 
461  // For convenience, create a State from the values directly
462  State(const Data& values);
463  const Data& getValues() const { return _values; }
464 
465  const GPUObjectPointer gpuObject{};
466 
467 protected:
468  State& operator=(const State& state);
469 
470  Data _values;
471  Signature _signature{ 0 };
472  Stamp _stamp{ 0 };
473 };
474 
475 typedef std::shared_ptr<State> StatePointer;
476 typedef std::vector<StatePointer> States;
477 
478 }; // namespace gpu
479 
480 #endif