// // Copyright (c) 2015 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // StateManagerGL.h: Defines a class for caching applied OpenGL state #include "libANGLE/renderer/gl/StateManagerGL.h" #include #include #include "common/BitSetIterator.h" #include "common/mathutil.h" #include "common/matrix_utils.h" #include "libANGLE/ContextState.h" #include "libANGLE/Framebuffer.h" #include "libANGLE/TransformFeedback.h" #include "libANGLE/VertexArray.h" #include "libANGLE/Query.h" #include "libANGLE/renderer/gl/BufferGL.h" #include "libANGLE/renderer/gl/FramebufferGL.h" #include "libANGLE/renderer/gl/FunctionsGL.h" #include "libANGLE/renderer/gl/ProgramGL.h" #include "libANGLE/renderer/gl/SamplerGL.h" #include "libANGLE/renderer/gl/TextureGL.h" #include "libANGLE/renderer/gl/TransformFeedbackGL.h" #include "libANGLE/renderer/gl/VertexArrayGL.h" #include "libANGLE/renderer/gl/QueryGL.h" namespace rx { static const GLenum QueryTypes[] = {GL_ANY_SAMPLES_PASSED, GL_ANY_SAMPLES_PASSED_CONSERVATIVE, GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, GL_TIME_ELAPSED, GL_COMMANDS_COMPLETED_CHROMIUM}; StateManagerGL::IndexedBufferBinding::IndexedBufferBinding() : offset(0), size(0), buffer(0) { } StateManagerGL::StateManagerGL(const FunctionsGL *functions, const gl::Caps &rendererCaps) : mFunctions(functions), mProgram(0), mVAO(0), mVertexAttribCurrentValues(rendererCaps.maxVertexAttributes), mBuffers(), mIndexedBuffers(), mTextureUnitIndex(0), mTextures(), mSamplers(rendererCaps.maxCombinedTextureImageUnits, 0), mTransformFeedback(0), mQueries(), mPrevDrawTransformFeedback(nullptr), mCurrentQueries(), mPrevDrawContext(0), mUnpackAlignment(4), mUnpackRowLength(0), mUnpackSkipRows(0), mUnpackSkipPixels(0), mUnpackImageHeight(0), mUnpackSkipImages(0), mPackAlignment(4), mPackRowLength(0), mPackSkipRows(0), mPackSkipPixels(0), mFramebuffers(angle::FramebufferBindingSingletonMax, 0), mRenderbuffer(0), mScissorTestEnabled(false), mScissor(0, 0, 0, 0), mViewport(0, 0, 0, 0), mNear(0.0f), mFar(1.0f), mBlendEnabled(false), mBlendColor(0, 0, 0, 0), mSourceBlendRGB(GL_ONE), mDestBlendRGB(GL_ZERO), mSourceBlendAlpha(GL_ONE), mDestBlendAlpha(GL_ZERO), mBlendEquationRGB(GL_FUNC_ADD), mBlendEquationAlpha(GL_FUNC_ADD), mColorMaskRed(true), mColorMaskGreen(true), mColorMaskBlue(true), mColorMaskAlpha(true), mSampleAlphaToCoverageEnabled(false), mSampleCoverageEnabled(false), mSampleCoverageValue(1.0f), mSampleCoverageInvert(false), mDepthTestEnabled(false), mDepthFunc(GL_LESS), mDepthMask(true), mStencilTestEnabled(false), mStencilFrontFunc(GL_ALWAYS), mStencilFrontRef(0), mStencilFrontValueMask(static_cast(-1)), mStencilFrontStencilFailOp(GL_KEEP), mStencilFrontStencilPassDepthFailOp(GL_KEEP), mStencilFrontStencilPassDepthPassOp(GL_KEEP), mStencilFrontWritemask(static_cast(-1)), mStencilBackFunc(GL_ALWAYS), mStencilBackRef(0), mStencilBackValueMask(static_cast(-1)), mStencilBackStencilFailOp(GL_KEEP), mStencilBackStencilPassDepthFailOp(GL_KEEP), mStencilBackStencilPassDepthPassOp(GL_KEEP), mStencilBackWritemask(static_cast(-1)), mCullFaceEnabled(false), mCullFace(GL_BACK), mFrontFace(GL_CCW), mPolygonOffsetFillEnabled(false), mPolygonOffsetFactor(0.0f), mPolygonOffsetUnits(0.0f), mRasterizerDiscardEnabled(false), mLineWidth(1.0f), mPrimitiveRestartEnabled(false), mClearColor(0.0f, 0.0f, 0.0f, 0.0f), mClearDepth(1.0f), mClearStencil(0), mFramebufferSRGBEnabled(false), mTextureCubemapSeamlessEnabled(false), mMultisamplingEnabled(true), mSampleAlphaToOneEnabled(false), mCoverageModulation(GL_NONE), mPathStencilFunc(GL_ALWAYS), mPathStencilRef(0), mPathStencilMask(std::numeric_limits::max()), mLocalDirtyBits() { ASSERT(mFunctions); mTextures[GL_TEXTURE_2D].resize(rendererCaps.maxCombinedTextureImageUnits); mTextures[GL_TEXTURE_CUBE_MAP].resize(rendererCaps.maxCombinedTextureImageUnits); mTextures[GL_TEXTURE_2D_ARRAY].resize(rendererCaps.maxCombinedTextureImageUnits); mTextures[GL_TEXTURE_3D].resize(rendererCaps.maxCombinedTextureImageUnits); mIndexedBuffers[GL_UNIFORM_BUFFER].resize(rendererCaps.maxCombinedUniformBlocks); for (GLenum queryType : QueryTypes) { mQueries[queryType] = 0; } // Initialize point sprite state for desktop GL if (mFunctions->standard == STANDARD_GL_DESKTOP) { mFunctions->enable(GL_PROGRAM_POINT_SIZE); // GL_POINT_SPRITE was deprecated in the core profile. Point rasterization is always // performed // as though POINT_SPRITE were enabled. if ((mFunctions->profile & GL_CONTEXT_CORE_PROFILE_BIT) == 0) { mFunctions->enable(GL_POINT_SPRITE); } } angle::Matrix::setToIdentity(mPathMatrixProj); angle::Matrix::setToIdentity(mPathMatrixMV); } void StateManagerGL::deleteProgram(GLuint program) { if (program != 0) { if (mProgram == program) { useProgram(0); } mFunctions->deleteProgram(program); } } void StateManagerGL::deleteVertexArray(GLuint vao) { if (vao != 0) { if (mVAO == vao) { bindVertexArray(0, 0); } mFunctions->deleteVertexArrays(1, &vao); } } void StateManagerGL::deleteTexture(GLuint texture) { if (texture != 0) { for (const auto &textureTypeIter : mTextures) { const std::vector &textureVector = textureTypeIter.second; for (size_t textureUnitIndex = 0; textureUnitIndex < textureVector.size(); textureUnitIndex++) { if (textureVector[textureUnitIndex] == texture) { activeTexture(textureUnitIndex); bindTexture(textureTypeIter.first, 0); } } } mFunctions->deleteTextures(1, &texture); } } void StateManagerGL::deleteSampler(GLuint sampler) { if (sampler != 0) { for (size_t unit = 0; unit < mSamplers.size(); unit++) { if (mSamplers[unit] == sampler) { bindSampler(unit, 0); } } mFunctions->deleteSamplers(1, &sampler); } } void StateManagerGL::deleteBuffer(GLuint buffer) { if (buffer != 0) { for (const auto &bufferTypeIter : mBuffers) { if (bufferTypeIter.second == buffer) { bindBuffer(bufferTypeIter.first, 0); } } for (const auto &bufferTypeIter : mIndexedBuffers) { for (size_t bindIndex = 0; bindIndex < bufferTypeIter.second.size(); bindIndex++) { if (bufferTypeIter.second[bindIndex].buffer == buffer) { bindBufferBase(bufferTypeIter.first, bindIndex, 0); } } } mFunctions->deleteBuffers(1, &buffer); } } void StateManagerGL::deleteFramebuffer(GLuint fbo) { if (fbo != 0) { for (size_t binding = 0; binding < mFramebuffers.size(); ++binding) { if (mFramebuffers[binding] == fbo) { GLenum enumValue = angle::FramebufferBindingToEnum( static_cast(binding)); bindFramebuffer(enumValue, 0); } mFunctions->deleteFramebuffers(1, &fbo); } } } void StateManagerGL::deleteRenderbuffer(GLuint rbo) { if (rbo != 0) { if (mRenderbuffer == rbo) { bindRenderbuffer(GL_RENDERBUFFER, 0); } mFunctions->deleteRenderbuffers(1, &rbo); } } void StateManagerGL::deleteTransformFeedback(GLuint transformFeedback) { if (transformFeedback != 0) { if (mTransformFeedback == transformFeedback) { bindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0); } if (mPrevDrawTransformFeedback != nullptr && mPrevDrawTransformFeedback->getTransformFeedbackID() == transformFeedback) { mPrevDrawTransformFeedback = nullptr; } mFunctions->deleteTransformFeedbacks(1, &transformFeedback); } } void StateManagerGL::deleteQuery(GLuint query) { if (query != 0) { for (auto &activeQuery : mQueries) { GLuint activeQueryID = activeQuery.second; if (activeQueryID == query) { GLenum type = activeQuery.first; endQuery(type, query); } } } } void StateManagerGL::useProgram(GLuint program) { if (mProgram != program) { forceUseProgram(program); } } void StateManagerGL::forceUseProgram(GLuint program) { mProgram = program; mFunctions->useProgram(mProgram); } void StateManagerGL::bindVertexArray(GLuint vao, GLuint elementArrayBuffer) { if (mVAO != vao) { mVAO = vao; mBuffers[GL_ELEMENT_ARRAY_BUFFER] = elementArrayBuffer; mFunctions->bindVertexArray(vao); } } void StateManagerGL::bindBuffer(GLenum type, GLuint buffer) { if (mBuffers[type] != buffer) { mBuffers[type] = buffer; mFunctions->bindBuffer(type, buffer); } } void StateManagerGL::bindBufferBase(GLenum type, size_t index, GLuint buffer) { auto &binding = mIndexedBuffers[type][index]; if (binding.buffer != buffer || binding.offset != static_cast(-1) || binding.size != static_cast(-1)) { binding.buffer = buffer; binding.offset = static_cast(-1); binding.size = static_cast(-1); mFunctions->bindBufferBase(type, static_cast(index), buffer); } } void StateManagerGL::bindBufferRange(GLenum type, size_t index, GLuint buffer, size_t offset, size_t size) { auto &binding = mIndexedBuffers[type][index]; if (binding.buffer != buffer || binding.offset != offset || binding.size != size) { binding.buffer = buffer; binding.offset = offset; binding.size = size; mFunctions->bindBufferRange(type, static_cast(index), buffer, offset, size); } } void StateManagerGL::activeTexture(size_t unit) { if (mTextureUnitIndex != unit) { mTextureUnitIndex = unit; mFunctions->activeTexture(GL_TEXTURE0 + static_cast(mTextureUnitIndex)); } } void StateManagerGL::bindTexture(GLenum type, GLuint texture) { if (mTextures[type][mTextureUnitIndex] != texture) { mTextures[type][mTextureUnitIndex] = texture; mFunctions->bindTexture(type, texture); } } void StateManagerGL::bindSampler(size_t unit, GLuint sampler) { if (mSamplers[unit] != sampler) { mSamplers[unit] = sampler; mFunctions->bindSampler(static_cast(unit), sampler); } } void StateManagerGL::setPixelUnpackState(const gl::PixelUnpackState &unpack) { GLuint unpackBufferID = 0; const gl::Buffer *unpackBuffer = unpack.pixelBuffer.get(); if (unpackBuffer != nullptr) { unpackBufferID = GetImplAs(unpackBuffer)->getBufferID(); } setPixelUnpackState(unpack.alignment, unpack.rowLength, unpack.skipRows, unpack.skipPixels, unpack.imageHeight, unpack.skipImages, unpackBufferID); } void StateManagerGL::setPixelUnpackState(GLint alignment, GLint rowLength, GLint skipRows, GLint skipPixels, GLint imageHeight, GLint skipImages, GLuint unpackBuffer) { if (mUnpackAlignment != alignment) { mUnpackAlignment = alignment; mFunctions->pixelStorei(GL_UNPACK_ALIGNMENT, mUnpackAlignment); mLocalDirtyBits.set(gl::State::DIRTY_BIT_UNPACK_ALIGNMENT); } if (mUnpackRowLength != rowLength) { mUnpackRowLength = rowLength; mFunctions->pixelStorei(GL_UNPACK_ROW_LENGTH, mUnpackRowLength); mLocalDirtyBits.set(gl::State::DIRTY_BIT_UNPACK_ROW_LENGTH); } if (mUnpackSkipRows != skipRows) { mUnpackSkipRows = skipRows; mFunctions->pixelStorei(GL_UNPACK_SKIP_ROWS, mUnpackSkipRows); mLocalDirtyBits.set(gl::State::DIRTY_BIT_UNPACK_SKIP_ROWS); } if (mUnpackSkipPixels != skipPixels) { mUnpackSkipPixels = skipPixels; mFunctions->pixelStorei(GL_UNPACK_SKIP_PIXELS, mUnpackSkipPixels); mLocalDirtyBits.set(gl::State::DIRTY_BIT_UNPACK_SKIP_PIXELS); } if (mUnpackImageHeight != imageHeight) { mUnpackImageHeight = imageHeight; mFunctions->pixelStorei(GL_UNPACK_IMAGE_HEIGHT, mUnpackImageHeight); mLocalDirtyBits.set(gl::State::DIRTY_BIT_UNPACK_IMAGE_HEIGHT); } if (mUnpackSkipImages != skipImages) { mUnpackSkipImages = skipImages; mFunctions->pixelStorei(GL_UNPACK_SKIP_IMAGES, mUnpackSkipImages); mLocalDirtyBits.set(gl::State::DIRTY_BIT_UNPACK_SKIP_IMAGES); } bindBuffer(GL_PIXEL_UNPACK_BUFFER, unpackBuffer); } void StateManagerGL::setPixelPackState(const gl::PixelPackState &pack) { GLuint packBufferID = 0; const gl::Buffer *packBuffer = pack.pixelBuffer.get(); if (packBuffer != nullptr) { packBufferID = GetImplAs(packBuffer)->getBufferID(); } setPixelPackState(pack.alignment, pack.rowLength, pack.skipRows, pack.skipPixels, packBufferID); } void StateManagerGL::setPixelPackState(GLint alignment, GLint rowLength, GLint skipRows, GLint skipPixels, GLuint packBuffer) { if (mPackAlignment != alignment) { mPackAlignment = alignment; mFunctions->pixelStorei(GL_PACK_ALIGNMENT, mPackAlignment); mLocalDirtyBits.set(gl::State::DIRTY_BIT_PACK_ALIGNMENT); } if (mPackRowLength != rowLength) { mPackRowLength = rowLength; mFunctions->pixelStorei(GL_PACK_ROW_LENGTH, mPackRowLength); mLocalDirtyBits.set(gl::State::DIRTY_BIT_UNPACK_ROW_LENGTH); } if (mPackSkipRows != skipRows) { mPackSkipRows = skipRows; mFunctions->pixelStorei(GL_PACK_SKIP_ROWS, mPackSkipRows); // TODO: set dirty bit once one exists } if (mPackSkipPixels != skipPixels) { mPackSkipPixels = skipPixels; mFunctions->pixelStorei(GL_PACK_SKIP_PIXELS, mPackSkipPixels); // TODO: set dirty bit once one exists } bindBuffer(GL_PIXEL_PACK_BUFFER, packBuffer); } void StateManagerGL::bindFramebuffer(GLenum type, GLuint framebuffer) { if (type == GL_FRAMEBUFFER) { if (mFramebuffers[angle::FramebufferBindingRead] != framebuffer || mFramebuffers[angle::FramebufferBindingDraw] != framebuffer) { mFramebuffers[angle::FramebufferBindingRead] = framebuffer; mFramebuffers[angle::FramebufferBindingDraw] = framebuffer; mFunctions->bindFramebuffer(GL_FRAMEBUFFER, framebuffer); } } else { angle::FramebufferBinding binding = angle::EnumToFramebufferBinding(type); if (mFramebuffers[binding] != framebuffer) { mFramebuffers[binding] = framebuffer; mFunctions->bindFramebuffer(type, framebuffer); } } } void StateManagerGL::bindRenderbuffer(GLenum type, GLuint renderbuffer) { ASSERT(type == GL_RENDERBUFFER); if (mRenderbuffer != renderbuffer) { mRenderbuffer = renderbuffer; mFunctions->bindRenderbuffer(type, mRenderbuffer); } } void StateManagerGL::bindTransformFeedback(GLenum type, GLuint transformFeedback) { ASSERT(type == GL_TRANSFORM_FEEDBACK); if (mTransformFeedback != transformFeedback) { // Pause the current transform feedback if one is active. // To handle virtualized contexts, StateManagerGL needs to be able to bind a new transform // feedback at any time, even if there is one active. if (mPrevDrawTransformFeedback != nullptr && mPrevDrawTransformFeedback->getTransformFeedbackID() != transformFeedback) { mPrevDrawTransformFeedback->syncPausedState(true); mPrevDrawTransformFeedback = nullptr; } mTransformFeedback = transformFeedback; mFunctions->bindTransformFeedback(type, mTransformFeedback); } } void StateManagerGL::beginQuery(GLenum type, GLuint query) { // Make sure this is a valid query type and there is no current active query of this type ASSERT(mQueries.find(type) != mQueries.end()); ASSERT(mQueries[type] == 0); ASSERT(query != 0); mQueries[type] = query; mFunctions->beginQuery(type, query); } void StateManagerGL::endQuery(GLenum type, GLuint query) { ASSERT(mQueries[type] == query); mQueries[type] = 0; mFunctions->endQuery(type); } void StateManagerGL::onBeginQuery(QueryGL *query) { mCurrentQueries.insert(query); } void StateManagerGL::onDeleteQueryObject(QueryGL *query) { mCurrentQueries.erase(query); } gl::Error StateManagerGL::setDrawArraysState(const gl::ContextState &data, GLint first, GLsizei count, GLsizei instanceCount) { const gl::State &state = data.getState(); const gl::Program *program = state.getProgram(); const gl::VertexArray *vao = state.getVertexArray(); const VertexArrayGL *vaoGL = GetImplAs(vao); gl::Error error = vaoGL->syncDrawArraysState(program->getActiveAttribLocationsMask(), first, count, instanceCount); if (error.isError()) { return error; } bindVertexArray(vaoGL->getVertexArrayID(), vaoGL->getAppliedElementArrayBufferID()); return setGenericDrawState(data); } gl::Error StateManagerGL::setDrawElementsState(const gl::ContextState &data, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instanceCount, const GLvoid **outIndices) { const gl::State &state = data.getState(); const gl::Program *program = state.getProgram(); const gl::VertexArray *vao = state.getVertexArray(); const VertexArrayGL *vaoGL = GetImplAs(vao); gl::Error error = vaoGL->syncDrawElementsState(program->getActiveAttribLocationsMask(), count, type, indices, instanceCount, state.isPrimitiveRestartEnabled(), outIndices); if (error.isError()) { return error; } bindVertexArray(vaoGL->getVertexArrayID(), vaoGL->getAppliedElementArrayBufferID()); return setGenericDrawState(data); } gl::Error StateManagerGL::pauseTransformFeedback(const gl::ContextState &data) { // If the context is going to be changed, pause the previous context's transform feedback if (data.getContext() != mPrevDrawContext) { if (mPrevDrawTransformFeedback != nullptr) { mPrevDrawTransformFeedback->syncPausedState(true); } } return gl::Error(GL_NO_ERROR); } gl::Error StateManagerGL::onMakeCurrent(const gl::ContextState &data) { const gl::State &state = data.getState(); // If the context has changed, pause the previous context's queries if (data.getContext() != mPrevDrawContext) { for (QueryGL *prevQuery : mCurrentQueries) { prevQuery->pause(); } } mCurrentQueries.clear(); mPrevDrawTransformFeedback = nullptr; mPrevDrawContext = data.getContext(); // Set the current query state for (GLenum queryType : QueryTypes) { gl::Query *query = state.getActiveQuery(queryType); if (query != nullptr) { QueryGL *queryGL = GetImplAs(query); queryGL->resume(); mCurrentQueries.insert(queryGL); } } return gl::Error(GL_NO_ERROR); } gl::Error StateManagerGL::setGenericDrawState(const gl::ContextState &data) { const gl::State &state = data.getState(); // Sync the current program state const gl::Program *program = state.getProgram(); const ProgramGL *programGL = GetImplAs(program); useProgram(programGL->getProgramID()); for (size_t uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++) { GLuint binding = program->getUniformBlockBinding(static_cast(uniformBlockIndex)); const auto &uniformBuffer = state.getIndexedUniformBuffer(binding); if (uniformBuffer.get() != nullptr) { BufferGL *bufferGL = GetImplAs(uniformBuffer.get()); if (uniformBuffer.getSize() == 0) { bindBufferBase(GL_UNIFORM_BUFFER, binding, bufferGL->getBufferID()); } else { bindBufferRange(GL_UNIFORM_BUFFER, binding, bufferGL->getBufferID(), uniformBuffer.getOffset(), uniformBuffer.getSize()); } } } const std::vector &appliedSamplerUniforms = programGL->getAppliedSamplerUniforms(); for (const SamplerBindingGL &samplerUniform : appliedSamplerUniforms) { GLenum textureType = samplerUniform.textureType; for (GLuint textureUnitIndex : samplerUniform.boundTextureUnits) { const gl::Texture *texture = state.getSamplerTexture(textureUnitIndex, textureType); if (texture != nullptr) { const TextureGL *textureGL = GetImplAs(texture); if (mTextures[textureType][textureUnitIndex] != textureGL->getTextureID()) { activeTexture(textureUnitIndex); bindTexture(textureType, textureGL->getTextureID()); } textureGL->syncState(textureUnitIndex); } else { if (mTextures[textureType][textureUnitIndex] != 0) { activeTexture(textureUnitIndex); bindTexture(textureType, 0); } } const gl::Sampler *sampler = state.getSampler(textureUnitIndex); if (sampler != nullptr) { const SamplerGL *samplerGL = GetImplAs(sampler); samplerGL->syncState(sampler->getSamplerState()); bindSampler(textureUnitIndex, samplerGL->getSamplerID()); } else { bindSampler(textureUnitIndex, 0); } } } const gl::Framebuffer *framebuffer = state.getDrawFramebuffer(); const FramebufferGL *framebufferGL = GetImplAs(framebuffer); bindFramebuffer(GL_DRAW_FRAMEBUFFER, framebufferGL->getFramebufferID()); framebufferGL->syncDrawState(); // Seamless cubemaps are required for ES3 and higher contexts. setTextureCubemapSeamlessEnabled(data.getClientMajorVersion() >= 3); // Set the current transform feedback state gl::TransformFeedback *transformFeedback = state.getCurrentTransformFeedback(); if (transformFeedback) { TransformFeedbackGL *transformFeedbackGL = GetImplAs(transformFeedback); bindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedbackGL->getTransformFeedbackID()); transformFeedbackGL->syncActiveState(transformFeedback->isActive(), transformFeedback->getPrimitiveMode()); transformFeedbackGL->syncPausedState(transformFeedback->isPaused()); mPrevDrawTransformFeedback = transformFeedbackGL; } else { bindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0); mPrevDrawTransformFeedback = nullptr; } return gl::Error(GL_NO_ERROR); } void StateManagerGL::setAttributeCurrentData(size_t index, const gl::VertexAttribCurrentValueData &data) { if (mVertexAttribCurrentValues[index] != data) { mVertexAttribCurrentValues[index] = data; switch (mVertexAttribCurrentValues[index].Type) { case GL_FLOAT: mFunctions->vertexAttrib4fv(static_cast(index), mVertexAttribCurrentValues[index].FloatValues); break; case GL_INT: mFunctions->vertexAttribI4iv(static_cast(index), mVertexAttribCurrentValues[index].IntValues); break; case GL_UNSIGNED_INT: mFunctions->vertexAttribI4uiv(static_cast(index), mVertexAttribCurrentValues[index].UnsignedIntValues); break; default: UNREACHABLE(); } mLocalDirtyBits.set(gl::State::DIRTY_BIT_CURRENT_VALUE_0 + index); } } void StateManagerGL::setScissorTestEnabled(bool enabled) { if (mScissorTestEnabled != enabled) { mScissorTestEnabled = enabled; if (mScissorTestEnabled) { mFunctions->enable(GL_SCISSOR_TEST); } else { mFunctions->disable(GL_SCISSOR_TEST); } mLocalDirtyBits.set(gl::State::DIRTY_BIT_SCISSOR_TEST_ENABLED); } } void StateManagerGL::setScissor(const gl::Rectangle &scissor) { if (scissor != mScissor) { mScissor = scissor; mFunctions->scissor(mScissor.x, mScissor.y, mScissor.width, mScissor.height); mLocalDirtyBits.set(gl::State::DIRTY_BIT_SCISSOR); } } void StateManagerGL::setViewport(const gl::Rectangle &viewport) { if (viewport != mViewport) { mViewport = viewport; mFunctions->viewport(mViewport.x, mViewport.y, mViewport.width, mViewport.height); mLocalDirtyBits.set(gl::State::DIRTY_BIT_VIEWPORT); } } void StateManagerGL::setDepthRange(float near, float far) { if (mNear != near || mFar != far) { mNear = near; mFar = far; // The glDepthRangef function isn't available until OpenGL 4.1. Prefer it when it is // available because OpenGL ES only works in floats. if (mFunctions->depthRangef) { mFunctions->depthRangef(mNear, mFar); } else { ASSERT(mFunctions->depthRange); mFunctions->depthRange(mNear, mFar); } mLocalDirtyBits.set(gl::State::DIRTY_BIT_DEPTH_RANGE); } } void StateManagerGL::setBlendEnabled(bool enabled) { if (mBlendEnabled != enabled) { mBlendEnabled = enabled; if (mBlendEnabled) { mFunctions->enable(GL_BLEND); } else { mFunctions->disable(GL_BLEND); } mLocalDirtyBits.set(gl::State::DIRTY_BIT_BLEND_ENABLED); } } void StateManagerGL::setBlendColor(const gl::ColorF &blendColor) { if (mBlendColor != blendColor) { mBlendColor = blendColor; mFunctions->blendColor(mBlendColor.red, mBlendColor.green, mBlendColor.blue, mBlendColor.alpha); mLocalDirtyBits.set(gl::State::DIRTY_BIT_BLEND_COLOR); } } void StateManagerGL::setBlendFuncs(GLenum sourceBlendRGB, GLenum destBlendRGB, GLenum sourceBlendAlpha, GLenum destBlendAlpha) { if (mSourceBlendRGB != sourceBlendRGB || mDestBlendRGB != destBlendRGB || mSourceBlendAlpha != sourceBlendAlpha || mDestBlendAlpha != destBlendAlpha) { mSourceBlendRGB = sourceBlendRGB; mDestBlendRGB = destBlendRGB; mSourceBlendAlpha = sourceBlendAlpha; mDestBlendAlpha = destBlendAlpha; mFunctions->blendFuncSeparate(mSourceBlendRGB, mDestBlendRGB, mSourceBlendAlpha, mDestBlendAlpha); mLocalDirtyBits.set(gl::State::DIRTY_BIT_BLEND_FUNCS); } } void StateManagerGL::setBlendEquations(GLenum blendEquationRGB, GLenum blendEquationAlpha) { if (mBlendEquationRGB != blendEquationRGB || mBlendEquationAlpha != blendEquationAlpha) { mBlendEquationRGB = blendEquationRGB; mBlendEquationAlpha = blendEquationAlpha; mFunctions->blendEquationSeparate(mBlendEquationRGB, mBlendEquationAlpha); mLocalDirtyBits.set(gl::State::DIRTY_BIT_BLEND_EQUATIONS); } } void StateManagerGL::setColorMask(bool red, bool green, bool blue, bool alpha) { if (mColorMaskRed != red || mColorMaskGreen != green || mColorMaskBlue != blue || mColorMaskAlpha != alpha) { mColorMaskRed = red; mColorMaskGreen = green; mColorMaskBlue = blue; mColorMaskAlpha = alpha; mFunctions->colorMask(mColorMaskRed, mColorMaskGreen, mColorMaskBlue, mColorMaskAlpha); mLocalDirtyBits.set(gl::State::DIRTY_BIT_COLOR_MASK); } } void StateManagerGL::setSampleAlphaToCoverageEnabled(bool enabled) { if (mSampleAlphaToCoverageEnabled != enabled) { mSampleAlphaToCoverageEnabled = enabled; if (mSampleAlphaToCoverageEnabled) { mFunctions->enable(GL_SAMPLE_ALPHA_TO_COVERAGE); } else { mFunctions->disable(GL_SAMPLE_ALPHA_TO_COVERAGE); } mLocalDirtyBits.set(gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED); } } void StateManagerGL::setSampleCoverageEnabled(bool enabled) { if (mSampleCoverageEnabled != enabled) { mSampleCoverageEnabled = enabled; if (mSampleCoverageEnabled) { mFunctions->enable(GL_SAMPLE_COVERAGE); } else { mFunctions->disable(GL_SAMPLE_COVERAGE); } mLocalDirtyBits.set(gl::State::DIRTY_BIT_SAMPLE_COVERAGE_ENABLED); } } void StateManagerGL::setSampleCoverage(float value, bool invert) { if (mSampleCoverageValue != value || mSampleCoverageInvert != invert) { mSampleCoverageValue = value; mSampleCoverageInvert = invert; mFunctions->sampleCoverage(mSampleCoverageValue, mSampleCoverageInvert); mLocalDirtyBits.set(gl::State::DIRTY_BIT_SAMPLE_COVERAGE); } } void StateManagerGL::setDepthTestEnabled(bool enabled) { if (mDepthTestEnabled != enabled) { mDepthTestEnabled = enabled; if (mDepthTestEnabled) { mFunctions->enable(GL_DEPTH_TEST); } else { mFunctions->disable(GL_DEPTH_TEST); } mLocalDirtyBits.set(gl::State::DIRTY_BIT_DEPTH_TEST_ENABLED); } } void StateManagerGL::setDepthFunc(GLenum depthFunc) { if (mDepthFunc != depthFunc) { mDepthFunc = depthFunc; mFunctions->depthFunc(mDepthFunc); mLocalDirtyBits.set(gl::State::DIRTY_BIT_DEPTH_FUNC); } } void StateManagerGL::setDepthMask(bool mask) { if (mDepthMask != mask) { mDepthMask = mask; mFunctions->depthMask(mDepthMask); mLocalDirtyBits.set(gl::State::DIRTY_BIT_DEPTH_MASK); } } void StateManagerGL::setStencilTestEnabled(bool enabled) { if (mStencilTestEnabled != enabled) { mStencilTestEnabled = enabled; if (mStencilTestEnabled) { mFunctions->enable(GL_STENCIL_TEST); } else { mFunctions->disable(GL_STENCIL_TEST); } mLocalDirtyBits.set(gl::State::DIRTY_BIT_STENCIL_TEST_ENABLED); } } void StateManagerGL::setStencilFrontWritemask(GLuint mask) { if (mStencilFrontWritemask != mask) { mStencilFrontWritemask = mask; mFunctions->stencilMaskSeparate(GL_FRONT, mStencilFrontWritemask); mLocalDirtyBits.set(gl::State::DIRTY_BIT_STENCIL_WRITEMASK_FRONT); } } void StateManagerGL::setStencilBackWritemask(GLuint mask) { if (mStencilBackWritemask != mask) { mStencilBackWritemask = mask; mFunctions->stencilMaskSeparate(GL_BACK, mStencilBackWritemask); mLocalDirtyBits.set(gl::State::DIRTY_BIT_STENCIL_WRITEMASK_BACK); } } void StateManagerGL::setStencilFrontFuncs(GLenum func, GLint ref, GLuint mask) { if (mStencilFrontFunc != func || mStencilFrontRef != ref || mStencilFrontValueMask != mask) { mStencilFrontFunc = func; mStencilFrontRef = ref; mStencilFrontValueMask = mask; mFunctions->stencilFuncSeparate(GL_FRONT, mStencilFrontFunc, mStencilFrontRef, mStencilFrontValueMask); mLocalDirtyBits.set(gl::State::DIRTY_BIT_STENCIL_FUNCS_FRONT); } } void StateManagerGL::setStencilBackFuncs(GLenum func, GLint ref, GLuint mask) { if (mStencilBackFunc != func || mStencilBackRef != ref || mStencilBackValueMask != mask) { mStencilBackFunc = func; mStencilBackRef = ref; mStencilBackValueMask = mask; mFunctions->stencilFuncSeparate(GL_BACK, mStencilBackFunc, mStencilBackRef, mStencilBackValueMask); mLocalDirtyBits.set(gl::State::DIRTY_BIT_STENCIL_FUNCS_BACK); } } void StateManagerGL::setStencilFrontOps(GLenum sfail, GLenum dpfail, GLenum dppass) { if (mStencilFrontStencilFailOp != sfail || mStencilFrontStencilPassDepthFailOp != dpfail || mStencilFrontStencilPassDepthPassOp != dppass) { mStencilFrontStencilFailOp = sfail; mStencilFrontStencilPassDepthFailOp = dpfail; mStencilFrontStencilPassDepthPassOp = dppass; mFunctions->stencilOpSeparate(GL_FRONT, mStencilFrontStencilFailOp, mStencilFrontStencilPassDepthFailOp, mStencilFrontStencilPassDepthPassOp); mLocalDirtyBits.set(gl::State::DIRTY_BIT_STENCIL_OPS_FRONT); } } void StateManagerGL::setStencilBackOps(GLenum sfail, GLenum dpfail, GLenum dppass) { if (mStencilBackStencilFailOp != sfail || mStencilBackStencilPassDepthFailOp != dpfail || mStencilBackStencilPassDepthPassOp != dppass) { mStencilBackStencilFailOp = sfail; mStencilBackStencilPassDepthFailOp = dpfail; mStencilBackStencilPassDepthPassOp = dppass; mFunctions->stencilOpSeparate(GL_BACK, mStencilBackStencilFailOp, mStencilBackStencilPassDepthFailOp, mStencilBackStencilPassDepthPassOp); mLocalDirtyBits.set(gl::State::DIRTY_BIT_STENCIL_OPS_BACK); } } void StateManagerGL::setCullFaceEnabled(bool enabled) { if (mCullFaceEnabled != enabled) { mCullFaceEnabled = enabled; if (mCullFaceEnabled) { mFunctions->enable(GL_CULL_FACE); } else { mFunctions->disable(GL_CULL_FACE); } mLocalDirtyBits.set(gl::State::DIRTY_BIT_CULL_FACE_ENABLED); } } void StateManagerGL::setCullFace(GLenum cullFace) { if (mCullFace != cullFace) { mCullFace = cullFace; mFunctions->cullFace(mCullFace); mLocalDirtyBits.set(gl::State::DIRTY_BIT_CULL_FACE); } } void StateManagerGL::setFrontFace(GLenum frontFace) { if (mFrontFace != frontFace) { mFrontFace = frontFace; mFunctions->frontFace(mFrontFace); mLocalDirtyBits.set(gl::State::DIRTY_BIT_FRONT_FACE); } } void StateManagerGL::setPolygonOffsetFillEnabled(bool enabled) { if (mPolygonOffsetFillEnabled != enabled) { mPolygonOffsetFillEnabled = enabled; if (mPolygonOffsetFillEnabled) { mFunctions->enable(GL_POLYGON_OFFSET_FILL); } else { mFunctions->disable(GL_POLYGON_OFFSET_FILL); } mLocalDirtyBits.set(gl::State::DIRTY_BIT_POLYGON_OFFSET_FILL_ENABLED); } } void StateManagerGL::setPolygonOffset(float factor, float units) { if (mPolygonOffsetFactor != factor || mPolygonOffsetUnits != units) { mPolygonOffsetFactor = factor; mPolygonOffsetUnits = units; mFunctions->polygonOffset(mPolygonOffsetFactor, mPolygonOffsetUnits); mLocalDirtyBits.set(gl::State::DIRTY_BIT_POLYGON_OFFSET); } } void StateManagerGL::setRasterizerDiscardEnabled(bool enabled) { if (mRasterizerDiscardEnabled != enabled) { mRasterizerDiscardEnabled = enabled; if (mRasterizerDiscardEnabled) { mFunctions->enable(GL_RASTERIZER_DISCARD); } else { mFunctions->disable(GL_RASTERIZER_DISCARD); } mLocalDirtyBits.set(gl::State::DIRTY_BIT_RASTERIZER_DISCARD_ENABLED); } } void StateManagerGL::setLineWidth(float width) { if (mLineWidth != width) { mLineWidth = width; mFunctions->lineWidth(mLineWidth); mLocalDirtyBits.set(gl::State::DIRTY_BIT_LINE_WIDTH); } } void StateManagerGL::setPrimitiveRestartEnabled(bool enabled) { if (mPrimitiveRestartEnabled != enabled) { mPrimitiveRestartEnabled = enabled; if (mPrimitiveRestartEnabled) { mFunctions->enable(GL_PRIMITIVE_RESTART_FIXED_INDEX); } else { mFunctions->disable(GL_PRIMITIVE_RESTART_FIXED_INDEX); } mLocalDirtyBits.set(gl::State::DIRTY_BIT_PRIMITIVE_RESTART_ENABLED); } } void StateManagerGL::setClearDepth(float clearDepth) { if (mClearDepth != clearDepth) { mClearDepth = clearDepth; // The glClearDepthf function isn't available until OpenGL 4.1. Prefer it when it is // available because OpenGL ES only works in floats. if (mFunctions->clearDepthf) { mFunctions->clearDepthf(mClearDepth); } else { ASSERT(mFunctions->clearDepth); mFunctions->clearDepth(mClearDepth); } mLocalDirtyBits.set(gl::State::DIRTY_BIT_CLEAR_DEPTH); } } void StateManagerGL::setClearColor(const gl::ColorF &clearColor) { if (mClearColor != clearColor) { mClearColor = clearColor; mFunctions->clearColor(mClearColor.red, mClearColor.green, mClearColor.blue, mClearColor.alpha); mLocalDirtyBits.set(gl::State::DIRTY_BIT_CLEAR_COLOR); } } void StateManagerGL::setClearStencil(GLint clearStencil) { if (mClearStencil != clearStencil) { mClearStencil = clearStencil; mFunctions->clearStencil(mClearStencil); mLocalDirtyBits.set(gl::State::DIRTY_BIT_CLEAR_STENCIL); } } void StateManagerGL::syncState(const gl::State &state, const gl::State::DirtyBits &glDirtyBits) { const auto &glAndLocalDirtyBits = (glDirtyBits | mLocalDirtyBits); if (!glAndLocalDirtyBits.any()) { return; } // TODO(jmadill): Investigate only syncing vertex state for active attributes for (auto dirtyBit : angle::IterateBitSet(glAndLocalDirtyBits)) { switch (dirtyBit) { case gl::State::DIRTY_BIT_SCISSOR_TEST_ENABLED: setScissorTestEnabled(state.isScissorTestEnabled()); break; case gl::State::DIRTY_BIT_SCISSOR: setScissor(state.getScissor()); break; case gl::State::DIRTY_BIT_VIEWPORT: setViewport(state.getViewport()); break; case gl::State::DIRTY_BIT_DEPTH_RANGE: setDepthRange(state.getNearPlane(), state.getFarPlane()); break; case gl::State::DIRTY_BIT_BLEND_ENABLED: setBlendEnabled(state.isBlendEnabled()); break; case gl::State::DIRTY_BIT_BLEND_COLOR: setBlendColor(state.getBlendColor()); break; case gl::State::DIRTY_BIT_BLEND_FUNCS: { const auto &blendState = state.getBlendState(); setBlendFuncs(blendState.sourceBlendRGB, blendState.destBlendRGB, blendState.sourceBlendAlpha, blendState.destBlendAlpha); break; } case gl::State::DIRTY_BIT_BLEND_EQUATIONS: { const auto &blendState = state.getBlendState(); setBlendEquations(blendState.blendEquationRGB, blendState.blendEquationAlpha); break; } case gl::State::DIRTY_BIT_COLOR_MASK: { const auto &blendState = state.getBlendState(); setColorMask(blendState.colorMaskRed, blendState.colorMaskGreen, blendState.colorMaskBlue, blendState.colorMaskAlpha); break; } case gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED: setSampleAlphaToCoverageEnabled(state.isSampleAlphaToCoverageEnabled()); break; case gl::State::DIRTY_BIT_SAMPLE_COVERAGE_ENABLED: setSampleCoverageEnabled(state.isSampleCoverageEnabled()); break; case gl::State::DIRTY_BIT_SAMPLE_COVERAGE: setSampleCoverage(state.getSampleCoverageValue(), state.getSampleCoverageInvert()); break; case gl::State::DIRTY_BIT_DEPTH_TEST_ENABLED: setDepthTestEnabled(state.isDepthTestEnabled()); break; case gl::State::DIRTY_BIT_DEPTH_FUNC: setDepthFunc(state.getDepthStencilState().depthFunc); break; case gl::State::DIRTY_BIT_DEPTH_MASK: setDepthMask(state.getDepthStencilState().depthMask); break; case gl::State::DIRTY_BIT_STENCIL_TEST_ENABLED: setStencilTestEnabled(state.isStencilTestEnabled()); break; case gl::State::DIRTY_BIT_STENCIL_FUNCS_FRONT: { const auto &depthStencilState = state.getDepthStencilState(); setStencilFrontFuncs(depthStencilState.stencilFunc, state.getStencilRef(), depthStencilState.stencilMask); break; } case gl::State::DIRTY_BIT_STENCIL_FUNCS_BACK: { const auto &depthStencilState = state.getDepthStencilState(); setStencilBackFuncs(depthStencilState.stencilBackFunc, state.getStencilBackRef(), depthStencilState.stencilBackMask); break; } case gl::State::DIRTY_BIT_STENCIL_OPS_FRONT: { const auto &depthStencilState = state.getDepthStencilState(); setStencilFrontOps(depthStencilState.stencilFail, depthStencilState.stencilPassDepthFail, depthStencilState.stencilPassDepthPass); break; } case gl::State::DIRTY_BIT_STENCIL_OPS_BACK: { const auto &depthStencilState = state.getDepthStencilState(); setStencilBackOps(depthStencilState.stencilBackFail, depthStencilState.stencilBackPassDepthFail, depthStencilState.stencilBackPassDepthPass); break; } case gl::State::DIRTY_BIT_STENCIL_WRITEMASK_FRONT: setStencilFrontWritemask(state.getDepthStencilState().stencilWritemask); break; case gl::State::DIRTY_BIT_STENCIL_WRITEMASK_BACK: setStencilBackWritemask(state.getDepthStencilState().stencilBackWritemask); break; case gl::State::DIRTY_BIT_CULL_FACE_ENABLED: setCullFaceEnabled(state.isCullFaceEnabled()); break; case gl::State::DIRTY_BIT_CULL_FACE: setCullFace(state.getRasterizerState().cullMode); break; case gl::State::DIRTY_BIT_FRONT_FACE: setFrontFace(state.getRasterizerState().frontFace); break; case gl::State::DIRTY_BIT_POLYGON_OFFSET_FILL_ENABLED: setPolygonOffsetFillEnabled(state.isPolygonOffsetFillEnabled()); break; case gl::State::DIRTY_BIT_POLYGON_OFFSET: { const auto &rasterizerState = state.getRasterizerState(); setPolygonOffset(rasterizerState.polygonOffsetFactor, rasterizerState.polygonOffsetUnits); break; } case gl::State::DIRTY_BIT_RASTERIZER_DISCARD_ENABLED: setRasterizerDiscardEnabled(state.isRasterizerDiscardEnabled()); break; case gl::State::DIRTY_BIT_LINE_WIDTH: setLineWidth(state.getLineWidth()); break; case gl::State::DIRTY_BIT_PRIMITIVE_RESTART_ENABLED: setPrimitiveRestartEnabled(state.isPrimitiveRestartEnabled()); break; case gl::State::DIRTY_BIT_CLEAR_COLOR: setClearColor(state.getColorClearValue()); break; case gl::State::DIRTY_BIT_CLEAR_DEPTH: setClearDepth(state.getDepthClearValue()); break; case gl::State::DIRTY_BIT_CLEAR_STENCIL: setClearStencil(state.getStencilClearValue()); break; case gl::State::DIRTY_BIT_UNPACK_ALIGNMENT: // TODO(jmadill): split this setPixelUnpackState(state.getUnpackState()); break; case gl::State::DIRTY_BIT_UNPACK_ROW_LENGTH: // TODO(jmadill): split this setPixelUnpackState(state.getUnpackState()); break; case gl::State::DIRTY_BIT_UNPACK_IMAGE_HEIGHT: // TODO(jmadill): split this setPixelUnpackState(state.getUnpackState()); break; case gl::State::DIRTY_BIT_UNPACK_SKIP_IMAGES: // TODO(jmadill): split this setPixelUnpackState(state.getUnpackState()); break; case gl::State::DIRTY_BIT_UNPACK_SKIP_ROWS: // TODO(jmadill): split this setPixelUnpackState(state.getUnpackState()); break; case gl::State::DIRTY_BIT_UNPACK_SKIP_PIXELS: // TODO(jmadill): split this setPixelUnpackState(state.getUnpackState()); break; case gl::State::DIRTY_BIT_UNPACK_BUFFER_BINDING: // TODO(jmadill): split this setPixelUnpackState(state.getUnpackState()); break; case gl::State::DIRTY_BIT_PACK_ALIGNMENT: // TODO(jmadill): split this setPixelPackState(state.getPackState()); break; case gl::State::DIRTY_BIT_PACK_REVERSE_ROW_ORDER: // TODO(jmadill): split this setPixelPackState(state.getPackState()); break; case gl::State::DIRTY_BIT_PACK_ROW_LENGTH: // TODO(jmadill): split this setPixelPackState(state.getPackState()); break; case gl::State::DIRTY_BIT_PACK_SKIP_ROWS: // TODO(jmadill): split this setPixelPackState(state.getPackState()); break; case gl::State::DIRTY_BIT_PACK_SKIP_PIXELS: // TODO(jmadill): split this setPixelPackState(state.getPackState()); break; case gl::State::DIRTY_BIT_PACK_BUFFER_BINDING: // TODO(jmadill): split this setPixelPackState(state.getPackState()); break; case gl::State::DIRTY_BIT_DITHER_ENABLED: // TODO(jmadill): implement this break; case gl::State::DIRTY_BIT_GENERATE_MIPMAP_HINT: // TODO(jmadill): implement this break; case gl::State::DIRTY_BIT_SHADER_DERIVATIVE_HINT: // TODO(jmadill): implement this break; case gl::State::DIRTY_BIT_READ_FRAMEBUFFER_BINDING: // TODO(jmadill): implement this break; case gl::State::DIRTY_BIT_DRAW_FRAMEBUFFER_BINDING: // TODO(jmadill): implement this break; case gl::State::DIRTY_BIT_RENDERBUFFER_BINDING: // TODO(jmadill): implement this break; case gl::State::DIRTY_BIT_VERTEX_ARRAY_BINDING: // TODO(jmadill): implement this break; case gl::State::DIRTY_BIT_PROGRAM_BINDING: // TODO(jmadill): implement this break; case gl::State::DIRTY_BIT_MULTISAMPLING: setMultisamplingStateEnabled(state.isMultisamplingEnabled()); break; case gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_ONE: setSampleAlphaToOneStateEnabled(state.isSampleAlphaToOneEnabled()); case gl::State::DIRTY_BIT_COVERAGE_MODULATION: setCoverageModulation(state.getCoverageModulation()); break; case gl::State::DIRTY_BIT_PATH_RENDERING_MATRIX_MV: setPathRenderingModelViewMatrix( state.getPathRenderingMatrix(GL_PATH_MODELVIEW_MATRIX_CHROMIUM)); break; case gl::State::DIRTY_BIT_PATH_RENDERING_MATRIX_PROJ: setPathRenderingProjectionMatrix( state.getPathRenderingMatrix(GL_PATH_PROJECTION_MATRIX_CHROMIUM)); break; case gl::State::DIRTY_BIT_PATH_RENDERING_STENCIL_STATE: setPathRenderingStencilState(state.getPathStencilFunc(), state.getPathStencilRef(), state.getPathStencilMask()); break; default: { ASSERT(dirtyBit >= gl::State::DIRTY_BIT_CURRENT_VALUE_0 && dirtyBit < gl::State::DIRTY_BIT_CURRENT_VALUE_MAX); size_t attribIndex = static_cast(dirtyBit) - gl::State::DIRTY_BIT_CURRENT_VALUE_0; setAttributeCurrentData(attribIndex, state.getVertexAttribCurrentValue( static_cast(attribIndex))); break; } } mLocalDirtyBits.reset(); } } void StateManagerGL::setFramebufferSRGBEnabled(bool enabled) { if (mFramebufferSRGBEnabled != enabled) { mFramebufferSRGBEnabled = enabled; if (mFramebufferSRGBEnabled) { mFunctions->enable(GL_FRAMEBUFFER_SRGB); } else { mFunctions->disable(GL_FRAMEBUFFER_SRGB); } } } void StateManagerGL::setMultisamplingStateEnabled(bool enabled) { if (mMultisamplingEnabled != enabled) { mMultisamplingEnabled = enabled; if (mMultisamplingEnabled) { mFunctions->enable(GL_MULTISAMPLE_EXT); } else { mFunctions->disable(GL_MULTISAMPLE_EXT); } mLocalDirtyBits.set(gl::State::DIRTY_BIT_MULTISAMPLING); } } void StateManagerGL::setSampleAlphaToOneStateEnabled(bool enabled) { if (mSampleAlphaToOneEnabled != enabled) { mSampleAlphaToOneEnabled = enabled; if (mSampleAlphaToOneEnabled) { mFunctions->enable(GL_SAMPLE_ALPHA_TO_ONE); } else { mFunctions->disable(GL_SAMPLE_ALPHA_TO_ONE); } mLocalDirtyBits.set(gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_ONE); } } void StateManagerGL::setCoverageModulation(GLenum components) { if (mCoverageModulation != components) { mCoverageModulation = components; mFunctions->coverageModulationNV(components); mLocalDirtyBits.set(gl::State::DIRTY_BIT_COVERAGE_MODULATION); } } void StateManagerGL::setPathRenderingModelViewMatrix(const GLfloat *m) { if (memcmp(mPathMatrixMV, m, sizeof(mPathMatrixMV)) != 0) { memcpy(mPathMatrixMV, m, sizeof(mPathMatrixMV)); mFunctions->matrixLoadEXT(GL_PATH_MODELVIEW_CHROMIUM, m); mLocalDirtyBits.set(gl::State::DIRTY_BIT_PATH_RENDERING_MATRIX_MV); } } void StateManagerGL::setPathRenderingProjectionMatrix(const GLfloat *m) { if (memcmp(mPathMatrixProj, m, sizeof(mPathMatrixProj)) != 0) { memcpy(mPathMatrixProj, m, sizeof(mPathMatrixProj)); mFunctions->matrixLoadEXT(GL_PATH_PROJECTION_CHROMIUM, m); mLocalDirtyBits.set(gl::State::DIRTY_BIT_PATH_RENDERING_MATRIX_PROJ); } } void StateManagerGL::setPathRenderingStencilState(GLenum func, GLint ref, GLuint mask) { if (func != mPathStencilFunc || ref != mPathStencilRef || mask != mPathStencilMask) { mPathStencilFunc = func; mPathStencilRef = ref; mPathStencilMask = mask; mFunctions->pathStencilFuncNV(func, ref, mask); mLocalDirtyBits.set(gl::State::DIRTY_BIT_PATH_RENDERING_STENCIL_STATE); } } void StateManagerGL::setTextureCubemapSeamlessEnabled(bool enabled) { if (mTextureCubemapSeamlessEnabled != enabled) { mTextureCubemapSeamlessEnabled = enabled; if (mTextureCubemapSeamlessEnabled) { mFunctions->enable(GL_TEXTURE_CUBE_MAP_SEAMLESS); } else { mFunctions->disable(GL_TEXTURE_CUBE_MAP_SEAMLESS); } } } GLuint StateManagerGL::getBoundBuffer(GLenum type) { ASSERT(mBuffers.find(type) != mBuffers.end()); return mBuffers[type]; } }