summaryrefslogtreecommitdiffstats
path: root/gfx/angle/src/libANGLE/renderer/gl/StateManagerGL.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/angle/src/libANGLE/renderer/gl/StateManagerGL.cpp')
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/gl/StateManagerGL.cpp1742
1 files changed, 1742 insertions, 0 deletions
diff --git a/gfx/angle/src/libANGLE/renderer/gl/StateManagerGL.cpp b/gfx/angle/src/libANGLE/renderer/gl/StateManagerGL.cpp
new file mode 100755
index 000000000..3a227906f
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/gl/StateManagerGL.cpp
@@ -0,0 +1,1742 @@
+//
+// 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 <limits>
+#include <string.h>
+
+#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<GLuint>(-1)),
+ mStencilFrontStencilFailOp(GL_KEEP),
+ mStencilFrontStencilPassDepthFailOp(GL_KEEP),
+ mStencilFrontStencilPassDepthPassOp(GL_KEEP),
+ mStencilFrontWritemask(static_cast<GLuint>(-1)),
+ mStencilBackFunc(GL_ALWAYS),
+ mStencilBackRef(0),
+ mStencilBackValueMask(static_cast<GLuint>(-1)),
+ mStencilBackStencilFailOp(GL_KEEP),
+ mStencilBackStencilPassDepthFailOp(GL_KEEP),
+ mStencilBackStencilPassDepthPassOp(GL_KEEP),
+ mStencilBackWritemask(static_cast<GLuint>(-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),
+ mDitherEnabled(true),
+ mTextureCubemapSeamlessEnabled(false),
+ mMultisamplingEnabled(true),
+ mSampleAlphaToOneEnabled(false),
+ mCoverageModulation(GL_NONE),
+ mPathStencilFunc(GL_ALWAYS),
+ mPathStencilRef(0),
+ mPathStencilMask(std::numeric_limits<GLuint>::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<GLfloat>::setToIdentity(mPathMatrixProj);
+ angle::Matrix<GLfloat>::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<GLuint> &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<angle::FramebufferBinding>(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<size_t>(-1) ||
+ binding.size != static_cast<size_t>(-1))
+ {
+ binding.buffer = buffer;
+ binding.offset = static_cast<size_t>(-1);
+ binding.size = static_cast<size_t>(-1);
+ mFunctions->bindBufferBase(type, static_cast<GLuint>(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<GLuint>(index), buffer, offset, size);
+ }
+}
+
+void StateManagerGL::activeTexture(size_t unit)
+{
+ if (mTextureUnitIndex != unit)
+ {
+ mTextureUnitIndex = unit;
+ mFunctions->activeTexture(GL_TEXTURE0 + static_cast<GLenum>(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<GLuint>(unit), sampler);
+ }
+}
+
+void StateManagerGL::setPixelUnpackState(const gl::PixelUnpackState &unpack)
+{
+ GLuint unpackBufferID = 0;
+ const gl::Buffer *unpackBuffer = unpack.pixelBuffer.get();
+ if (unpackBuffer != nullptr)
+ {
+ unpackBufferID = GetImplAs<BufferGL>(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<BufferGL>(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<VertexArrayGL>(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<VertexArrayGL>(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<QueryGL>(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<ProgramGL>(program);
+ useProgram(programGL->getProgramID());
+
+ for (size_t uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount();
+ uniformBlockIndex++)
+ {
+ GLuint binding = program->getUniformBlockBinding(static_cast<GLuint>(uniformBlockIndex));
+ const auto &uniformBuffer = state.getIndexedUniformBuffer(binding);
+
+ if (uniformBuffer.get() != nullptr)
+ {
+ BufferGL *bufferGL = GetImplAs<BufferGL>(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<SamplerBindingGL> &appliedSamplerUniforms = programGL->getAppliedSamplerUniforms();
+ for (const SamplerBindingGL &samplerUniform : appliedSamplerUniforms)
+ {
+ GLenum textureType = samplerUniform.textureType;
+ for (GLuint textureUnitIndex : samplerUniform.boundTextureUnits)
+ {
+ gl::Texture *texture = state.getSamplerTexture(textureUnitIndex, textureType);
+ if (texture != nullptr)
+ {
+ const TextureGL *textureGL = GetImplAs<TextureGL>(texture);
+
+ if (mTextures[textureType][textureUnitIndex] != textureGL->getTextureID() ||
+ texture->hasAnyDirtyBit() || textureGL->hasAnyDirtyBit())
+ {
+ activeTexture(textureUnitIndex);
+ bindTexture(textureType, textureGL->getTextureID());
+
+ // TODO: Call this from the gl:: layer once other backends use dirty bits for
+ // texture state.
+ texture->syncImplState();
+ }
+ }
+ 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<SamplerGL>(sampler);
+ samplerGL->syncState(sampler->getSamplerState());
+ bindSampler(textureUnitIndex, samplerGL->getSamplerID());
+ }
+ else
+ {
+ bindSampler(textureUnitIndex, 0);
+ }
+ }
+ }
+
+ const gl::Framebuffer *framebuffer = state.getDrawFramebuffer();
+ const FramebufferGL *framebufferGL = GetImplAs<FramebufferGL>(framebuffer);
+ bindFramebuffer(GL_DRAW_FRAMEBUFFER, framebufferGL->getFramebufferID());
+
+ // 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<TransformFeedbackGL>(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<GLuint>(index),
+ mVertexAttribCurrentValues[index].FloatValues);
+ break;
+ case GL_INT:
+ mFunctions->vertexAttribI4iv(static_cast<GLuint>(index),
+ mVertexAttribCurrentValues[index].IntValues);
+ break;
+ case GL_UNSIGNED_INT:
+ mFunctions->vertexAttribI4uiv(static_cast<GLuint>(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)
+{
+ // The the current framebuffer binding sometimes requires resetting the srgb blending
+ if (glDirtyBits[gl::State::DIRTY_BIT_DRAW_FRAMEBUFFER_BINDING] &&
+ mFunctions->standard == STANDARD_GL_DESKTOP)
+ {
+ mLocalDirtyBits.set(gl::State::DIRTY_BIT_FRAMEBUFFER_SRGB);
+ }
+
+ 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:
+ setDitherEnabled(state.isDitherEnabled());
+ 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;
+ case gl::State::DIRTY_BIT_FRAMEBUFFER_SRGB:
+ setFramebufferSRGBEnabledForFramebuffer(
+ state.getFramebufferSRGB(),
+ GetImplAs<FramebufferGL>(state.getDrawFramebuffer()));
+ break;
+ default:
+ {
+ ASSERT(dirtyBit >= gl::State::DIRTY_BIT_CURRENT_VALUE_0 &&
+ dirtyBit < gl::State::DIRTY_BIT_CURRENT_VALUE_MAX);
+ size_t attribIndex =
+ static_cast<size_t>(dirtyBit) - gl::State::DIRTY_BIT_CURRENT_VALUE_0;
+ setAttributeCurrentData(attribIndex, state.getVertexAttribCurrentValue(
+ static_cast<unsigned int>(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);
+ }
+ mLocalDirtyBits.set(gl::State::DIRTY_BIT_FRAMEBUFFER_SRGB);
+ }
+}
+
+void StateManagerGL::setFramebufferSRGBEnabledForFramebuffer(bool enabled,
+ const FramebufferGL *framebuffer)
+{
+ if (mFunctions->standard == STANDARD_GL_DESKTOP && framebuffer->isDefault())
+ {
+ // Obey the framebuffer sRGB state for blending on all framebuffers except the default
+ // framebuffer on Desktop OpenGL.
+ // When SRGB blending is enabled, only SRGB capable formats will use it but the default
+ // framebuffer will always use it if it is enabled.
+ // TODO(geofflang): Update this when the framebuffer binding dirty changes, when it exists.
+ setFramebufferSRGBEnabled(false);
+ }
+ else
+ {
+ setFramebufferSRGBEnabled(enabled);
+ }
+}
+
+void StateManagerGL::setDitherEnabled(bool enabled)
+{
+ if (mDitherEnabled != enabled)
+ {
+ mDitherEnabled = enabled;
+ if (mDitherEnabled)
+ {
+ mFunctions->enable(GL_DITHER);
+ }
+ else
+ {
+ mFunctions->disable(GL_DITHER);
+ }
+ }
+}
+
+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];
+}
+}