gl-renderer: Add EXT_texture_format_BGRA8888 support to utilities

EXT_texture_format_BGRA8888 allows OpenGL ES implementations to
support GL_BGRA8_EXT FBO and texture format.

OpenGL implementations handle the spec differently regarding the use
of GL_BGRA8_EXT or GL_BGRA_EXT with TexStorage*D(), TexImage*D() and
RenderbufferStorage(). A recent revision of the spec (and Mesa)
clarifies all that, but in order to support most drivers we simply
check which method is supported by order of preference.

Co-authored-by: Daniel Stone <daniels@collabora.com>
Signed-off-by: Loïc Molinari <loic.molinari@collabora.com>
This commit is contained in:
Loïc Molinari 2024-10-04 19:26:01 +02:00 committed by Daniel Stone
parent dcee21f02f
commit 85dd477466
3 changed files with 163 additions and 5 deletions

View file

@ -182,6 +182,11 @@ enum gl_feature_flag {
/* GL renderer can create two-component red-green textures. */
FEATURE_TEXTURE_RG = 1ull << 7,
/* GL renderer supports the GL_EXT_texture_format_BGRA8888 extension
* with the GL_BGRA8_EXT sized internal format revision (23/06/2024) for
* renderbuffer objects. */
FEATURE_SIZED_BGRA8_RENDERBUFFER = 1ull << 8,
};
/* Keep the following in sync with vertex.glsl. */
@ -237,6 +242,13 @@ static_assert(TEX_UNIT_LAST < 8, "OpenGL ES 2.0 requires at least 8 texture "
"GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS check at display creation "
"to require more.");
enum gl_bgra8_texture_support {
BGRA8_TEXTURE_SUPPORT_STORAGE = 0,
BGRA8_TEXTURE_SUPPORT_IMAGE_REVISED,
BGRA8_TEXTURE_SUPPORT_IMAGE_ORIGINAL,
BGRA8_TEXTURE_SUPPORT_NONE,
};
struct gl_extension_table {
const char *str;
size_t len;
@ -428,6 +440,7 @@ struct gl_renderer {
uint64_t features;
GLenum pbo_usage;
enum gl_bgra8_texture_support bgra8_texture_support;
struct wl_list dmabuf_images;
struct wl_list dmabuf_formats;
@ -506,6 +519,12 @@ gl_features_has(struct gl_renderer *gr,
return (bool) (gr->features & ((uint64_t) flag));
}
enum gl_bgra8_texture_support
gl_get_bgra8_texture_support(struct gl_renderer *gr);
bool
gl_has_sized_bgra8_renderbuffer(struct gl_renderer *gr);
bool
gl_texture_is_format_supported(struct gl_renderer *gr,
GLenum format);

View file

@ -4845,6 +4845,12 @@ gl_renderer_setup(struct weston_compositor *ec)
gl_extensions_has(gr, EXTENSION_EXT_TEXTURE_RG))
gr->features |= FEATURE_TEXTURE_RG;
/* Sized BGRA renderbuffer feature. */
if (gl_has_sized_bgra8_renderbuffer(gr))
gr->features |= FEATURE_SIZED_BGRA8_RENDERBUFFER;
gr->bgra8_texture_support = gl_get_bgra8_texture_support(gr);
wl_list_init(&gr->pending_capture_list);
glActiveTexture(GL_TEXTURE0);

View file

@ -101,6 +101,7 @@
* GL_RGBA16F 3.0 3.0 3.2 GL_RGBA GL_HALF_FLOAT,
* GL_FLOAT
* GL_RGBA32F 3.0 3.2 GL_RGBA GL_FLOAT
* GL_BGRA8_EXT E E E GL_BGRA_EXT GL_UNSIGNED_BYTE
* GL_RGBA8UI 3.0 3.0 GL_RGBA_INTEGER GL_UNSIGNED_BYTE
* GL_RGBA8I 3.0 3.0 GL_RGBA_INTEGER GL_BYTE
* GL_RGB10_A2UI 3.0 3.0 GL_RGBA_INTEGER GL_UNSIGNED_INT_2_10_10_10_REV
@ -224,6 +225,13 @@ is_valid_format_es3(struct gl_renderer *gr,
return gl_extensions_has(gr, EXTENSION_EXT_TEXTURE_NORM16) &&
external_format == GL_RGBA;
/* GL_BGRA_EXT must be here even though it's not a proper sized internal
* format to crrectly support EXT_texture_format_BGRA8888. */
case GL_BGRA8_EXT:
case GL_BGRA_EXT:
return gl_extensions_has(gr, EXTENSION_EXT_TEXTURE_FORMAT_BGRA8888) &&
external_format == GL_BGRA_EXT;
default:
return false;
}
@ -260,6 +268,12 @@ is_valid_type_es3(struct gl_renderer *gr,
return gl_extensions_has(gr, EXTENSION_EXT_TEXTURE_SRGB_RG8) &&
type == GL_UNSIGNED_BYTE;
/* See comment in is_valid_format_es3(). */
case GL_BGRA8_EXT:
case GL_BGRA_EXT:
return gl_extensions_has(gr, EXTENSION_EXT_TEXTURE_FORMAT_BGRA8888) &&
type == GL_UNSIGNED_BYTE;
case GL_R8I:
case GL_R8_SNORM:
case GL_RG8I:
@ -451,6 +465,14 @@ is_valid_combination_es3(struct gl_renderer *gr,
return false;
}
case GL_BGRA_EXT:
switch (type) {
case GL_UNSIGNED_BYTE:
return gl_extensions_has(gr, EXTENSION_EXT_TEXTURE_FORMAT_BGRA8888);
default:
return false;
};
default:
return false;
}
@ -544,6 +566,14 @@ is_valid_combination_es2(struct gl_renderer *gr,
return false;
}
case GL_BGRA_EXT:
switch (type) {
case GL_UNSIGNED_BYTE:
return gl_extensions_has(gr, EXTENSION_EXT_TEXTURE_FORMAT_BGRA8888);
default:
return false;
};
default:
return false;
}
@ -551,6 +581,83 @@ is_valid_combination_es2(struct gl_renderer *gr,
#endif /* !defined(NDEBUG) */
/* Get the supported BGRA8 texture creation method. This is needed to correctly
* handle the behaviour of different drivers. This function should only be used
* at renderer setup once the extensions have been initialised.
*/
enum gl_bgra8_texture_support
gl_get_bgra8_texture_support(struct gl_renderer *gr)
{
enum gl_bgra8_texture_support support;
GLuint tex;
if (!gl_extensions_has(gr, EXTENSION_EXT_TEXTURE_FORMAT_BGRA8888))
return BGRA8_TEXTURE_SUPPORT_NONE;
/* Empty error queue. */
while (glGetError() != GL_NO_ERROR);
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
if (gl_features_has(gr, FEATURE_TEXTURE_IMMUTABILITY)) {
gr->tex_storage_2d(GL_TEXTURE_2D, 1, GL_BGRA8_EXT, 16, 16);
if (glGetError() == GL_NO_ERROR) {
support = BGRA8_TEXTURE_SUPPORT_STORAGE;
goto done;
}
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA8_EXT, 16, 16, 0, GL_BGRA_EXT,
GL_UNSIGNED_BYTE, NULL);
if (glGetError() == GL_NO_ERROR) {
support = BGRA8_TEXTURE_SUPPORT_IMAGE_REVISED;
goto done;
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT, 16, 16, 0, GL_BGRA_EXT,
GL_UNSIGNED_BYTE, NULL);
if (glGetError() == GL_NO_ERROR) {
support = BGRA8_TEXTURE_SUPPORT_IMAGE_ORIGINAL;
goto done;
}
support = BGRA8_TEXTURE_SUPPORT_NONE;
done:
glDeleteTextures(1, &tex);
return support;
}
/* Check whether the sized BGRA8 renderbuffer feature is available. This
* function should only be used at renderer setup once the extensions have been
* initialised.
*/
bool
gl_has_sized_bgra8_renderbuffer(struct gl_renderer *gr)
{
bool available = false;
GLuint rb;
if (!gl_extensions_has(gr, EXTENSION_EXT_TEXTURE_FORMAT_BGRA8888))
return false;
/* Empty error queue. */
while (glGetError() != GL_NO_ERROR);
glGenRenderbuffers(1, &rb);
glBindRenderbuffer(GL_RENDERBUFFER, rb);
glRenderbufferStorage(GL_RENDERBUFFER, GL_BGRA8_EXT, 16, 16);
if (glGetError() == GL_NO_ERROR)
available = true;
glDeleteRenderbuffers(1, &rb);
return available;
}
/* Check whether gl_texture_2d_init() supports texture creation for a given
* coloured sized internal format or not.
*/
@ -574,6 +681,9 @@ gl_texture_is_format_supported(struct gl_renderer *gr,
case GL_SRG8_EXT:
return gl_extensions_has(gr, EXTENSION_EXT_TEXTURE_SRGB_RG8);
case GL_BGRA8_EXT:
return gr->bgra8_texture_support != BGRA8_TEXTURE_SUPPORT_NONE;
case GL_R16F:
case GL_RG16F:
case GL_RGB16F:
@ -660,8 +770,8 @@ gl_texture_is_format_supported(struct gl_renderer *gr,
* Implementations support at least this subset of formats: GL_R8, GL_RG8,
* GL_RGB8, GL_RGB565, GL_RGBA8, GL_RGBA4 and GL_RGB5_A1. Additional formats are
* supported depending on extensions: GL_R16F, GL_RG16F, GL_RGB16F, GL_RGBA16F,
* GL_R32F, GL_RG32F, GL_RGB32F, GL_RGBA32F, GL_R11F_G11F_B10F, GL_RGB9_E5 and
* GL_RGB10_A2.
* GL_R32F, GL_RG32F, GL_RGB32F, GL_RGBA32F, GL_R11F_G11F_B10F, GL_RGB9_E5,
* GL_RGB10_A2 and GL_BGRA8_EXT.
*
* This is implemented by implicitly converting 'format' into an external
* format. If the red and red-green texture formats aren't supported
@ -680,6 +790,7 @@ gl_texture_2d_init(struct gl_renderer *gr,
int height,
GLuint *tex_out)
{
bool bgra_fallback;
GLuint tex;
assert(width > 0);
@ -694,7 +805,13 @@ gl_texture_2d_init(struct gl_renderer *gr,
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
if (gl_features_has(gr, FEATURE_TEXTURE_IMMUTABILITY)) {
/* Fallback to TexImage*D() when GL_BGRA8_EXT isn't supported by
* TexStorage*D(). */
bgra_fallback = format == GL_BGRA8_EXT &&
gr->bgra8_texture_support != BGRA8_TEXTURE_SUPPORT_STORAGE;
if (gl_features_has(gr, FEATURE_TEXTURE_IMMUTABILITY) &&
!bgra_fallback) {
if (!gl_features_has(gr, FEATURE_TEXTURE_RG)) {
switch (format) {
case GL_R8:
@ -824,6 +941,13 @@ gl_texture_2d_init(struct gl_renderer *gr,
type = GL_UNSIGNED_BYTE;
break;
case GL_BGRA8_EXT:
if (gr->bgra8_texture_support == BGRA8_TEXTURE_SUPPORT_IMAGE_ORIGINAL)
format = GL_BGRA_EXT;
external_format = GL_BGRA_EXT;
type = GL_UNSIGNED_BYTE;
break;
case GL_RGBA4:
if (!gl_extensions_has(gr, EXTENSION_OES_REQUIRED_INTERNALFORMAT))
format = GL_RGBA;
@ -994,6 +1118,9 @@ gl_fbo_is_format_supported(struct gl_renderer *gr,
gl_extensions_has(gr, EXTENSION_OES_RGB8_RGBA8) ||
gl_extensions_has(gr, EXTENSION_OES_REQUIRED_INTERNALFORMAT);
case GL_BGRA8_EXT:
return gl_extensions_has(gr, EXTENSION_EXT_TEXTURE_FORMAT_BGRA8888);
case GL_SRGB8_ALPHA8:
case GL_R8I:
case GL_R8UI:
@ -1079,8 +1206,8 @@ gl_fbo_is_format_supported(struct gl_renderer *gr,
*
* Implementations support at least these formats: GL_RGBA4, GL_RGB5_A1 and
* GL_RGB565. Additional formats are supported depending on extensions: GL_R8,
* GL_RG8, GL_RGB8, GL_RGBA8, GL_R16F, GL_RG16F, GL_RGB16F, GL_RGBA16F and
* GL_R11F_G11F_B10F.
* GL_RG8, GL_RGB8, GL_RGBA8, GL_R16F, GL_RG16F, GL_RGB16F, GL_RGBA16F,
* GL_R11F_G11F_B10F and GL_BGRA8_EXT.
*
* See gl_fbo_is_format_supported().
*/
@ -1100,6 +1227,10 @@ gl_fbo_init(struct gl_renderer *gr,
return false;
}
if (format == GL_BGRA8_EXT &&
!gl_features_has(gr, FEATURE_SIZED_BGRA8_RENDERBUFFER))
format = GL_BGRA_EXT;
glGenFramebuffers(1, &fb);
glBindFramebuffer(GL_FRAMEBUFFER, fb);
glGenRenderbuffers(1, &rb);
@ -1194,6 +1325,8 @@ gl_fbo_texture_init(GLenum internal_format,
GLenum status;
GLuint fb, tex;
/* XXX Port to new texture utilities and had sized BGRA8 support. */
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0,