Commit 02df796f by Austin Kinross Committed by Jamie Madill

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/282814Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Tested-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 09e2d93b
......@@ -193,6 +193,13 @@ std::vector<std::string> Extensions::getStrings() const
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)
{
......
......@@ -225,6 +225,22 @@ struct Extensions
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();
......
......@@ -1389,6 +1389,11 @@ const Extensions &Context::getExtensions() const
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 @@ void Context::initCaps(GLuint clientVersion)
mExtensions = mRenderer->getRendererExtensions();
mLimitations = mRenderer->getRendererLimitations();
if (clientVersion < 3)
{
// Disable ES3+ extensions
......
......@@ -190,6 +190,7 @@ class Context final : angle::NonCopyable
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 @@ class Context final : angle::NonCopyable
Caps mCaps;
TextureCapsMap mTextureCaps;
Extensions mExtensions;
Limitations mLimitations;
// Shader compiler
Compiler *mCompiler;
......
......@@ -25,39 +25,43 @@ Renderer::~Renderer()
{
}
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)
......
......@@ -77,16 +77,21 @@ class Renderer : public ImplFactory
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;
......
......@@ -1067,6 +1067,15 @@ LinkResult ProgramD3D::link(const gl::Data &data, gl::InfoLog &infoLog,
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);
......
......@@ -43,6 +43,7 @@ class ShaderD3D : public ShaderImpl
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;
......
......@@ -3748,9 +3748,11 @@ GLenum Renderer11::getVertexComponentType(gl::VertexFormatType vertexFormatType)
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
......
......@@ -273,7 +273,10 @@ class Renderer11 : public RendererD3D
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);
......
......@@ -1004,7 +1004,8 @@ static size_t GetMaximumStreamOutputSeparateComponents(D3D_FEATURE_LEVEL feature
}
}
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 @@ void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, cons
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
}
}
......
......@@ -53,7 +53,8 @@ namespace d3d11_gl
{
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);
}
......
......@@ -2935,9 +2935,12 @@ GLenum Renderer9::getVertexComponentType(gl::VertexFormatType vertexFormatType)
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
......
......@@ -241,7 +241,10 @@ class Renderer9 : public RendererD3D
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();
......
......@@ -303,7 +303,9 @@ const gl::Version &RendererGL::getMaxSupportedESVersion() const
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);
}
......
......@@ -79,7 +79,10 @@ class RendererGL : public Renderer
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;
......
......@@ -1264,6 +1264,20 @@ void GL_APIENTRY Enable(GLenum cap)
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);
}
}
......
......@@ -644,6 +644,21 @@ void GL_APIENTRY VertexAttribDivisorANGLE(GLuint index, GLuint divisor)
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);
}
}
......
......@@ -553,15 +553,6 @@ TEST_P(GLSLTest, FrontFacingAndVarying)
{
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 @@ TEST_P(GLSLTest, FrontFacingAndVarying)
);
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);
}
......
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