// // GLBackendState.cpp // libraries/gpu/src/gpu // // Created by Sam Gateau on 3/22/2015. // Copyright 2014 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include "GLBackend.h" #include "GLState.h" #include using namespace gpu; using namespace gpu::gl; void GLBackend::resetPipelineState(State::Signature nextSignature) { auto currentNotSignature = ~_pipeline._stateSignatureCache; auto nextNotSignature = ~nextSignature; auto fieldsToBeReset = currentNotSignature ^ (currentNotSignature | nextNotSignature); if (fieldsToBeReset.any()) { for (auto i = 0; i < State::NUM_FIELDS; i++) { if (fieldsToBeReset[i]) { GLState::_resetStateCommands[i]->run(this); _pipeline._stateSignatureCache.reset(i); } } } // Default line width accross the board glLineWidth(1.0f); #if !defined(USE_GLES) // force a few states regardless glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); // Point size is always on //glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); glEnable(GL_PROGRAM_POINT_SIZE_EXT); glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); glEnable(GL_LINE_SMOOTH); #endif } void GLBackend::syncPipelineStateCache() { State::Data state; // force a few states regardless // Default line width accross the board glLineWidth(1.0f); #if !defined(USE_GLES) glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); // Point size is always on //glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); glEnable(GL_PROGRAM_POINT_SIZE_EXT); glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); glEnable(GL_LINE_SMOOTH); #endif getCurrentGLState(state); State::Signature signature = State::evalSignature(state); _pipeline._stateCache = state; _pipeline._stateSignatureCache = signature; } void GLBackend::do_setStateFillMode(int32 mode) { if (_pipeline._stateCache.fillMode != mode) { #if !defined(USE_GLES) static GLenum GL_FILL_MODES[] = { GL_POINT, GL_LINE, GL_FILL }; glPolygonMode(GL_FRONT_AND_BACK, GL_FILL_MODES[mode]); (void)CHECK_GL_ERROR(); _pipeline._stateCache.fillMode = State::FillMode(mode); #endif } } void GLBackend::do_setStateCullMode(int32 mode) { if (_pipeline._stateCache.cullMode != mode) { static GLenum GL_CULL_MODES[] = { GL_FRONT_AND_BACK, GL_FRONT, GL_BACK }; if (mode == State::CULL_NONE) { glDisable(GL_CULL_FACE); glCullFace(GL_FRONT_AND_BACK); } else { glEnable(GL_CULL_FACE); glCullFace(GL_CULL_MODES[mode]); } (void)CHECK_GL_ERROR(); _pipeline._stateCache.cullMode = State::CullMode(mode); } } void GLBackend::do_setStateFrontFaceClockwise(bool 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.flags.frontFaceClockwise = isClockwise; } } void GLBackend::do_setStateDepthClampEnable(bool enable) { if (_pipeline._stateCache.flags.depthClampEnable != enable) { #if !defined(USE_GLES) if (enable) { glEnable(GL_DEPTH_CLAMP); } else { glDisable(GL_DEPTH_CLAMP); } (void)CHECK_GL_ERROR(); _pipeline._stateCache.flags.depthClampEnable = enable; #endif } } void GLBackend::do_setStateScissorEnable(bool enable) { if (_pipeline._stateCache.flags.scissorEnable != enable) { if (enable) { glEnable(GL_SCISSOR_TEST); } else { glDisable(GL_SCISSOR_TEST); } (void)CHECK_GL_ERROR(); _pipeline._stateCache.flags.scissorEnable = enable; } } void GLBackend::do_setStateMultisampleEnable(bool enable) { if (_pipeline._stateCache.flags.multisampleEnable != enable) { #if !defined(USE_GLES) if (enable) { glEnable(GL_MULTISAMPLE); } else { glDisable(GL_MULTISAMPLE); } (void)CHECK_GL_ERROR(); _pipeline._stateCache.flags.multisampleEnable = enable; #endif } } void GLBackend::do_setStateAntialiasedLineEnable(bool enable) { if (_pipeline._stateCache.flags.antialisedLineEnable != enable) { #if !defined(USE_GLES) if (enable) { glEnable(GL_LINE_SMOOTH); } else { glDisable(GL_LINE_SMOOTH); } (void)CHECK_GL_ERROR(); _pipeline._stateCache.flags.antialisedLineEnable = enable; #endif } } void GLBackend::do_setStateDepthBias(Vec2 bias) { if ((bias.x != _pipeline._stateCache.depthBias) || (bias.y != _pipeline._stateCache.depthBiasSlopeScale)) { if ((bias.x != 0.0f) || (bias.y != 0.0f)) { glEnable(GL_POLYGON_OFFSET_FILL); #if !defined(USE_GLES) glEnable(GL_POLYGON_OFFSET_LINE); glEnable(GL_POLYGON_OFFSET_POINT); #endif glPolygonOffset(bias.x, bias.y); } else { glDisable(GL_POLYGON_OFFSET_FILL); #if !defined(USE_GLES) glDisable(GL_POLYGON_OFFSET_LINE); glDisable(GL_POLYGON_OFFSET_POINT); #endif } (void)CHECK_GL_ERROR(); _pipeline._stateCache.depthBias = bias.x; _pipeline._stateCache.depthBiasSlopeScale = bias.y; } } void GLBackend::do_setStateDepthTest(State::DepthTest test) { const auto& current = _pipeline._stateCache.depthTest; if (current != test) { if (test.isEnabled()) { glEnable(GL_DEPTH_TEST); } else { glDisable(GL_DEPTH_TEST); } if (test.getWriteMask() != current.getWriteMask()) { glDepthMask(test.getWriteMask()); } if (test.getFunction() != current.getFunction()) { glDepthFunc(COMPARISON_TO_GL[test.getFunction()]); } if (CHECK_GL_ERROR()) { qCDebug(gpulogging) << "DepthTest = " << test; } _pipeline._stateCache.depthTest = test; } } void GLBackend::do_setStateStencil(State::StencilActivation activation, State::StencilTest testFront, State::StencilTest testBack) { const auto& currentActivation = _pipeline._stateCache.stencilActivation; const auto& currentTestFront = _pipeline._stateCache.stencilTestFront; const auto& currentTestBack = _pipeline._stateCache.stencilTestBack; if ((currentActivation != activation) || (currentTestFront != testFront) || (currentTestBack != testBack)) { if (activation.isEnabled()) { glEnable(GL_STENCIL_TEST); } else { glDisable(GL_STENCIL_TEST); } if (activation.getWriteMaskFront() != activation.getWriteMaskBack()) { glStencilMaskSeparate(GL_FRONT, activation.getWriteMaskFront()); glStencilMaskSeparate(GL_BACK, activation.getWriteMaskBack()); } else { glStencilMask(activation.getWriteMaskFront()); } static GLenum STENCIL_OPS[State::NUM_STENCIL_OPS] = { GL_KEEP, GL_ZERO, GL_REPLACE, GL_INCR_WRAP, GL_DECR_WRAP, GL_INVERT, GL_INCR, GL_DECR }; if (testFront != testBack) { glStencilOpSeparate(GL_FRONT, STENCIL_OPS[testFront.getFailOp()], STENCIL_OPS[testFront.getDepthFailOp()], STENCIL_OPS[testFront.getPassOp()]); glStencilFuncSeparate(GL_FRONT, COMPARISON_TO_GL[testFront.getFunction()], testFront.getReference(), testFront.getReadMask()); glStencilOpSeparate(GL_BACK, STENCIL_OPS[testBack.getFailOp()], STENCIL_OPS[testBack.getDepthFailOp()], STENCIL_OPS[testBack.getPassOp()]); glStencilFuncSeparate(GL_BACK, COMPARISON_TO_GL[testBack.getFunction()], testBack.getReference(), testBack.getReadMask()); } else { glStencilOp(STENCIL_OPS[testFront.getFailOp()], STENCIL_OPS[testFront.getDepthFailOp()], STENCIL_OPS[testFront.getPassOp()]); glStencilFunc(COMPARISON_TO_GL[testFront.getFunction()], testFront.getReference(), testFront.getReadMask()); } (void)CHECK_GL_ERROR(); _pipeline._stateCache.stencilActivation = activation; _pipeline._stateCache.stencilTestFront = testFront; _pipeline._stateCache.stencilTestBack = testBack; } } void GLBackend::do_setStateAlphaToCoverageEnable(bool enable) { if (_pipeline._stateCache.flags.alphaToCoverageEnable != enable) { if (enable) { glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE); } else { glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); } (void)CHECK_GL_ERROR(); _pipeline._stateCache.flags.alphaToCoverageEnable = enable; } } void GLBackend::do_setStateSampleMask(uint32 mask) { if (_pipeline._stateCache.sampleMask != mask) { if (mask == 0xFFFFFFFF) { glDisable(GL_SAMPLE_MASK); } else { glEnable(GL_SAMPLE_MASK); glSampleMaski(0, mask); } (void)CHECK_GL_ERROR(); _pipeline._stateCache.sampleMask = mask; } } void GLBackend::do_setStateBlend(State::BlendFunction function) { if (_pipeline._stateCache.blendFunction != function) { if (function.isEnabled()) { glEnable(GL_BLEND); glBlendEquationSeparate(BLEND_OPS_TO_GL[function.getOperationColor()], BLEND_OPS_TO_GL[function.getOperationAlpha()]); (void)CHECK_GL_ERROR(); glBlendFuncSeparate(BLEND_ARGS_TO_GL[function.getSourceColor()], BLEND_ARGS_TO_GL[function.getDestinationColor()], BLEND_ARGS_TO_GL[function.getSourceAlpha()], BLEND_ARGS_TO_GL[function.getDestinationAlpha()]); } else { glDisable(GL_BLEND); } (void)CHECK_GL_ERROR(); _pipeline._stateCache.blendFunction = function; } } void GLBackend::do_setStateColorWriteMask(uint32 mask) { if (_pipeline._stateCache.colorWriteMask != mask) { glColorMask(mask & State::ColorMask::WRITE_RED, mask & State::ColorMask::WRITE_GREEN, mask & State::ColorMask::WRITE_BLUE, mask & State::ColorMask::WRITE_ALPHA); (void)CHECK_GL_ERROR(); _pipeline._stateCache.colorWriteMask = (State::ColorMask)mask; } } void GLBackend::do_setStateBlendFactor(const Batch& batch, size_t paramOffset) { Vec4 factor(batch._params[paramOffset + 0]._float, batch._params[paramOffset + 1]._float, batch._params[paramOffset + 2]._float, batch._params[paramOffset + 3]._float); glBlendColor(factor.x, factor.y, factor.z, factor.w); (void)CHECK_GL_ERROR(); } void GLBackend::do_setStateScissorRect(const Batch& batch, size_t paramOffset) { Vec4i rect; memcpy(&rect, batch.readData(batch._params[paramOffset]._uint), sizeof(Vec4i)); if (_stereo.isStereo()) { rect.z /= 2; if (_stereo._pass) { rect.x += rect.z; } } glScissor(rect.x, rect.y, rect.z, rect.w); (void)CHECK_GL_ERROR(); }