WebGL: validate texture format matches sampler type
WebGL requires that drawing produces INVALID_OPERATION if a texture's
format doesn't match the sampler type it is bound to. This is a little
confusing because samplers have two attributes that could be called
"type": addressing mode (2D/3D/Cube), and component format
(float/signed/unsigned/shadow). ANGLE already handled checking the
addressing mode; this change adds checking for the component format.
Fixes WebGL conformance test
conformance2/uniforms/incompatible-texture-type-for-sampler.html
Bug: chromium:809237
Change-Id: I52ebfecd92625e3ee10274cb5f548d7e53de72dd
Reviewed-on: https://chromium-review.googlesource.com/c/1377611
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Yuly Novikov <ynovikov@chromium.org>
Commit-Queue: James Darpinian <jdarpinian@chromium.org>
diff --git a/src/libANGLE/Program.cpp b/src/libANGLE/Program.cpp
index b907aad..7771425 100644
--- a/src/libANGLE/Program.cpp
+++ b/src/libANGLE/Program.cpp
@@ -724,8 +724,14 @@
}
// SamplerBindings implementation.
-SamplerBinding::SamplerBinding(TextureType textureTypeIn, size_t elementCount, bool unreferenced)
- : textureType(textureTypeIn), boundTextureUnits(elementCount, 0), unreferenced(unreferenced)
+SamplerBinding::SamplerBinding(TextureType textureTypeIn,
+ SamplerFormat formatIn,
+ size_t elementCount,
+ bool unreferenced)
+ : textureType(textureTypeIn),
+ format(formatIn),
+ boundTextureUnits(elementCount, 0),
+ unreferenced(unreferenced)
{}
SamplerBinding::SamplerBinding(const SamplerBinding &other) = default;
@@ -1356,6 +1362,8 @@
void ProgramState::updateActiveSamplers()
{
+ mActiveSamplerRefCounts.fill(0);
+
for (SamplerBinding &samplerBinding : mSamplerBindings)
{
if (samplerBinding.unreferenced)
@@ -1363,8 +1371,22 @@
for (GLint textureUnit : samplerBinding.boundTextureUnits)
{
- mActiveSamplerRefCounts[textureUnit]++;
- mActiveSamplerTypes[textureUnit] = getSamplerUniformTextureType(textureUnit);
+ if (++mActiveSamplerRefCounts[textureUnit] == 1)
+ {
+ mActiveSamplerTypes[textureUnit] = samplerBinding.textureType;
+ mActiveSamplerFormats[textureUnit] = samplerBinding.format;
+ }
+ else
+ {
+ if (mActiveSamplerTypes[textureUnit] != samplerBinding.textureType)
+ {
+ mActiveSamplerTypes[textureUnit] = TextureType::InvalidEnum;
+ }
+ if (mActiveSamplerFormats[textureUnit] != samplerBinding.format)
+ {
+ mActiveSamplerFormats[textureUnit] = SamplerFormat::InvalidEnum;
+ }
+ }
mActiveSamplersMask.set(textureUnit);
}
}
@@ -2895,7 +2917,8 @@
const auto &samplerUniform = mState.mUniforms[samplerIndex];
TextureType textureType = SamplerTypeToTextureType(samplerUniform.type);
unsigned int elementCount = samplerUniform.getBasicTypeElementCount();
- mState.mSamplerBindings.emplace_back(textureType, elementCount, false);
+ SamplerFormat format = samplerUniform.typeInfo->samplerFormat;
+ mState.mSamplerBindings.emplace_back(textureType, format, elementCount, false);
}
}
@@ -3896,30 +3919,45 @@
newRefCount++;
// Check for binding type change.
- TextureType &newSamplerType = mState.mActiveSamplerTypes[newTextureUnit];
- TextureType &oldSamplerType = mState.mActiveSamplerTypes[oldTextureUnit];
+ TextureType &newSamplerType = mState.mActiveSamplerTypes[newTextureUnit];
+ TextureType &oldSamplerType = mState.mActiveSamplerTypes[oldTextureUnit];
+ SamplerFormat &newSamplerFormat = mState.mActiveSamplerFormats[newTextureUnit];
+ SamplerFormat &oldSamplerFormat = mState.mActiveSamplerFormats[oldTextureUnit];
if (newRefCount == 1)
{
- newSamplerType = samplerBinding.textureType;
+ newSamplerType = samplerBinding.textureType;
+ newSamplerFormat = samplerBinding.format;
mState.mActiveSamplersMask.set(newTextureUnit);
}
- else if (newSamplerType != samplerBinding.textureType)
+ else
{
- // Conflict detected. Ensure we reset it properly.
- newSamplerType = TextureType::InvalidEnum;
+ if (newSamplerType != samplerBinding.textureType)
+ {
+ // Conflict detected. Ensure we reset it properly.
+ newSamplerType = TextureType::InvalidEnum;
+ }
+ if (newSamplerFormat != samplerBinding.format)
+ {
+ newSamplerFormat = SamplerFormat::InvalidEnum;
+ }
}
// Unset previously active sampler.
if (oldRefCount == 0)
{
- oldSamplerType = TextureType::InvalidEnum;
+ oldSamplerType = TextureType::InvalidEnum;
+ oldSamplerFormat = SamplerFormat::InvalidEnum;
mState.mActiveSamplersMask.reset(oldTextureUnit);
}
- else if (oldSamplerType == TextureType::InvalidEnum)
+ else
{
- // Previous conflict. Check if this new change fixed the conflict.
- oldSamplerType = mState.getSamplerUniformTextureType(oldTextureUnit);
+ if (oldSamplerType == TextureType::InvalidEnum ||
+ oldSamplerFormat == SamplerFormat::InvalidEnum)
+ {
+ // Previous conflict. Check if this new change fixed the conflict.
+ mState.setSamplerUniformTextureTypeAndFormat(oldTextureUnit);
+ }
}
// Notify context.
@@ -3934,9 +3972,11 @@
mCachedValidateSamplersResult.reset();
}
-TextureType ProgramState::getSamplerUniformTextureType(size_t textureUnitIndex) const
+void ProgramState::setSamplerUniformTextureTypeAndFormat(size_t textureUnitIndex)
{
- TextureType foundType = TextureType::InvalidEnum;
+ bool foundBinding = false;
+ TextureType foundType = TextureType::InvalidEnum;
+ SamplerFormat foundFormat = SamplerFormat::InvalidEnum;
for (const SamplerBinding &binding : mSamplerBindings)
{
@@ -3949,19 +3989,29 @@
{
if (textureUnit == textureUnitIndex)
{
- if (foundType == TextureType::InvalidEnum)
+ if (!foundBinding)
{
- foundType = binding.textureType;
+ foundBinding = true;
+ foundType = binding.textureType;
+ foundFormat = binding.format;
}
- else if (foundType != binding.textureType)
+ else
{
- return TextureType::InvalidEnum;
+ if (foundType != binding.textureType)
+ {
+ foundType = TextureType::InvalidEnum;
+ }
+ if (foundFormat != binding.format)
+ {
+ foundFormat = SamplerFormat::InvalidEnum;
+ }
}
}
}
}
- return foundType;
+ mActiveSamplerTypes[textureUnitIndex] = foundType;
+ mActiveSamplerFormats[textureUnitIndex] = foundFormat;
}
template <typename T>