Commit 6cc845bb by Brandon Schade Committed by Commit Bot

Vulkan: Add support for EXT_blend_func_extended

This implementation utilizes vulkan's dualSrcBlend feature. Expose this extension if the underlying vulkan backend allows the use of this feature. Test: angle_end2end_tests --gtest_filter=EXTBlendFuncExtendedDrawTest* Bug: angleproject:5074 Change-Id: I7d2f611df89d65e5cac35158cb5f41a0ebd58aae Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2593151 Commit-Queue: Brandon Schade <b.schade@samsung.com> Commit-Queue: Mohan Maiya <m.maiya@samsung.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org>
parent 926d1cea
...@@ -1009,6 +1009,8 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root, ...@@ -1009,6 +1009,8 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root,
bool hasGLFragData = false; bool hasGLFragData = false;
bool usePreRotation = (compileOptions & SH_ADD_PRE_ROTATION) != 0; bool usePreRotation = (compileOptions & SH_ADD_PRE_ROTATION) != 0;
bool hasGLSampleMask = false; bool hasGLSampleMask = false;
bool hasGLSecondaryFragColor = false;
bool hasGLSecondaryFragData = false;
for (const ShaderVariable &outputVar : mOutputVariables) for (const ShaderVariable &outputVar : mOutputVariables)
{ {
...@@ -1030,11 +1032,24 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root, ...@@ -1030,11 +1032,24 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root,
hasGLSampleMask = true; hasGLSampleMask = true;
continue; continue;
} }
else if (outputVar.name == "gl_SecondaryFragColorEXT")
{
ASSERT(!hasGLSecondaryFragColor);
hasGLSecondaryFragColor = true;
continue;
}
else if (outputVar.name == "gl_SecondaryFragDataEXT")
{
ASSERT(!hasGLSecondaryFragData);
hasGLSecondaryFragData = true;
continue;
}
} }
// Declare gl_FragColor and glFragData as webgl_FragColor and webgl_FragData // Declare gl_FragColor and glFragData as webgl_FragColor and webgl_FragData
// if it's core profile shaders and they are used. // if it's core profile shaders and they are used.
ASSERT(!(hasGLFragColor && hasGLFragData)); ASSERT(!((hasGLFragColor || hasGLSecondaryFragColor) &&
(hasGLFragData || hasGLSecondaryFragData)));
if (hasGLFragColor) if (hasGLFragColor)
{ {
sink << "layout(location = 0) out vec4 webgl_FragColor;\n"; sink << "layout(location = 0) out vec4 webgl_FragColor;\n";
...@@ -1043,6 +1058,15 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root, ...@@ -1043,6 +1058,15 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root,
{ {
sink << "layout(location = 0) out vec4 webgl_FragData[gl_MaxDrawBuffers];\n"; sink << "layout(location = 0) out vec4 webgl_FragData[gl_MaxDrawBuffers];\n";
} }
if (hasGLSecondaryFragColor)
{
sink << "layout(location = 0, index = 1) out vec4 angle_SecondaryFragColor;\n";
}
if (hasGLSecondaryFragData)
{
sink << "layout(location = 0, index = 1) out vec4 angle_SecondaryFragData["
<< getResources().MaxDualSourceDrawBuffers << "];\n";
}
if (usesPointCoord) if (usesPointCoord)
{ {
......
...@@ -1794,8 +1794,6 @@ void Program::unlink() ...@@ -1794,8 +1794,6 @@ void Program::unlink()
mState.mUniformLocations.clear(); mState.mUniformLocations.clear();
mState.mBufferVariables.clear(); mState.mBufferVariables.clear();
mState.mActiveUniformBlockBindings.reset();
mState.mSecondaryOutputLocations.clear();
mState.mOutputVariableTypes.clear(); mState.mOutputVariableTypes.clear();
mState.mDrawBufferTypeMask.reset(); mState.mDrawBufferTypeMask.reset();
mState.mYUVOutput = false; mState.mYUVOutput = false;
...@@ -2434,7 +2432,7 @@ GLint Program::getFragDataLocation(const std::string &name) const ...@@ -2434,7 +2432,7 @@ GLint Program::getFragDataLocation(const std::string &name) const
return primaryLocation; return primaryLocation;
} }
return GetVariableLocation(mState.mExecutable->getOutputVariables(), return GetVariableLocation(mState.mExecutable->getOutputVariables(),
mState.mSecondaryOutputLocations, name); mState.mExecutable->getSecondaryOutputLocations(), name);
} }
GLint Program::getFragDataIndex(const std::string &name) const GLint Program::getFragDataIndex(const std::string &name) const
...@@ -2446,7 +2444,7 @@ GLint Program::getFragDataIndex(const std::string &name) const ...@@ -2446,7 +2444,7 @@ GLint Program::getFragDataIndex(const std::string &name) const
return 0; return 0;
} }
if (GetVariableLocation(mState.mExecutable->getOutputVariables(), if (GetVariableLocation(mState.mExecutable->getOutputVariables(),
mState.mSecondaryOutputLocations, name) != -1) mState.mExecutable->getSecondaryOutputLocations(), name) != -1)
{ {
return 1; return 1;
} }
...@@ -3144,7 +3142,8 @@ void Program::bindUniformBlock(UniformBlockIndex uniformBlockIndex, GLuint unifo ...@@ -3144,7 +3142,8 @@ void Program::bindUniformBlock(UniformBlockIndex uniformBlockIndex, GLuint unifo
{ {
ASSERT(!mLinkingState); ASSERT(!mLinkingState);
mState.mExecutable->mUniformBlocks[uniformBlockIndex.value].binding = uniformBlockBinding; mState.mExecutable->mUniformBlocks[uniformBlockIndex.value].binding = uniformBlockBinding;
mState.mActiveUniformBlockBindings.set(uniformBlockIndex.value, uniformBlockBinding != 0); mState.mExecutable->mActiveUniformBlockBindings.set(uniformBlockIndex.value,
uniformBlockBinding != 0);
mDirtyBits.set(DIRTY_BIT_UNIFORM_BLOCK_BINDING_0 + uniformBlockIndex.value); mDirtyBits.set(DIRTY_BIT_UNIFORM_BLOCK_BINDING_0 + uniformBlockIndex.value);
} }
...@@ -4174,7 +4173,7 @@ bool Program::linkOutputVariables(const Caps &caps, ...@@ -4174,7 +4173,7 @@ bool Program::linkOutputVariables(const Caps &caps,
// Get the API index that corresponds to this exact binding. // Get the API index that corresponds to this exact binding.
// This index may differ from the index used for the array's base. // This index may differ from the index used for the array's base.
auto &outputLocations = mFragmentOutputIndexes.getBindingByName(binding.first) == 1 auto &outputLocations = mFragmentOutputIndexes.getBindingByName(binding.first) == 1
? mState.mSecondaryOutputLocations ? mState.mExecutable->mSecondaryOutputLocations
: mState.mExecutable->mOutputLocations; : mState.mExecutable->mOutputLocations;
unsigned int location = binding.second.location; unsigned int location = binding.second.location;
VariableLocation locationInfo(arrayIndex, outputVariableIndex); VariableLocation locationInfo(arrayIndex, outputVariableIndex);
...@@ -4217,7 +4216,7 @@ bool Program::linkOutputVariables(const Caps &caps, ...@@ -4217,7 +4216,7 @@ bool Program::linkOutputVariables(const Caps &caps,
unsigned int baseLocation = static_cast<unsigned int>(fixedLocation); unsigned int baseLocation = static_cast<unsigned int>(fixedLocation);
auto &outputLocations = isOutputSecondaryForLink(outputVariable) auto &outputLocations = isOutputSecondaryForLink(outputVariable)
? mState.mSecondaryOutputLocations ? mState.mExecutable->mSecondaryOutputLocations
: mState.mExecutable->mOutputLocations; : mState.mExecutable->mOutputLocations;
// GLSL ES 3.10 section 4.3.6: Output variables cannot be arrays of arrays or arrays of // GLSL ES 3.10 section 4.3.6: Output variables cannot be arrays of arrays or arrays of
...@@ -4241,7 +4240,7 @@ bool Program::linkOutputVariables(const Caps &caps, ...@@ -4241,7 +4240,7 @@ bool Program::linkOutputVariables(const Caps &caps,
// we got the output variables. The spec isn't clear on what kind of algorithm is required for // we got the output variables. The spec isn't clear on what kind of algorithm is required for
// finding locations for the output variables, so this should be acceptable at least for now. // finding locations for the output variables, so this should be acceptable at least for now.
GLuint maxLocation = static_cast<GLuint>(caps.maxDrawBuffers); GLuint maxLocation = static_cast<GLuint>(caps.maxDrawBuffers);
if (!mState.mSecondaryOutputLocations.empty()) if (!mState.mExecutable->getSecondaryOutputLocations().empty())
{ {
// EXT_blend_func_extended: Program outputs will be validated against // EXT_blend_func_extended: Program outputs will be validated against
// MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT if there's even one output with index one. // MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT if there's even one output with index one.
...@@ -4261,7 +4260,7 @@ bool Program::linkOutputVariables(const Caps &caps, ...@@ -4261,7 +4260,7 @@ bool Program::linkOutputVariables(const Caps &caps,
int fixedLocation = getOutputLocationForLink(outputVariable); int fixedLocation = getOutputLocationForLink(outputVariable);
auto &outputLocations = isOutputSecondaryForLink(outputVariable) auto &outputLocations = isOutputSecondaryForLink(outputVariable)
? mState.mSecondaryOutputLocations ? mState.mExecutable->mSecondaryOutputLocations
: mState.mExecutable->mOutputLocations; : mState.mExecutable->mOutputLocations;
unsigned int baseLocation = 0; unsigned int baseLocation = 0;
unsigned int elementCount = outputVariable.getBasicTypeElementCount(); unsigned int elementCount = outputVariable.getBasicTypeElementCount();
...@@ -4581,32 +4580,6 @@ angle::Result Program::serialize(const Context *context, angle::MemoryBuffer *bi ...@@ -4581,32 +4580,6 @@ angle::Result Program::serialize(const Context *context, angle::MemoryBuffer *bi
stream.writeBool(mState.mEarlyFramentTestsOptimization); stream.writeBool(mState.mEarlyFramentTestsOptimization);
stream.writeInt(mState.mSpecConstUsageBits.bits()); stream.writeInt(mState.mSpecConstUsageBits.bits());
stream.writeInt(mState.getProgramInputs().size());
for (const sh::ShaderVariable &attrib : mState.getProgramInputs())
{
WriteShaderVar(&stream, attrib);
stream.writeInt(attrib.location);
}
stream.writeInt(mState.getUniforms().size());
for (const LinkedUniform &uniform : mState.getUniforms())
{
WriteShaderVar(&stream, uniform);
// FIXME: referenced
stream.writeInt(uniform.bufferIndex);
WriteBlockMemberInfo(&stream, uniform.blockInfo);
stream.writeIntVector(uniform.outerArraySizes);
// Active shader info
for (ShaderType shaderType : gl::AllShaderTypes())
{
stream.writeBool(uniform.isActive(shaderType));
}
}
stream.writeInt(mState.getUniformLocations().size()); stream.writeInt(mState.getUniformLocations().size());
for (const auto &variable : mState.getUniformLocations()) for (const auto &variable : mState.getUniformLocations())
{ {
...@@ -4615,31 +4588,12 @@ angle::Result Program::serialize(const Context *context, angle::MemoryBuffer *bi ...@@ -4615,31 +4588,12 @@ angle::Result Program::serialize(const Context *context, angle::MemoryBuffer *bi
stream.writeBool(variable.ignored); stream.writeBool(variable.ignored);
} }
stream.writeInt(mState.getUniformBlocks().size());
for (const InterfaceBlock &uniformBlock : mState.getUniformBlocks())
{
WriteInterfaceBlock(&stream, uniformBlock);
}
stream.writeInt(mState.getBufferVariables().size()); stream.writeInt(mState.getBufferVariables().size());
for (const BufferVariable &bufferVariable : mState.getBufferVariables()) for (const BufferVariable &bufferVariable : mState.getBufferVariables())
{ {
WriteBufferVariable(&stream, bufferVariable); WriteBufferVariable(&stream, bufferVariable);
} }
stream.writeInt(mState.getShaderStorageBlocks().size());
for (const InterfaceBlock &shaderStorageBlock : mState.getShaderStorageBlocks())
{
WriteInterfaceBlock(&stream, shaderStorageBlock);
}
stream.writeInt(mState.mExecutable->mAtomicCounterBuffers.size());
for (const AtomicCounterBuffer &atomicCounterBuffer :
mState.mExecutable->getAtomicCounterBuffers())
{
WriteShaderVariableBuffer(&stream, atomicCounterBuffer);
}
// Warn the app layer if saving a binary with unsupported transform feedback. // Warn the app layer if saving a binary with unsupported transform feedback.
if (!mState.getLinkedTransformFeedbackVaryings().empty() && if (!mState.getLinkedTransformFeedbackVaryings().empty() &&
context->getFrontendFeatures().disableProgramCachingForTransformFeedback.enabled) context->getFrontendFeatures().disableProgramCachingForTransformFeedback.enabled)
...@@ -4648,42 +4602,6 @@ angle::Result Program::serialize(const Context *context, angle::MemoryBuffer *bi ...@@ -4648,42 +4602,6 @@ angle::Result Program::serialize(const Context *context, angle::MemoryBuffer *bi
"driver."; "driver.";
} }
stream.writeInt(mState.getLinkedTransformFeedbackVaryings().size());
for (const auto &var : mState.getLinkedTransformFeedbackVaryings())
{
stream.writeIntVector(var.arraySizes);
stream.writeInt(var.type);
stream.writeString(var.name);
stream.writeIntOrNegOne(var.arrayIndex);
}
stream.writeInt(mState.getTransformFeedbackBufferMode());
stream.writeInt(mState.getOutputVariables().size());
for (const sh::ShaderVariable &output : mState.getOutputVariables())
{
WriteShaderVar(&stream, output);
stream.writeInt(output.location);
stream.writeInt(output.index);
}
stream.writeInt(mState.getOutputLocations().size());
for (const auto &outputVar : mState.getOutputLocations())
{
stream.writeInt(outputVar.arrayIndex);
stream.writeIntOrNegOne(outputVar.index);
stream.writeBool(outputVar.ignored);
}
stream.writeInt(mState.getSecondaryOutputLocations().size());
for (const auto &outputVar : mState.getSecondaryOutputLocations())
{
stream.writeInt(outputVar.arrayIndex);
stream.writeIntOrNegOne(outputVar.index);
stream.writeBool(outputVar.ignored);
}
stream.writeInt(mState.mOutputVariableTypes.size()); stream.writeInt(mState.mOutputVariableTypes.size());
for (const auto &outputVariableType : mState.mOutputVariableTypes) for (const auto &outputVariableType : mState.mOutputVariableTypes)
{ {
...@@ -4698,35 +4616,6 @@ angle::Result Program::serialize(const Context *context, angle::MemoryBuffer *bi ...@@ -4698,35 +4616,6 @@ angle::Result Program::serialize(const Context *context, angle::MemoryBuffer *bi
stream.writeBool(mState.isYUVOutput()); stream.writeBool(mState.isYUVOutput());
stream.writeInt(mState.getDefaultUniformRange().low());
stream.writeInt(mState.getDefaultUniformRange().high());
stream.writeInt(mState.getSamplerUniformRange().low());
stream.writeInt(mState.getSamplerUniformRange().high());
stream.writeInt(mState.getSamplerBindings().size());
for (const auto &samplerBinding : mState.getSamplerBindings())
{
stream.writeEnum(samplerBinding.textureType);
stream.writeInt(samplerBinding.samplerType);
stream.writeEnum(samplerBinding.format);
stream.writeInt(samplerBinding.boundTextureUnits.size());
}
stream.writeInt(mState.getImageUniformRange().low());
stream.writeInt(mState.getImageUniformRange().high());
stream.writeInt(mState.getImageBindings().size());
for (const auto &imageBinding : mState.getImageBindings())
{
stream.writeInt(imageBinding.boundImageUnits.size());
stream.writeInt(static_cast<unsigned int>(imageBinding.textureType));
for (size_t i = 0; i < imageBinding.boundImageUnits.size(); ++i)
{
stream.writeInt(imageBinding.boundImageUnits[i]);
}
}
stream.writeInt(mState.getAtomicCounterUniformRange().low()); stream.writeInt(mState.getAtomicCounterUniformRange().low());
stream.writeInt(mState.getAtomicCounterUniformRange().high()); stream.writeInt(mState.getAtomicCounterUniformRange().high());
...@@ -4775,39 +4664,6 @@ angle::Result Program::deserialize(const Context *context, ...@@ -4775,39 +4664,6 @@ angle::Result Program::deserialize(const Context *context,
mState.mEarlyFramentTestsOptimization = stream.readBool(); mState.mEarlyFramentTestsOptimization = stream.readBool();
mState.mSpecConstUsageBits = rx::SpecConstUsageBits(stream.readInt<uint32_t>()); mState.mSpecConstUsageBits = rx::SpecConstUsageBits(stream.readInt<uint32_t>());
size_t attribCount = stream.readInt<size_t>();
ASSERT(mState.mExecutable->getProgramInputs().empty());
for (size_t attribIndex = 0; attribIndex < attribCount; ++attribIndex)
{
sh::ShaderVariable attrib;
LoadShaderVar(&stream, &attrib);
attrib.location = stream.readInt<int>();
mState.mExecutable->mProgramInputs.push_back(attrib);
}
size_t uniformCount = stream.readInt<size_t>();
ASSERT(mState.mExecutable->getUniforms().empty());
for (size_t uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
{
LinkedUniform uniform;
LoadShaderVar(&stream, &uniform);
uniform.bufferIndex = stream.readInt<int>();
LoadBlockMemberInfo(&stream, &uniform.blockInfo);
stream.readIntVector<unsigned int>(&uniform.outerArraySizes);
uniform.typeInfo = &GetUniformTypeInfo(uniform.type);
// Active shader info
for (ShaderType shaderType : gl::AllShaderTypes())
{
uniform.setActive(shaderType, stream.readBool());
}
mState.mExecutable->mUniforms.push_back(uniform);
}
const size_t uniformIndexCount = stream.readInt<size_t>(); const size_t uniformIndexCount = stream.readInt<size_t>();
ASSERT(mState.mUniformLocations.empty()); ASSERT(mState.mUniformLocations.empty());
for (size_t uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount; ++uniformIndexIndex) for (size_t uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount; ++uniformIndexIndex)
...@@ -4820,17 +4676,6 @@ angle::Result Program::deserialize(const Context *context, ...@@ -4820,17 +4676,6 @@ angle::Result Program::deserialize(const Context *context,
mState.mUniformLocations.push_back(variable); mState.mUniformLocations.push_back(variable);
} }
size_t uniformBlockCount = stream.readInt<size_t>();
ASSERT(mState.mExecutable->getUniformBlocks().empty());
for (size_t uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount; ++uniformBlockIndex)
{
InterfaceBlock uniformBlock;
LoadInterfaceBlock(&stream, &uniformBlock);
mState.mExecutable->mUniformBlocks.push_back(uniformBlock);
mState.mActiveUniformBlockBindings.set(uniformBlockIndex, uniformBlock.binding != 0);
}
size_t bufferVariableCount = stream.readInt<size_t>(); size_t bufferVariableCount = stream.readInt<size_t>();
ASSERT(mState.mBufferVariables.empty()); ASSERT(mState.mBufferVariables.empty());
for (size_t bufferVarIndex = 0; bufferVarIndex < bufferVariableCount; ++bufferVarIndex) for (size_t bufferVarIndex = 0; bufferVarIndex < bufferVariableCount; ++bufferVarIndex)
...@@ -4840,93 +4685,6 @@ angle::Result Program::deserialize(const Context *context, ...@@ -4840,93 +4685,6 @@ angle::Result Program::deserialize(const Context *context,
mState.mBufferVariables.push_back(bufferVariable); mState.mBufferVariables.push_back(bufferVariable);
} }
size_t shaderStorageBlockCount = stream.readInt<size_t>();
ASSERT(mState.mExecutable->getShaderStorageBlocks().empty());
for (size_t shaderStorageBlockIndex = 0; shaderStorageBlockIndex < shaderStorageBlockCount;
++shaderStorageBlockIndex)
{
InterfaceBlock shaderStorageBlock;
LoadInterfaceBlock(&stream, &shaderStorageBlock);
if (getExecutable().isCompute())
{
mState.mExecutable->mComputeShaderStorageBlocks.push_back(shaderStorageBlock);
}
else
{
mState.mExecutable->mGraphicsShaderStorageBlocks.push_back(shaderStorageBlock);
}
}
size_t atomicCounterBufferCount = stream.readInt<size_t>();
ASSERT(mState.mExecutable->getAtomicCounterBuffers().empty());
for (size_t bufferIndex = 0; bufferIndex < atomicCounterBufferCount; ++bufferIndex)
{
AtomicCounterBuffer atomicCounterBuffer;
LoadShaderVariableBuffer(&stream, &atomicCounterBuffer);
mState.mExecutable->mAtomicCounterBuffers.push_back(atomicCounterBuffer);
}
size_t transformFeedbackVaryingCount = stream.readInt<size_t>();
// Reject programs that use transform feedback varyings if the hardware cannot support them.
if (transformFeedbackVaryingCount > 0 &&
context->getFrontendFeatures().disableProgramCachingForTransformFeedback.enabled)
{
infoLog << "Current driver does not support transform feedback in binary programs.";
return angle::Result::Stop;
}
ASSERT(mState.mExecutable->mLinkedTransformFeedbackVaryings.empty());
for (size_t transformFeedbackVaryingIndex = 0;
transformFeedbackVaryingIndex < transformFeedbackVaryingCount;
++transformFeedbackVaryingIndex)
{
sh::ShaderVariable varying;
stream.readIntVector<unsigned int>(&varying.arraySizes);
stream.readInt(&varying.type);
stream.readString(&varying.name);
GLuint arrayIndex = stream.readInt<GLuint>();
mState.mExecutable->mLinkedTransformFeedbackVaryings.emplace_back(varying, arrayIndex);
}
stream.readInt(&mState.mExecutable->mTransformFeedbackBufferMode);
size_t outputCount = stream.readInt<size_t>();
ASSERT(mState.mExecutable->getOutputVariables().empty());
for (size_t outputIndex = 0; outputIndex < outputCount; ++outputIndex)
{
sh::ShaderVariable output;
LoadShaderVar(&stream, &output);
output.location = stream.readInt<int>();
output.index = stream.readInt<int>();
mState.mExecutable->mOutputVariables.push_back(output);
}
size_t outputVarCount = stream.readInt<size_t>();
ASSERT(mState.mExecutable->getOutputLocations().empty());
for (size_t outputIndex = 0; outputIndex < outputVarCount; ++outputIndex)
{
VariableLocation locationData;
stream.readInt(&locationData.arrayIndex);
stream.readInt(&locationData.index);
stream.readBool(&locationData.ignored);
mState.mExecutable->mOutputLocations.push_back(locationData);
}
size_t secondaryOutputVarCount = stream.readInt<size_t>();
ASSERT(mState.mSecondaryOutputLocations.empty());
for (size_t outputIndex = 0; outputIndex < secondaryOutputVarCount; ++outputIndex)
{
VariableLocation locationData;
stream.readInt(&locationData.arrayIndex);
stream.readInt(&locationData.index);
stream.readBool(&locationData.ignored);
mState.mSecondaryOutputLocations.push_back(locationData);
}
size_t outputTypeCount = stream.readInt<size_t>(); size_t outputTypeCount = stream.readInt<size_t>();
for (size_t outputIndex = 0; outputIndex < outputTypeCount; ++outputIndex) for (size_t outputIndex = 0; outputIndex < outputTypeCount; ++outputIndex)
{ {
...@@ -4942,48 +4700,6 @@ angle::Result Program::deserialize(const Context *context, ...@@ -4942,48 +4700,6 @@ angle::Result Program::deserialize(const Context *context,
stream.readBool(&mState.mYUVOutput); stream.readBool(&mState.mYUVOutput);
unsigned int defaultUniformRangeLow = stream.readInt<unsigned int>();
unsigned int defaultUniformRangeHigh = stream.readInt<unsigned int>();
mState.mExecutable->mDefaultUniformRange =
RangeUI(defaultUniformRangeLow, defaultUniformRangeHigh);
unsigned int samplerRangeLow = stream.readInt<unsigned int>();
unsigned int samplerRangeHigh = stream.readInt<unsigned int>();
mState.mExecutable->mSamplerUniformRange = RangeUI(samplerRangeLow, samplerRangeHigh);
size_t samplerCount = stream.readInt<size_t>();
for (size_t samplerIndex = 0; samplerIndex < samplerCount; ++samplerIndex)
{
TextureType textureType = stream.readEnum<TextureType>();
GLenum samplerType = stream.readInt<GLenum>();
SamplerFormat format = stream.readEnum<SamplerFormat>();
size_t bindingCount = stream.readInt<size_t>();
mState.mExecutable->mSamplerBindings.emplace_back(textureType, samplerType, format,
bindingCount);
}
unsigned int imageRangeLow = stream.readInt<unsigned int>();
unsigned int imageRangeHigh = stream.readInt<unsigned int>();
mState.mExecutable->mImageUniformRange = RangeUI(imageRangeLow, imageRangeHigh);
size_t imageBindingCount = stream.readInt<size_t>();
for (size_t imageIndex = 0; imageIndex < imageBindingCount; ++imageIndex)
{
size_t elementCount = stream.readInt<size_t>();
TextureType textureType = static_cast<TextureType>(stream.readInt<unsigned int>());
ImageBinding imageBinding(elementCount, textureType);
for (size_t elementIndex = 0; elementIndex < elementCount; ++elementIndex)
{
imageBinding.boundImageUnits[elementIndex] = stream.readInt<unsigned int>();
}
if (getExecutable().isCompute())
{
mState.mExecutable->mComputeImageBindings.emplace_back(imageBinding);
}
else
{
mState.mExecutable->mGraphicsImageBindings.emplace_back(imageBinding);
}
}
unsigned int atomicCounterRangeLow = stream.readInt<unsigned int>(); unsigned int atomicCounterRangeLow = stream.readInt<unsigned int>();
unsigned int atomicCounterRangeHigh = stream.readInt<unsigned int>(); unsigned int atomicCounterRangeHigh = stream.readInt<unsigned int>();
mState.mAtomicCounterUniformRange = RangeUI(atomicCounterRangeLow, atomicCounterRangeHigh); mState.mAtomicCounterUniformRange = RangeUI(atomicCounterRangeLow, atomicCounterRangeHigh);
...@@ -4991,6 +4707,14 @@ angle::Result Program::deserialize(const Context *context, ...@@ -4991,6 +4707,14 @@ angle::Result Program::deserialize(const Context *context,
static_assert(static_cast<unsigned long>(ShaderType::EnumCount) <= sizeof(unsigned long) * 8, static_assert(static_cast<unsigned long>(ShaderType::EnumCount) <= sizeof(unsigned long) * 8,
"Too many shader types"); "Too many shader types");
// Reject programs that use transform feedback varyings if the hardware cannot support them.
if (mState.mExecutable->getLinkedTransformFeedbackVaryings().size() > 0 &&
context->getFrontendFeatures().disableProgramCachingForTransformFeedback.enabled)
{
infoLog << "Current driver does not support transform feedback in binary programs.";
return angle::Result::Stop;
}
if (!mState.mAttachedShaders[ShaderType::Compute]) if (!mState.mAttachedShaders[ShaderType::Compute])
{ {
mState.mExecutable->updateTransformFeedbackStrides(); mState.mExecutable->updateTransformFeedbackStrides();
......
...@@ -108,6 +108,12 @@ void LoadBlockMemberInfo(BinaryInputStream *stream, sh::BlockMemberInfo *var); ...@@ -108,6 +108,12 @@ void LoadBlockMemberInfo(BinaryInputStream *stream, sh::BlockMemberInfo *var);
void WriteShaderVar(BinaryOutputStream *stream, const sh::ShaderVariable &var); void WriteShaderVar(BinaryOutputStream *stream, const sh::ShaderVariable &var);
void LoadShaderVar(BinaryInputStream *stream, sh::ShaderVariable *var); void LoadShaderVar(BinaryInputStream *stream, sh::ShaderVariable *var);
void WriteInterfaceBlock(BinaryOutputStream *stream, const InterfaceBlock &block);
void LoadInterfaceBlock(BinaryInputStream *stream, InterfaceBlock *block);
void WriteShaderVariableBuffer(BinaryOutputStream *stream, const ShaderVariableBuffer &var);
void LoadShaderVariableBuffer(BinaryInputStream *stream, ShaderVariableBuffer *var);
// Struct used for correlating uniforms/elements of uniform arrays to handles // Struct used for correlating uniforms/elements of uniform arrays to handles
struct VariableLocation struct VariableLocation
{ {
...@@ -233,7 +239,7 @@ class ProgramState final : angle::NonCopyable ...@@ -233,7 +239,7 @@ class ProgramState final : angle::NonCopyable
} }
const UniformBlockBindingMask &getActiveUniformBlockBindingsMask() const const UniformBlockBindingMask &getActiveUniformBlockBindingsMask() const
{ {
return mActiveUniformBlockBindings; return mExecutable->getActiveUniformBlockBindings();
} }
const std::vector<sh::ShaderVariable> &getProgramInputs() const const std::vector<sh::ShaderVariable> &getProgramInputs() const
{ {
...@@ -250,7 +256,7 @@ class ProgramState final : angle::NonCopyable ...@@ -250,7 +256,7 @@ class ProgramState final : angle::NonCopyable
} }
const std::vector<VariableLocation> &getSecondaryOutputLocations() const const std::vector<VariableLocation> &getSecondaryOutputLocations() const
{ {
return mSecondaryOutputLocations; return mExecutable->getSecondaryOutputLocations();
} }
const std::vector<LinkedUniform> &getUniforms() const { return mExecutable->getUniforms(); } const std::vector<LinkedUniform> &getUniforms() const { return mExecutable->getUniforms(); }
const std::vector<VariableLocation> &getUniformLocations() const { return mUniformLocations; } const std::vector<VariableLocation> &getUniformLocations() const { return mUniformLocations; }
...@@ -386,16 +392,10 @@ class ProgramState final : angle::NonCopyable ...@@ -386,16 +392,10 @@ class ProgramState final : angle::NonCopyable
uint32_t mLocationsUsedForXfbExtension; uint32_t mLocationsUsedForXfbExtension;
std::vector<std::string> mTransformFeedbackVaryingNames; std::vector<std::string> mTransformFeedbackVaryingNames;
// For faster iteration on the blocks currently being bound.
UniformBlockBindingMask mActiveUniformBlockBindings;
std::vector<VariableLocation> mUniformLocations; std::vector<VariableLocation> mUniformLocations;
std::vector<BufferVariable> mBufferVariables; std::vector<BufferVariable> mBufferVariables;
RangeUI mAtomicCounterUniformRange; RangeUI mAtomicCounterUniformRange;
// EXT_blend_func_extended secondary outputs (ones with index 1) in ESSL 3.00 shaders.
std::vector<VariableLocation> mSecondaryOutputLocations;
DrawBufferMask mActiveOutputVariables; DrawBufferMask mActiveOutputVariables;
// Fragment output variable base types: FLOAT, INT, or UINT. Ordered by location. // Fragment output variable base types: FLOAT, INT, or UINT. Ordered by location.
......
...@@ -122,6 +122,7 @@ ProgramExecutable::ProgramExecutable(const ProgramExecutable &other) ...@@ -122,6 +122,7 @@ ProgramExecutable::ProgramExecutable(const ProgramExecutable &other)
mCanDrawWith(other.mCanDrawWith), mCanDrawWith(other.mCanDrawWith),
mOutputVariables(other.mOutputVariables), mOutputVariables(other.mOutputVariables),
mOutputLocations(other.mOutputLocations), mOutputLocations(other.mOutputLocations),
mSecondaryOutputLocations(other.mSecondaryOutputLocations),
mYUVOutput(other.mYUVOutput), mYUVOutput(other.mYUVOutput),
mProgramInputs(other.mProgramInputs), mProgramInputs(other.mProgramInputs),
mLinkedTransformFeedbackVaryings(other.mLinkedTransformFeedbackVaryings), mLinkedTransformFeedbackVaryings(other.mLinkedTransformFeedbackVaryings),
...@@ -131,6 +132,7 @@ ProgramExecutable::ProgramExecutable(const ProgramExecutable &other) ...@@ -131,6 +132,7 @@ ProgramExecutable::ProgramExecutable(const ProgramExecutable &other)
mDefaultUniformRange(other.mDefaultUniformRange), mDefaultUniformRange(other.mDefaultUniformRange),
mSamplerUniformRange(other.mSamplerUniformRange), mSamplerUniformRange(other.mSamplerUniformRange),
mUniformBlocks(other.mUniformBlocks), mUniformBlocks(other.mUniformBlocks),
mActiveUniformBlockBindings(other.mActiveUniformBlockBindings),
mAtomicCounterBuffers(other.mAtomicCounterBuffers), mAtomicCounterBuffers(other.mAtomicCounterBuffers),
mImageUniformRange(other.mImageUniformRange), mImageUniformRange(other.mImageUniformRange),
mComputeShaderStorageBlocks(other.mComputeShaderStorageBlocks), mComputeShaderStorageBlocks(other.mComputeShaderStorageBlocks),
...@@ -174,11 +176,13 @@ void ProgramExecutable::reset() ...@@ -174,11 +176,13 @@ void ProgramExecutable::reset()
mLinkedTransformFeedbackVaryings.clear(); mLinkedTransformFeedbackVaryings.clear();
mUniforms.clear(); mUniforms.clear();
mUniformBlocks.clear(); mUniformBlocks.clear();
mActiveUniformBlockBindings.reset();
mComputeShaderStorageBlocks.clear(); mComputeShaderStorageBlocks.clear();
mGraphicsShaderStorageBlocks.clear(); mGraphicsShaderStorageBlocks.clear();
mAtomicCounterBuffers.clear(); mAtomicCounterBuffers.clear();
mOutputVariables.clear(); mOutputVariables.clear();
mOutputLocations.clear(); mOutputLocations.clear();
mSecondaryOutputLocations.clear();
mYUVOutput = false; mYUVOutput = false;
mSamplerBindings.clear(); mSamplerBindings.clear();
mComputeImageBindings.clear(); mComputeImageBindings.clear();
...@@ -242,6 +246,170 @@ void ProgramExecutable::load(gl::BinaryInputStream *stream) ...@@ -242,6 +246,170 @@ void ProgramExecutable::load(gl::BinaryInputStream *stream)
mTessGenSpacing = stream->readInt<GLenum>(); mTessGenSpacing = stream->readInt<GLenum>();
mTessGenVertexOrder = stream->readInt<GLenum>(); mTessGenVertexOrder = stream->readInt<GLenum>();
mTessGenPointMode = stream->readInt<GLenum>(); mTessGenPointMode = stream->readInt<GLenum>();
size_t attribCount = stream->readInt<size_t>();
ASSERT(getProgramInputs().empty());
for (size_t attribIndex = 0; attribIndex < attribCount; ++attribIndex)
{
sh::ShaderVariable attrib;
LoadShaderVar(stream, &attrib);
attrib.location = stream->readInt<int>();
mProgramInputs.push_back(attrib);
}
size_t uniformCount = stream->readInt<size_t>();
ASSERT(getUniforms().empty());
for (size_t uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
{
LinkedUniform uniform;
LoadShaderVar(stream, &uniform);
uniform.bufferIndex = stream->readInt<int>();
LoadBlockMemberInfo(stream, &uniform.blockInfo);
stream->readIntVector<unsigned int>(&uniform.outerArraySizes);
uniform.typeInfo = &GetUniformTypeInfo(uniform.type);
// Active shader info
for (ShaderType shaderType : gl::AllShaderTypes())
{
uniform.setActive(shaderType, stream->readBool());
}
mUniforms.push_back(uniform);
}
size_t uniformBlockCount = stream->readInt<size_t>();
ASSERT(getUniformBlocks().empty());
for (size_t uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount; ++uniformBlockIndex)
{
InterfaceBlock uniformBlock;
LoadInterfaceBlock(stream, &uniformBlock);
mUniformBlocks.push_back(uniformBlock);
mActiveUniformBlockBindings.set(uniformBlockIndex, uniformBlock.binding != 0);
}
size_t shaderStorageBlockCount = stream->readInt<size_t>();
ASSERT(getShaderStorageBlocks().empty());
for (size_t shaderStorageBlockIndex = 0; shaderStorageBlockIndex < shaderStorageBlockCount;
++shaderStorageBlockIndex)
{
InterfaceBlock shaderStorageBlock;
LoadInterfaceBlock(stream, &shaderStorageBlock);
if (isCompute())
{
mComputeShaderStorageBlocks.push_back(shaderStorageBlock);
}
else
{
mGraphicsShaderStorageBlocks.push_back(shaderStorageBlock);
}
}
size_t atomicCounterBufferCount = stream->readInt<size_t>();
ASSERT(getAtomicCounterBuffers().empty());
for (size_t bufferIndex = 0; bufferIndex < atomicCounterBufferCount; ++bufferIndex)
{
AtomicCounterBuffer atomicCounterBuffer;
LoadShaderVariableBuffer(stream, &atomicCounterBuffer);
mAtomicCounterBuffers.push_back(atomicCounterBuffer);
}
size_t transformFeedbackVaryingCount = stream->readInt<size_t>();
ASSERT(mLinkedTransformFeedbackVaryings.empty());
for (size_t transformFeedbackVaryingIndex = 0;
transformFeedbackVaryingIndex < transformFeedbackVaryingCount;
++transformFeedbackVaryingIndex)
{
sh::ShaderVariable varying;
stream->readIntVector<unsigned int>(&varying.arraySizes);
stream->readInt(&varying.type);
stream->readString(&varying.name);
GLuint arrayIndex = stream->readInt<GLuint>();
mLinkedTransformFeedbackVaryings.emplace_back(varying, arrayIndex);
}
mTransformFeedbackBufferMode = stream->readInt<GLint>();
size_t outputCount = stream->readInt<size_t>();
ASSERT(getOutputVariables().empty());
for (size_t outputIndex = 0; outputIndex < outputCount; ++outputIndex)
{
sh::ShaderVariable output;
LoadShaderVar(stream, &output);
output.location = stream->readInt<int>();
output.index = stream->readInt<int>();
mOutputVariables.push_back(output);
}
size_t outputVarCount = stream->readInt<size_t>();
ASSERT(getOutputLocations().empty());
for (size_t outputIndex = 0; outputIndex < outputVarCount; ++outputIndex)
{
VariableLocation locationData;
stream->readInt(&locationData.arrayIndex);
stream->readInt(&locationData.index);
stream->readBool(&locationData.ignored);
mOutputLocations.push_back(locationData);
}
size_t secondaryOutputVarCount = stream->readInt<size_t>();
ASSERT(getSecondaryOutputLocations().empty());
for (size_t outputIndex = 0; outputIndex < secondaryOutputVarCount; ++outputIndex)
{
VariableLocation locationData;
stream->readInt(&locationData.arrayIndex);
stream->readInt(&locationData.index);
stream->readBool(&locationData.ignored);
mSecondaryOutputLocations.push_back(locationData);
}
unsigned int defaultUniformRangeLow = stream->readInt<unsigned int>();
unsigned int defaultUniformRangeHigh = stream->readInt<unsigned int>();
mDefaultUniformRange = RangeUI(defaultUniformRangeLow, defaultUniformRangeHigh);
unsigned int samplerRangeLow = stream->readInt<unsigned int>();
unsigned int samplerRangeHigh = stream->readInt<unsigned int>();
mSamplerUniformRange = RangeUI(samplerRangeLow, samplerRangeHigh);
size_t samplerCount = stream->readInt<size_t>();
for (size_t samplerIndex = 0; samplerIndex < samplerCount; ++samplerIndex)
{
TextureType textureType = stream->readEnum<TextureType>();
GLenum samplerType = stream->readInt<GLenum>();
SamplerFormat format = stream->readEnum<SamplerFormat>();
size_t bindingCount = stream->readInt<size_t>();
mSamplerBindings.emplace_back(textureType, samplerType, format, bindingCount);
}
unsigned int imageRangeLow = stream->readInt<unsigned int>();
unsigned int imageRangeHigh = stream->readInt<unsigned int>();
mImageUniformRange = RangeUI(imageRangeLow, imageRangeHigh);
size_t imageBindingCount = stream->readInt<size_t>();
for (size_t imageIndex = 0; imageIndex < imageBindingCount; ++imageIndex)
{
size_t elementCount = stream->readInt<size_t>();
TextureType textureType = static_cast<TextureType>(stream->readInt<unsigned int>());
ImageBinding imageBinding(elementCount, textureType);
for (size_t elementIndex = 0; elementIndex < elementCount; ++elementIndex)
{
imageBinding.boundImageUnits[elementIndex] = stream->readInt<unsigned int>();
}
if (isCompute())
{
mComputeImageBindings.emplace_back(imageBinding);
}
else
{
mGraphicsImageBindings.emplace_back(imageBinding);
}
}
} }
void ProgramExecutable::save(gl::BinaryOutputStream *stream) const void ProgramExecutable::save(gl::BinaryOutputStream *stream) const
...@@ -279,6 +447,115 @@ void ProgramExecutable::save(gl::BinaryOutputStream *stream) const ...@@ -279,6 +447,115 @@ void ProgramExecutable::save(gl::BinaryOutputStream *stream) const
stream->writeInt(mTessGenSpacing); stream->writeInt(mTessGenSpacing);
stream->writeInt(mTessGenVertexOrder); stream->writeInt(mTessGenVertexOrder);
stream->writeInt(mTessGenPointMode); stream->writeInt(mTessGenPointMode);
stream->writeInt(getProgramInputs().size());
for (const sh::ShaderVariable &attrib : getProgramInputs())
{
WriteShaderVar(stream, attrib);
stream->writeInt(attrib.location);
}
stream->writeInt(getUniforms().size());
for (const LinkedUniform &uniform : getUniforms())
{
WriteShaderVar(stream, uniform);
// FIXME: referenced
stream->writeInt(uniform.bufferIndex);
WriteBlockMemberInfo(stream, uniform.blockInfo);
stream->writeIntVector(uniform.outerArraySizes);
// Active shader info
for (ShaderType shaderType : gl::AllShaderTypes())
{
stream->writeBool(uniform.isActive(shaderType));
}
}
stream->writeInt(getUniformBlocks().size());
for (const InterfaceBlock &uniformBlock : getUniformBlocks())
{
WriteInterfaceBlock(stream, uniformBlock);
}
stream->writeInt(getShaderStorageBlocks().size());
for (const InterfaceBlock &shaderStorageBlock : getShaderStorageBlocks())
{
WriteInterfaceBlock(stream, shaderStorageBlock);
}
stream->writeInt(mAtomicCounterBuffers.size());
for (const AtomicCounterBuffer &atomicCounterBuffer : getAtomicCounterBuffers())
{
WriteShaderVariableBuffer(stream, atomicCounterBuffer);
}
stream->writeInt(getLinkedTransformFeedbackVaryings().size());
for (const auto &var : getLinkedTransformFeedbackVaryings())
{
stream->writeIntVector(var.arraySizes);
stream->writeInt(var.type);
stream->writeString(var.name);
stream->writeIntOrNegOne(var.arrayIndex);
}
stream->writeInt(getTransformFeedbackBufferMode());
stream->writeInt(getOutputVariables().size());
for (const sh::ShaderVariable &output : getOutputVariables())
{
WriteShaderVar(stream, output);
stream->writeInt(output.location);
stream->writeInt(output.index);
}
stream->writeInt(getOutputLocations().size());
for (const auto &outputVar : getOutputLocations())
{
stream->writeInt(outputVar.arrayIndex);
stream->writeIntOrNegOne(outputVar.index);
stream->writeBool(outputVar.ignored);
}
stream->writeInt(getSecondaryOutputLocations().size());
for (const auto &outputVar : getSecondaryOutputLocations())
{
stream->writeInt(outputVar.arrayIndex);
stream->writeIntOrNegOne(outputVar.index);
stream->writeBool(outputVar.ignored);
}
stream->writeInt(getDefaultUniformRange().low());
stream->writeInt(getDefaultUniformRange().high());
stream->writeInt(getSamplerUniformRange().low());
stream->writeInt(getSamplerUniformRange().high());
stream->writeInt(getSamplerBindings().size());
for (const auto &samplerBinding : getSamplerBindings())
{
stream->writeEnum(samplerBinding.textureType);
stream->writeInt(samplerBinding.samplerType);
stream->writeEnum(samplerBinding.format);
stream->writeInt(samplerBinding.boundTextureUnits.size());
}
stream->writeInt(getImageUniformRange().low());
stream->writeInt(getImageUniformRange().high());
stream->writeInt(getImageBindings().size());
for (const auto &imageBinding : getImageBindings())
{
stream->writeInt(imageBinding.boundImageUnits.size());
stream->writeInt(static_cast<unsigned int>(imageBinding.textureType));
for (size_t i = 0; i < imageBinding.boundImageUnits.size(); ++i)
{
stream->writeInt(imageBinding.boundImageUnits[i]);
}
}
} }
int ProgramExecutable::getInfoLogLength() const int ProgramExecutable::getInfoLogLength() const
......
...@@ -233,8 +233,16 @@ class ProgramExecutable final : public angle::Subject ...@@ -233,8 +233,16 @@ class ProgramExecutable final : public angle::Subject
const std::vector<sh::ShaderVariable> &getProgramInputs() const { return mProgramInputs; } const std::vector<sh::ShaderVariable> &getProgramInputs() const { return mProgramInputs; }
const std::vector<sh::ShaderVariable> &getOutputVariables() const { return mOutputVariables; } const std::vector<sh::ShaderVariable> &getOutputVariables() const { return mOutputVariables; }
const std::vector<VariableLocation> &getOutputLocations() const { return mOutputLocations; } const std::vector<VariableLocation> &getOutputLocations() const { return mOutputLocations; }
const std::vector<VariableLocation> &getSecondaryOutputLocations() const
{
return mSecondaryOutputLocations;
}
const std::vector<LinkedUniform> &getUniforms() const { return mUniforms; } const std::vector<LinkedUniform> &getUniforms() const { return mUniforms; }
const std::vector<InterfaceBlock> &getUniformBlocks() const { return mUniformBlocks; } const std::vector<InterfaceBlock> &getUniformBlocks() const { return mUniformBlocks; }
const UniformBlockBindingMask &getActiveUniformBlockBindings() const
{
return mActiveUniformBlockBindings;
}
const std::vector<SamplerBinding> &getSamplerBindings() const { return mSamplerBindings; } const std::vector<SamplerBinding> &getSamplerBindings() const { return mSamplerBindings; }
const std::vector<ImageBinding> &getImageBindings() const const std::vector<ImageBinding> &getImageBindings() const
{ {
...@@ -392,6 +400,8 @@ class ProgramExecutable final : public angle::Subject ...@@ -392,6 +400,8 @@ class ProgramExecutable final : public angle::Subject
// to uniforms. // to uniforms.
std::vector<sh::ShaderVariable> mOutputVariables; std::vector<sh::ShaderVariable> mOutputVariables;
std::vector<VariableLocation> mOutputLocations; std::vector<VariableLocation> mOutputLocations;
// EXT_blend_func_extended secondary outputs (ones with index 1)
std::vector<VariableLocation> mSecondaryOutputLocations;
bool mYUVOutput; bool mYUVOutput;
// Vertex attributes, Fragment input varyings, etc. // Vertex attributes, Fragment input varyings, etc.
std::vector<sh::ShaderVariable> mProgramInputs; std::vector<sh::ShaderVariable> mProgramInputs;
...@@ -414,6 +424,10 @@ class ProgramExecutable final : public angle::Subject ...@@ -414,6 +424,10 @@ class ProgramExecutable final : public angle::Subject
RangeUI mDefaultUniformRange; RangeUI mDefaultUniformRange;
RangeUI mSamplerUniformRange; RangeUI mSamplerUniformRange;
std::vector<InterfaceBlock> mUniformBlocks; std::vector<InterfaceBlock> mUniformBlocks;
// For faster iteration on the blocks currently being bound.
UniformBlockBindingMask mActiveUniformBlockBindings;
std::vector<AtomicCounterBuffer> mAtomicCounterBuffers; std::vector<AtomicCounterBuffer> mAtomicCounterBuffers;
RangeUI mImageUniformRange; RangeUI mImageUniformRange;
std::vector<InterfaceBlock> mComputeShaderStorageBlocks; std::vector<InterfaceBlock> mComputeShaderStorageBlocks;
......
...@@ -539,13 +539,70 @@ void AssignAttributeLocations(const gl::ProgramExecutable &programExecutable, ...@@ -539,13 +539,70 @@ void AssignAttributeLocations(const gl::ProgramExecutable &programExecutable,
} }
} }
void AssignOutputLocations(const gl::ProgramExecutable &programExecutable, void AssignSecondaryOutputLocations(const gl::ProgramState &programState,
ShaderInterfaceVariableInfoMap *variableInfoMapOut)
{
const auto &secondaryOutputLocations =
programState.getExecutable().getSecondaryOutputLocations();
const auto &outputVariables = programState.getExecutable().getOutputVariables();
// Handle EXT_blend_func_extended secondary outputs (ones with index=1)
for (const gl::VariableLocation &outputLocation : secondaryOutputLocations)
{
if (outputLocation.arrayIndex == 0 && outputLocation.used() && !outputLocation.ignored)
{
const sh::ShaderVariable &outputVar = outputVariables[outputLocation.index];
uint32_t location = 0;
if (outputVar.location != -1)
{
location = outputVar.location;
}
ShaderInterfaceVariableInfo *info =
AddLocationInfo(variableInfoMapOut, gl::ShaderType::Fragment, outputVar.mappedName,
location, ShaderInterfaceVariableInfo::kInvalid, 0, 0);
// If the shader source has not specified the index, specify it here.
if (outputVar.index == -1)
{
// Index 1 is used to specify that the color be used as the second color input to
// the blend equation
info->index = 1;
}
}
}
// Handle secondary outputs for ESSL version less than 3.00
gl::Shader *fragmentShader = programState.getAttachedShader(gl::ShaderType::Fragment);
if (fragmentShader && fragmentShader->getShaderVersion() == 100)
{
const auto &shaderOutputs = fragmentShader->getActiveOutputVariables();
for (const auto &outputVar : shaderOutputs)
{
if (outputVar.name == "gl_SecondaryFragColorEXT")
{
AddLocationInfo(variableInfoMapOut, gl::ShaderType::Fragment,
"angle_SecondaryFragColor", 0,
ShaderInterfaceVariableInfo::kInvalid, 0, 0);
}
else if (outputVar.name == "gl_SecondaryFragDataEXT")
{
AddLocationInfo(variableInfoMapOut, gl::ShaderType::Fragment,
"angle_SecondaryFragData", 0, ShaderInterfaceVariableInfo::kInvalid,
0, 0);
}
}
}
}
void AssignOutputLocations(const gl::ProgramState &programState,
const gl::ShaderType shaderType, const gl::ShaderType shaderType,
ShaderInterfaceVariableInfoMap *variableInfoMapOut) ShaderInterfaceVariableInfoMap *variableInfoMapOut)
{ {
// Assign output locations for the fragment shader. // Assign output locations for the fragment shader.
ASSERT(shaderType == gl::ShaderType::Fragment); ASSERT(shaderType == gl::ShaderType::Fragment);
// TODO(syoussefi): Add support for EXT_blend_func_extended. http://anglebug.com/3385
const gl::ProgramExecutable &programExecutable = programState.getExecutable();
const auto &outputLocations = programExecutable.getOutputLocations(); const auto &outputLocations = programExecutable.getOutputLocations();
const auto &outputVariables = programExecutable.getOutputVariables(); const auto &outputVariables = programExecutable.getOutputVariables();
const std::array<std::string, 3> implicitOutputs = {"gl_FragDepth", "gl_SampleMask", const std::array<std::string, 3> implicitOutputs = {"gl_FragDepth", "gl_SampleMask",
...@@ -576,6 +633,8 @@ void AssignOutputLocations(const gl::ProgramExecutable &programExecutable, ...@@ -576,6 +633,8 @@ void AssignOutputLocations(const gl::ProgramExecutable &programExecutable,
} }
} }
AssignSecondaryOutputLocations(programState, variableInfoMapOut);
// When no fragment output is specified by the shader, the translator outputs webgl_FragColor or // When no fragment output is specified by the shader, the translator outputs webgl_FragColor or
// webgl_FragData. Add an entry for these. Even though the translator is already assigning // webgl_FragData. Add an entry for these. Even though the translator is already assigning
// location 0 to these entries, adding an entry for them here allows us to ASSERT that every // location 0 to these entries, adding an entry for them here allows us to ASSERT that every
...@@ -2223,6 +2282,13 @@ bool SpirvTransformer::transformDecorate(const uint32_t *instruction) ...@@ -2223,6 +2282,13 @@ bool SpirvTransformer::transformDecorate(const uint32_t *instruction)
{spirv::LiteralInteger(info->component)}); {spirv::LiteralInteger(info->component)});
} }
// Add index decoration, if any.
if (info->index != ShaderInterfaceVariableInfo::kInvalid)
{
spirv::WriteDecorate(mSpirvBlobOut, id, spv::DecorationIndex,
{spirv::LiteralInteger(info->index)});
}
// Add Xfb decorations, if any. // Add Xfb decorations, if any.
if (mOptions.isTransformFeedbackStage && if (mOptions.isTransformFeedbackStage &&
info->xfb.buffer != ShaderInterfaceVariableXfbInfo::kInvalid) info->xfb.buffer != ShaderInterfaceVariableXfbInfo::kInvalid)
...@@ -3743,7 +3809,7 @@ void GlslangAssignLocations(const GlslangSourceOptions &options, ...@@ -3743,7 +3809,7 @@ void GlslangAssignLocations(const GlslangSourceOptions &options,
if ((shaderType == gl::ShaderType::Fragment) && if ((shaderType == gl::ShaderType::Fragment) &&
programExecutable.hasLinkedShaderStage(gl::ShaderType::Fragment)) programExecutable.hasLinkedShaderStage(gl::ShaderType::Fragment))
{ {
AssignOutputLocations(programExecutable, gl::ShaderType::Fragment, variableInfoMapOut); AssignOutputLocations(programState, gl::ShaderType::Fragment, variableInfoMapOut);
} }
// Assign attributes to the vertex shader, if any. // Assign attributes to the vertex shader, if any.
......
...@@ -97,6 +97,7 @@ struct ShaderInterfaceVariableInfo ...@@ -97,6 +97,7 @@ struct ShaderInterfaceVariableInfo
// locations in their respective slots. // locations in their respective slots.
uint32_t location = kInvalid; uint32_t location = kInvalid;
uint32_t component = kInvalid; uint32_t component = kInvalid;
uint32_t index = kInvalid;
// The stages this shader interface variable is active. // The stages this shader interface variable is active.
gl::ShaderBitSet activeStages; gl::ShaderBitSet activeStages;
// Used for transform feedback extension to decorate vertex shader output. // Used for transform feedback extension to decorate vertex shader output.
......
...@@ -1545,6 +1545,8 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF ...@@ -1545,6 +1545,8 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF
enabledFeatures.features.shaderCullDistance = mPhysicalDeviceFeatures.shaderCullDistance; enabledFeatures.features.shaderCullDistance = mPhysicalDeviceFeatures.shaderCullDistance;
// Used to support tessellation Shader: // Used to support tessellation Shader:
enabledFeatures.features.tessellationShader = mPhysicalDeviceFeatures.tessellationShader; enabledFeatures.features.tessellationShader = mPhysicalDeviceFeatures.tessellationShader;
// Used to support EXT_blend_func_extended
enabledFeatures.features.dualSrcBlend = mPhysicalDeviceFeatures.dualSrcBlend;
if (!vk::CommandBuffer::ExecutesInline()) if (!vk::CommandBuffer::ExecutesInline())
{ {
......
...@@ -90,6 +90,14 @@ uint8_t PackGLBlendFactor(GLenum blendFactor) ...@@ -90,6 +90,14 @@ uint8_t PackGLBlendFactor(GLenum blendFactor)
return static_cast<uint8_t>(VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR); return static_cast<uint8_t>(VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR);
case GL_ONE_MINUS_CONSTANT_ALPHA: case GL_ONE_MINUS_CONSTANT_ALPHA:
return static_cast<uint8_t>(VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA); return static_cast<uint8_t>(VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA);
case GL_SRC1_COLOR_EXT:
return static_cast<uint8_t>(VK_BLEND_FACTOR_SRC1_COLOR);
case GL_SRC1_ALPHA_EXT:
return static_cast<uint8_t>(VK_BLEND_FACTOR_SRC1_ALPHA);
case GL_ONE_MINUS_SRC1_COLOR_EXT:
return static_cast<uint8_t>(VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR);
case GL_ONE_MINUS_SRC1_ALPHA_EXT:
return static_cast<uint8_t>(VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA);
default: default:
UNREACHABLE(); UNREACHABLE();
return 0; return 0;
......
...@@ -997,6 +997,10 @@ void RendererVk::ensureCapsInitialized() const ...@@ -997,6 +997,10 @@ void RendererVk::ensureCapsInitialized() const
mNativeCaps.maxCombinedClipAndCullDistances = limitsVk.maxCombinedClipAndCullDistances; mNativeCaps.maxCombinedClipAndCullDistances = limitsVk.maxCombinedClipAndCullDistances;
} }
} }
// GL_EXT_blend_func_extended
mNativeExtensions.blendFuncExtended = (mPhysicalDeviceFeatures.dualSrcBlend == VK_TRUE);
mNativeExtensions.maxDualSourceDrawBuffers = LimitToInt(limitsVk.maxFragmentDualSrcAttachments);
} }
namespace vk namespace vk
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
// Test EXT_blend_func_extended // Test EXT_blend_func_extended
#include "test_utils/ANGLETest.h" #include "test_utils/ANGLETest.h"
#include "test_utils/gl_raii.h"
#include "util/shader_utils.h" #include "util/shader_utils.h"
...@@ -134,13 +135,28 @@ class EXTBlendFuncExtendedDrawTest : public ANGLETest ...@@ -134,13 +135,28 @@ class EXTBlendFuncExtendedDrawTest : public ANGLETest
ASSERT_NE(0u, mProgram); ASSERT_NE(0u, mProgram);
} }
virtual GLint getVertexAttribLocation(const char *name)
{
return glGetAttribLocation(mProgram, name);
}
virtual GLint getFragmentUniformLocation(const char *name)
{
return glGetUniformLocation(mProgram, name);
}
virtual void setUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3)
{
glUniform4f(location, v0, v1, v2, v3);
}
void drawTest() void drawTest()
{ {
glUseProgram(mProgram); glUseProgram(mProgram);
GLint position = glGetAttribLocation(mProgram, essl1_shaders::PositionAttrib()); GLint position = getVertexAttribLocation(essl1_shaders::PositionAttrib());
GLint src0 = glGetUniformLocation(mProgram, "src0"); GLint src0 = getFragmentUniformLocation("src0");
GLint src1 = glGetUniformLocation(mProgram, "src1"); GLint src1 = getFragmentUniformLocation("src1");
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
glBindBuffer(GL_ARRAY_BUFFER, mVBO); glBindBuffer(GL_ARRAY_BUFFER, mVBO);
...@@ -152,8 +168,8 @@ class EXTBlendFuncExtendedDrawTest : public ANGLETest ...@@ -152,8 +168,8 @@ class EXTBlendFuncExtendedDrawTest : public ANGLETest
static const float kSrc0[4] = {1.0f, 1.0f, 1.0f, 1.0f}; static const float kSrc0[4] = {1.0f, 1.0f, 1.0f, 1.0f};
static const float kSrc1[4] = {0.3f, 0.6f, 0.9f, 0.7f}; static const float kSrc1[4] = {0.3f, 0.6f, 0.9f, 0.7f};
glUniform4f(src0, kSrc0[0], kSrc0[1], kSrc0[2], kSrc0[3]); setUniform4f(src0, kSrc0[0], kSrc0[1], kSrc0[2], kSrc0[3]);
glUniform4f(src1, kSrc1[0], kSrc1[1], kSrc1[2], kSrc1[3]); setUniform4f(src1, kSrc1[0], kSrc1[1], kSrc1[2], kSrc1[3]);
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
glEnable(GL_BLEND); glEnable(GL_BLEND);
...@@ -216,7 +232,8 @@ class EXTBlendFuncExtendedDrawTestES3 : public EXTBlendFuncExtendedDrawTest ...@@ -216,7 +232,8 @@ class EXTBlendFuncExtendedDrawTestES3 : public EXTBlendFuncExtendedDrawTest
mIsES31OrNewer = true; mIsES31OrNewer = true;
} }
} }
void checkOutputIndexQuery(const char *name, GLint expectedIndex)
virtual void checkOutputIndexQuery(const char *name, GLint expectedIndex)
{ {
GLint index = glGetFragDataIndexEXT(mProgram, name); GLint index = glGetFragDataIndexEXT(mProgram, name);
EXPECT_EQ(expectedIndex, index); EXPECT_EQ(expectedIndex, index);
...@@ -246,6 +263,109 @@ class EXTBlendFuncExtendedDrawTestES3 : public EXTBlendFuncExtendedDrawTest ...@@ -246,6 +263,109 @@ class EXTBlendFuncExtendedDrawTestES3 : public EXTBlendFuncExtendedDrawTest
bool mIsES31OrNewer; bool mIsES31OrNewer;
}; };
class EXTBlendFuncExtendedDrawTestES31 : public EXTBlendFuncExtendedDrawTestES3
{
protected:
EXTBlendFuncExtendedDrawTestES31()
: EXTBlendFuncExtendedDrawTestES3(), mPipeline(0), mVertexProgram(0), mFragProgram(0)
{}
GLint getVertexAttribLocation(const char *name) override
{
return glGetAttribLocation(mVertexProgram, name);
}
GLint getFragmentUniformLocation(const char *name) override
{
return glGetUniformLocation(mFragProgram, name);
}
void setUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) override
{
glActiveShaderProgram(mPipeline, mFragProgram);
EXTBlendFuncExtendedDrawTest::setUniform4f(location, v0, v1, v2, v3);
}
void checkOutputIndexQuery(const char *name, GLint expectedIndex) override
{
GLint index = glGetFragDataIndexEXT(mFragProgram, name);
EXPECT_EQ(expectedIndex, index);
index = glGetProgramResourceLocationIndexEXT(mFragProgram, GL_PROGRAM_OUTPUT, name);
EXPECT_EQ(expectedIndex, index);
}
void setupProgramPipeline(const char *vertexSource, const char *fragmentSource)
{
mVertexProgram = createShaderProgram(GL_VERTEX_SHADER, vertexSource);
ASSERT_NE(mVertexProgram, 0u);
mFragProgram = createShaderProgram(GL_FRAGMENT_SHADER, fragmentSource);
ASSERT_NE(mFragProgram, 0u);
// Generate a program pipeline and attach the programs to their respective stages
glGenProgramPipelines(1, &mPipeline);
EXPECT_GL_NO_ERROR();
glUseProgramStages(mPipeline, GL_VERTEX_SHADER_BIT, mVertexProgram);
EXPECT_GL_NO_ERROR();
glUseProgramStages(mPipeline, GL_FRAGMENT_SHADER_BIT, mFragProgram);
EXPECT_GL_NO_ERROR();
glBindProgramPipeline(mPipeline);
EXPECT_GL_NO_ERROR();
}
GLuint createShaderProgram(GLenum type, const GLchar *shaderString)
{
GLShader shader(type);
if (!shader.get())
{
return 0;
}
glShaderSource(shader, 1, &shaderString, nullptr);
glCompileShader(shader);
GLuint program = glCreateProgram();
if (program)
{
GLint compiled;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
glProgramParameteri(program, GL_PROGRAM_SEPARABLE, GL_TRUE);
if (compiled)
{
glAttachShader(program, shader);
glLinkProgram(program);
glDetachShader(program, shader);
}
}
EXPECT_GL_NO_ERROR();
return program;
}
void testTearDown() override
{
EXTBlendFuncExtendedDrawTest::testTearDown();
if (mVertexProgram)
{
glDeleteProgram(mVertexProgram);
}
if (mFragProgram)
{
glDeleteProgram(mFragProgram);
}
if (mPipeline)
{
glDeleteProgramPipelines(1, &mPipeline);
}
ASSERT_GL_NO_ERROR();
}
GLuint mPipeline;
GLuint mVertexProgram;
GLuint mFragProgram;
};
} // namespace } // namespace
// Test EXT_blend_func_extended related gets. // Test EXT_blend_func_extended related gets.
...@@ -287,6 +407,12 @@ TEST_P(EXTBlendFuncExtendedDrawTest, FragData) ...@@ -287,6 +407,12 @@ TEST_P(EXTBlendFuncExtendedDrawTest, FragData)
{ {
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended")); ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
// Suspected VK driver bug http://anglebug.com/5523
ANGLE_SKIP_TEST_IF(IsVulkan() && (IsNVIDIA() || IsPixel2()));
// Suspected AMD VK driver bug http://anglebug.com/5537
ANGLE_SKIP_TEST_IF(IsVulkan() && IsWindows() && IsAMD());
const char *kFragColorShader = const char *kFragColorShader =
"#extension GL_EXT_blend_func_extended : require\n" "#extension GL_EXT_blend_func_extended : require\n"
"precision mediump float;\n" "precision mediump float;\n"
...@@ -396,6 +522,9 @@ TEST_P(EXTBlendFuncExtendedDrawTestES3, FragmentArrayOutputLocationsAPI) ...@@ -396,6 +522,9 @@ TEST_P(EXTBlendFuncExtendedDrawTestES3, FragmentArrayOutputLocationsAPI)
// TODO: Investigate this mac-only failure. http://angleproject.com/1085 // TODO: Investigate this mac-only failure. http://angleproject.com/1085
ANGLE_SKIP_TEST_IF(IsOSX()); ANGLE_SKIP_TEST_IF(IsOSX());
// Suspected VK driver bug http://anglebug.com/5523
ANGLE_SKIP_TEST_IF(IsVulkan() && (IsNVIDIA() || IsPixel2()));
constexpr char kFS[] = R"(#version 300 es constexpr char kFS[] = R"(#version 300 es
#extension GL_EXT_blend_func_extended : require #extension GL_EXT_blend_func_extended : require
precision mediump float; precision mediump float;
...@@ -708,8 +837,103 @@ void main() { ...@@ -708,8 +837,103 @@ void main() {
glDeleteProgram(program); glDeleteProgram(program);
} }
// Use a program pipeline with EXT_blend_func_extended
TEST_P(EXTBlendFuncExtendedDrawTestES31, UseProgramPipeline)
{
// Only the Vulkan backend supports PPO
ANGLE_SKIP_TEST_IF(!IsVulkan());
// Create two separable program objects from a
// single source string respectively (vertSrc and fragSrc)
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
const char *kFragColorShader = R"(#version 300 es
#extension GL_EXT_blend_func_extended : require
precision mediump float;
uniform vec4 src0;
uniform vec4 src1;
layout(location = 0, index = 1) out vec4 outSrc1;
layout(location = 0, index = 0) out vec4 outSrc0;
void main() {
outSrc0 = src0;
outSrc1 = src1;
})";
setupProgramPipeline(essl3_shaders::vs::Simple(), kFragColorShader);
checkOutputIndexQuery("outSrc0", 0);
checkOutputIndexQuery("outSrc1", 1);
ASSERT_EQ(mProgram, 0u);
drawTest();
ASSERT_GL_NO_ERROR();
}
// Use program pipeline where the fragment program is changed
TEST_P(EXTBlendFuncExtendedDrawTestES31, UseTwoProgramStages)
{
// Only the Vulkan backend supports PPO
ANGLE_SKIP_TEST_IF(!IsVulkan());
// Create two separable program objects from a
// single source string respectively (vertSrc and fragSrc)
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
const char *kFragColorShaderFlipped = R"(#version 300 es
#extension GL_EXT_blend_func_extended : require
precision mediump float;
uniform vec4 src0;
uniform vec4 src1;
layout(location = 0, index = 0) out vec4 outSrc1;
layout(location = 0, index = 1) out vec4 outSrc0;
void main() {
outSrc0 = src0;
outSrc1 = src1;
})";
const char *kFragColorShader = R"(#version 300 es
#extension GL_EXT_blend_func_extended : require
precision mediump float;
uniform vec4 src0;
uniform vec4 src1;
layout(location = 0, index = 1) out vec4 outSrc1;
layout(location = 0, index = 0) out vec4 outSrc0;
void main() {
outSrc0 = src0;
outSrc1 = src1;
})";
setupProgramPipeline(essl3_shaders::vs::Simple(), kFragColorShaderFlipped);
// Check index values frag shader with the "flipped" index values
checkOutputIndexQuery("outSrc0", 1);
checkOutputIndexQuery("outSrc1", 0);
GLuint previousProgram = mFragProgram;
mFragProgram = createShaderProgram(GL_FRAGMENT_SHADER, kFragColorShader);
ASSERT_NE(mFragProgram, 0u);
// Change the Fragment program of the pipeline
glUseProgramStages(mPipeline, GL_FRAGMENT_SHADER_BIT, mFragProgram);
EXPECT_GL_NO_ERROR();
checkOutputIndexQuery("outSrc0", 0);
checkOutputIndexQuery("outSrc1", 1);
ASSERT_EQ(mProgram, 0u);
drawTest();
if (previousProgram)
{
glDeleteProgram(previousProgram);
}
ASSERT_GL_NO_ERROR();
}
ANGLE_INSTANTIATE_TEST_ES2(EXTBlendFuncExtendedTest); ANGLE_INSTANTIATE_TEST_ES2(EXTBlendFuncExtendedTest);
ANGLE_INSTANTIATE_TEST_ES3_AND_ES31(EXTBlendFuncExtendedTestES3); ANGLE_INSTANTIATE_TEST_ES3_AND_ES31(EXTBlendFuncExtendedTestES3);
ANGLE_INSTANTIATE_TEST_ES2(EXTBlendFuncExtendedDrawTest); ANGLE_INSTANTIATE_TEST_ES2(EXTBlendFuncExtendedDrawTest);
ANGLE_INSTANTIATE_TEST_ES3_AND_ES31(EXTBlendFuncExtendedDrawTestES3); ANGLE_INSTANTIATE_TEST_ES3_AND_ES31(EXTBlendFuncExtendedDrawTestES3);
ANGLE_INSTANTIATE_TEST_ES31(EXTBlendFuncExtendedDrawTestES31);
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