Centralize renderer limitations for non-conformant renderers
Some renderer configurations (e.g. D3D11 Feature Level 9_3) have
some limitations and aren't quite conformant. This change
generates errors when applications hit these limitations, and
informs developers that they must work around them.
BUG=angleproject:1055
Change-Id: I6a4a9e5cc71288ca366a54c769ca0eb82e79a7f7
Reviewed-on: https://chromium-review.googlesource.com/282814
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Tested-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/Caps.cpp b/src/libANGLE/Caps.cpp
index ddda278..b413578 100644
--- a/src/libANGLE/Caps.cpp
+++ b/src/libANGLE/Caps.cpp
@@ -193,6 +193,13 @@
return extensionStrings;
}
+Limitations::Limitations()
+ : noFrontFacingSupport(false),
+ noSampleAlphaToCoverageSupport(false),
+ attributeZeroRequiresZeroDivisorInEXT(false)
+{
+}
+
static bool GetFormatSupport(const TextureCapsMap &textureCaps, const std::vector<GLenum> &requiredFormats,
bool requiresTexturing, bool requiresFiltering, bool requiresRendering)
{
diff --git a/src/libANGLE/Caps.h b/src/libANGLE/Caps.h
index 85e6260..b700d00 100644
--- a/src/libANGLE/Caps.h
+++ b/src/libANGLE/Caps.h
@@ -225,6 +225,22 @@
bool colorBufferFloat;
};
+struct Limitations
+{
+ Limitations();
+
+ // Renderer doesn't support gl_FrontFacing in fragment shaders
+ bool noFrontFacingSupport;
+
+ // Renderer doesn't support GL_SAMPLE_ALPHA_TO_COVERAGE
+ bool noSampleAlphaToCoverageSupport;
+
+ // In glVertexAttribDivisorANGLE, attribute zero must have a zero divisor
+ bool attributeZeroRequiresZeroDivisorInEXT;
+
+ // TODO: add entry for renderers that don't support separate stencil masks/refs
+};
+
struct TypePrecision
{
TypePrecision();
diff --git a/src/libANGLE/Context.cpp b/src/libANGLE/Context.cpp
index b21c7ee..2a24990 100644
--- a/src/libANGLE/Context.cpp
+++ b/src/libANGLE/Context.cpp
@@ -1389,6 +1389,11 @@
return mExtensions;
}
+const Limitations &Context::getLimitations() const
+{
+ return mLimitations;
+}
+
void Context::detachTexture(GLuint texture)
{
// Simple pass-through to State's detachTexture method, as textures do not require
@@ -1605,6 +1610,8 @@
mExtensions = mRenderer->getRendererExtensions();
+ mLimitations = mRenderer->getRendererLimitations();
+
if (clientVersion < 3)
{
// Disable ES3+ extensions
diff --git a/src/libANGLE/Context.h b/src/libANGLE/Context.h
index e7c8515..367a922 100644
--- a/src/libANGLE/Context.h
+++ b/src/libANGLE/Context.h
@@ -190,6 +190,7 @@
const Caps &getCaps() const;
const TextureCapsMap &getTextureCaps() const;
const Extensions &getExtensions() const;
+ const Limitations &getLimitations() const;
const std::string &getRendererString() const;
@@ -222,6 +223,7 @@
Caps mCaps;
TextureCapsMap mTextureCaps;
Extensions mExtensions;
+ Limitations mLimitations;
// Shader compiler
Compiler *mCompiler;
diff --git a/src/libANGLE/renderer/Renderer.cpp b/src/libANGLE/renderer/Renderer.cpp
index fbc2ad5..0370161 100644
--- a/src/libANGLE/renderer/Renderer.cpp
+++ b/src/libANGLE/renderer/Renderer.cpp
@@ -25,39 +25,43 @@
{
}
-const gl::Caps &Renderer::getRendererCaps() const
+void Renderer::ensureCapsInitialized() const
{
if (!mCapsInitialized)
{
- generateCaps(&mCaps, &mTextureCaps, &mExtensions);
+ generateCaps(&mCaps, &mTextureCaps, &mExtensions, &mLimitations);
mCapsInitialized = true;
}
+}
+
+const gl::Caps &Renderer::getRendererCaps() const
+{
+ ensureCapsInitialized();
return mCaps;
}
const gl::TextureCapsMap &Renderer::getRendererTextureCaps() const
{
- if (!mCapsInitialized)
- {
- generateCaps(&mCaps, &mTextureCaps, &mExtensions);
- mCapsInitialized = true;
- }
+ ensureCapsInitialized();
return mTextureCaps;
}
const gl::Extensions &Renderer::getRendererExtensions() const
{
- if (!mCapsInitialized)
- {
- generateCaps(&mCaps, &mTextureCaps, &mExtensions);
- mCapsInitialized = true;
- }
+ ensureCapsInitialized();
return mExtensions;
}
+const gl::Limitations &Renderer::getRendererLimitations() const
+{
+ ensureCapsInitialized();
+
+ return mLimitations;
+}
+
const Workarounds &Renderer::getWorkarounds() const
{
if (!mWorkaroundsInitialized)
diff --git a/src/libANGLE/renderer/Renderer.h b/src/libANGLE/renderer/Renderer.h
index 0fae014..1359688 100644
--- a/src/libANGLE/renderer/Renderer.h
+++ b/src/libANGLE/renderer/Renderer.h
@@ -77,16 +77,21 @@
const gl::Caps &getRendererCaps() const;
const gl::TextureCapsMap &getRendererTextureCaps() const;
const gl::Extensions &getRendererExtensions() const;
+ const gl::Limitations &getRendererLimitations() const;
const Workarounds &getWorkarounds() const;
private:
- virtual void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap* outTextureCaps, gl::Extensions *outExtensions) const = 0;
+ void ensureCapsInitialized() const;
+ virtual void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap* outTextureCaps,
+ gl::Extensions *outExtensions,
+ gl::Limitations *outLimitations) const = 0;
virtual Workarounds generateWorkarounds() const = 0;
mutable bool mCapsInitialized;
mutable gl::Caps mCaps;
mutable gl::TextureCapsMap mTextureCaps;
mutable gl::Extensions mExtensions;
+ mutable gl::Limitations mLimitations;
mutable bool mWorkaroundsInitialized;
mutable Workarounds mWorkarounds;
diff --git a/src/libANGLE/renderer/d3d/ProgramD3D.cpp b/src/libANGLE/renderer/d3d/ProgramD3D.cpp
index edbe3d5..0059516 100644
--- a/src/libANGLE/renderer/d3d/ProgramD3D.cpp
+++ b/src/libANGLE/renderer/d3d/ProgramD3D.cpp
@@ -1067,6 +1067,15 @@
vertexShaderD3D->generateWorkarounds(&mVertexWorkarounds);
mShaderVersion = vertexShaderD3D->getShaderVersion();
+ if (mRenderer->getRendererLimitations().noFrontFacingSupport)
+ {
+ if (fragmentShaderD3D->usesFrontFacing())
+ {
+ infoLog << "The current renderer doesn't support gl_FrontFacing";
+ return LinkResult(false, gl::Error(GL_NO_ERROR));
+ }
+ }
+
// Map the varyings to the register file
VaryingPacking packing = {};
*registers = mDynamicHLSL->packVaryings(infoLog, packing, fragmentShaderD3D, vertexShaderD3D, transformFeedbackVaryings);
diff --git a/src/libANGLE/renderer/d3d/ShaderD3D.h b/src/libANGLE/renderer/d3d/ShaderD3D.h
index 5d9fc8b..0838ebe 100644
--- a/src/libANGLE/renderer/d3d/ShaderD3D.h
+++ b/src/libANGLE/renderer/d3d/ShaderD3D.h
@@ -43,6 +43,7 @@
bool usesDepthRange() const { return mUsesDepthRange; }
bool usesPointSize() const { return mUsesPointSize; }
bool usesDeferredInit() const { return mUsesDeferredInit; }
+ bool usesFrontFacing() const { return mUsesFrontFacing; }
GLenum getShaderType() const;
ShShaderOutput getCompilerOutputType() const;
diff --git a/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp b/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
index 3a84cab..04f099d 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
@@ -3748,9 +3748,11 @@
return d3d11::GetDXGIFormatInfo(d3d11::GetVertexFormatInfo(vertexFormatType, mRenderer11DeviceCaps.featureLevel).nativeFormat).componentType;
}
-void Renderer11::generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions) const
+void Renderer11::generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps,
+ gl::Extensions *outExtensions, gl::Limitations *outLimitations) const
{
- d3d11_gl::GenerateCaps(mDevice, mDeviceContext, mRenderer11DeviceCaps, outCaps, outTextureCaps, outExtensions);
+ d3d11_gl::GenerateCaps(mDevice, mDeviceContext, mRenderer11DeviceCaps, outCaps, outTextureCaps,
+ outExtensions, outLimitations);
}
Workarounds Renderer11::generateWorkarounds() const
diff --git a/src/libANGLE/renderer/d3d/d3d11/Renderer11.h b/src/libANGLE/renderer/d3d/d3d11/Renderer11.h
index 6ded0a0..d33c643 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Renderer11.h
+++ b/src/libANGLE/renderer/d3d/d3d11/Renderer11.h
@@ -273,7 +273,10 @@
gl::Error clearTextures(gl::SamplerType samplerType, size_t rangeStart, size_t rangeEnd) override;
private:
- void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions) const override;
+ void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps,
+ gl::Extensions *outExtensions,
+ gl::Limitations *outLimitations) const override;
+
Workarounds generateWorkarounds() const override;
gl::Error drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer);
diff --git a/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp b/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp
index a863977..78d150d 100644
--- a/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp
@@ -1004,7 +1004,8 @@
}
}
-void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, const Renderer11DeviceCaps &renderer11DeviceCaps, gl::Caps *caps, gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions)
+void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, const Renderer11DeviceCaps &renderer11DeviceCaps, gl::Caps *caps,
+ gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions, gl::Limitations *limitations)
{
GLuint maxSamples = 0;
D3D_FEATURE_LEVEL featureLevel = renderer11DeviceCaps.featureLevel;
@@ -1152,6 +1153,20 @@
extensions->translatedShaderSource = true;
extensions->fboRenderMipmap = false;
extensions->debugMarker = true;
+
+ // D3D11 Feature Level 10_0+ uses SV_IsFrontFace in HLSL to emulate gl_FrontFacing.
+ // D3D11 Feature Level 9_3 doesn't support SV_IsFrontFace, and has no equivalent, so can't support gl_FrontFacing.
+ limitations->noFrontFacingSupport = (renderer11DeviceCaps.featureLevel <= D3D_FEATURE_LEVEL_9_3);
+
+ // D3D11 Feature Level 9_3 doesn't support alpha-to-coverage
+ limitations->noSampleAlphaToCoverageSupport = (renderer11DeviceCaps.featureLevel <= D3D_FEATURE_LEVEL_9_3);
+
+#ifdef ANGLE_ENABLE_WINDOWS_STORE
+ // Setting a non-zero divisor on attribute zero doesn't work on certain Windows Phone 8-era devices.
+ // We should prevent developers from doing this on ALL Windows Store devices. This will maintain consistency across all Windows devices.
+ // We allow non-zero divisors on attribute zero if the Client Version >= 3, since devices affected by this issue don't support ES3+.
+ limitations->attributeZeroRequiresZeroDivisorInEXT = true;
+#endif
}
}
diff --git a/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.h b/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.h
index 376741f..108e84c 100644
--- a/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.h
+++ b/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.h
@@ -53,7 +53,8 @@
{
GLint GetMaximumClientVersion(D3D_FEATURE_LEVEL featureLevel);
-void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, const Renderer11DeviceCaps &renderer11DeviceCaps, gl::Caps *caps, gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions);
+void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, const Renderer11DeviceCaps &renderer11DeviceCaps, gl::Caps *caps,
+ gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions, gl::Limitations *limitations);
}
diff --git a/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp b/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp
index e46080f..dad178e 100644
--- a/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp
+++ b/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp
@@ -2935,9 +2935,12 @@
return d3d9::GetVertexFormatInfo(getCapsDeclTypes(), vertexFormatType).componentType;
}
-void Renderer9::generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions) const
+void Renderer9::generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps,
+ gl::Extensions *outExtensions,
+ gl::Limitations * /*outLimitations */) const
{
- d3d9_gl::GenerateCaps(mD3d9, mDevice, mDeviceType, mAdapter, outCaps, outTextureCaps, outExtensions);
+ d3d9_gl::GenerateCaps(mD3d9, mDevice, mDeviceType, mAdapter, outCaps,
+ outTextureCaps, outExtensions);
}
Workarounds Renderer9::generateWorkarounds() const
diff --git a/src/libANGLE/renderer/d3d/d3d9/Renderer9.h b/src/libANGLE/renderer/d3d/d3d9/Renderer9.h
index 2883774..9d2e9d8 100644
--- a/src/libANGLE/renderer/d3d/d3d9/Renderer9.h
+++ b/src/libANGLE/renderer/d3d/d3d9/Renderer9.h
@@ -241,7 +241,10 @@
gl::Error clearTextures(gl::SamplerType samplerType, size_t rangeStart, size_t rangeEnd) override;
private:
- void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions) const override;
+ void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps,
+ gl::Extensions *outExtensions,
+ gl::Limitations *outLimitations) const override;
+
Workarounds generateWorkarounds() const override;
void release();
diff --git a/src/libANGLE/renderer/gl/RendererGL.cpp b/src/libANGLE/renderer/gl/RendererGL.cpp
index 9b410ac..5b6d1f6 100644
--- a/src/libANGLE/renderer/gl/RendererGL.cpp
+++ b/src/libANGLE/renderer/gl/RendererGL.cpp
@@ -303,7 +303,9 @@
return mMaxSupportedESVersion;
}
-void RendererGL::generateCaps(gl::Caps *outCaps, gl::TextureCapsMap* outTextureCaps, gl::Extensions *outExtensions) const
+void RendererGL::generateCaps(gl::Caps *outCaps, gl::TextureCapsMap* outTextureCaps,
+ gl::Extensions *outExtensions,
+ gl::Limitations * /* outLimitations */) const
{
nativegl_gl::GenerateCaps(mFunctions, outCaps, outTextureCaps, outExtensions, &mMaxSupportedESVersion);
}
diff --git a/src/libANGLE/renderer/gl/RendererGL.h b/src/libANGLE/renderer/gl/RendererGL.h
index 6d2b97e..c08a976 100644
--- a/src/libANGLE/renderer/gl/RendererGL.h
+++ b/src/libANGLE/renderer/gl/RendererGL.h
@@ -79,7 +79,10 @@
const gl::Version &getMaxSupportedESVersion() const;
private:
- void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap* outTextureCaps, gl::Extensions *outExtensions) const override;
+ void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap* outTextureCaps,
+ gl::Extensions *outExtensions,
+ gl::Limitations *outLimitations) const override;
+
Workarounds generateWorkarounds() const override;
mutable gl::Version mMaxSupportedESVersion;
diff --git a/src/libGLESv2/entry_points_gles_2_0.cpp b/src/libGLESv2/entry_points_gles_2_0.cpp
index ff480a4..2773de5 100644
--- a/src/libGLESv2/entry_points_gles_2_0.cpp
+++ b/src/libGLESv2/entry_points_gles_2_0.cpp
@@ -1264,6 +1264,20 @@
return;
}
+ if (context->getLimitations().noSampleAlphaToCoverageSupport)
+ {
+ if (cap == GL_SAMPLE_ALPHA_TO_COVERAGE)
+ {
+ const char *errorMessage = "Current renderer doesn't support alpha-to-coverage";
+ context->recordError(Error(GL_INVALID_OPERATION, errorMessage));
+
+ // We also output an error message to the debugger window if tracing is active, so that developers can see the error message.
+ ERR("%s", errorMessage);
+
+ return;
+ }
+ }
+
context->getState().setEnableFeature(cap, true);
}
}
diff --git a/src/libGLESv2/entry_points_gles_2_0_ext.cpp b/src/libGLESv2/entry_points_gles_2_0_ext.cpp
index 1379a33..1c2da75 100644
--- a/src/libGLESv2/entry_points_gles_2_0_ext.cpp
+++ b/src/libGLESv2/entry_points_gles_2_0_ext.cpp
@@ -644,6 +644,21 @@
return;
}
+ if (context->getLimitations().attributeZeroRequiresZeroDivisorInEXT)
+ {
+ if (index == 0 && divisor != 0)
+ {
+ const char *errorMessage = "The current context doesn't support setting a non-zero divisor on the attribute with index zero. "
+ "Please reorder the attributes in your vertex shader so that attribute zero can have a zero divisor.";
+ context->recordError(Error(GL_INVALID_OPERATION, errorMessage));
+
+ // We also output an error message to the debugger window if tracing is active, so that developers can see the error message.
+ ERR("%s", errorMessage);
+
+ return;
+ }
+ }
+
context->setVertexAttribDivisor(index, divisor);
}
}
diff --git a/src/tests/gl_tests/GLSLTest.cpp b/src/tests/gl_tests/GLSLTest.cpp
index 0d579e5..470f20d 100644
--- a/src/tests/gl_tests/GLSLTest.cpp
+++ b/src/tests/gl_tests/GLSLTest.cpp
@@ -553,15 +553,6 @@
{
EGLPlatformParameters platform = GetParam().eglParameters;
- // Disable this test on D3D11 feature level 9_3, since gl_FrontFacing isn't supported.
- if (platform.renderer == EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
- {
- if (platform.majorVersion == 9 && platform.minorVersion == 3)
- {
- return;
- }
- }
-
const std::string vertexShaderSource = SHADER_SOURCE
(
attribute vec4 a_position;
@@ -594,6 +585,18 @@
);
GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+
+ // Compilation should fail on D3D11 feature level 9_3, since gl_FrontFacing isn't supported.
+ if (platform.renderer == EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
+ {
+ if (platform.majorVersion == 9 && platform.minorVersion == 3)
+ {
+ EXPECT_EQ(0u, program);
+ return;
+ }
+ }
+
+ // Otherwise, compilation should succeed
EXPECT_NE(0u, program);
}