GPU state cleanup

This commit is contained in:
Brad Davis 2018-10-28 16:10:21 -07:00
parent 6cb8cf0202
commit 6fb869126e
10 changed files with 437 additions and 336 deletions

View file

@ -78,129 +78,6 @@
namespace gpu { namespace gl {
#if defined(GPU_POINTER_STORAGE_SHARED)
template <typename T>
static inline bool compare(const std::shared_ptr<T>& a, const std::shared_ptr<T>& b) {
return a == b;
}
template <typename T>
static inline T* acquire(const std::shared_ptr<T>& pointer) {
return pointer.get();
}
template <typename T>
static inline void reset(std::shared_ptr<T>& pointer) {
return pointer.reset();
}
template <typename T>
static inline bool valid(const std::shared_ptr<T>& pointer) {
return pointer.operator bool();
}
template <typename T>
static inline void assign(std::shared_ptr<T>& pointer, const std::shared_ptr<T>& source) {
pointer = source;
}
using BufferReference = BufferPointer;
using TextureReference = TexturePointer;
using FramebufferReference = FramebufferPointer;
using FormatReference = Stream::FormatPointer;
using PipelineReference = PipelinePointer;
#define GPU_REFERENCE_INIT_VALUE nullptr
#elif defined(GPU_POINTER_STORAGE_REF)
template <typename T>
class PointerReferenceWrapper : public std::reference_wrapper<const std::shared_ptr<T>> {
using Parent = std::reference_wrapper<const std::shared_ptr<T>>;
public:
using Pointer = std::shared_ptr<T>;
PointerReferenceWrapper() : Parent(EMPTY()) {}
PointerReferenceWrapper(const Pointer& pointer) : Parent(pointer) {}
void clear() { *this = EMPTY(); }
private:
static const Pointer& EMPTY() {
static const Pointer EMPTY_VALUE;
return EMPTY_VALUE;
};
};
template <typename T>
static bool compare(const PointerReferenceWrapper<T>& reference, const std::shared_ptr<T>& pointer) {
return reference.get() == pointer;
}
template <typename T>
static inline T* acquire(const PointerReferenceWrapper<T>& reference) {
return reference.get().get();
}
template <typename T>
static void assign(PointerReferenceWrapper<T>& reference, const std::shared_ptr<T>& pointer) {
reference = pointer;
}
template <typename T>
static bool valid(const PointerReferenceWrapper<T>& reference) {
return reference.get().operator bool();
}
template <typename T>
static inline void reset(PointerReferenceWrapper<T>& reference) {
return reference.clear();
}
using BufferReference = PointerReferenceWrapper<Buffer>;
using TextureReference = PointerReferenceWrapper<Texture>;
using FramebufferReference = PointerReferenceWrapper<Framebuffer>;
using FormatReference = PointerReferenceWrapper<Stream::Format>;
using PipelineReference = PointerReferenceWrapper<Pipeline>;
#define GPU_REFERENCE_INIT_VALUE
#elif defined(GPU_POINTER_STORAGE_RAW)
template <typename T>
static bool compare(const T* const& rawPointer, const std::shared_ptr<T>& pointer) {
return rawPointer == pointer.get();
}
template <typename T>
static inline T* acquire(T*& rawPointer) {
return rawPointer;
}
template <typename T>
static inline bool valid(const T* const& rawPointer) {
return rawPointer;
}
template <typename T>
static inline void reset(T*& rawPointer) {
rawPointer = nullptr;
}
template <typename T>
static inline void assign(T*& rawPointer, const std::shared_ptr<T>& pointer) {
rawPointer = pointer.get();
}
using BufferReference = Buffer*;
using TextureReference = Texture*;
using FramebufferReference = Framebuffer*;
using FormatReference = Stream::Format*;
using PipelineReference = Pipeline*;
#define GPU_REFERENCE_INIT_VALUE nullptr
#endif
class GLBackend : public Backend, public std::enable_shared_from_this<GLBackend> {
// Context Backend static interface required
friend class gpu::Context;
@ -583,13 +460,13 @@ protected:
BufferState& operator=(const BufferState& other) = delete;
void reset() {
gpu::gl::reset(buffer);
gpu::reset(buffer);
offset = 0;
size = 0;
}
bool compare(const BufferPointer& buffer, GLintptr offset, GLsizeiptr size) {
const auto& self = *this;
return (self.offset == offset && self.size == size && gpu::gl::compare(self.buffer, buffer));
return (self.offset == offset && self.size == size && gpu::compare(self.buffer, buffer));
}
};

View file

@ -73,7 +73,7 @@ void GLBackend::do_advance(const Batch& batch, size_t paramOffset) {
}
void GLBackend::do_clearFramebuffer(const Batch& batch, size_t paramOffset) {
if (_stereo.isStereo() && !_pipeline._stateCache.scissorEnable) {
if (_stereo.isStereo() && !_pipeline._stateCache.flags.scissorEnable) {
qWarning("Clear without scissor in stereo mode");
}
@ -140,7 +140,7 @@ void GLBackend::do_clearFramebuffer(const Batch& batch, size_t paramOffset) {
}
// Apply scissor if needed and if not already on
bool doEnableScissor = (useScissor && (!_pipeline._stateCache.scissorEnable));
bool doEnableScissor = (useScissor && (!_pipeline._stateCache.flags.scissorEnable));
if (doEnableScissor) {
glEnable(GL_SCISSOR_TEST);
}

View file

@ -100,17 +100,17 @@ void GLBackend::do_setStateCullMode(int32 mode) {
}
void GLBackend::do_setStateFrontFaceClockwise(bool isClockwise) {
if (_pipeline._stateCache.frontFaceClockwise != isClockwise) {
if (_pipeline._stateCache.flags.frontFaceClockwise != isClockwise) {
static GLenum GL_FRONT_FACES[] = { GL_CCW, GL_CW };
glFrontFace(GL_FRONT_FACES[isClockwise]);
(void)CHECK_GL_ERROR();
_pipeline._stateCache.frontFaceClockwise = isClockwise;
_pipeline._stateCache.flags.frontFaceClockwise = isClockwise;
}
}
void GLBackend::do_setStateDepthClampEnable(bool enable) {
if (_pipeline._stateCache.depthClampEnable != enable) {
if (_pipeline._stateCache.flags.depthClampEnable != enable) {
#if !defined(USE_GLES)
if (enable) {
glEnable(GL_DEPTH_CLAMP);
@ -118,13 +118,13 @@ void GLBackend::do_setStateDepthClampEnable(bool enable) {
glDisable(GL_DEPTH_CLAMP);
}
(void)CHECK_GL_ERROR();
_pipeline._stateCache.depthClampEnable = enable;
_pipeline._stateCache.flags.depthClampEnable = enable;
#endif
}
}
void GLBackend::do_setStateScissorEnable(bool enable) {
if (_pipeline._stateCache.scissorEnable != enable) {
if (_pipeline._stateCache.flags.scissorEnable != enable) {
if (enable) {
glEnable(GL_SCISSOR_TEST);
} else {
@ -132,12 +132,12 @@ void GLBackend::do_setStateScissorEnable(bool enable) {
}
(void)CHECK_GL_ERROR();
_pipeline._stateCache.scissorEnable = enable;
_pipeline._stateCache.flags.scissorEnable = enable;
}
}
void GLBackend::do_setStateMultisampleEnable(bool enable) {
if (_pipeline._stateCache.multisampleEnable != enable) {
if (_pipeline._stateCache.flags.multisampleEnable != enable) {
#if !defined(USE_GLES)
if (enable) {
glEnable(GL_MULTISAMPLE);
@ -146,13 +146,13 @@ void GLBackend::do_setStateMultisampleEnable(bool enable) {
}
(void)CHECK_GL_ERROR();
_pipeline._stateCache.multisampleEnable = enable;
_pipeline._stateCache.flags.multisampleEnable = enable;
#endif
}
}
void GLBackend::do_setStateAntialiasedLineEnable(bool enable) {
if (_pipeline._stateCache.antialisedLineEnable != enable) {
if (_pipeline._stateCache.flags.antialisedLineEnable != enable) {
#if !defined(USE_GLES)
if (enable) {
glEnable(GL_LINE_SMOOTH);
@ -161,7 +161,7 @@ void GLBackend::do_setStateAntialiasedLineEnable(bool enable) {
}
(void)CHECK_GL_ERROR();
_pipeline._stateCache.antialisedLineEnable = enable;
_pipeline._stateCache.flags.antialisedLineEnable = enable;
#endif
}
}
@ -206,7 +206,7 @@ void GLBackend::do_setStateDepthTest(State::DepthTest test) {
if (CHECK_GL_ERROR()) {
qCDebug(gpulogging) << "DepthTest" << (test.isEnabled() ? "Enabled" : "Disabled")
<< "Mask=" << (test.getWriteMask() ? "Write" : "no Write")
<< "Func=" << test.getFunction()
<< "Func=" << (uint16_t)test.getFunction()
<< "Raw=" << test.getRaw();
}
_pipeline._stateCache.depthTest = test;
@ -264,7 +264,7 @@ void GLBackend::do_setStateStencil(State::StencilActivation activation, State::S
}
void GLBackend::do_setStateAlphaToCoverageEnable(bool enable) {
if (_pipeline._stateCache.alphaToCoverageEnable != enable) {
if (_pipeline._stateCache.flags.alphaToCoverageEnable != enable) {
if (enable) {
glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE);
} else {
@ -272,7 +272,7 @@ void GLBackend::do_setStateAlphaToCoverageEnable(bool enable) {
}
(void)CHECK_GL_ERROR();
_pipeline._stateCache.alphaToCoverageEnable = enable;
_pipeline._stateCache.flags.alphaToCoverageEnable = enable;
}
}
@ -317,7 +317,7 @@ void GLBackend::do_setStateColorWriteMask(uint32 mask) {
mask & State::ColorMask::WRITE_ALPHA);
(void)CHECK_GL_ERROR();
_pipeline._stateCache.colorWriteMask = mask;
_pipeline._stateCache.colorWriteMask = (State::ColorMask)mask;
}
}

View file

@ -174,17 +174,17 @@ void getCurrentGLState(State::Data& state) {
{
GLint winding;
glGetIntegerv(GL_FRONT_FACE, &winding);
state.frontFaceClockwise = (winding == GL_CW);
state.flags.frontFaceClockwise = (winding == GL_CW);
#if defined(USE_GLES)
state.multisampleEnable = glIsEnabled(GL_MULTISAMPLE_EXT);
state.antialisedLineEnable = false;
state.depthClampEnable = false;
state.flags.multisampleEnable = glIsEnabled(GL_MULTISAMPLE_EXT);
state.flags.antialisedLineEnable = false;
state.flags.depthClampEnable = false;
#else
state.multisampleEnable = glIsEnabled(GL_MULTISAMPLE);
state.antialisedLineEnable = glIsEnabled(GL_LINE_SMOOTH);
state.depthClampEnable = glIsEnabled(GL_DEPTH_CLAMP);
state.flags.multisampleEnable = glIsEnabled(GL_MULTISAMPLE);
state.flags.antialisedLineEnable = glIsEnabled(GL_LINE_SMOOTH);
state.flags.depthClampEnable = glIsEnabled(GL_DEPTH_CLAMP);
#endif
state.scissorEnable = glIsEnabled(GL_SCISSOR_TEST);
state.flags.scissorEnable = glIsEnabled(GL_SCISSOR_TEST);
}
{
if (glIsEnabled(GL_POLYGON_OFFSET_FILL)) {
@ -247,7 +247,7 @@ void getCurrentGLState(State::Data& state) {
state.sampleMask = mask;
}
{
state.alphaToCoverageEnable = glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE);
state.flags.alphaToCoverageEnable = glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE);
}
{
GLboolean isEnabled = glIsEnabled(GL_BLEND);
@ -272,10 +272,10 @@ void getCurrentGLState(State::Data& state) {
{
GLboolean mask[4];
glGetBooleanv(GL_COLOR_WRITEMASK, mask);
state.colorWriteMask = (mask[0] ? State::WRITE_RED : 0)
state.colorWriteMask = (State::ColorMask)((mask[0] ? State::WRITE_RED : 0)
| (mask[1] ? State::WRITE_GREEN : 0)
| (mask[2] ? State::WRITE_BLUE : 0)
| (mask[3] ? State::WRITE_ALPHA : 0);
| (mask[3] ? State::WRITE_ALPHA : 0));
}
(void)CHECK_GL_ERROR();

View file

@ -44,7 +44,7 @@ const GLState::Commands makeResetStateCommands() {
// and we have a 50/50 chance that State::DEFAULT is not yet initialized.
// Since State::DEFAULT = State::Data() it is much easier to not use the actual State::DEFAULT
// but another State::Data object with a default initialization.
const State::Data DEFAULT = State::Data();
const State::Data& DEFAULT = State::DEFAULT;
auto depthBiasCommand = std::make_shared<CommandDepthBias>(&GLBackend::do_setStateDepthBias,
Vec2(DEFAULT.depthBias, DEFAULT.depthBiasSlopeScale));
@ -56,11 +56,11 @@ const GLState::Commands makeResetStateCommands() {
return {
std::make_shared<Command1I>(&GLBackend::do_setStateFillMode, DEFAULT.fillMode),
std::make_shared<Command1I>(&GLBackend::do_setStateCullMode, DEFAULT.cullMode),
std::make_shared<Command1B>(&GLBackend::do_setStateFrontFaceClockwise, DEFAULT.frontFaceClockwise),
std::make_shared<Command1B>(&GLBackend::do_setStateDepthClampEnable, DEFAULT.depthClampEnable),
std::make_shared<Command1B>(&GLBackend::do_setStateScissorEnable, DEFAULT.scissorEnable),
std::make_shared<Command1B>(&GLBackend::do_setStateMultisampleEnable, DEFAULT.multisampleEnable),
std::make_shared<Command1B>(&GLBackend::do_setStateAntialiasedLineEnable, DEFAULT.antialisedLineEnable),
std::make_shared<Command1B>(&GLBackend::do_setStateFrontFaceClockwise, DEFAULT.flags.frontFaceClockwise),
std::make_shared<Command1B>(&GLBackend::do_setStateDepthClampEnable, DEFAULT.flags.depthClampEnable),
std::make_shared<Command1B>(&GLBackend::do_setStateScissorEnable, DEFAULT.flags.scissorEnable),
std::make_shared<Command1B>(&GLBackend::do_setStateMultisampleEnable, DEFAULT.flags.multisampleEnable),
std::make_shared<Command1B>(&GLBackend::do_setStateAntialiasedLineEnable, DEFAULT.flags.antialisedLineEnable),
// Depth bias has 2 fields in State but really one call in GLBackend
CommandPointer(depthBiasCommand),
@ -75,7 +75,7 @@ const GLState::Commands makeResetStateCommands() {
std::make_shared<Command1U>(&GLBackend::do_setStateSampleMask, DEFAULT.sampleMask),
std::make_shared<Command1B>(&GLBackend::do_setStateAlphaToCoverageEnable, DEFAULT.alphaToCoverageEnable),
std::make_shared<Command1B>(&GLBackend::do_setStateAlphaToCoverageEnable, DEFAULT.flags.alphaToCoverageEnable),
std::make_shared<CommandBlend>(&GLBackend::do_setStateBlend, DEFAULT.blendFunction),

View file

@ -29,6 +29,152 @@ class QImage;
namespace gpu {
//
// GL Backend pointer storage mechanism
// One of the following three defines must be defined.
// GPU_POINTER_STORAGE_SHARED
// The platonic ideal, use references to smart pointers.
// However, this produces artifacts because there are too many places in the code right now that
// create temporary values (undesirable smart pointer duplications) and then those temp variables
// get passed on and have their reference taken, and then invalidated
// GPU_POINTER_STORAGE_REF
// Raw pointer manipulation. Seems more dangerous than the reference wrappers,
// but in practice, the danger of grabbing a reference to a temporary variable
// is causing issues
// GPU_POINTER_STORAGE_RAW
#if defined(USE_GLES)
#define GPU_POINTER_STORAGE_SHARED
#else
#define GPU_POINTER_STORAGE_RAW
#endif
#if defined(GPU_POINTER_STORAGE_SHARED)
template <typename T>
static inline bool compare(const std::shared_ptr<T>& a, const std::shared_ptr<T>& b) {
return a == b;
}
template <typename T>
static inline T* acquire(const std::shared_ptr<T>& pointer) {
return pointer.get();
}
template <typename T>
static inline void reset(std::shared_ptr<T>& pointer) {
return pointer.reset();
}
template <typename T>
static inline bool valid(const std::shared_ptr<T>& pointer) {
return pointer.operator bool();
}
template <typename T>
static inline void assign(std::shared_ptr<T>& pointer, const std::shared_ptr<T>& source) {
pointer = source;
}
using BufferReference = BufferPointer;
using TextureReference = TexturePointer;
using FramebufferReference = FramebufferPointer;
using FormatReference = Stream::FormatPointer;
using PipelineReference = PipelinePointer;
#define GPU_REFERENCE_INIT_VALUE nullptr
#elif defined(GPU_POINTER_STORAGE_REF)
template <typename T>
class PointerReferenceWrapper : public std::reference_wrapper<const std::shared_ptr<T>> {
using Parent = std::reference_wrapper<const std::shared_ptr<T>>;
public:
using Pointer = std::shared_ptr<T>;
PointerReferenceWrapper() : Parent(EMPTY()) {}
PointerReferenceWrapper(const Pointer& pointer) : Parent(pointer) {}
void clear() { *this = EMPTY(); }
private:
static const Pointer& EMPTY() {
static const Pointer EMPTY_VALUE;
return EMPTY_VALUE;
};
};
template <typename T>
static bool compare(const PointerReferenceWrapper<T>& reference, const std::shared_ptr<T>& pointer) {
return reference.get() == pointer;
}
template <typename T>
static inline T* acquire(const PointerReferenceWrapper<T>& reference) {
return reference.get().get();
}
template <typename T>
static void assign(PointerReferenceWrapper<T>& reference, const std::shared_ptr<T>& pointer) {
reference = pointer;
}
template <typename T>
static bool valid(const PointerReferenceWrapper<T>& reference) {
return reference.get().operator bool();
}
template <typename T>
static inline void reset(PointerReferenceWrapper<T>& reference) {
return reference.clear();
}
using BufferReference = PointerReferenceWrapper<Buffer>;
using TextureReference = PointerReferenceWrapper<Texture>;
using FramebufferReference = PointerReferenceWrapper<Framebuffer>;
using FormatReference = PointerReferenceWrapper<Stream::Format>;
using PipelineReference = PointerReferenceWrapper<Pipeline>;
#define GPU_REFERENCE_INIT_VALUE
#elif defined(GPU_POINTER_STORAGE_RAW)
template <typename T>
static bool compare(const T* const& rawPointer, const std::shared_ptr<T>& pointer) {
return rawPointer == pointer.get();
}
template <typename T>
static inline T* acquire(T* const& rawPointer) {
return rawPointer;
}
template <typename T>
static inline bool valid(const T* const& rawPointer) {
return rawPointer;
}
template <typename T>
static inline void reset(T*& rawPointer) {
rawPointer = nullptr;
}
template <typename T>
static inline void assign(T*& rawPointer, const std::shared_ptr<T>& pointer) {
rawPointer = pointer.get();
}
using BufferReference = Buffer*;
using TextureReference = Texture*;
using FramebufferReference = Framebuffer*;
using FormatReference = Stream::Format*;
using PipelineReference = Pipeline*;
#define GPU_REFERENCE_INIT_VALUE nullptr
#endif
struct ContextStats {
public:
int _ISNumFormatChanges = 0;

View file

@ -376,7 +376,7 @@ public:
};
enum ComparisonFunction {
enum ComparisonFunction : uint16 {
NEVER = 0,
LESS,
EQUAL,

View file

@ -33,19 +33,19 @@ State::Signature State::evalSignature(const Data& state) {
if (state.cullMode != State::DEFAULT.cullMode) {
signature.set(State::CULL_MODE);
}
if (state.frontFaceClockwise != State::DEFAULT.frontFaceClockwise) {
if (state.flags.frontFaceClockwise != State::DEFAULT.flags.frontFaceClockwise) {
signature.set(State::FRONT_FACE_CLOCKWISE);
}
if (state.depthClampEnable != State::DEFAULT.depthClampEnable) {
if (state.flags.depthClampEnable != State::DEFAULT.flags.depthClampEnable) {
signature.set(State::DEPTH_CLAMP_ENABLE);
}
if (state.scissorEnable != State::DEFAULT.scissorEnable) {
if (state.flags.scissorEnable != State::DEFAULT.flags.scissorEnable) {
signature.set(State::SCISSOR_ENABLE);
}
if (state.multisampleEnable != State::DEFAULT.multisampleEnable) {
if (state.flags.multisampleEnable != State::DEFAULT.flags.multisampleEnable) {
signature.set(State::MULTISAMPLE_ENABLE);
}
if (state.antialisedLineEnable != State::DEFAULT.antialisedLineEnable) {
if (state.flags.antialisedLineEnable != State::DEFAULT.flags.antialisedLineEnable) {
signature.set(State::ANTIALISED_LINE_ENABLE);
}
if (state.depthBias != State::DEFAULT.depthBias) {
@ -69,7 +69,7 @@ State::Signature State::evalSignature(const Data& state) {
if (state.sampleMask != State::DEFAULT.sampleMask) {
signature.set(State::SAMPLE_MASK);
}
if (state.alphaToCoverageEnable != State::DEFAULT.alphaToCoverageEnable) {
if (state.flags.alphaToCoverageEnable != State::DEFAULT.flags.alphaToCoverageEnable) {
signature.set(State::ALPHA_TO_COVERAGE_ENABLE);
}
if (state.blendFunction != State::DEFAULT.blendFunction) {
@ -86,3 +86,29 @@ State::State(const Data& values) :
_values(values) {
_signature = evalSignature(_values);
}
template <typename T>
static std::string hex(T t) {
std::stringstream stream;
stream << std::hex << t;
return stream.str();
}
std::string State::getKey() const {
std::string key;
key = hex(*(int*)&_values.depthBias);
key += ":" + hex(*(int*)&_values.depthBiasSlopeScale);
key += ":" + hex(_values.depthTest.getRaw());
key += ":" + hex(_values.stencilActivation.getRaw());
key += ":" + hex(_values.stencilTestFront.getRaw());
key += ":" + hex(_values.stencilTestBack.getRaw());
key += ":" + hex(_values.blendFunction.getRaw());
key += ":" + hex(_values.sampleMask);
key += ":" + hex(_values.sampleMask);
// fillMode, cullMode, colorMaskWrite and the flags consume 32 bits alltogether
static_assert(0 == offsetof(State::Data, fillMode) % 4, "Validate fillMode offset");
key += ":" + hex(*(int*)&_values.fillMode);
return key;
}

View file

@ -14,6 +14,7 @@
#include "Format.h"
#include <memory>
#include <sstream>
#include <vector>
#include <unordered_map>
#include <bitset>
@ -21,16 +22,16 @@
// Why a macro and not a fancy template you will ask me ?
// Because some of the fields are bool packed tightly in the State::Cache class
// and it s just not good anymore for template T& variable manipulation...
#define SET_FIELD(field, defaultValue, value, dest) {\
dest = value;\
if (value == defaultValue) {\
_signature.reset(field);\
} else {\
_signature.set(field);\
}\
_stamp++;\
}\
#define SET_FIELD(FIELD, PATH, value) \
{ \
_values.PATH = value; \
if (value == DEFAULT.PATH) { \
_signature.reset(FIELD); \
} else { \
_signature.set(FIELD); \
} \
_stamp++; \
}
namespace gpu {
@ -45,7 +46,8 @@ public:
typedef ::gpu::ComparisonFunction ComparisonFunction;
enum FillMode {
enum FillMode : uint8
{
FILL_POINT = 0,
FILL_LINE,
FILL_FACE,
@ -53,7 +55,8 @@ public:
NUM_FILL_MODES,
};
enum CullMode {
enum CullMode : uint8
{
CULL_NONE = 0,
CULL_FRONT,
CULL_BACK,
@ -61,7 +64,8 @@ public:
NUM_CULL_MODES,
};
enum StencilOp {
enum StencilOp : uint16
{
STENCIL_OP_KEEP = 0,
STENCIL_OP_ZERO,
STENCIL_OP_REPLACE,
@ -74,7 +78,8 @@ public:
NUM_STENCIL_OPS,
};
enum BlendArg {
enum BlendArg : uint16
{
ZERO = 0,
ONE,
SRC_COLOR,
@ -94,7 +99,8 @@ public:
NUM_BLEND_ARGS,
};
enum BlendOp {
enum BlendOp : uint16
{
BLEND_OP_ADD = 0,
BLEND_OP_SUBTRACT,
BLEND_OP_REV_SUBTRACT,
@ -104,204 +110,234 @@ public:
NUM_BLEND_OPS,
};
enum ColorMask
enum ColorMask : uint8
{
WRITE_NONE = 0,
WRITE_RED = 1,
WRITE_GREEN = 2,
WRITE_BLUE = 4,
WRITE_ALPHA = 8,
WRITE_ALL = (WRITE_RED | WRITE_GREEN | WRITE_BLUE | WRITE_ALPHA ),
WRITE_ALL = (WRITE_RED | WRITE_GREEN | WRITE_BLUE | WRITE_ALPHA),
};
class DepthTest {
uint8 _function = LESS;
uint8 _writeMask = true;
uint8 _enabled = false;
#if defined(__clang__)
__attribute__((unused))
#endif
uint8 _spare = 0; // Padding
public:
uint8 writeMask{ true };
uint8 enabled{ false };
ComparisonFunction function{ LESS };
public:
DepthTest(bool enabled = false, bool writeMask = true, ComparisonFunction func = LESS) :
_function(func), _writeMask(writeMask), _enabled(enabled) {
}
function(func), writeMask(writeMask), enabled(enabled) {}
bool isEnabled() const { return _enabled != 0; }
ComparisonFunction getFunction() const { return ComparisonFunction(_function); }
uint8 getWriteMask() const { return _writeMask; }
bool isEnabled() const { return enabled != 0; }
ComparisonFunction getFunction() const { return function; }
uint8 getWriteMask() const { return writeMask; }
int32 getRaw() const { return *(reinterpret_cast<const int32*>(this)); }
DepthTest(int32 raw) { *(reinterpret_cast<int32*>(this)) = raw; }
bool operator== (const DepthTest& right) const { return getRaw() == right.getRaw(); }
bool operator!= (const DepthTest& right) const { return getRaw() != right.getRaw(); }
};
bool operator==(const DepthTest& right) const { return getRaw() == right.getRaw(); }
bool operator!=(const DepthTest& right) const { return getRaw() != right.getRaw(); }
};
class StencilTest {
static const int FUNC_MASK = 0x000f;
static const int FAIL_OP_MASK = 0x00f0;
static const int DEPTH_FAIL_OP_MASK = 0x0f00;
static const int PASS_OP_MASK = 0xf000;
static const int FAIL_OP_OFFSET = 4;
static const int DEPTH_FAIL_OP_OFFSET = 8;
static const int PASS_OP_OFFSET = 12;
static_assert(sizeof(DepthTest) == sizeof(uint32_t), "DepthTest size check");
uint16 _functionAndOperations;
int8 _reference = 0;
uint8 _readMask = 0xff;
public:
struct StencilTest {
ComparisonFunction function : 4;
StencilOp failOp : 4;
StencilOp depthFailOp : 4;
StencilOp passOp : 4;
int8 reference{ 0 };
uint8 readMask{ 0xff };
StencilTest(int8 reference = 0, uint8 readMask =0xFF, ComparisonFunction func = ALWAYS, StencilOp failOp = STENCIL_OP_KEEP, StencilOp depthFailOp = STENCIL_OP_KEEP, StencilOp passOp = STENCIL_OP_KEEP) :
_functionAndOperations(func | (failOp << FAIL_OP_OFFSET) | (depthFailOp << DEPTH_FAIL_OP_OFFSET) | (passOp << PASS_OP_OFFSET)),
_reference(reference), _readMask(readMask)
{}
public:
StencilTest(int8 reference = 0,
uint8 readMask = 0xFF,
ComparisonFunction func = ALWAYS,
StencilOp failOp = STENCIL_OP_KEEP,
StencilOp depthFailOp = STENCIL_OP_KEEP,
StencilOp passOp = STENCIL_OP_KEEP) :
function(func),
failOp(failOp), depthFailOp(depthFailOp), passOp(passOp), reference(reference), readMask(readMask) {}
ComparisonFunction getFunction() const { return ComparisonFunction(_functionAndOperations & FUNC_MASK); }
StencilOp getFailOp() const { return StencilOp((_functionAndOperations & FAIL_OP_MASK) >> FAIL_OP_OFFSET); }
StencilOp getDepthFailOp() const { return StencilOp((_functionAndOperations & DEPTH_FAIL_OP_MASK) >> DEPTH_FAIL_OP_OFFSET); }
StencilOp getPassOp() const { return StencilOp((_functionAndOperations & PASS_OP_MASK) >> PASS_OP_OFFSET); }
ComparisonFunction getFunction() const { return function; }
StencilOp getFailOp() const { return failOp; }
StencilOp getDepthFailOp() const { return depthFailOp; }
StencilOp getPassOp() const { return passOp; }
int8 getReference() const { return _reference; }
uint8 getReadMask() const { return _readMask; }
int8 getReference() const { return reference; }
uint8 getReadMask() const { return readMask; }
int32 getRaw() const { return *(reinterpret_cast<const int32*>(this)); }
StencilTest(int32 raw) { *(reinterpret_cast<int32*>(this)) = raw; }
bool operator== (const StencilTest& right) const { return getRaw() == right.getRaw(); }
bool operator!= (const StencilTest& right) const { return getRaw() != right.getRaw(); }
};
bool operator==(const StencilTest& right) const { return getRaw() == right.getRaw(); }
bool operator!=(const StencilTest& right) const { return getRaw() != right.getRaw(); }
};
static_assert(sizeof(StencilTest) == sizeof(uint32_t), "StencilTest size check");
class StencilActivation {
uint8 _frontWriteMask = 0xFF;
uint8 _backWriteMask = 0xFF;
uint16 _enabled = 0;
public:
StencilTest stencilTestFront;
StencilActivation(bool enabled, uint8 frontWriteMask = 0xFF, uint8 backWriteMask = 0xFF) :
_frontWriteMask(frontWriteMask), _backWriteMask(backWriteMask), _enabled(enabled) {}
struct StencilActivation {
uint8 frontWriteMask = 0xFF;
uint8 backWriteMask = 0xFF;
bool enabled : 1;
uint8 _spare1 : 7;
uint8 _spare2{ 0 };
bool isEnabled() const { return (_enabled != 0); }
uint8 getWriteMaskFront() const { return _frontWriteMask; }
uint8 getWriteMaskBack() const { return _backWriteMask; }
public:
StencilActivation(bool enabled = false, uint8 frontWriteMask = 0xFF, uint8 backWriteMask = 0xFF) :
frontWriteMask(frontWriteMask), backWriteMask(backWriteMask), enabled(enabled), _spare1{ 0 } {}
bool isEnabled() const { return enabled; }
uint8 getWriteMaskFront() const { return frontWriteMask; }
uint8 getWriteMaskBack() const { return backWriteMask; }
int32 getRaw() const { return *(reinterpret_cast<const int32*>(this)); }
StencilActivation(int32 raw) { *(reinterpret_cast<int32*>(this)) = raw; }
bool operator== (const StencilActivation& right) const { return getRaw() == right.getRaw(); }
bool operator!= (const StencilActivation& right) const { return getRaw() != right.getRaw(); }
bool operator==(const StencilActivation& right) const { return getRaw() == right.getRaw(); }
bool operator!=(const StencilActivation& right) const { return getRaw() != right.getRaw(); }
};
class BlendFunction {
static const int COLOR_MASK = 0x0f;
static const int ALPHA_MASK = 0xf0;
static const int ALPHA_OFFSET = 4;
static_assert(sizeof(StencilActivation) == sizeof(uint32_t), "StencilActivation size check");
struct BlendFunction {
// Using uint8 here will make the structure as a whole not align to 32 bits
uint16 enabled : 8;
BlendArg sourceColor : 4;
BlendArg sourceAlpha : 4;
BlendArg destColor : 4;
BlendArg destAlpha : 4;
BlendOp opColor : 4;
BlendOp opAlpha : 4;
uint8 _enabled;
uint8 _source;
uint8 _destination;
uint8 _operation;
public:
BlendFunction(bool enabled,
BlendArg sourceColor, BlendOp operationColor, BlendArg destinationColor,
BlendArg sourceAlpha, BlendOp operationAlpha, BlendArg destinationAlpha) :
_enabled(enabled),
_source(sourceColor | (sourceAlpha << ALPHA_OFFSET)),
_destination(destinationColor | (destinationAlpha << ALPHA_OFFSET)),
_operation(operationColor | (operationAlpha << ALPHA_OFFSET)) {}
BlendArg sourceColor,
BlendOp operationColor,
BlendArg destinationColor,
BlendArg sourceAlpha,
BlendOp operationAlpha,
BlendArg destinationAlpha) :
enabled(enabled),
sourceColor(sourceColor), sourceAlpha(sourceAlpha),
destColor(destinationColor), destAlpha(destinationAlpha),
opColor(operationColor), opAlpha(operationAlpha) {}
BlendFunction(bool enabled, BlendArg source = ONE, BlendOp operation = BLEND_OP_ADD, BlendArg destination = ZERO) :
_enabled(enabled),
_source(source | (source << ALPHA_OFFSET)),
_destination(destination | (destination << ALPHA_OFFSET)),
_operation(operation | (operation << ALPHA_OFFSET)) {}
BlendFunction(bool enabled = false, BlendArg source = ONE, BlendOp operation = BLEND_OP_ADD, BlendArg destination = ZERO) :
BlendFunction(enabled, source, operation, destination, source, operation, destination) {}
bool isEnabled() const { return (_enabled != 0); }
bool isEnabled() const { return (enabled != 0); }
BlendArg getSourceColor() const { return BlendArg(_source & COLOR_MASK); }
BlendArg getDestinationColor() const { return BlendArg(_destination & COLOR_MASK); }
BlendOp getOperationColor() const { return BlendOp(_operation & COLOR_MASK); }
BlendArg getSourceColor() const { return sourceColor; }
BlendArg getDestinationColor() const { return destColor; }
BlendOp getOperationColor() const { return opColor; }
BlendArg getSourceAlpha() const { return BlendArg((_source & ALPHA_MASK) >> ALPHA_OFFSET); }
BlendArg getDestinationAlpha() const { return BlendArg((_destination & ALPHA_MASK) >> ALPHA_OFFSET); }
BlendOp getOperationAlpha() const { return BlendOp((_operation & ALPHA_MASK) >> ALPHA_OFFSET); }
BlendArg getSourceAlpha() const { return sourceAlpha; }
BlendArg getDestinationAlpha() const { return destAlpha; }
BlendOp getOperationAlpha() const { return opAlpha; }
int32 getRaw() const { return *(reinterpret_cast<const int32*>(this)); }
BlendFunction(int32 raw) { *(reinterpret_cast<int32*>(this)) = raw; }
bool operator== (const BlendFunction& right) const { return getRaw() == right.getRaw(); }
bool operator!= (const BlendFunction& right) const { return getRaw() != right.getRaw(); }
bool operator==(const BlendFunction& right) const { return getRaw() == right.getRaw(); }
bool operator!=(const BlendFunction& right) const { return getRaw() != right.getRaw(); }
};
// The Data class is the full explicit description of the State class fields value.
// Useful for having one const static called Default for reference or for the gpu::Backend to keep track of the current value
class Data {
public:
float depthBias = 0.0f;
float depthBiasSlopeScale = 0.0f;
DepthTest depthTest = DepthTest(false, true, LESS);
StencilActivation stencilActivation = StencilActivation(false);
StencilTest stencilTestFront = StencilTest(0, 0xff, ALWAYS, STENCIL_OP_KEEP, STENCIL_OP_KEEP, STENCIL_OP_KEEP);
StencilTest stencilTestBack = StencilTest(0, 0xff, ALWAYS, STENCIL_OP_KEEP, STENCIL_OP_KEEP, STENCIL_OP_KEEP);
uint32 sampleMask = 0xFFFFFFFF;
BlendFunction blendFunction = BlendFunction(false);
uint8 fillMode = FILL_FACE;
uint8 cullMode = CULL_NONE;
uint8 colorWriteMask = WRITE_ALL;
static_assert(sizeof(BlendFunction) == sizeof(uint32_t), "BlendFunction size check");
struct Flags {
Flags() :
frontFaceClockwise(false), depthClampEnable(false), scissorEnable(false), multisampleEnable(false),
antialisedLineEnable(true), alphaToCoverageEnable(false), _spare1(0) {}
bool frontFaceClockwise : 1;
bool depthClampEnable : 1;
bool scissorEnable : 1;
bool multisampleEnable : 1;
bool antialisedLineEnable : 1;
bool alphaToCoverageEnable : 1;
uint8 _spare1 : 2;
Data() :
frontFaceClockwise(false),
depthClampEnable(false),
scissorEnable(false),
multisampleEnable(false),
antialisedLineEnable(true),
alphaToCoverageEnable(false)
{}
bool operator==(const Flags& right) const { return *(uint8*)this == *(uint8*)&right; }
bool operator!=(const Flags& right) const { return *(uint8*)this != *(uint8*)&right; }
};
static_assert(sizeof(Flags) == sizeof(uint8), "Flags size check");
// The Data class is the full explicit description of the State class fields value.
// Useful for having one const static called Default for reference or for the gpu::Backend to keep track of the current value
class Data {
public:
float depthBias = 0.0f;
float depthBiasSlopeScale = 0.0f;
DepthTest depthTest;
StencilActivation stencilActivation;
StencilTest stencilTestFront;
StencilTest stencilTestBack;
BlendFunction blendFunction;
uint32 sampleMask = 0xFFFFFFFF;
FillMode fillMode = FILL_FACE;
CullMode cullMode = CULL_NONE;
ColorMask colorWriteMask = WRITE_ALL;
Flags flags;
};
static_assert(offsetof(Data, depthBias) == 0, "Data offsets");
static_assert(offsetof(Data, depthBiasSlopeScale) == 4, "Data offsets");
static_assert(offsetof(Data, depthTest) == 8, "Data offsets");
static_assert(offsetof(Data, stencilActivation) == 12, "Data offsets");
static_assert(offsetof(Data, stencilTestFront) == 16, "Data offsets");
static_assert(offsetof(Data, stencilTestBack) == 20, "Data offsets");
static_assert(offsetof(Data, blendFunction) == 24, "Data offsets");
static_assert(offsetof(Data, sampleMask) == 28, "Data offsets");
static_assert(offsetof(Data, fillMode) == 32, "Data offsets");
static_assert(offsetof(Data, cullMode) == 33, "Data offsets");
static_assert(offsetof(Data, colorWriteMask) == 34, "Data offsets");
static_assert(offsetof(Data, flags) == 35, "Data offsets");
static_assert(sizeof(Data) == 36, "Data Size Check");
std::string getKey() const;
// The unique default values for all the fields
static const Data DEFAULT;
void setFillMode(FillMode fill) { SET_FIELD(FILL_MODE, DEFAULT.fillMode, fill, _values.fillMode); }
FillMode getFillMode() const { return FillMode(_values.fillMode); }
void setFillMode(FillMode fill) { SET_FIELD(FILL_MODE, fillMode, fill); }
FillMode getFillMode() const { return _values.fillMode; }
void setCullMode(CullMode cull) { SET_FIELD(CULL_MODE, DEFAULT.cullMode, cull, _values.cullMode); }
CullMode getCullMode() const { return CullMode(_values.cullMode); }
void setCullMode(CullMode cull) { SET_FIELD(CULL_MODE, cullMode, cull); }
CullMode getCullMode() const { return _values.cullMode; }
void setFrontFaceClockwise(bool isClockwise) { SET_FIELD(FRONT_FACE_CLOCKWISE, DEFAULT.frontFaceClockwise, isClockwise, _values.frontFaceClockwise); }
bool isFrontFaceClockwise() const { return _values.frontFaceClockwise; }
const Flags& getFlags() const { return _values.flags; }
void setFrontFaceClockwise(bool isClockwise) { SET_FIELD(FRONT_FACE_CLOCKWISE, flags.frontFaceClockwise, isClockwise); }
bool isFrontFaceClockwise() const { return _values.flags.frontFaceClockwise; }
void setDepthClampEnable(bool enable) { SET_FIELD(DEPTH_CLAMP_ENABLE, DEFAULT.depthClampEnable, enable, _values.depthClampEnable); }
bool isDepthClampEnable() const { return _values.depthClampEnable; }
void setDepthClampEnable(bool enable) { SET_FIELD(DEPTH_CLAMP_ENABLE, flags.depthClampEnable, enable); }
bool isDepthClampEnable() const { return _values.flags.depthClampEnable; }
void setScissorEnable(bool enable) { SET_FIELD(SCISSOR_ENABLE, DEFAULT.scissorEnable, enable, _values.scissorEnable); }
bool isScissorEnable() const { return _values.scissorEnable; }
void setScissorEnable(bool enable) { SET_FIELD(SCISSOR_ENABLE, flags.scissorEnable, enable); }
bool isScissorEnable() const { return _values.flags.scissorEnable; }
void setMultisampleEnable(bool enable) { SET_FIELD(MULTISAMPLE_ENABLE, DEFAULT.multisampleEnable, enable, _values.multisampleEnable); }
bool isMultisampleEnable() const { return _values.multisampleEnable; }
void setMultisampleEnable(bool enable) { SET_FIELD(MULTISAMPLE_ENABLE, flags.multisampleEnable, enable); }
bool isMultisampleEnable() const { return _values.flags.multisampleEnable; }
void setAntialiasedLineEnable(bool enable) { SET_FIELD(ANTIALISED_LINE_ENABLE, DEFAULT.antialisedLineEnable, enable, _values.antialisedLineEnable); }
bool isAntialiasedLineEnable() const { return _values.antialisedLineEnable; }
void setAntialiasedLineEnable(bool enable) { SET_FIELD(ANTIALISED_LINE_ENABLE, flags.antialisedLineEnable, enable); }
bool isAntialiasedLineEnable() const { return _values.flags.antialisedLineEnable; }
// Depth Bias
void setDepthBias(float bias) { SET_FIELD(DEPTH_BIAS, DEFAULT.depthBias, bias, _values.depthBias); }
void setDepthBias(float bias) { SET_FIELD(DEPTH_BIAS, depthBias, bias); }
float getDepthBias() const { return _values.depthBias; }
void setDepthBiasSlopeScale(float scale) { SET_FIELD(DEPTH_BIAS_SLOPE_SCALE, DEFAULT.depthBiasSlopeScale, scale, _values.depthBiasSlopeScale); }
void setDepthBiasSlopeScale(float scale) { SET_FIELD(DEPTH_BIAS_SLOPE_SCALE, depthBiasSlopeScale, scale); }
float getDepthBiasSlopeScale() const { return _values.depthBiasSlopeScale; }
// Depth Test
void setDepthTest(DepthTest depthTest) { SET_FIELD(DEPTH_TEST, DEFAULT.depthTest, depthTest, _values.depthTest); }
void setDepthTest(bool enable, bool writeMask, ComparisonFunction func) { setDepthTest(DepthTest(enable, writeMask, func)); }
void setDepthTest(DepthTest newDepthTest) { SET_FIELD(DEPTH_TEST, depthTest, newDepthTest); }
void setDepthTest(bool enable, bool writeMask, ComparisonFunction func) {
setDepthTest(DepthTest(enable, writeMask, func));
}
DepthTest getDepthTest() const { return _values.depthTest; }
bool isDepthTestEnabled() const { return getDepthTest().isEnabled(); }
@ -310,11 +346,14 @@ public:
// Stencil test
void setStencilTest(bool enabled, uint8 frontWriteMask, StencilTest frontTest, uint8 backWriteMask, StencilTest backTest) {
SET_FIELD(STENCIL_ACTIVATION, DEFAULT.stencilActivation, StencilActivation(enabled, frontWriteMask, backWriteMask), _values.stencilActivation);
SET_FIELD(STENCIL_TEST_FRONT, DEFAULT.stencilTestFront, frontTest, _values.stencilTestFront);
SET_FIELD(STENCIL_TEST_BACK, DEFAULT.stencilTestBack, backTest, _values.stencilTestBack); }
SET_FIELD(STENCIL_ACTIVATION, stencilActivation, StencilActivation(enabled, frontWriteMask, backWriteMask));
SET_FIELD(STENCIL_TEST_FRONT, stencilTestFront, frontTest);
SET_FIELD(STENCIL_TEST_BACK, stencilTestBack, backTest);
}
void setStencilTest(bool enabled, uint8 frontWriteMask, StencilTest frontTest) {
setStencilTest(enabled, frontWriteMask, frontTest, frontWriteMask, frontTest); }
setStencilTest(enabled, frontWriteMask, frontTest, frontWriteMask, frontTest);
}
StencilActivation getStencilActivation() const { return _values.stencilActivation; }
StencilTest getStencilTestFront() const { return _values.stencilTestFront; }
@ -325,32 +364,45 @@ public:
uint8 getStencilWriteMaskBack() const { return getStencilActivation().getWriteMaskBack(); }
// Alpha to coverage
void setAlphaToCoverageEnable(bool enable) { SET_FIELD(ALPHA_TO_COVERAGE_ENABLE, DEFAULT.alphaToCoverageEnable, enable, _values.alphaToCoverageEnable); }
bool isAlphaToCoverageEnabled() const { return _values.alphaToCoverageEnable; }
void setAlphaToCoverageEnable(bool enable) { SET_FIELD(ALPHA_TO_COVERAGE_ENABLE, flags.alphaToCoverageEnable, enable); }
bool isAlphaToCoverageEnabled() const { return _values.flags.alphaToCoverageEnable; }
// Sample mask
void setSampleMask(uint32 mask) { SET_FIELD(SAMPLE_MASK, DEFAULT.sampleMask, mask, _values.sampleMask); }
void setSampleMask(uint32 mask) { SET_FIELD(SAMPLE_MASK, sampleMask, mask); }
uint32 getSampleMask() const { return _values.sampleMask; }
// Blend Function
void setBlendFunction(BlendFunction function) { SET_FIELD(BLEND_FUNCTION, DEFAULT.blendFunction, function, _values.blendFunction); }
BlendFunction getBlendFunction() const { return _values.blendFunction; }
void setBlendFunction(BlendFunction function) { SET_FIELD(BLEND_FUNCTION, blendFunction, function); }
const BlendFunction& getBlendFunction() const { return _values.blendFunction; }
void setBlendFunction(bool enabled, BlendArg sourceColor, BlendOp operationColor, BlendArg destinationColor, BlendArg sourceAlpha, BlendOp operationAlpha, BlendArg destinationAlpha) {
setBlendFunction(BlendFunction(enabled, sourceColor, operationColor, destinationColor, sourceAlpha, operationAlpha, destinationAlpha)); }
void setBlendFunction(bool enabled,
BlendArg sourceColor,
BlendOp operationColor,
BlendArg destinationColor,
BlendArg sourceAlpha,
BlendOp operationAlpha,
BlendArg destinationAlpha) {
setBlendFunction(BlendFunction(enabled, sourceColor, operationColor, destinationColor, sourceAlpha, operationAlpha,
destinationAlpha));
}
void setBlendFunction(bool enabled, BlendArg source, BlendOp operation, BlendArg destination) {
setBlendFunction(BlendFunction(enabled, source, operation, destination)); }
setBlendFunction(BlendFunction(enabled, source, operation, destination));
}
bool isBlendEnabled() const { return getBlendFunction().isEnabled(); }
// Color write mask
void setColorWriteMask(uint8 mask) { SET_FIELD(COLOR_WRITE_MASK, DEFAULT.colorWriteMask, mask, _values.colorWriteMask); }
void setColorWriteMask(bool red, bool green, bool blue, bool alpha) { uint32 value = ((WRITE_RED * red) | (WRITE_GREEN * green) | (WRITE_BLUE * blue) | (WRITE_ALPHA * alpha)); SET_FIELD(COLOR_WRITE_MASK, DEFAULT.colorWriteMask, value, _values.colorWriteMask); }
uint8 getColorWriteMask() const { return _values.colorWriteMask; }
void setColorWriteMask(ColorMask mask) { SET_FIELD(COLOR_WRITE_MASK, colorWriteMask, mask); }
void setColorWriteMask(bool red, bool green, bool blue, bool alpha) {
ColorMask value = (ColorMask)((WRITE_RED * red) | (WRITE_GREEN * green) | (WRITE_BLUE * blue) | (WRITE_ALPHA * alpha));
SET_FIELD(COLOR_WRITE_MASK, colorWriteMask, value);
}
ColorMask getColorWriteMask() const { return _values.colorWriteMask; }
// All the possible fields
// NOTE: If you change this, you must update GLBackend::GLState::_resetStateCommands
enum Field {
enum Field
{
FILL_MODE,
CULL_MODE,
FRONT_FACE_CLOCKWISE,
@ -376,7 +428,7 @@ public:
COLOR_WRITE_MASK,
NUM_FIELDS, // not a valid field, just the count
NUM_FIELDS, // not a valid field, just the count
};
// The signature of the state tells which fields of the state are not default
@ -391,20 +443,20 @@ public:
State(const Data& values);
const Data& getValues() const { return _values; }
const GPUObjectPointer gpuObject {};
const GPUObjectPointer gpuObject{};
protected:
State(const State& state);
State& operator=(const State& state);
Data _values;
Signature _signature{0};
Stamp _stamp{0};
Signature _signature{ 0 };
Stamp _stamp{ 0 };
};
typedef std::shared_ptr< State > StatePointer;
typedef std::vector< StatePointer > States;
typedef std::shared_ptr<State> StatePointer;
typedef std::vector<StatePointer> States;
};
}; // namespace gpu
#endif

View file

@ -42,7 +42,7 @@ gpu::PipelinePointer PrepareStencil::getMeshStencilPipeline() {
auto program = gpu::Shader::createProgram(shader::gpu::program::drawNothing);
auto state = std::make_shared<gpu::State>();
drawMask(*state);
state->setColorWriteMask(0);
state->setColorWriteMask(gpu::State::WRITE_NONE);
_meshStencilPipeline = gpu::Pipeline::create(program, state);
}
@ -54,7 +54,7 @@ gpu::PipelinePointer PrepareStencil::getPaintStencilPipeline() {
auto program = gpu::Shader::createProgram(shader::render_utils::program::stencil_drawMask);
auto state = std::make_shared<gpu::State>();
drawMask(*state);
state->setColorWriteMask(0);
state->setColorWriteMask(gpu::State::WRITE_NONE);
_paintStencilPipeline = gpu::Pipeline::create(program, state);
}