diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index 3ca65d45eb..7e5c6c775f 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -256,8 +256,13 @@ protected: void do_setUniformBuffer(Batch& batch, uint32 paramOffset); void do_setUniformTexture(Batch& batch, uint32 paramOffset); + // Standard update pipeline check that the current Program and current State or good to go for a void updatePipeline(); - void resetPipelineState(State::Signature toBeReset); + // Force to reset all the state fields indicated by the 'toBeReset" signature + void resetPipelineState(State::Signature toBeReset); + // Synchronize the state cache of this Backend with the actual real state of the GL Context + void syncPipelineStateCache(); + struct PipelineStageState { PipelinePointer _pipeline; @@ -270,6 +275,7 @@ protected: GLState* _state; bool _invalidState; + bool _needStateSync; PipelineStageState() : _pipeline(), @@ -278,7 +284,8 @@ protected: _stateSignatureCache(0), _stateCache(State::DEFAULT), _state(nullptr), - _invalidState(false) + _invalidState(false), + _needStateSync(true) {} } _pipeline; diff --git a/libraries/gpu/src/gpu/GLBackendPipeline.cpp b/libraries/gpu/src/gpu/GLBackendPipeline.cpp index d0ef01c4a4..409cf5594c 100755 --- a/libraries/gpu/src/gpu/GLBackendPipeline.cpp +++ b/libraries/gpu/src/gpu/GLBackendPipeline.cpp @@ -64,6 +64,11 @@ void GLBackend::do_setPipeline(Batch& batch, uint32 paramOffset) { return; } + if (_pipeline._needStateSync) { + syncPipelineStateCache(); + _pipeline._needStateSync = false; + } + // null pipeline == reset if (!pipeline) { _pipeline._pipeline.reset(); diff --git a/libraries/gpu/src/gpu/GLBackendState.cpp b/libraries/gpu/src/gpu/GLBackendState.cpp index 2397af7cec..809f4177c8 100644 --- a/libraries/gpu/src/gpu/GLBackendState.cpp +++ b/libraries/gpu/src/gpu/GLBackendState.cpp @@ -223,8 +223,6 @@ GLBackend::GLState* GLBackend::syncGPUObject(const State& state) { } - - void GLBackend::resetPipelineState(State::Signature nextSignature) { auto currentNotSignature = ~_pipeline._stateSignatureCache; auto nextNotSignature = ~nextSignature; @@ -237,6 +235,231 @@ void GLBackend::resetPipelineState(State::Signature nextSignature) { } } } +} + +State::ComparisonFunction comparisonFuncFromGL(GLenum func) { + if (func == GL_NEVER) { + return State::NEVER; + } else if (func == GL_LESS) { + return State::LESS; + } else if (func == GL_EQUAL) { + return State::EQUAL; + } else if (func == GL_LEQUAL) { + return State::LESS_EQUAL; + } else if (func == GL_GREATER) { + return State::GREATER; + } else if (func == GL_NOTEQUAL) { + return State::NOT_EQUAL; + } else if (func == GL_GEQUAL) { + return State::GREATER_EQUAL; + } else if (func == GL_ALWAYS) { + return State::ALWAYS; + } + + return State::ALWAYS; +} + +State::StencilOp stencilOpFromGL(GLenum stencilOp) { + if (stencilOp == GL_KEEP) { + return State::STENCIL_OP_KEEP; + } else if (stencilOp == GL_ZERO) { + return State::STENCIL_OP_ZERO; + } else if (stencilOp == GL_REPLACE) { + return State::STENCIL_OP_REPLACE; + } else if (stencilOp == GL_INCR_WRAP) { + return State::STENCIL_OP_INCR_SAT; + } else if (stencilOp == GL_DECR_WRAP) { + return State::STENCIL_OP_DECR_SAT; + } else if (stencilOp == GL_INVERT) { + return State::STENCIL_OP_INVERT; + } else if (stencilOp == GL_INCR) { + return State::STENCIL_OP_INCR; + } else if (stencilOp == GL_DECR) { + return State::STENCIL_OP_DECR; + } + + return State::STENCIL_OP_KEEP; +} + +State::BlendOp blendOpFromGL(GLenum blendOp) { + if (blendOp == GL_FUNC_ADD) { + return State::BLEND_OP_ADD; + } else if (blendOp == GL_FUNC_SUBTRACT) { + return State::BLEND_OP_SUBTRACT; + } else if (blendOp == GL_FUNC_REVERSE_SUBTRACT) { + return State::BLEND_OP_REV_SUBTRACT; + } else if (blendOp == GL_MIN) { + return State::BLEND_OP_MIN; + } else if (blendOp == GL_MAX) { + return State::BLEND_OP_MAX; + } + + return State::BLEND_OP_ADD; +} + +State::BlendArg blendArgFromGL(GLenum blendArg) { + if (blendArg == GL_ZERO) { + return State::ZERO; + } else if (blendArg == GL_ONE) { + return State::ONE; + } else if (blendArg == GL_SRC_COLOR) { + return State::SRC_COLOR; + } else if (blendArg == GL_ONE_MINUS_SRC_COLOR) { + return State::INV_SRC_COLOR; + } else if (blendArg == GL_DST_COLOR) { + return State::DEST_COLOR; + } else if (blendArg == GL_ONE_MINUS_DST_COLOR) { + return State::INV_DEST_COLOR; + } else if (blendArg == GL_SRC_ALPHA) { + return State::SRC_ALPHA; + } else if (blendArg == GL_ONE_MINUS_SRC_ALPHA) { + return State::INV_SRC_ALPHA; + } else if (blendArg == GL_DST_ALPHA) { + return State::DEST_ALPHA; + } else if (blendArg == GL_ONE_MINUS_DST_ALPHA) { + return State::INV_DEST_ALPHA; + } else if (blendArg == GL_CONSTANT_COLOR) { + return State::FACTOR_COLOR; + } else if (blendArg == GL_ONE_MINUS_CONSTANT_COLOR) { + return State::INV_FACTOR_COLOR; + } else if (blendArg == GL_CONSTANT_ALPHA) { + return State::FACTOR_ALPHA; + } else if (blendArg == GL_ONE_MINUS_CONSTANT_ALPHA) { + return State::INV_FACTOR_ALPHA; + } + + return State::ONE; +} + + +void GLBackend::syncPipelineStateCache() { + State::Cache state; + { + GLint modes[2]; + glGetIntegerv(GL_POLYGON_MODE, modes); + if (modes[0] == GL_FILL) { + state.fillMode = State::FILL_FACE; + } else { + if (modes[0] == GL_LINE) { + state.fillMode = State::FILL_LINE; + } else { + state.fillMode = State::FILL_POINT; + } + } + } + { + if (glIsEnabled(GL_CULL_FACE)) { + GLint mode; + glGetIntegerv(GL_CULL_FACE_MODE, &mode); + state.cullMode = (mode == GL_FRONT ? State::CULL_FRONT : State::CULL_BACK); + } else { + state.cullMode = State::CULL_NONE; + } + } + { + GLint winding; + glGetIntegerv(GL_FRONT_FACE, &winding); + state.frontFaceClockwise = (winding == GL_CW); + state.depthClipEnable = glIsEnabled(GL_DEPTH_CLAMP); + state.scissorEnable = glIsEnabled(GL_SCISSOR_TEST); + state.multisampleEnable = glIsEnabled(GL_MULTISAMPLE); + state.antialisedLineEnable = glIsEnabled(GL_LINE_SMOOTH); + } + { + if (glIsEnabled(GL_POLYGON_OFFSET_FILL)) { + glGetFloatv(GL_POLYGON_OFFSET_FACTOR, &state.depthBiasSlopeScale); + glGetFloatv(GL_POLYGON_OFFSET_UNITS, &state.depthBias); + } + } + { + GLboolean isEnabled = glIsEnabled(GL_DEPTH_TEST); + GLboolean writeMask; + glGetBooleanv(GL_DEPTH_WRITEMASK, &writeMask); + GLint func; + glGetIntegerv(GL_DEPTH_FUNC, &func); + + state.depthTest = State::DepthTest(isEnabled, writeMask, comparisonFuncFromGL(func)); + } + { + GLboolean isEnabled = glIsEnabled(GL_STENCIL_TEST); + + GLint frontWriteMask; + GLint frontReadMask; + GLint frontRef; + GLint frontFail; + GLint frontDepthFail; + GLint frontPass; + GLint frontFunc; + glGetIntegerv(GL_STENCIL_WRITEMASK, &frontWriteMask); + glGetIntegerv(GL_STENCIL_VALUE_MASK, &frontReadMask); + glGetIntegerv(GL_STENCIL_REF, &frontRef); + glGetIntegerv(GL_STENCIL_FAIL, &frontFail); + glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &frontDepthFail); + glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &frontPass); + glGetIntegerv(GL_STENCIL_FUNC, &frontFunc); + + GLint backWriteMask; + GLint backReadMask; + GLint backRef; + GLint backFail; + GLint backDepthFail; + GLint backPass; + GLint backFunc; + glGetIntegerv(GL_STENCIL_BACK_WRITEMASK, &backWriteMask); + glGetIntegerv(GL_STENCIL_BACK_VALUE_MASK, &backReadMask); + glGetIntegerv(GL_STENCIL_BACK_REF, &backRef); + glGetIntegerv(GL_STENCIL_BACK_FAIL, &backFail); + glGetIntegerv(GL_STENCIL_BACK_PASS_DEPTH_FAIL, &backDepthFail); + glGetIntegerv(GL_STENCIL_BACK_PASS_DEPTH_PASS, &backPass); + glGetIntegerv(GL_STENCIL_BACK_FUNC, &backFunc); + + state.stencilActivation = State::StencilActivation(isEnabled, frontWriteMask, backWriteMask); + state.stencilTestFront = State::StencilTest(frontRef, frontReadMask, comparisonFuncFromGL(frontFunc), stencilOpFromGL(frontFail), stencilOpFromGL(frontDepthFail), stencilOpFromGL(frontPass)); + state.stencilTestBack = State::StencilTest(backRef, backReadMask, comparisonFuncFromGL(backFunc), stencilOpFromGL(backFail), stencilOpFromGL(backDepthFail), stencilOpFromGL(backPass)); + } + { + GLint mask; + glGetIntegerv(GL_SAMPLE_COVERAGE, &mask); + state.sampleMask = mask; + } + { + state.alphaToCoverageEnable = glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE); + } + { + GLboolean isEnabled = glIsEnabled(GL_BLEND); + GLint srcRGB; + GLint srcA; + GLint dstRGB; + GLint dstA; + glGetIntegerv(GL_BLEND_SRC_RGB, &srcRGB); + glGetIntegerv(GL_BLEND_SRC_ALPHA, &srcA); + glGetIntegerv(GL_BLEND_DST_RGB, &dstRGB); + glGetIntegerv(GL_BLEND_DST_ALPHA, &dstA); + + GLint opRGB; + GLint opA; + glGetIntegerv(GL_BLEND_EQUATION_RGB, &opRGB); + glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &opA); + + state.blendFunction = State::BlendFunction(false, + blendArgFromGL(srcRGB), blendOpFromGL(opRGB), blendArgFromGL(dstRGB), + blendArgFromGL(srcA), blendOpFromGL(opA), blendArgFromGL(dstA)); + } + { + GLboolean mask[4]; + glGetBooleanv(GL_COLOR_WRITEMASK, mask); + state.colorWriteMask = (mask[0] ? State::WRITE_RED : 0) + | (mask[1] ? State::WRITE_GREEN : 0) + | (mask[2] ? State::WRITE_BLUE : 0) + | (mask[3] ? State::WRITE_ALPHA : 0); + } + + CHECK_GL_ERROR(); + + State::Signature signature = State::evalSignature(state); + + _pipeline._stateCache = state; + _pipeline._stateSignatureCache = signature; } static GLenum GL_COMPARISON_FUNCTIONS[] = { diff --git a/libraries/gpu/src/gpu/State.cpp b/libraries/gpu/src/gpu/State.cpp index 4276e19dbb..d2488aac17 100755 --- a/libraries/gpu/src/gpu/State.cpp +++ b/libraries/gpu/src/gpu/State.cpp @@ -21,3 +21,61 @@ State::~State() { } const State::Cache State::DEFAULT = State::Cache(); + +State::Signature State::evalSignature(const Cache& state) { + Signature signature(0); + + if (state.fillMode != State::DEFAULT.fillMode) { + signature.set(State::FILL_MODE); + } + if (state.cullMode != State::DEFAULT.cullMode) { + signature.set(State::CULL_MODE); + } + if (state.frontFaceClockwise != State::DEFAULT.frontFaceClockwise) { + signature.set(State::FRONT_FACE_CLOCKWISE); + } + if (state.depthClipEnable != State::DEFAULT.depthClipEnable) { + signature.set(State::DEPTH_CLIP_ENABLE); + } + if (state.scissorEnable != State::DEFAULT.scissorEnable) { + signature.set(State::SCISSOR_ENABLE); + } + if (state.multisampleEnable != State::DEFAULT.multisampleEnable) { + signature.set(State::MULTISAMPLE_ENABLE); + } + if (state.antialisedLineEnable != State::DEFAULT.antialisedLineEnable) { + signature.set(State::ANTIALISED_LINE_ENABLE); + } + if (state.depthBias != State::DEFAULT.depthBias) { + signature.set(State::DEPTH_BIAS); + } + if (state.depthBiasSlopeScale != State::DEFAULT.depthBiasSlopeScale) { + signature.set(State::DEPTH_BIAS_SLOPE_SCALE); + } + if (state.depthTest != State::DEFAULT.depthTest) { + signature.set(State::DEPTH_TEST); + } + if (state.stencilActivation != State::DEFAULT.stencilActivation) { + signature.set(State::STENCIL_ACTIVATION); + } + if (state.stencilTestFront != State::DEFAULT.stencilTestFront) { + signature.set(State::STENCIL_TEST_FRONT); + } + if (state.stencilTestBack != State::DEFAULT.stencilTestBack) { + signature.set(State::STENCIL_TEST_BACK); + } + if (state.sampleMask != State::DEFAULT.sampleMask) { + signature.set(State::SAMPLE_MASK); + } + if (state.alphaToCoverageEnable != State::DEFAULT.alphaToCoverageEnable) { + signature.set(State::ALPHA_TO_COVERAGE_ENABLE); + } + if (state.blendFunction != State::DEFAULT.blendFunction) { + signature.set(State::BLEND_FUNCTION); + } + if (state.colorWriteMask != State::DEFAULT.colorWriteMask) { + signature.set(State::COLOR_WRITE_MASK); + } + + return signature; +} diff --git a/libraries/gpu/src/gpu/State.h b/libraries/gpu/src/gpu/State.h index c4ac2d0a5d..32b91c544c 100755 --- a/libraries/gpu/src/gpu/State.h +++ b/libraries/gpu/src/gpu/State.h @@ -125,8 +125,8 @@ public: int32 getRaw() const { return *(reinterpret_cast(this)); } DepthTest(int32 raw) { *(reinterpret_cast(this)) = raw; } - bool operator== (const DepthTest& right) { return getRaw() == right.getRaw(); } - bool operator!= (const DepthTest& right) { 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 { @@ -157,8 +157,8 @@ public: int32 getRaw() const { return *(reinterpret_cast(this)); } StencilTest(int32 raw) { *(reinterpret_cast(this)) = raw; } - bool operator== (const StencilTest& right) { return getRaw() == right.getRaw(); } - bool operator!= (const StencilTest& right) { return getRaw() != right.getRaw(); } + bool operator== (const StencilTest& right) const { return getRaw() == right.getRaw(); } + bool operator!= (const StencilTest& right) const { return getRaw() != right.getRaw(); } }; class StencilActivation { @@ -176,8 +176,8 @@ public: int32 getRaw() const { return *(reinterpret_cast(this)); } StencilActivation(int32 raw) { *(reinterpret_cast(this)) = raw; } - bool operator== (const StencilActivation& right) { return getRaw() == right.getRaw(); } - bool operator!= (const StencilActivation& right) { 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 { @@ -217,8 +217,8 @@ public: int32 getRaw() const { return *(reinterpret_cast(this)); } BlendFunction(int32 raw) { *(reinterpret_cast(this)) = raw; } - bool operator== (const BlendFunction& right) { return getRaw() == right.getRaw(); } - bool operator!= (const BlendFunction& right) { 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 Cache class is the full explicit description of the State class fields value. @@ -400,6 +400,8 @@ public: Signature getSignature() const { return _signature; } + static Signature evalSignature(const Cache& state); + protected: State(const State& state); State& operator=(const State& state);