diff --git a/libweston/renderer-gl/gl-renderer-internal.h b/libweston/renderer-gl/gl-renderer-internal.h index 4a1905e39..956732122 100644 --- a/libweston/renderer-gl/gl-renderer-internal.h +++ b/libweston/renderer-gl/gl-renderer-internal.h @@ -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); diff --git a/libweston/renderer-gl/gl-renderer.c b/libweston/renderer-gl/gl-renderer.c index 72f9b8227..3f4441249 100644 --- a/libweston/renderer-gl/gl-renderer.c +++ b/libweston/renderer-gl/gl-renderer.c @@ -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); diff --git a/libweston/renderer-gl/gl-utils.c b/libweston/renderer-gl/gl-utils.c index d29d310a9..1bf335721 100644 --- a/libweston/renderer-gl/gl-utils.c +++ b/libweston/renderer-gl/gl-utils.c @@ -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,