Skip to content

Commit 4f2b94c

Browse files
vontureCommit Bot
authored andcommitted
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: Yuly Novikov <ynovikov@chromium.org>
1 parent 6494c41 commit 4f2b94c

File tree

3 files changed

+133
-24
lines changed

3 files changed

+133
-24
lines changed

src/libANGLE/Caps.cpp

Lines changed: 8 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -371,30 +371,16 @@ static bool DetermineBGRA8TextureSupport(const TextureCapsMap &textureCaps)
371371
}
372372

373373
// Checks for GL_OES_color_buffer_half_float support
374-
static bool DetermineColorBufferHalfFloatSupport(const TextureCapsMap &textureCaps,
375-
bool checkRGFormats)
374+
static bool DetermineColorBufferHalfFloatSupport(const TextureCapsMap &textureCaps)
376375
{
377-
constexpr GLenum requiredRGRenderbufferFormats[] = {
378-
GL_R16F, GL_RG16F,
379-
};
380-
constexpr GLenum requiredRenderbufferFormats[] = {
381-
GL_RGB16F, GL_RGBA16F,
382-
};
383-
// GL_RGBA16F since the extension says format=RGBA type=HALF_FLOAT_OES textures are renderable
384-
// GL_RGB16F because dEQP GLES3 tests for it in es3fFboColorbufferTests.cpp
385-
constexpr GLenum requiredTextureAttachmentFormats[] = {
386-
GL_RGB16F, GL_RGBA16F,
376+
// EXT_color_buffer_half_float issue #2 states that an implementation doesn't need to support
377+
// rendering to any of the formats but is expected to be able to render to at least one. WebGL
378+
// requires that at least RGBA16F is renderable so we make the same requirement.
379+
constexpr GLenum requiredFormats[] = {
380+
GL_RGBA16F,
387381
};
388382

389-
if (checkRGFormats &&
390-
!GetFormatSupport(textureCaps, requiredRGRenderbufferFormats, false, false, false, true))
391-
{
392-
return false;
393-
}
394-
395-
return GetFormatSupport(textureCaps, requiredRenderbufferFormats, false, false, false, true) &&
396-
GetFormatSupport(textureCaps, requiredTextureAttachmentFormats, false, false, true,
397-
false);
383+
return GetFormatSupport(textureCaps, requiredFormats, false, false, true, true);
398384
}
399385

400386
// Checks for GL_OES_texture_half_float support
@@ -762,8 +748,7 @@ void Extensions::setTextureExtensionSupport(const TextureCapsMap &textureCaps)
762748
textureFloat = DetermineFloatTextureSupport(textureCaps);
763749
textureFloatLinear = textureFloat && DetermineFloatTextureFilteringSupport(textureCaps);
764750
textureRG = DetermineRGTextureSupport(textureCaps, textureHalfFloat, textureFloat);
765-
colorBufferHalfFloat =
766-
textureHalfFloat && DetermineColorBufferHalfFloatSupport(textureCaps, textureRG);
751+
colorBufferHalfFloat = textureHalfFloat && DetermineColorBufferHalfFloatSupport(textureCaps);
767752
textureCompressionDXT1 = DetermineDXT1TextureSupport(textureCaps);
768753
textureCompressionDXT3 = DetermineDXT3TextureSupport(textureCaps);
769754
textureCompressionDXT5 = DetermineDXT5TextureSupport(textureCaps);

src/libANGLE/renderer/gl/formatutilsgl.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,16 @@ static GLenum GetNativeType(const FunctionsGL *functions,
544544
}
545545
}
546546
}
547+
else if (functions->standard == STANDARD_GL_ES && functions->version == gl::Version(2, 0))
548+
{
549+
// On ES2, convert GL_HALF_FLOAT to GL_HALF_FLOAT_OES as a convenience for internal
550+
// functions. It should not be possible to get here by a normal glTexImage2D call.
551+
if (type == GL_HALF_FLOAT)
552+
{
553+
ASSERT(functions->hasGLExtension("GL_OES_texture_half_float"));
554+
result = GL_HALF_FLOAT_OES;
555+
}
556+
}
547557

548558
return result;
549559
}

src/libANGLE/renderer/gl/renderergl_utils.cpp

Lines changed: 115 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,103 @@ static bool MeetsRequirements(const FunctionsGL *functions,
109109
}
110110
}
111111

112+
static bool CheckSizedInternalFormatTextureRenderability(const FunctionsGL *functions,
113+
const WorkaroundsGL &workarounds,
114+
GLenum internalFormat)
115+
{
116+
const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat);
117+
ASSERT(formatInfo.sized);
118+
119+
// Query the current texture so it can be rebound afterwards
120+
GLint oldTextureBinding = 0;
121+
functions->getIntegerv(GL_TEXTURE_BINDING_2D, &oldTextureBinding);
122+
123+
// Create a small texture with the same format and type that gl::Texture would use
124+
GLuint texture = 0;
125+
functions->genTextures(1, &texture);
126+
functions->bindTexture(GL_TEXTURE_2D, texture);
127+
128+
// Nearest filter needed for framebuffer completeness on some drivers.
129+
functions->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
130+
131+
nativegl::TexImageFormat texImageFormat = nativegl::GetTexImageFormat(
132+
functions, workarounds, formatInfo.internalFormat, formatInfo.format, formatInfo.type);
133+
constexpr GLsizei kTextureSize = 16;
134+
functions->texImage2D(GL_TEXTURE_2D, 0, texImageFormat.internalFormat, kTextureSize,
135+
kTextureSize, 0, texImageFormat.format, texImageFormat.type, nullptr);
136+
137+
// Query the current framebuffer so it can be rebound afterwards
138+
GLint oldFramebufferBinding = 0;
139+
functions->getIntegerv(GL_FRAMEBUFFER_BINDING, &oldFramebufferBinding);
140+
141+
// Bind the texture to the framebuffer and check renderability
142+
GLuint fbo = 0;
143+
functions->genFramebuffers(1, &fbo);
144+
functions->bindFramebuffer(GL_FRAMEBUFFER, fbo);
145+
functions->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture,
146+
0);
147+
148+
bool supported = functions->checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE;
149+
150+
// Delete the framebuffer and restore the previous binding
151+
functions->deleteFramebuffers(1, &fbo);
152+
functions->bindFramebuffer(GL_FRAMEBUFFER, static_cast<GLuint>(oldFramebufferBinding));
153+
154+
// Delete the texture and restore the previous binding
155+
functions->deleteTextures(1, &texture);
156+
functions->bindTexture(GL_TEXTURE_2D, static_cast<GLuint>(oldTextureBinding));
157+
158+
return supported;
159+
}
160+
161+
static bool CheckInternalFormatRenderbufferRenderability(const FunctionsGL *functions,
162+
const WorkaroundsGL &workarounds,
163+
GLenum internalFormat)
164+
{
165+
const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat);
166+
ASSERT(formatInfo.sized);
167+
168+
// Query the current renderbuffer so it can be rebound afterwards
169+
GLint oldRenderbufferBinding = 0;
170+
functions->getIntegerv(GL_RENDERBUFFER_BINDING, &oldRenderbufferBinding);
171+
172+
// Create a small renderbuffer with the same format and type that gl::Renderbuffer would use
173+
GLuint renderbuffer = 0;
174+
functions->genRenderbuffers(1, &renderbuffer);
175+
functions->bindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
176+
177+
nativegl::RenderbufferFormat renderbufferFormat =
178+
nativegl::GetRenderbufferFormat(functions, workarounds, formatInfo.internalFormat);
179+
constexpr GLsizei kRenderbufferSize = 16;
180+
functions->renderbufferStorage(GL_RENDERBUFFER, renderbufferFormat.internalFormat,
181+
kRenderbufferSize, kRenderbufferSize);
182+
183+
// Query the current framebuffer so it can be rebound afterwards
184+
GLint oldFramebufferBinding = 0;
185+
functions->getIntegerv(GL_FRAMEBUFFER_BINDING, &oldFramebufferBinding);
186+
187+
// Bind the texture to the framebuffer and check renderability
188+
GLuint fbo = 0;
189+
functions->genFramebuffers(1, &fbo);
190+
functions->bindFramebuffer(GL_FRAMEBUFFER, fbo);
191+
functions->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
192+
renderbuffer);
193+
194+
bool supported = functions->checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE;
195+
196+
// Delete the framebuffer and restore the previous binding
197+
functions->deleteFramebuffers(1, &fbo);
198+
functions->bindFramebuffer(GL_FRAMEBUFFER, static_cast<GLuint>(oldFramebufferBinding));
199+
200+
// Delete the renderbuffer and restore the previous binding
201+
functions->deleteRenderbuffers(1, &renderbuffer);
202+
functions->bindRenderbuffer(GL_RENDERBUFFER, static_cast<GLuint>(oldRenderbufferBinding));
203+
204+
return supported;
205+
}
206+
112207
static gl::TextureCaps GenerateTextureFormatCaps(const FunctionsGL *functions,
208+
const WorkaroundsGL &workarounds,
113209
GLenum internalFormat)
114210
{
115211
ASSERT(functions->getError() == GL_NO_ERROR);
@@ -124,6 +220,23 @@ static gl::TextureCaps GenerateTextureFormatCaps(const FunctionsGL *functions,
124220
textureCaps.textureAttachment = MeetsRequirements(functions, formatInfo.textureAttachment);
125221
textureCaps.renderbuffer = MeetsRequirements(functions, formatInfo.renderbuffer);
126222

223+
// Do extra renderability validation for some formats.
224+
// We require GL_RGBA16F is renderable to expose EXT_color_buffer_half_float but we can't know
225+
// if the format is supported unless we try to create a framebuffer.
226+
if (internalFormat == GL_RGBA16F)
227+
{
228+
if (textureCaps.textureAttachment)
229+
{
230+
textureCaps.textureAttachment = CheckSizedInternalFormatTextureRenderability(
231+
functions, workarounds, internalFormat);
232+
}
233+
if (textureCaps.renderbuffer)
234+
{
235+
textureCaps.renderbuffer = CheckInternalFormatRenderbufferRenderability(
236+
functions, workarounds, internalFormat);
237+
}
238+
}
239+
127240
// glGetInternalformativ is not available until version 4.2 but may be available through the 3.0
128241
// extension GL_ARB_internalformat_query
129242
if (textureCaps.renderbuffer && functions->getInternalformativ)
@@ -281,7 +394,8 @@ void GenerateCaps(const FunctionsGL *functions,
281394
const gl::FormatSet &allFormats = gl::GetAllSizedInternalFormats();
282395
for (GLenum internalFormat : allFormats)
283396
{
284-
gl::TextureCaps textureCaps = GenerateTextureFormatCaps(functions, internalFormat);
397+
gl::TextureCaps textureCaps =
398+
GenerateTextureFormatCaps(functions, workarounds, internalFormat);
285399
textureCapsMap->insert(internalFormat, textureCaps);
286400

287401
if (gl::GetSizedInternalFormatInfo(internalFormat).compressed)

0 commit comments

Comments
 (0)