Commit 6193fd69 by Alexey Knyazev Committed by Commit Bot

OpenGL: Implement OES_draw_buffers_indexed

OpenGL state sync issues as few GL commands as possible to update the blend state regardless of an application input. Enhanced ClearTestES3.MaskedIndexedClearMultipleAttachments regression test. Disabled OES_draw_buffers_indexed on Windows/AMD/OpenGL. Bug: angleproject:4394 Change-Id: I244ac2975678bc559634152cf4eb997d9dbe83d0 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2145874 Commit-Queue: Kenneth Russell <kbr@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 6e7d7296
...@@ -426,6 +426,12 @@ struct FeaturesGL : FeatureSetBase ...@@ -426,6 +426,12 @@ struct FeaturesGL : FeatureSetBase
"avoid_dxt1_srgb_texture_format", FeatureCategory::OpenGLWorkarounds, "avoid_dxt1_srgb_texture_format", FeatureCategory::OpenGLWorkarounds,
"Replaces DXT1 sRGB with DXT1 sRGB Alpha as a driver bug workaround.", &members}; "Replaces DXT1 sRGB with DXT1 sRGB Alpha as a driver bug workaround.", &members};
// Bugs exist in OpenGL AMD drivers on Windows that produce incorrect pipeline state for
// colorMaski calls.
Feature disableDrawBuffersIndexed = {"disable_draw_buffers_indexed",
FeatureCategory::OpenGLWorkarounds,
"Disable OES_draw_buffers_indexed extension.", &members};
// GL_EXT_semaphore_fd doesn't work properly with Mesa 19.3.4 and earlier versions. // GL_EXT_semaphore_fd doesn't work properly with Mesa 19.3.4 and earlier versions.
Feature disableSemaphoreFd = {"disable_semaphore_fd", FeatureCategory::OpenGLWorkarounds, Feature disableSemaphoreFd = {"disable_semaphore_fd", FeatureCategory::OpenGLWorkarounds,
"Disable GL_EXT_semaphore_fd extension", &members, "Disable GL_EXT_semaphore_fd extension", &members,
......
...@@ -388,6 +388,7 @@ void State::initialize(Context *context) ...@@ -388,6 +388,7 @@ void State::initialize(Context *context)
const Version &clientVersion = context->getClientVersion(); const Version &clientVersion = context->getClientVersion();
mMaxDrawBuffers = static_cast<GLuint>(caps.maxDrawBuffers); mMaxDrawBuffers = static_cast<GLuint>(caps.maxDrawBuffers);
mBlendStateExt = BlendStateExt(mMaxDrawBuffers);
mMaxCombinedTextureImageUnits = static_cast<GLuint>(caps.maxCombinedTextureImageUnits); mMaxCombinedTextureImageUnits = static_cast<GLuint>(caps.maxCombinedTextureImageUnits);
setColorClearValue(0.0f, 0.0f, 0.0f, 0.0f); setColorClearValue(0.0f, 0.0f, 0.0f, 0.0f);
...@@ -706,6 +707,8 @@ void State::setColorMask(bool red, bool green, bool blue, bool alpha) ...@@ -706,6 +707,8 @@ void State::setColorMask(bool red, bool green, bool blue, bool alpha)
blendState.colorMaskBlue = blue; blendState.colorMaskBlue = blue;
blendState.colorMaskAlpha = alpha; blendState.colorMaskAlpha = alpha;
} }
mBlendStateExt.setColorMask(red, green, blue, alpha);
mDirtyBits.set(DIRTY_BIT_COLOR_MASK); mDirtyBits.set(DIRTY_BIT_COLOR_MASK);
} }
...@@ -716,6 +719,8 @@ void State::setColorMaskIndexed(bool red, bool green, bool blue, bool alpha, GLu ...@@ -716,6 +719,8 @@ void State::setColorMaskIndexed(bool red, bool green, bool blue, bool alpha, GLu
mBlendStateArray[index].colorMaskGreen = green; mBlendStateArray[index].colorMaskGreen = green;
mBlendStateArray[index].colorMaskBlue = blue; mBlendStateArray[index].colorMaskBlue = blue;
mBlendStateArray[index].colorMaskAlpha = alpha; mBlendStateArray[index].colorMaskAlpha = alpha;
mBlendStateExt.setColorMaskIndexed(index, red, green, blue, alpha);
mDirtyBits.set(DIRTY_BIT_COLOR_MASK); mDirtyBits.set(DIRTY_BIT_COLOR_MASK);
} }
...@@ -814,7 +819,7 @@ void State::setBlend(bool enabled) ...@@ -814,7 +819,7 @@ void State::setBlend(bool enabled)
{ {
blendState.blend = enabled; blendState.blend = enabled;
} }
enabled ? mBlendEnabledDrawBuffers.set() : mBlendEnabledDrawBuffers.reset(); mBlendStateExt.setEnabled(enabled);
mDirtyBits.set(DIRTY_BIT_BLEND_ENABLED); mDirtyBits.set(DIRTY_BIT_BLEND_ENABLED);
} }
...@@ -822,7 +827,7 @@ void State::setBlendIndexed(bool enabled, GLuint index) ...@@ -822,7 +827,7 @@ void State::setBlendIndexed(bool enabled, GLuint index)
{ {
ASSERT(index < mBlendStateArray.size()); ASSERT(index < mBlendStateArray.size());
mBlendStateArray[index].blend = enabled; mBlendStateArray[index].blend = enabled;
mBlendEnabledDrawBuffers.set(index, enabled); mBlendStateExt.setEnabledIndexed(index, enabled);
mDirtyBits.set(DIRTY_BIT_BLEND_ENABLED); mDirtyBits.set(DIRTY_BIT_BLEND_ENABLED);
} }
...@@ -856,6 +861,8 @@ void State::setBlendFactors(GLenum sourceRGB, GLenum destRGB, GLenum sourceAlpha ...@@ -856,6 +861,8 @@ void State::setBlendFactors(GLenum sourceRGB, GLenum destRGB, GLenum sourceAlpha
mBlendFuncConstantAlphaDrawBuffers.reset(); mBlendFuncConstantAlphaDrawBuffers.reset();
} }
} }
mBlendStateExt.setFactors(sourceRGB, destRGB, sourceAlpha, destAlpha);
mDirtyBits.set(DIRTY_BIT_BLEND_FUNCS); mDirtyBits.set(DIRTY_BIT_BLEND_FUNCS);
} }
...@@ -876,6 +883,8 @@ void State::setBlendFactorsIndexed(GLenum sourceRGB, ...@@ -876,6 +883,8 @@ void State::setBlendFactorsIndexed(GLenum sourceRGB,
mBlendFuncConstantColorDrawBuffers.set(index, hasConstantColor(sourceRGB, destRGB)); mBlendFuncConstantColorDrawBuffers.set(index, hasConstantColor(sourceRGB, destRGB));
mBlendFuncConstantAlphaDrawBuffers.set(index, hasConstantAlpha(sourceRGB, destRGB)); mBlendFuncConstantAlphaDrawBuffers.set(index, hasConstantAlpha(sourceRGB, destRGB));
} }
mBlendStateExt.setFactorsIndexed(index, sourceRGB, destRGB, sourceAlpha, destAlpha);
mDirtyBits.set(DIRTY_BIT_BLEND_FUNCS); mDirtyBits.set(DIRTY_BIT_BLEND_FUNCS);
} }
...@@ -909,6 +918,8 @@ void State::setBlendEquation(GLenum rgbEquation, GLenum alphaEquation) ...@@ -909,6 +918,8 @@ void State::setBlendEquation(GLenum rgbEquation, GLenum alphaEquation)
blendState.blendEquationRGB = rgbEquation; blendState.blendEquationRGB = rgbEquation;
blendState.blendEquationAlpha = alphaEquation; blendState.blendEquationAlpha = alphaEquation;
} }
mBlendStateExt.setEquations(rgbEquation, alphaEquation);
mDirtyBits.set(DIRTY_BIT_BLEND_EQUATIONS); mDirtyBits.set(DIRTY_BIT_BLEND_EQUATIONS);
} }
...@@ -917,6 +928,8 @@ void State::setBlendEquationIndexed(GLenum rgbEquation, GLenum alphaEquation, GL ...@@ -917,6 +928,8 @@ void State::setBlendEquationIndexed(GLenum rgbEquation, GLenum alphaEquation, GL
ASSERT(index < mBlendStateArray.size()); ASSERT(index < mBlendStateArray.size());
mBlendStateArray[index].blendEquationRGB = rgbEquation; mBlendStateArray[index].blendEquationRGB = rgbEquation;
mBlendStateArray[index].blendEquationAlpha = alphaEquation; mBlendStateArray[index].blendEquationAlpha = alphaEquation;
mBlendStateExt.setEquationsIndexed(index, rgbEquation, alphaEquation);
mDirtyBits.set(DIRTY_BIT_BLEND_EQUATIONS); mDirtyBits.set(DIRTY_BIT_BLEND_EQUATIONS);
} }
......
...@@ -172,7 +172,7 @@ class State : angle::NonCopyable ...@@ -172,7 +172,7 @@ class State : angle::NonCopyable
ASSERT(index < mBlendStateArray.size()); ASSERT(index < mBlendStateArray.size());
return mBlendStateArray[index].blend; return mBlendStateArray[index].blend;
} }
DrawBufferMask getBlendEnabledDrawBufferMask() const { return mBlendEnabledDrawBuffers; } DrawBufferMask getBlendEnabledDrawBufferMask() const { return mBlendStateExt.mEnabledMask; }
void setBlend(bool enabled); void setBlend(bool enabled);
void setBlendIndexed(bool enabled, GLuint index); void setBlendIndexed(bool enabled, GLuint index);
void setBlendFactors(GLenum sourceRGB, GLenum destRGB, GLenum sourceAlpha, GLenum destAlpha); void setBlendFactors(GLenum sourceRGB, GLenum destRGB, GLenum sourceAlpha, GLenum destAlpha);
...@@ -764,12 +764,12 @@ class State : angle::NonCopyable ...@@ -764,12 +764,12 @@ class State : angle::NonCopyable
bool hasConstantAlphaBlendFunc() const bool hasConstantAlphaBlendFunc() const
{ {
return (mBlendFuncConstantAlphaDrawBuffers & mBlendEnabledDrawBuffers).any(); return (mBlendFuncConstantAlphaDrawBuffers & mBlendStateExt.mEnabledMask).any();
} }
bool hasSimultaneousConstantColorAndAlphaBlendFunc() const bool hasSimultaneousConstantColorAndAlphaBlendFunc() const
{ {
return (mBlendFuncConstantColorDrawBuffers & mBlendEnabledDrawBuffers).any() && return (mBlendFuncConstantColorDrawBuffers & mBlendStateExt.mEnabledMask).any() &&
hasConstantAlphaBlendFunc(); hasConstantAlphaBlendFunc();
} }
...@@ -780,6 +780,8 @@ class State : angle::NonCopyable ...@@ -780,6 +780,8 @@ class State : angle::NonCopyable
bool isEarlyFragmentTestsOptimizationAllowed() const { return isSampleCoverageEnabled(); } bool isEarlyFragmentTestsOptimizationAllowed() const { return isSampleCoverageEnabled(); }
const BlendStateExt &getBlendStateExt() const { return mBlendStateExt; }
private: private:
friend class Context; friend class Context;
...@@ -875,6 +877,7 @@ class State : angle::NonCopyable ...@@ -875,6 +877,7 @@ class State : angle::NonCopyable
Rectangle mScissor; Rectangle mScissor;
BlendStateArray mBlendStateArray; BlendStateArray mBlendStateArray;
BlendStateExt mBlendStateExt;
ColorF mBlendColor; ColorF mBlendColor;
bool mSampleAlphaToCoverage; bool mSampleAlphaToCoverage;
bool mSampleCoverage; bool mSampleCoverage;
...@@ -1002,7 +1005,6 @@ class State : angle::NonCopyable ...@@ -1002,7 +1005,6 @@ class State : angle::NonCopyable
const OverlayType *mOverlay; const OverlayType *mOverlay;
// OES_draw_buffers_indexed // OES_draw_buffers_indexed
DrawBufferMask mBlendEnabledDrawBuffers;
DrawBufferMask mBlendFuncConstantAlphaDrawBuffers; DrawBufferMask mBlendFuncConstantAlphaDrawBuffers;
DrawBufferMask mBlendFuncConstantColorDrawBuffers; DrawBufferMask mBlendFuncConstantColorDrawBuffers;
bool mNoSimultaneousConstantColorAndAlphaBlendFunc; bool mNoSimultaneousConstantColorAndAlphaBlendFunc;
......
...@@ -94,18 +94,9 @@ StateManagerGL::StateManagerGL(const FunctionsGL *functions, ...@@ -94,18 +94,9 @@ StateManagerGL::StateManagerGL(const FunctionsGL *functions,
mViewport(0, 0, 0, 0), mViewport(0, 0, 0, 0),
mNear(0.0f), mNear(0.0f),
mFar(1.0f), mFar(1.0f),
mBlendEnabled(false),
mBlendColor(0, 0, 0, 0), mBlendColor(0, 0, 0, 0),
mSourceBlendRGB(GL_ONE), mBlendStateExt(rendererCaps.maxDrawBuffers),
mDestBlendRGB(GL_ZERO), mIndependentBlendStates(extensions.drawBuffersIndexedAny()),
mSourceBlendAlpha(GL_ONE),
mDestBlendAlpha(GL_ZERO),
mBlendEquationRGB(GL_FUNC_ADD),
mBlendEquationAlpha(GL_FUNC_ADD),
mColorMaskRed(true),
mColorMaskGreen(true),
mColorMaskBlue(true),
mColorMaskAlpha(true),
mSampleAlphaToCoverageEnabled(false), mSampleAlphaToCoverageEnabled(false),
mSampleCoverageEnabled(false), mSampleCoverageEnabled(false),
mSampleCoverageValue(1.0f), mSampleCoverageValue(1.0f),
...@@ -1062,20 +1053,75 @@ void StateManagerGL::setDepthRange(float near, float far) ...@@ -1062,20 +1053,75 @@ void StateManagerGL::setDepthRange(float near, float far)
void StateManagerGL::setBlendEnabled(bool enabled) void StateManagerGL::setBlendEnabled(bool enabled)
{ {
if (mBlendEnabled != enabled) const gl::DrawBufferMask mask =
enabled ? mBlendStateExt.mMaxEnabledMask : gl::DrawBufferMask::Zero();
if (mBlendStateExt.mEnabledMask == mask)
{ {
mBlendEnabled = enabled; return;
if (mBlendEnabled) }
if (enabled)
{
mFunctions->enable(GL_BLEND);
}
else
{
mFunctions->disable(GL_BLEND);
}
mBlendStateExt.setEnabled(enabled);
mLocalDirtyBits.set(gl::State::DIRTY_BIT_BLEND_ENABLED);
}
void StateManagerGL::setBlendEnabledIndexed(const gl::DrawBufferMask enabledMask)
{
if (mBlendStateExt.mEnabledMask == enabledMask)
{
return;
}
// Get DrawBufferMask of buffers with different blend enable state
gl::DrawBufferMask diffMask = mBlendStateExt.mEnabledMask ^ enabledMask;
const size_t diffCount = diffMask.count();
// Check if enabling or disabling blending for all buffers reduces the number of subsequent
// indexed commands. Implicitly handles the case when the new blend enable state is the same for
// all buffers.
if (diffCount > 1)
{
// The number of indexed blend enable commands in case a mass disable is used.
const size_t enabledCount = enabledMask.count();
// The mask and the number of indexed blend disable commands in case a mass enable is used.
const gl::DrawBufferMask disabledMask = enabledMask ^ mBlendStateExt.mMaxEnabledMask;
const size_t disabledCount = disabledMask.count();
if (enabledCount < diffCount && enabledCount <= disabledCount)
{
diffMask = enabledMask;
mFunctions->disable(GL_BLEND);
}
else if (disabledCount < diffCount && disabledCount <= enabledCount)
{ {
diffMask = disabledMask;
mFunctions->enable(GL_BLEND); mFunctions->enable(GL_BLEND);
} }
}
for (size_t drawBufferIndex : diffMask)
{
if (enabledMask.test(drawBufferIndex))
{
mFunctions->enablei(GL_BLEND, static_cast<GLuint>(drawBufferIndex));
}
else else
{ {
mFunctions->disable(GL_BLEND); mFunctions->disablei(GL_BLEND, static_cast<GLuint>(drawBufferIndex));
} }
mLocalDirtyBits.set(gl::State::DIRTY_BIT_BLEND_ENABLED);
} }
mBlendStateExt.mEnabledMask = enabledMask;
mLocalDirtyBits.set(gl::State::DIRTY_BIT_BLEND_ENABLED);
} }
void StateManagerGL::setBlendColor(const gl::ColorF &blendColor) void StateManagerGL::setBlendColor(const gl::ColorF &blendColor)
...@@ -1090,50 +1136,179 @@ void StateManagerGL::setBlendColor(const gl::ColorF &blendColor) ...@@ -1090,50 +1136,179 @@ void StateManagerGL::setBlendColor(const gl::ColorF &blendColor)
} }
} }
void StateManagerGL::setBlendFuncs(GLenum sourceBlendRGB, void StateManagerGL::setBlendFuncs(const gl::BlendStateExt &blendStateExt)
GLenum destBlendRGB,
GLenum sourceBlendAlpha,
GLenum destBlendAlpha)
{ {
if (mSourceBlendRGB != sourceBlendRGB || mDestBlendRGB != destBlendRGB || if (mBlendStateExt.mSrcColor == blendStateExt.mSrcColor &&
mSourceBlendAlpha != sourceBlendAlpha || mDestBlendAlpha != destBlendAlpha) mBlendStateExt.mDstColor == blendStateExt.mDstColor &&
mBlendStateExt.mSrcAlpha == blendStateExt.mSrcAlpha &&
mBlendStateExt.mDstAlpha == blendStateExt.mDstAlpha)
{ {
mSourceBlendRGB = sourceBlendRGB; return;
mDestBlendRGB = destBlendRGB; }
mSourceBlendAlpha = sourceBlendAlpha;
mDestBlendAlpha = destBlendAlpha;
mFunctions->blendFuncSeparate(mSourceBlendRGB, mDestBlendRGB, mSourceBlendAlpha, if (!mIndependentBlendStates)
mDestBlendAlpha); {
mFunctions->blendFuncSeparate(
blendStateExt.getSrcColorIndexed(0), blendStateExt.getDstColorIndexed(0),
blendStateExt.getSrcAlphaIndexed(0), blendStateExt.getDstAlphaIndexed(0));
}
else
{
// Get DrawBufferMask of buffers with different blend factors
gl::DrawBufferMask diffMask =
mBlendStateExt.compareFactors(blendStateExt.mSrcColor, blendStateExt.mDstColor,
blendStateExt.mSrcAlpha, blendStateExt.mDstAlpha);
size_t diffCount = diffMask.count();
// Check if setting all buffers to the same value reduces the number of subsequent indexed
// commands. Implicitly handles the case when the new blend function state is the same for
// all buffers.
if (diffCount > 1)
{
bool found = false;
gl::BlendStateExt::FactorStorage::Type commonSrcColor = 0;
gl::BlendStateExt::FactorStorage::Type commonDstColor = 0;
gl::BlendStateExt::FactorStorage::Type commonSrcAlpha = 0;
gl::BlendStateExt::FactorStorage::Type commonDstAlpha = 0;
for (size_t i = 0; i < mBlendStateExt.mMaxDrawBuffers - 1; i++)
{
const gl::BlendStateExt::FactorStorage::Type tempCommonSrcColor =
blendStateExt.expandSrcColorIndexed(i);
const gl::BlendStateExt::FactorStorage::Type tempCommonDstColor =
blendStateExt.expandDstColorIndexed(i);
const gl::BlendStateExt::FactorStorage::Type tempCommonSrcAlpha =
blendStateExt.expandSrcAlphaIndexed(i);
const gl::BlendStateExt::FactorStorage::Type tempCommonDstAlpha =
blendStateExt.expandDstAlphaIndexed(i);
const gl::DrawBufferMask tempDiffMask = blendStateExt.compareFactors(
tempCommonSrcColor, tempCommonDstColor, tempCommonSrcAlpha, tempCommonDstAlpha);
const size_t tempDiffCount = tempDiffMask.count();
if (tempDiffCount < diffCount)
{
found = true;
diffMask = tempDiffMask;
diffCount = tempDiffCount;
commonSrcColor = tempCommonSrcColor;
commonDstColor = tempCommonDstColor;
commonSrcAlpha = tempCommonSrcAlpha;
commonDstAlpha = tempCommonDstAlpha;
if (tempDiffCount == 0)
{
break; // the blend factors are the same for all buffers
}
}
}
if (found)
{
mFunctions->blendFuncSeparate(
ToGLenum(gl::BlendStateExt::FactorStorage::GetValueIndexed(0, commonSrcColor)),
ToGLenum(gl::BlendStateExt::FactorStorage::GetValueIndexed(0, commonDstColor)),
ToGLenum(gl::BlendStateExt::FactorStorage::GetValueIndexed(0, commonSrcAlpha)),
ToGLenum(gl::BlendStateExt::FactorStorage::GetValueIndexed(0, commonDstAlpha)));
}
}
mLocalDirtyBits.set(gl::State::DIRTY_BIT_BLEND_FUNCS); for (size_t drawBufferIndex : diffMask)
{
mFunctions->blendFuncSeparatei(static_cast<GLuint>(drawBufferIndex),
blendStateExt.getSrcColorIndexed(drawBufferIndex),
blendStateExt.getDstColorIndexed(drawBufferIndex),
blendStateExt.getSrcAlphaIndexed(drawBufferIndex),
blendStateExt.getDstAlphaIndexed(drawBufferIndex));
}
} }
mBlendStateExt.mSrcColor = blendStateExt.mSrcColor;
mBlendStateExt.mDstColor = blendStateExt.mDstColor;
mBlendStateExt.mSrcAlpha = blendStateExt.mSrcAlpha;
mBlendStateExt.mDstAlpha = blendStateExt.mDstAlpha;
mLocalDirtyBits.set(gl::State::DIRTY_BIT_BLEND_FUNCS);
} }
void StateManagerGL::setBlendEquations(GLenum blendEquationRGB, GLenum blendEquationAlpha) void StateManagerGL::setBlendEquations(const gl::BlendStateExt &blendStateExt)
{ {
if (mBlendEquationRGB != blendEquationRGB || mBlendEquationAlpha != blendEquationAlpha) if (mBlendStateExt.mEquationColor == blendStateExt.mEquationColor &&
mBlendStateExt.mEquationAlpha == blendStateExt.mEquationAlpha)
{ {
mBlendEquationRGB = blendEquationRGB; return;
mBlendEquationAlpha = blendEquationAlpha; }
if (!mIndependentBlendStates)
{
mFunctions->blendEquationSeparate(blendStateExt.getEquationColorIndexed(0),
blendStateExt.getEquationAlphaIndexed(0));
}
else
{
// Get DrawBufferMask of buffers with different blend equations
gl::DrawBufferMask diffMask = mBlendStateExt.compareEquations(blendStateExt.mEquationColor,
blendStateExt.mEquationAlpha);
size_t diffCount = diffMask.count();
// Check if setting all buffers to the same value reduces the number of subsequent indexed
// commands. Implicitly handles the case when the new blend equation state is the same for
// all buffers.
if (diffCount > 1)
{
bool found = false;
gl::BlendStateExt::EquationStorage::Type commonEquationColor = 0;
gl::BlendStateExt::EquationStorage::Type commonEquationAlpha = 0;
for (size_t i = 0; i < mBlendStateExt.mMaxDrawBuffers - 1; i++)
{
const gl::BlendStateExt::EquationStorage::Type tempCommonEquationColor =
blendStateExt.expandEquationColorIndexed(i);
const gl::BlendStateExt::EquationStorage::Type tempCommonEquationAlpha =
blendStateExt.expandEquationAlphaIndexed(i);
const gl::DrawBufferMask tempDiffMask = blendStateExt.compareEquations(
tempCommonEquationColor, tempCommonEquationAlpha);
mFunctions->blendEquationSeparate(mBlendEquationRGB, mBlendEquationAlpha); const size_t tempDiffCount = tempDiffMask.count();
if (tempDiffCount < diffCount)
{
found = true;
diffMask = tempDiffMask;
diffCount = tempDiffCount;
commonEquationColor = tempCommonEquationColor;
commonEquationAlpha = tempCommonEquationAlpha;
if (tempDiffCount == 0)
{
break; // the new blend equations are the same for all buffers
}
}
}
if (found)
{
mFunctions->blendEquationSeparate(
ToGLenum(gl::BlendStateExt::EquationStorage::GetValueIndexed(
0, commonEquationColor)),
ToGLenum(gl::BlendStateExt::EquationStorage::GetValueIndexed(
0, commonEquationAlpha)));
}
}
mLocalDirtyBits.set(gl::State::DIRTY_BIT_BLEND_EQUATIONS); for (size_t drawBufferIndex : diffMask)
{
mFunctions->blendEquationSeparatei(
static_cast<GLuint>(drawBufferIndex),
blendStateExt.getEquationColorIndexed(drawBufferIndex),
blendStateExt.getEquationAlphaIndexed(drawBufferIndex));
}
} }
mBlendStateExt.mEquationColor = blendStateExt.mEquationColor;
mBlendStateExt.mEquationAlpha = blendStateExt.mEquationAlpha;
mLocalDirtyBits.set(gl::State::DIRTY_BIT_COLOR_MASK);
} }
void StateManagerGL::setColorMask(bool red, bool green, bool blue, bool alpha) void StateManagerGL::setColorMask(bool red, bool green, bool blue, bool alpha)
{ {
if (mColorMaskRed != red || mColorMaskGreen != green || mColorMaskBlue != blue || const gl::BlendStateExt::ColorMaskStorage::Type mask =
mColorMaskAlpha != alpha) mBlendStateExt.expandColorMaskValue(red, green, blue, alpha);
if (mBlendStateExt.mColorMask != mask)
{ {
mColorMaskRed = red; mFunctions->colorMask(red, green, blue, alpha);
mColorMaskGreen = green; mBlendStateExt.mColorMask = mask;
mColorMaskBlue = blue;
mColorMaskAlpha = alpha;
mFunctions->colorMask(mColorMaskRed, mColorMaskGreen, mColorMaskBlue, mColorMaskAlpha);
mLocalDirtyBits.set(gl::State::DIRTY_BIT_COLOR_MASK); mLocalDirtyBits.set(gl::State::DIRTY_BIT_COLOR_MASK);
} }
} }
...@@ -1562,33 +1737,36 @@ angle::Result StateManagerGL::syncState(const gl::Context *context, ...@@ -1562,33 +1737,36 @@ angle::Result StateManagerGL::syncState(const gl::Context *context,
setDepthRange(state.getNearPlane(), state.getFarPlane()); setDepthRange(state.getNearPlane(), state.getFarPlane());
break; break;
case gl::State::DIRTY_BIT_BLEND_ENABLED: case gl::State::DIRTY_BIT_BLEND_ENABLED:
setBlendEnabled(state.isBlendEnabled()); if (mIndependentBlendStates)
{
setBlendEnabledIndexed(state.getBlendEnabledDrawBufferMask());
}
else
{
setBlendEnabled(state.isBlendEnabled());
}
break; break;
case gl::State::DIRTY_BIT_BLEND_COLOR: case gl::State::DIRTY_BIT_BLEND_COLOR:
setBlendColor(state.getBlendColor()); setBlendColor(state.getBlendColor());
break; break;
case gl::State::DIRTY_BIT_BLEND_FUNCS: case gl::State::DIRTY_BIT_BLEND_FUNCS:
{ {
const auto &blendState = state.getBlendState(); setBlendFuncs(state.getBlendStateExt());
setBlendFuncs(blendState.sourceBlendRGB, blendState.destBlendRGB,
blendState.sourceBlendAlpha, blendState.destBlendAlpha);
break; break;
} }
case gl::State::DIRTY_BIT_BLEND_EQUATIONS: case gl::State::DIRTY_BIT_BLEND_EQUATIONS:
{ {
const auto &blendState = state.getBlendState(); setBlendEquations(state.getBlendStateExt());
setBlendEquations(blendState.blendEquationRGB, blendState.blendEquationAlpha);
break; break;
} }
case gl::State::DIRTY_BIT_COLOR_MASK: case gl::State::DIRTY_BIT_COLOR_MASK:
{ {
gl::Framebuffer *framebuffer = state.getDrawFramebuffer(); const gl::Framebuffer *framebuffer = state.getDrawFramebuffer();
FramebufferGL *framebufferGL = GetImplAs<FramebufferGL>(framebuffer); const FramebufferGL *framebufferGL = GetImplAs<FramebufferGL>(framebuffer);
const bool disableAlphaWrite =
framebufferGL->hasEmulatedAlphaChannelTextureAttachment();
const auto &blendState = state.getBlendState(); setColorMaskForFramebuffer(state.getBlendStateExt(), disableAlphaWrite);
setColorMaskForFramebuffer(blendState.colorMaskRed, blendState.colorMaskGreen,
blendState.colorMaskBlue, blendState.colorMaskAlpha,
framebufferGL);
break; break;
} }
case gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED: case gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED:
...@@ -1932,18 +2110,75 @@ void StateManagerGL::setFramebufferSRGBEnabledForFramebuffer(const gl::Context * ...@@ -1932,18 +2110,75 @@ void StateManagerGL::setFramebufferSRGBEnabledForFramebuffer(const gl::Context *
} }
} }
void StateManagerGL::setColorMaskForFramebuffer(bool red, void StateManagerGL::setColorMaskForFramebuffer(const gl::BlendStateExt &blendStateExt,
bool green, const bool disableAlpha)
bool blue,
bool alpha,
const FramebufferGL *framebuffer)
{ {
bool modifiedAlphaMask = alpha; bool r, g, b, a;
if (framebuffer->hasEmulatedAlphaChannelTextureAttachment())
// Given that disableAlpha can be true only on macOS backbuffers and color mask is re-synced on
// bound draw framebuffer change, switch all draw buffers color masks to avoid special case
// later.
if (!mIndependentBlendStates || disableAlpha)
{
blendStateExt.getColorMaskIndexed(0, &r, &g, &b, &a);
setColorMask(r, g, b, disableAlpha ? false : a);
return;
}
// Check if the current mask already matches the new state
if (mBlendStateExt.mColorMask == blendStateExt.mColorMask)
{ {
modifiedAlphaMask = false; return;
} }
setColorMask(red, green, blue, modifiedAlphaMask);
// Get DrawBufferMask of buffers with different color masks
gl::DrawBufferMask diffMask = mBlendStateExt.compareColorMask(blendStateExt.mColorMask);
size_t diffCount = diffMask.count();
// Check if setting all buffers to the same value reduces the number of subsequent indexed
// commands. Implicitly handles the case when the new mask is the same for all buffers.
// For instance, let's say that previously synced mask is ccccff00 and the new state is
// ffeeeeee. Instead of calling colorMaski 8 times, ANGLE can set all buffers to `e` and then
// use colorMaski only twice. On the other hand, if the new state is cceeee00, a non-indexed
// call will increase the total number of GL commands.
if (diffCount > 1)
{
bool found = false;
gl::BlendStateExt::ColorMaskStorage::Type commonColorMask = 0;
for (size_t i = 0; i < mBlendStateExt.mMaxDrawBuffers - 1; i++)
{
const gl::BlendStateExt::ColorMaskStorage::Type tempCommonColorMask =
blendStateExt.expandColorMaskIndexed(i);
const gl::DrawBufferMask tempDiffMask =
blendStateExt.compareColorMask(tempCommonColorMask);
const size_t tempDiffCount = tempDiffMask.count();
if (tempDiffCount < diffCount)
{
found = true;
diffMask = tempDiffMask;
diffCount = tempDiffCount;
commonColorMask = tempCommonColorMask;
if (tempDiffCount == 0)
{
break; // the new mask is the same for all buffers
}
}
}
if (found)
{
gl::BlendStateExt::UnpackColorMask(commonColorMask, &r, &g, &b, &a);
mFunctions->colorMask(r, g, b, a);
}
}
for (size_t drawBufferIndex : diffMask)
{
blendStateExt.getColorMaskIndexed(drawBufferIndex, &r, &g, &b, &a);
mFunctions->colorMaski(static_cast<GLuint>(drawBufferIndex), r, g, b, a);
}
mBlendStateExt.mColorMask = blendStateExt.mColorMask;
mLocalDirtyBits.set(gl::State::DIRTY_BIT_COLOR_MASK);
} }
void StateManagerGL::setDitherEnabled(bool enabled) void StateManagerGL::setDitherEnabled(bool enabled)
......
...@@ -89,12 +89,10 @@ class StateManagerGL final : angle::NonCopyable ...@@ -89,12 +89,10 @@ class StateManagerGL final : angle::NonCopyable
void setDepthRange(float near, float far); void setDepthRange(float near, float far);
void setBlendEnabled(bool enabled); void setBlendEnabled(bool enabled);
void setBlendEnabledIndexed(const gl::DrawBufferMask blendEnabledMask);
void setBlendColor(const gl::ColorF &blendColor); void setBlendColor(const gl::ColorF &blendColor);
void setBlendFuncs(GLenum sourceBlendRGB, void setBlendFuncs(const gl::BlendStateExt &blendStateExt);
GLenum destBlendRGB, void setBlendEquations(const gl::BlendStateExt &blendStateExt);
GLenum sourceBlendAlpha,
GLenum destBlendAlpha);
void setBlendEquations(GLenum blendEquationRGB, GLenum blendEquationAlpha);
void setColorMask(bool red, bool green, bool blue, bool alpha); void setColorMask(bool red, bool green, bool blue, bool alpha);
void setSampleAlphaToCoverageEnabled(bool enabled); void setSampleAlphaToCoverageEnabled(bool enabled);
void setSampleCoverageEnabled(bool enabled); void setSampleCoverageEnabled(bool enabled);
...@@ -137,11 +135,8 @@ class StateManagerGL final : angle::NonCopyable ...@@ -137,11 +135,8 @@ class StateManagerGL final : angle::NonCopyable
void setFramebufferSRGBEnabledForFramebuffer(const gl::Context *context, void setFramebufferSRGBEnabledForFramebuffer(const gl::Context *context,
bool enabled, bool enabled,
const FramebufferGL *framebuffer); const FramebufferGL *framebuffer);
void setColorMaskForFramebuffer(bool red, void setColorMaskForFramebuffer(const gl::BlendStateExt &blendStateExt,
bool green, const bool disableAlpha);
bool blue,
bool alpha,
const FramebufferGL *framebuffer);
void setDitherEnabled(bool enabled); void setDitherEnabled(bool enabled);
...@@ -279,18 +274,10 @@ class StateManagerGL final : angle::NonCopyable ...@@ -279,18 +274,10 @@ class StateManagerGL final : angle::NonCopyable
float mNear; float mNear;
float mFar; float mFar;
bool mBlendEnabled;
gl::ColorF mBlendColor; gl::ColorF mBlendColor;
GLenum mSourceBlendRGB; gl::BlendStateExt mBlendStateExt;
GLenum mDestBlendRGB; const bool mIndependentBlendStates;
GLenum mSourceBlendAlpha;
GLenum mDestBlendAlpha;
GLenum mBlendEquationRGB;
GLenum mBlendEquationAlpha;
bool mColorMaskRed;
bool mColorMaskGreen;
bool mColorMaskBlue;
bool mColorMaskAlpha;
bool mSampleAlphaToCoverageEnabled; bool mSampleAlphaToCoverageEnabled;
bool mSampleCoverageEnabled; bool mSampleCoverageEnabled;
float mSampleCoverageValue; float mSampleCoverageValue;
......
...@@ -1162,7 +1162,16 @@ void GenerateCaps(const FunctionsGL *functions, ...@@ -1162,7 +1162,16 @@ void GenerateCaps(const FunctionsGL *functions,
extensions->drawBuffers = functions->isAtLeastGL(gl::Version(2, 0)) || extensions->drawBuffers = functions->isAtLeastGL(gl::Version(2, 0)) ||
functions->hasGLExtension("ARB_draw_buffers") || functions->hasGLExtension("ARB_draw_buffers") ||
functions->hasGLESExtension("GL_EXT_draw_buffers"); functions->hasGLESExtension("GL_EXT_draw_buffers");
extensions->textureStorage = functions->standard == STANDARD_GL_DESKTOP || extensions->drawBuffersIndexedEXT =
!features.disableDrawBuffersIndexed.enabled &&
(functions->isAtLeastGL(gl::Version(4, 0)) ||
(functions->hasGLExtension("GL_EXT_draw_buffers2") &&
functions->hasGLExtension("GL_ARB_draw_buffers_blend")) ||
functions->isAtLeastGLES(gl::Version(3, 2)) ||
functions->hasGLESExtension("GL_OES_draw_buffers_indexed") ||
functions->hasGLESExtension("GL_EXT_draw_buffers_indexed"));
extensions->drawBuffersIndexedOES = extensions->drawBuffersIndexedEXT;
extensions->textureStorage = functions->standard == STANDARD_GL_DESKTOP ||
functions->hasGLESExtension("GL_EXT_texture_storage"); functions->hasGLESExtension("GL_EXT_texture_storage");
extensions->textureFilterAnisotropic = extensions->textureFilterAnisotropic =
functions->hasGLExtension("GL_EXT_texture_filter_anisotropic") || functions->hasGLExtension("GL_EXT_texture_filter_anisotropic") ||
...@@ -1705,6 +1714,8 @@ void InitializeFeatures(const FunctionsGL *functions, angle::FeaturesGL *feature ...@@ -1705,6 +1714,8 @@ void InitializeFeatures(const FunctionsGL *functions, angle::FeaturesGL *feature
// Workaround for incorrect sampling from DXT1 sRGB textures in Intel OpenGL on Windows. // Workaround for incorrect sampling from DXT1 sRGB textures in Intel OpenGL on Windows.
ANGLE_FEATURE_CONDITION(features, avoidDXT1sRGBTextureFormat, IsWindows() && isIntel); ANGLE_FEATURE_CONDITION(features, avoidDXT1sRGBTextureFormat, IsWindows() && isIntel);
ANGLE_FEATURE_CONDITION(features, disableDrawBuffersIndexed, IsWindows() && isAMD);
ANGLE_FEATURE_CONDITION( ANGLE_FEATURE_CONDITION(
features, disableSemaphoreFd, features, disableSemaphoreFd,
IsLinux() && isAMD && isMesa && mesaVersion < (std::array<int, 3>{19, 3, 5})); IsLinux() && isAMD && isMesa && mesaVersion < (std::array<int, 3>{19, 3, 5}));
......
...@@ -852,7 +852,7 @@ TEST_P(ClearTestES3, MaskedIndexedClearMultipleAttachments) ...@@ -852,7 +852,7 @@ TEST_P(ClearTestES3, MaskedIndexedClearMultipleAttachments)
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_draw_buffers_indexed")); ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_draw_buffers_indexed"));
constexpr uint32_t kSize = 16; constexpr uint32_t kSize = 16;
constexpr uint32_t kAttachmentCount = 2; constexpr uint32_t kAttachmentCount = 4;
std::vector<unsigned char> pixelData(kSize * kSize * 4, 255); std::vector<unsigned char> pixelData(kSize * kSize * 4, 255);
glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]); glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]);
...@@ -882,7 +882,8 @@ TEST_P(ClearTestES3, MaskedIndexedClearMultipleAttachments) ...@@ -882,7 +882,8 @@ TEST_P(ClearTestES3, MaskedIndexedClearMultipleAttachments)
// Block blue channel for all attachements // Block blue channel for all attachements
glColorMask(GL_TRUE, GL_TRUE, GL_FALSE, GL_TRUE); glColorMask(GL_TRUE, GL_TRUE, GL_FALSE, GL_TRUE);
// Unblock blue channel for attachement 1 // Unblock blue channel for attachments 0 and 1
glColorMaskiOES(0, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glColorMaskiOES(1, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glColorMaskiOES(1, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]); glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
...@@ -895,12 +896,12 @@ TEST_P(ClearTestES3, MaskedIndexedClearMultipleAttachments) ...@@ -895,12 +896,12 @@ TEST_P(ClearTestES3, MaskedIndexedClearMultipleAttachments)
glReadBuffer(GL_COLOR_ATTACHMENT0 + i); glReadBuffer(GL_COLOR_ATTACHMENT0 + i);
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
const GLColor attachementColor = (i == 1) ? clearColor : clearColorMasked; const GLColor attachmentColor = (i > 1) ? clearColorMasked : clearColor;
EXPECT_PIXEL_COLOR_EQ(0, 0, attachementColor); EXPECT_PIXEL_COLOR_EQ(0, 0, attachmentColor);
EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, attachementColor); EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, attachmentColor);
EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, attachementColor); EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, attachmentColor);
EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, attachementColor); EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, attachmentColor);
EXPECT_PIXEL_COLOR_EQ(kSize / 2, kSize / 2, attachementColor); EXPECT_PIXEL_COLOR_EQ(kSize / 2, kSize / 2, attachmentColor);
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment