Commit 3cd0dd37 by Olli Etuaho Committed by Commit Bot

Don't expose non-conformant multisampling modes on GL

Some NVIDIA GL drivers expose non-conformant multisampling modes. The conformance of multisampling modes can be queried using the extension NV_internalformat_sample_query. Use it to filter out the non-conformant modes from the modes that are exposed by ANGLE. The MAX_SAMPLES value and other similar values stored in caps also need to be lowered to match the maximum number of samples exposed for required formats. There seems to be an NVIDIA driver bug related to querying STENCIL_INDEX8 multisample format. Work around this by querying DEPTH24_STENCIL8 instead. There's also some confusion around whether RGB9_E5 should be renderable. Once the floating point texture extensions got rolled into the core GL spec, it was eventually made clear that RGB9_E5 is intended not to be renderable. The extension specs that predate float textures in the core spec do suggest that it would be renderable, but in practice drivers that advertise the extension strings don't reliably implement RGB9_E5 as renderable. Solve this by disabling it as a renderable format and adding an explanatory comment. BUG=chromium:682815 TEST=angle_end2end_tests, dEQP-GLES31.functional.state_query.internal_format.renderbuffer.* Change-Id: I2218e3a23ea7b48a0615fea77a91897dc7d5fe9e Reviewed-on: https://chromium-review.googlesource.com/525515Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
parent 30ca54f4
...@@ -71,6 +71,15 @@ TextureCaps GenerateMinimumTextureCaps(GLenum sizedInternalFormat, ...@@ -71,6 +71,15 @@ TextureCaps GenerateMinimumTextureCaps(GLenum sizedInternalFormat,
caps.filterable = internalFormatInfo.filterSupport(clientVersion, extensions); caps.filterable = internalFormatInfo.filterSupport(clientVersion, extensions);
caps.sampleCounts.insert(0); caps.sampleCounts.insert(0);
if (internalFormatInfo.isRequiredRenderbufferFormat(clientVersion))
{
if ((clientVersion.major >= 3 && clientVersion.minor >= 1) ||
(clientVersion.major >= 3 && internalFormatInfo.componentType != GL_UNSIGNED_INT &&
internalFormatInfo.componentType != GL_INT))
{
caps.sampleCounts.insert(4);
}
}
return caps; return caps;
} }
......
...@@ -2726,12 +2726,58 @@ void Context::updateCaps() ...@@ -2726,12 +2726,58 @@ void Context::updateCaps()
// OpenGL ES does not support multisampling with non-rendererable formats // OpenGL ES does not support multisampling with non-rendererable formats
// OpenGL ES 3.0 or prior does not support multisampling with integer formats // OpenGL ES 3.0 or prior does not support multisampling with integer formats
if (!formatInfo.renderSupport || if (!formatCaps.renderable ||
(getClientVersion() < ES_3_1 && (getClientVersion() < ES_3_1 &&
(formatInfo.componentType == GL_INT || formatInfo.componentType == GL_UNSIGNED_INT))) (formatInfo.componentType == GL_INT || formatInfo.componentType == GL_UNSIGNED_INT)))
{ {
formatCaps.sampleCounts.clear(); formatCaps.sampleCounts.clear();
} }
else
{
// We may have limited the max samples for some required renderbuffer formats due to
// non-conformant formats. In this case MAX_SAMPLES needs to be lowered accordingly.
GLuint formatMaxSamples = formatCaps.getMaxSamples();
// GLES 3.0.5 section 4.4.2.2: "Implementations must support creation of renderbuffers
// in these required formats with up to the value of MAX_SAMPLES multisamples, with the
// exception of signed and unsigned integer formats."
if (formatInfo.componentType != GL_INT && formatInfo.componentType != GL_UNSIGNED_INT &&
formatInfo.isRequiredRenderbufferFormat(getClientVersion()))
{
ASSERT(getClientVersion() < ES_3_0 || formatMaxSamples >= 4);
mCaps.maxSamples = std::min(mCaps.maxSamples, formatMaxSamples);
}
// Handle GLES 3.1 MAX_*_SAMPLES values similarly to MAX_SAMPLES.
if (getClientVersion() >= ES_3_1)
{
// GLES 3.1 section 9.2.5: "Implementations must support creation of renderbuffers
// in these required formats with up to the value of MAX_SAMPLES multisamples, with
// the exception that the signed and unsigned integer formats are required only to
// support creation of renderbuffers with up to the value of MAX_INTEGER_SAMPLES
// multisamples, which must be at least one."
if (formatInfo.componentType == GL_INT ||
formatInfo.componentType == GL_UNSIGNED_INT)
{
mCaps.maxIntegerSamples = std::min(mCaps.maxIntegerSamples, formatMaxSamples);
}
// GLES 3.1 section 19.3.1.
if (formatCaps.texturable)
{
if (formatInfo.depthBits > 0)
{
mCaps.maxDepthTextureSamples =
std::min(mCaps.maxDepthTextureSamples, formatMaxSamples);
}
else if (formatInfo.redBits > 0)
{
mCaps.maxColorTextureSamples =
std::min(mCaps.maxColorTextureSamples, formatMaxSamples);
}
}
}
}
if (formatCaps.texturable && formatInfo.compressed) if (formatCaps.texturable && formatInfo.compressed)
{ {
......
...@@ -327,6 +327,110 @@ GLenum InternalFormat::getReadPixelsType() const ...@@ -327,6 +327,110 @@ GLenum InternalFormat::getReadPixelsType() const
} }
} }
bool InternalFormat::isRequiredRenderbufferFormat(const Version &version) const
{
// GLES 3.0.5 section 4.4.2.2:
// "Implementations are required to support the same internal formats for renderbuffers as the
// required formats for textures enumerated in section 3.8.3.1, with the exception of the color
// formats labelled "texture-only"."
if (!sized || compressed)
{
return false;
}
// Luma formats.
if (isLUMA())
{
return false;
}
// Depth/stencil formats.
if (depthBits > 0 || stencilBits > 0)
{
// GLES 2.0.25 table 4.5.
// GLES 3.0.5 section 3.8.3.1.
// GLES 3.1 table 8.14.
// Required formats in all versions.
switch (internalFormat)
{
case GL_DEPTH_COMPONENT16:
case GL_STENCIL_INDEX8:
// Note that STENCIL_INDEX8 is not mentioned in GLES 3.0.5 section 3.8.3.1, but it
// is in section 4.4.2.2.
return true;
default:
break;
}
if (version.major < 3)
{
return false;
}
// Required formats in GLES 3.0 and up.
switch (internalFormat)
{
case GL_DEPTH_COMPONENT32F:
case GL_DEPTH_COMPONENT24:
case GL_DEPTH32F_STENCIL8:
case GL_DEPTH24_STENCIL8:
return true;
default:
return false;
}
}
// RGBA formats.
// GLES 2.0.25 table 4.5.
// GLES 3.0.5 section 3.8.3.1.
// GLES 3.1 table 8.13.
// Required formats in all versions.
switch (internalFormat)
{
case GL_RGBA4:
case GL_RGB5_A1:
case GL_RGB565:
return true;
default:
break;
}
if (version.major < 3)
{
return false;
}
if (format == GL_BGRA_EXT)
{
return false;
}
switch (componentType)
{
case GL_SIGNED_NORMALIZED:
case GL_FLOAT:
return false;
case GL_UNSIGNED_INT:
case GL_INT:
// Integer RGB formats are not required renderbuffer formats.
if (alphaBits == 0 && greenBits != 0)
{
return false;
}
// All integer R and RG formats are required.
// Integer RGBA formats including RGB10_A2_UI are required.
return true;
case GL_UNSIGNED_NORMALIZED:
if (internalFormat == GL_SRGB8)
{
return false;
}
return true;
default:
UNREACHABLE();
return false;
}
}
Format::Format(GLenum internalFormat) : Format(GetSizedInternalFormatInfo(internalFormat)) Format::Format(GLenum internalFormat) : Format(GetSizedInternalFormatInfo(internalFormat))
{ {
} }
......
...@@ -85,6 +85,12 @@ struct InternalFormat ...@@ -85,6 +85,12 @@ struct InternalFormat
GLenum getReadPixelsFormat() const; GLenum getReadPixelsFormat() const;
GLenum getReadPixelsType() const; GLenum getReadPixelsType() const;
// Return true if the format is a required renderbuffer format in the given version of the core
// spec. Note that it isn't always clear whether all the rules that apply to core required
// renderbuffer formats also apply to additional formats added by extensions. Because of this
// extension formats are conservatively not included.
bool isRequiredRenderbufferFormat(const Version &version) const;
bool operator==(const InternalFormat &other) const; bool operator==(const InternalFormat &other) const;
bool operator!=(const InternalFormat &other) const; bool operator!=(const InternalFormat &other) const;
......
...@@ -789,7 +789,8 @@ FunctionsGL::FunctionsGL() ...@@ -789,7 +789,8 @@ FunctionsGL::FunctionsGL()
primitiveBoundingBox(nullptr), primitiveBoundingBox(nullptr),
eglImageTargetRenderbufferStorageOES(nullptr), eglImageTargetRenderbufferStorageOES(nullptr),
eglImageTargetTexture2DOES(nullptr), eglImageTargetTexture2DOES(nullptr),
discardFramebuffer(nullptr) discardFramebuffer(nullptr),
getInternalformatSampleivNV(nullptr)
{ {
} }
...@@ -848,6 +849,9 @@ void FunctionsGL::initializeProcsDesktopGL() ...@@ -848,6 +849,9 @@ void FunctionsGL::initializeProcsDesktopGL()
// Even though extensions are written against specific versions of GL, many drivers expose the extensions // Even though extensions are written against specific versions of GL, many drivers expose the extensions
// in even older versions. Always try loading the extensions regardless of GL version. // in even older versions. Always try loading the extensions regardless of GL version.
// GL_NV_internalformat_sample_query
ASSIGN_WITH_EXT("GL_NV_internalformat_sample_query", "glGetInternalformatSampleivNV", getInternalformatSampleivNV);
// GL_ARB_program_interface_query (loading only functions relevant to GL_NV_path_rendering here) // GL_ARB_program_interface_query (loading only functions relevant to GL_NV_path_rendering here)
ASSIGN_WITH_EXT("GL_ARB_program_interface_query", "glGetProgramInterfaceiv", getProgramInterfaceiv); ASSIGN_WITH_EXT("GL_ARB_program_interface_query", "glGetProgramInterfaceiv", getProgramInterfaceiv);
ASSIGN_WITH_EXT("GL_ARB_program_interface_query", "glGetProgramResourceName", getProgramResourceName); ASSIGN_WITH_EXT("GL_ARB_program_interface_query", "glGetProgramResourceName", getProgramResourceName);
...@@ -1799,6 +1803,9 @@ void FunctionsGL::initializeProcsGLES() ...@@ -1799,6 +1803,9 @@ void FunctionsGL::initializeProcsGLES()
// clang-format off // clang-format off
// GL_NV_internalformat_sample_query
ASSIGN_WITH_EXT("GL_NV_internalformat_sample_query", "glGetInternalformatSampleivNV", getInternalformatSampleivNV);
// GL_NV_path_rendering // GL_NV_path_rendering
ASSIGN_WITH_EXT("GL_NV_path_rendering", "glMatrixLoadfEXT", matrixLoadEXT); ASSIGN_WITH_EXT("GL_NV_path_rendering", "glMatrixLoadfEXT", matrixLoadEXT);
ASSIGN_WITH_EXT("GL_NV_path_rendering", "glGenPathsNV", genPathsNV); ASSIGN_WITH_EXT("GL_NV_path_rendering", "glGenPathsNV", genPathsNV);
......
...@@ -782,6 +782,9 @@ class FunctionsGL ...@@ -782,6 +782,9 @@ class FunctionsGL
// GL_EXT_discard_framebuffer // GL_EXT_discard_framebuffer
PFNGLDISCARDFRAMEBUFFEREXTPROC discardFramebuffer; PFNGLDISCARDFRAMEBUFFEREXTPROC discardFramebuffer;
// GL_NV_internalformat_sample_query
PFNGLGETINTERNALFORMATSAMPLEIVNVPROC getInternalformatSampleivNV;
private: private:
void initializeProcsDesktopGL(); void initializeProcsDesktopGL();
void initializeProcsGLES(); void initializeProcsGLES();
......
...@@ -188,9 +188,13 @@ static InternalFormatInfoMap BuildInternalFormatInfoMap() ...@@ -188,9 +188,13 @@ static InternalFormatInfoMap BuildInternalFormatInfoMap()
InsertFormatMapping(&map, GL_BGRA_EXT, VersionOrExts(1, 2, "GL_EXT_bgra"), AlwaysSupported(), VersionOrExts(1, 2, "GL_EXT_bgra"), ExtsOnly("GL_EXT_texture_format_BGRA8888"), AlwaysSupported(), NeverSupported() ); InsertFormatMapping(&map, GL_BGRA_EXT, VersionOrExts(1, 2, "GL_EXT_bgra"), AlwaysSupported(), VersionOrExts(1, 2, "GL_EXT_bgra"), ExtsOnly("GL_EXT_texture_format_BGRA8888"), AlwaysSupported(), NeverSupported() );
// Floating point formats // Floating point formats
// Note that GL_EXT_texture_shared_exponent and GL_ARB_color_buffer_float suggest that RGB9_E5
// would be renderable, but once support for renderable float textures got rolled into core GL
// spec it wasn't intended to be renderable. In practice it's not reliably renderable even
// with the extensions, there's a known bug in at least NVIDIA driver version 370.
// | Format | OpenGL texture support | Filter | OpenGL render support | OpenGL ES texture support | Filter | OpenGL ES render support | // | Format | OpenGL texture support | Filter | OpenGL render support | OpenGL ES texture support | Filter | OpenGL ES render support |
InsertFormatMapping(&map, GL_R11F_G11F_B10F, VersionOrExts(3, 0, "GL_EXT_packed_float"), AlwaysSupported(), VersionOrExts(3, 0, "GL_EXT_packed_float GL_ARB_color_buffer_float"), VersionOnly(3, 0), AlwaysSupported(), ExtsOnly("GL_EXT_color_buffer_float") ); InsertFormatMapping(&map, GL_R11F_G11F_B10F, VersionOrExts(3, 0, "GL_EXT_packed_float"), AlwaysSupported(), VersionOrExts(3, 0, "GL_EXT_packed_float GL_ARB_color_buffer_float"), VersionOnly(3, 0), AlwaysSupported(), ExtsOnly("GL_EXT_color_buffer_float") );
InsertFormatMapping(&map, GL_RGB9_E5, VersionOrExts(3, 0, "GL_EXT_texture_shared_exponent"), AlwaysSupported(), VersionOrExts(3, 0, "GL_EXT_texture_shared_exponent GL_ARB_color_buffer_float"), VersionOnly(3, 0), AlwaysSupported(), NeverSupported() ); InsertFormatMapping(&map, GL_RGB9_E5, VersionOrExts(3, 0, "GL_EXT_texture_shared_exponent"), AlwaysSupported(), NeverSupported(), VersionOnly(3, 0), AlwaysSupported(), NeverSupported() );
InsertFormatMapping(&map, GL_R16F, VersionOrExts(3, 0, "GL_ARB_texture_rg ARB_texture_float"), AlwaysSupported(), VersionOrExts(3, 0, "GL_ARB_texture_rg GL_ARB_texture_float GL_ARB_color_buffer_float"), VersionOrExts(3, 0, "GL_OES_texture_half_float GL_EXT_texture_rg"), VersionOrExts(3, 0, "GL_OES_texture_half_float_linear"), VersionOrExtsAndExts(3, 0, "GL_EXT_texture_rg", "GL_EXT_color_buffer_half_float")); InsertFormatMapping(&map, GL_R16F, VersionOrExts(3, 0, "GL_ARB_texture_rg ARB_texture_float"), AlwaysSupported(), VersionOrExts(3, 0, "GL_ARB_texture_rg GL_ARB_texture_float GL_ARB_color_buffer_float"), VersionOrExts(3, 0, "GL_OES_texture_half_float GL_EXT_texture_rg"), VersionOrExts(3, 0, "GL_OES_texture_half_float_linear"), VersionOrExtsAndExts(3, 0, "GL_EXT_texture_rg", "GL_EXT_color_buffer_half_float"));
InsertFormatMapping(&map, GL_RG16F, VersionOrExts(3, 0, "GL_ARB_texture_rg ARB_texture_float"), AlwaysSupported(), VersionOrExts(3, 0, "GL_ARB_texture_rg GL_ARB_texture_float GL_ARB_color_buffer_float"), VersionOrExts(3, 0, "GL_OES_texture_half_float GL_EXT_texture_rg"), VersionOrExts(3, 0, "GL_OES_texture_half_float_linear"), VersionOrExtsAndExts(3, 0, "GL_EXT_texture_rg", "GL_EXT_color_buffer_half_float")); InsertFormatMapping(&map, GL_RG16F, VersionOrExts(3, 0, "GL_ARB_texture_rg ARB_texture_float"), AlwaysSupported(), VersionOrExts(3, 0, "GL_ARB_texture_rg GL_ARB_texture_float GL_ARB_color_buffer_float"), VersionOrExts(3, 0, "GL_OES_texture_half_float GL_EXT_texture_rg"), VersionOrExts(3, 0, "GL_OES_texture_half_float_linear"), VersionOrExtsAndExts(3, 0, "GL_EXT_texture_rg", "GL_EXT_color_buffer_half_float"));
InsertFormatMapping(&map, GL_RGB16F, VersionOrExts(3, 0, "GL_ARB_texture_float"), AlwaysSupported(), VersionOrExts(3, 0, "GL_ARB_texture_float GL_ARB_color_buffer_float"), VersionOrExts(3, 0, "GL_OES_texture_half_float"), VersionOrExts(3, 0, "GL_OES_texture_half_float_linear"), ExtsOnly("GL_EXT_color_buffer_half_float") ); InsertFormatMapping(&map, GL_RGB16F, VersionOrExts(3, 0, "GL_ARB_texture_float"), AlwaysSupported(), VersionOrExts(3, 0, "GL_ARB_texture_float GL_ARB_color_buffer_float"), VersionOrExts(3, 0, "GL_OES_texture_half_float"), VersionOrExts(3, 0, "GL_OES_texture_half_float_linear"), ExtsOnly("GL_EXT_color_buffer_half_float") );
......
...@@ -109,9 +109,34 @@ static gl::TextureCaps GenerateTextureFormatCaps(const FunctionsGL *functions, G ...@@ -109,9 +109,34 @@ static gl::TextureCaps GenerateTextureFormatCaps(const FunctionsGL *functions, G
std::vector<GLint> samples(numSamples); std::vector<GLint> samples(numSamples);
functions->getInternalformativ(GL_RENDERBUFFER, internalFormat, GL_SAMPLES, functions->getInternalformativ(GL_RENDERBUFFER, internalFormat, GL_SAMPLES,
static_cast<GLsizei>(samples.size()), &samples[0]); static_cast<GLsizei>(samples.size()), &samples[0]);
GLenum queryInternalFormat = internalFormat;
if (internalFormat == GL_STENCIL_INDEX8)
{
// The query below does generates an error with STENCIL_INDEX8 on NVIDIA driver
// 382.33. So for now we assume that the same sampling modes are conformant for
// STENCIL_INDEX8 as for DEPTH24_STENCIL8. Clean this up once the driver is fixed.
// http://anglebug.com/2059
queryInternalFormat = GL_DEPTH24_STENCIL8;
}
for (size_t sampleIndex = 0; sampleIndex < samples.size(); sampleIndex++) for (size_t sampleIndex = 0; sampleIndex < samples.size(); sampleIndex++)
{ {
textureCaps.sampleCounts.insert(samples[sampleIndex]); // Some NVIDIA drivers expose multisampling modes implemented as a combination of
// multisampling and supersampling. These are non-conformant and should not be
// exposed through ANGLE. Query which formats are conformant from the driver if
// supported.
GLint conformant = GL_TRUE;
if (functions->getInternalformatSampleivNV)
{
functions->getInternalformatSampleivNV(GL_RENDERBUFFER, queryInternalFormat,
samples[sampleIndex], GL_CONFORMANT_NV,
1, &conformant);
ASSERT(functions->getError() == GL_NO_ERROR);
}
if (conformant == GL_TRUE)
{
textureCaps.sampleCounts.insert(samples[sampleIndex]);
}
} }
} }
} }
......
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