Commit 4f2b94cb by Geoff Lang Committed by Commit Bot

Expose EXT_color_buffer_half_float if RGBA16F is renderable.

The EXT_color_buffer_half_float extension spec issue #2 states that none of the added color buffer formats are required to be renderable and the client must check for framebuffer completeness for using them. Chrome exposes the extension if at least RGBA16F is renderable for WebGL. Replicate Chrome's behaviour by loosening our requirements to only expose this extension if an explicit check for RGBA16F renderability succeeds. BUG=angleproject:2984 Change-Id: Id97f3043ebf3fd11b5e9e2d505e57b76baba9716 Reviewed-on: https://chromium-review.googlesource.com/c/1351350 Commit-Queue: Geoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarYuly Novikov <ynovikov@chromium.org>
parent 6494c415
......@@ -371,30 +371,16 @@ static bool DetermineBGRA8TextureSupport(const TextureCapsMap &textureCaps)
}
// Checks for GL_OES_color_buffer_half_float support
static bool DetermineColorBufferHalfFloatSupport(const TextureCapsMap &textureCaps,
bool checkRGFormats)
static bool DetermineColorBufferHalfFloatSupport(const TextureCapsMap &textureCaps)
{
constexpr GLenum requiredRGRenderbufferFormats[] = {
GL_R16F, GL_RG16F,
};
constexpr GLenum requiredRenderbufferFormats[] = {
GL_RGB16F, GL_RGBA16F,
};
// GL_RGBA16F since the extension says format=RGBA type=HALF_FLOAT_OES textures are renderable
// GL_RGB16F because dEQP GLES3 tests for it in es3fFboColorbufferTests.cpp
constexpr GLenum requiredTextureAttachmentFormats[] = {
GL_RGB16F, GL_RGBA16F,
// EXT_color_buffer_half_float issue #2 states that an implementation doesn't need to support
// rendering to any of the formats but is expected to be able to render to at least one. WebGL
// requires that at least RGBA16F is renderable so we make the same requirement.
constexpr GLenum requiredFormats[] = {
GL_RGBA16F,
};
if (checkRGFormats &&
!GetFormatSupport(textureCaps, requiredRGRenderbufferFormats, false, false, false, true))
{
return false;
}
return GetFormatSupport(textureCaps, requiredRenderbufferFormats, false, false, false, true) &&
GetFormatSupport(textureCaps, requiredTextureAttachmentFormats, false, false, true,
false);
return GetFormatSupport(textureCaps, requiredFormats, false, false, true, true);
}
// Checks for GL_OES_texture_half_float support
......@@ -762,8 +748,7 @@ void Extensions::setTextureExtensionSupport(const TextureCapsMap &textureCaps)
textureFloat = DetermineFloatTextureSupport(textureCaps);
textureFloatLinear = textureFloat && DetermineFloatTextureFilteringSupport(textureCaps);
textureRG = DetermineRGTextureSupport(textureCaps, textureHalfFloat, textureFloat);
colorBufferHalfFloat =
textureHalfFloat && DetermineColorBufferHalfFloatSupport(textureCaps, textureRG);
colorBufferHalfFloat = textureHalfFloat && DetermineColorBufferHalfFloatSupport(textureCaps);
textureCompressionDXT1 = DetermineDXT1TextureSupport(textureCaps);
textureCompressionDXT3 = DetermineDXT3TextureSupport(textureCaps);
textureCompressionDXT5 = DetermineDXT5TextureSupport(textureCaps);
......
......@@ -544,6 +544,16 @@ static GLenum GetNativeType(const FunctionsGL *functions,
}
}
}
else if (functions->standard == STANDARD_GL_ES && functions->version == gl::Version(2, 0))
{
// On ES2, convert GL_HALF_FLOAT to GL_HALF_FLOAT_OES as a convenience for internal
// functions. It should not be possible to get here by a normal glTexImage2D call.
if (type == GL_HALF_FLOAT)
{
ASSERT(functions->hasGLExtension("GL_OES_texture_half_float"));
result = GL_HALF_FLOAT_OES;
}
}
return result;
}
......
......@@ -109,7 +109,103 @@ static bool MeetsRequirements(const FunctionsGL *functions,
}
}
static bool CheckSizedInternalFormatTextureRenderability(const FunctionsGL *functions,
const WorkaroundsGL &workarounds,
GLenum internalFormat)
{
const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat);
ASSERT(formatInfo.sized);
// Query the current texture so it can be rebound afterwards
GLint oldTextureBinding = 0;
functions->getIntegerv(GL_TEXTURE_BINDING_2D, &oldTextureBinding);
// Create a small texture with the same format and type that gl::Texture would use
GLuint texture = 0;
functions->genTextures(1, &texture);
functions->bindTexture(GL_TEXTURE_2D, texture);
// Nearest filter needed for framebuffer completeness on some drivers.
functions->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
nativegl::TexImageFormat texImageFormat = nativegl::GetTexImageFormat(
functions, workarounds, formatInfo.internalFormat, formatInfo.format, formatInfo.type);
constexpr GLsizei kTextureSize = 16;
functions->texImage2D(GL_TEXTURE_2D, 0, texImageFormat.internalFormat, kTextureSize,
kTextureSize, 0, texImageFormat.format, texImageFormat.type, nullptr);
// Query the current framebuffer so it can be rebound afterwards
GLint oldFramebufferBinding = 0;
functions->getIntegerv(GL_FRAMEBUFFER_BINDING, &oldFramebufferBinding);
// Bind the texture to the framebuffer and check renderability
GLuint fbo = 0;
functions->genFramebuffers(1, &fbo);
functions->bindFramebuffer(GL_FRAMEBUFFER, fbo);
functions->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture,
0);
bool supported = functions->checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE;
// Delete the framebuffer and restore the previous binding
functions->deleteFramebuffers(1, &fbo);
functions->bindFramebuffer(GL_FRAMEBUFFER, static_cast<GLuint>(oldFramebufferBinding));
// Delete the texture and restore the previous binding
functions->deleteTextures(1, &texture);
functions->bindTexture(GL_TEXTURE_2D, static_cast<GLuint>(oldTextureBinding));
return supported;
}
static bool CheckInternalFormatRenderbufferRenderability(const FunctionsGL *functions,
const WorkaroundsGL &workarounds,
GLenum internalFormat)
{
const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat);
ASSERT(formatInfo.sized);
// Query the current renderbuffer so it can be rebound afterwards
GLint oldRenderbufferBinding = 0;
functions->getIntegerv(GL_RENDERBUFFER_BINDING, &oldRenderbufferBinding);
// Create a small renderbuffer with the same format and type that gl::Renderbuffer would use
GLuint renderbuffer = 0;
functions->genRenderbuffers(1, &renderbuffer);
functions->bindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
nativegl::RenderbufferFormat renderbufferFormat =
nativegl::GetRenderbufferFormat(functions, workarounds, formatInfo.internalFormat);
constexpr GLsizei kRenderbufferSize = 16;
functions->renderbufferStorage(GL_RENDERBUFFER, renderbufferFormat.internalFormat,
kRenderbufferSize, kRenderbufferSize);
// Query the current framebuffer so it can be rebound afterwards
GLint oldFramebufferBinding = 0;
functions->getIntegerv(GL_FRAMEBUFFER_BINDING, &oldFramebufferBinding);
// Bind the texture to the framebuffer and check renderability
GLuint fbo = 0;
functions->genFramebuffers(1, &fbo);
functions->bindFramebuffer(GL_FRAMEBUFFER, fbo);
functions->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
renderbuffer);
bool supported = functions->checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE;
// Delete the framebuffer and restore the previous binding
functions->deleteFramebuffers(1, &fbo);
functions->bindFramebuffer(GL_FRAMEBUFFER, static_cast<GLuint>(oldFramebufferBinding));
// Delete the renderbuffer and restore the previous binding
functions->deleteRenderbuffers(1, &renderbuffer);
functions->bindRenderbuffer(GL_RENDERBUFFER, static_cast<GLuint>(oldRenderbufferBinding));
return supported;
}
static gl::TextureCaps GenerateTextureFormatCaps(const FunctionsGL *functions,
const WorkaroundsGL &workarounds,
GLenum internalFormat)
{
ASSERT(functions->getError() == GL_NO_ERROR);
......@@ -124,6 +220,23 @@ static gl::TextureCaps GenerateTextureFormatCaps(const FunctionsGL *functions,
textureCaps.textureAttachment = MeetsRequirements(functions, formatInfo.textureAttachment);
textureCaps.renderbuffer = MeetsRequirements(functions, formatInfo.renderbuffer);
// Do extra renderability validation for some formats.
// We require GL_RGBA16F is renderable to expose EXT_color_buffer_half_float but we can't know
// if the format is supported unless we try to create a framebuffer.
if (internalFormat == GL_RGBA16F)
{
if (textureCaps.textureAttachment)
{
textureCaps.textureAttachment = CheckSizedInternalFormatTextureRenderability(
functions, workarounds, internalFormat);
}
if (textureCaps.renderbuffer)
{
textureCaps.renderbuffer = CheckInternalFormatRenderbufferRenderability(
functions, workarounds, internalFormat);
}
}
// glGetInternalformativ is not available until version 4.2 but may be available through the 3.0
// extension GL_ARB_internalformat_query
if (textureCaps.renderbuffer && functions->getInternalformativ)
......@@ -281,7 +394,8 @@ void GenerateCaps(const FunctionsGL *functions,
const gl::FormatSet &allFormats = gl::GetAllSizedInternalFormats();
for (GLenum internalFormat : allFormats)
{
gl::TextureCaps textureCaps = GenerateTextureFormatCaps(functions, internalFormat);
gl::TextureCaps textureCaps =
GenerateTextureFormatCaps(functions, workarounds, internalFormat);
textureCapsMap->insert(internalFormat, textureCaps);
if (gl::GetSizedInternalFormatInfo(internalFormat).compressed)
......
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