mirror of
https://github.com/overte-org/overte.git
synced 2025-04-08 05:52:38 +02:00
GPU state cleanup
This commit is contained in:
parent
6cb8cf0202
commit
6fb869126e
10 changed files with 437 additions and 336 deletions
|
@ -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));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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),
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -376,7 +376,7 @@ public:
|
|||
};
|
||||
|
||||
|
||||
enum ComparisonFunction {
|
||||
enum ComparisonFunction : uint16 {
|
||||
NEVER = 0,
|
||||
LESS,
|
||||
EQUAL,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue