2024-01-18 20:29:09 +01:00
/*
* Copyright ( c ) 2024 , Aliaksandr Kalenik < kalenik . aliaksandr @ gmail . com >
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
2025-01-17 15:42:17 +00:00
# include <AK/HashMap.h>
2024-01-18 20:29:09 +01:00
# include <AK/OwnPtr.h>
2024-11-29 22:15:02 +01:00
# include <AK/String.h>
# include <LibGfx/PaintingSurface.h>
2024-01-18 20:29:09 +01:00
# include <LibWeb/WebGL/OpenGLContext.h>
2024-11-29 22:15:02 +01:00
# ifdef AK_OS_MACOS
# include <EGL / egl.h>
# include <EGL / eglext.h>
2025-03-23 11:27:39 +00:00
# define EGL_EGLEXT_PROTOTYPES 1
extern " C " {
2024-11-29 22:15:02 +01:00
# include <EGL / eglext_angle.h>
2025-03-23 11:27:39 +00:00
}
2025-01-10 12:52:47 +00:00
# define GL_GLEXT_PROTOTYPES 1
2024-11-29 22:15:02 +01:00
# include <GLES2 / gl2.h>
# include <GLES2 / gl2ext.h>
2025-01-10 12:52:47 +00:00
extern " C " {
2024-11-29 22:15:02 +01:00
# include <GLES2 / gl2ext_angle.h>
2025-01-10 12:52:47 +00:00
}
2024-11-29 22:15:02 +01:00
# endif
2024-01-18 20:29:09 +01:00
namespace Web : : WebGL {
2024-11-29 22:15:02 +01:00
struct OpenGLContext : : Impl {
# ifdef AK_OS_MACOS
EGLDisplay display { nullptr } ;
EGLConfig config { nullptr } ;
EGLContext context { nullptr } ;
EGLSurface surface { nullptr } ;
GLuint framebuffer { 0 } ;
GLuint depth_buffer { 0 } ;
# endif
} ;
2025-03-23 10:38:00 +00:00
OpenGLContext : : OpenGLContext ( NonnullRefPtr < Gfx : : SkiaBackendContext > skia_backend_context , Impl impl , WebGLVersion webgl_version )
2024-11-29 22:15:02 +01:00
: m_skia_backend_context ( move ( skia_backend_context ) )
, m_impl ( make < Impl > ( impl ) )
2025-03-23 10:38:00 +00:00
, m_webgl_version ( webgl_version )
2024-11-29 22:15:02 +01:00
{
}
OpenGLContext : : ~ OpenGLContext ( )
2024-01-18 20:29:09 +01:00
{
2024-11-29 22:15:02 +01:00
# ifdef AK_OS_MACOS
eglMakeCurrent ( m_impl - > display , EGL_NO_SURFACE , EGL_NO_SURFACE , EGL_NO_CONTEXT ) ;
glDeleteFramebuffers ( 1 , & m_impl - > framebuffer ) ;
glDeleteRenderbuffers ( 1 , & m_impl - > depth_buffer ) ;
eglDestroyContext ( m_impl - > display , m_impl - > context ) ;
2025-03-23 11:23:32 +00:00
eglReleaseTexImage ( m_impl - > display , m_impl - > surface , EGL_BACK_BUFFER ) ;
2024-11-29 22:15:02 +01:00
eglDestroySurface ( m_impl - > display , m_impl - > surface ) ;
# endif
}
# ifdef AK_OS_MACOS
static EGLConfig get_egl_config ( EGLDisplay display )
{
EGLint const config_attribs [ ] = {
EGL_SURFACE_TYPE , EGL_WINDOW_BIT ,
EGL_RENDERABLE_TYPE , EGL_OPENGL_ES2_BIT ,
EGL_RED_SIZE , 8 ,
EGL_GREEN_SIZE , 8 ,
EGL_BLUE_SIZE , 8 ,
EGL_ALPHA_SIZE , 8 ,
EGL_DEPTH_SIZE , 24 ,
EGL_STENCIL_SIZE , 8 ,
EGL_NONE
} ;
EGLint number_of_configs ;
eglChooseConfig ( display , config_attribs , NULL , 0 , & number_of_configs ) ;
Vector < EGLConfig > configs ;
configs . resize ( number_of_configs ) ;
eglChooseConfig ( display , config_attribs , configs . data ( ) , number_of_configs , & number_of_configs ) ;
return configs [ 0 ] ;
}
# endif
2025-03-23 10:38:00 +00:00
OwnPtr < OpenGLContext > OpenGLContext : : create ( NonnullRefPtr < Gfx : : SkiaBackendContext > skia_backend_context , WebGLVersion webgl_version )
2024-11-29 22:15:02 +01:00
{
# ifdef AK_OS_MACOS
2025-03-23 10:51:05 +00:00
EGLAttrib display_attributes [ ] = {
EGL_PLATFORM_ANGLE_TYPE_ANGLE ,
EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE ,
EGL_NONE ,
} ;
EGLDisplay display = eglGetPlatformDisplay ( EGL_PLATFORM_ANGLE_ANGLE , reinterpret_cast < void * > ( EGL_DEFAULT_DISPLAY ) , display_attributes ) ;
2024-11-29 22:15:02 +01:00
if ( display = = EGL_NO_DISPLAY ) {
dbgln ( " Failed to get EGL display " ) ;
return { } ;
}
EGLint major , minor ;
if ( ! eglInitialize ( display , & major , & minor ) ) {
dbgln ( " Failed to initialize EGL " ) ;
return { } ;
}
auto * config = get_egl_config ( display ) ;
EGLint context_attributes [ ] = {
2025-01-10 12:52:47 +00:00
EGL_CONTEXT_CLIENT_VERSION ,
2025-03-23 10:38:00 +00:00
webgl_version = = WebGLVersion : : WebGL1 ? 2 : 3 ,
2025-01-10 12:52:47 +00:00
EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE ,
EGL_TRUE ,
2025-03-23 11:20:16 +00:00
EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE ,
EGL_TRUE ,
2025-03-23 10:38:00 +00:00
EGL_CONTEXT_OPENGL_BACKWARDS_COMPATIBLE_ANGLE ,
EGL_FALSE ,
2025-01-10 12:52:47 +00:00
EGL_NONE ,
EGL_NONE ,
2024-11-29 22:15:02 +01:00
} ;
EGLContext context = eglCreateContext ( display , config , EGL_NO_CONTEXT , context_attributes ) ;
if ( context = = EGL_NO_CONTEXT ) {
dbgln ( " Failed to create EGL context " ) ;
return { } ;
}
2025-03-23 10:38:00 +00:00
return make < OpenGLContext > ( skia_backend_context , Impl { . display = display , . config = config , . context = context } , webgl_version ) ;
2024-11-29 22:15:02 +01:00
# else
( void ) skia_backend_context ;
2025-03-23 10:38:00 +00:00
( void ) webgl_version ;
2024-11-29 22:15:02 +01:00
return nullptr ;
# endif
2024-01-18 20:29:09 +01:00
}
2024-11-29 23:15:43 +01:00
void OpenGLContext : : notify_content_will_change ( )
{
m_painting_surface - > notify_content_will_change ( ) ;
}
2024-01-18 20:29:09 +01:00
void OpenGLContext : : clear_buffer_to_default_values ( )
{
2025-01-28 17:11:47 +00:00
# ifdef AK_OS_MACOS
Array < GLfloat , 4 > current_clear_color ;
glGetFloatv ( GL_COLOR_CLEAR_VALUE , current_clear_color . data ( ) ) ;
GLfloat current_clear_depth ;
glGetFloatv ( GL_DEPTH_CLEAR_VALUE , & current_clear_depth ) ;
GLint current_clear_stencil ;
glGetIntegerv ( GL_STENCIL_CLEAR_VALUE , & current_clear_stencil ) ;
// The implicit clear value for the color buffer is (0, 0, 0, 0)
glClearColor ( 0 , 0 , 0 , 0 ) ;
// The implicit clear value for the depth buffer is 1.0.
glClearDepthf ( 1.0f ) ;
// The implicit clear value for the stencil buffer is 0.
glClearStencil ( 0 ) ;
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT ) ;
// Restore the clear values.
glClearColor ( current_clear_color [ 0 ] , current_clear_color [ 1 ] , current_clear_color [ 2 ] , current_clear_color [ 3 ] ) ;
glClearDepthf ( current_clear_depth ) ;
glClearStencil ( current_clear_stencil ) ;
# endif
2024-01-18 20:29:09 +01:00
}
2024-11-29 22:15:02 +01:00
void OpenGLContext : : allocate_painting_surface_if_needed ( )
{
# ifdef AK_OS_MACOS
if ( m_painting_surface )
return ;
VERIFY ( ! m_size . is_empty ( ) ) ;
auto iosurface = Core : : IOSurfaceHandle : : create ( m_size . width ( ) , m_size . height ( ) ) ;
auto width = m_size . width ( ) ;
auto height = m_size . height ( ) ;
auto * display = m_impl - > display ;
auto * config = m_impl - > config ;
EGLint target = 0 ;
eglGetConfigAttrib ( display , config , EGL_BIND_TO_TEXTURE_TARGET_ANGLE , & target ) ;
EGLint const surface_attributes [ ] = {
EGL_WIDTH ,
width ,
EGL_HEIGHT ,
height ,
EGL_IOSURFACE_PLANE_ANGLE ,
0 ,
EGL_TEXTURE_TARGET ,
target ,
EGL_TEXTURE_INTERNAL_FORMAT_ANGLE ,
GL_BGRA_EXT ,
EGL_TEXTURE_FORMAT ,
EGL_TEXTURE_RGBA ,
EGL_TEXTURE_TYPE_ANGLE ,
GL_UNSIGNED_BYTE ,
EGL_NONE ,
EGL_NONE ,
} ;
m_impl - > surface = eglCreatePbufferFromClientBuffer ( display , EGL_IOSURFACE_ANGLE , iosurface . core_foundation_pointer ( ) , config , surface_attributes ) ;
eglMakeCurrent ( m_impl - > display , m_impl - > surface , m_impl - > surface , m_impl - > context ) ;
2024-12-20 17:44:43 -07:00
EGLint texture_target_name = 0 ;
eglGetConfigAttrib ( display , config , EGL_BIND_TO_TEXTURE_TARGET_ANGLE , & texture_target_name ) ;
VERIFY ( texture_target_name = = EGL_TEXTURE_RECTANGLE_ANGLE | | texture_target_name = = EGL_TEXTURE_2D ) ;
2024-11-29 22:15:02 +01:00
GLuint texture = 0 ;
glGenTextures ( 1 , & texture ) ;
2024-12-20 17:44:43 -07:00
glBindTexture ( texture_target_name = = EGL_TEXTURE_RECTANGLE_ANGLE ? GL_TEXTURE_RECTANGLE_ANGLE : GL_TEXTURE_2D , texture ) ;
2024-11-29 22:15:02 +01:00
auto result = eglBindTexImage ( display , m_impl - > surface , EGL_BACK_BUFFER ) ;
VERIFY ( result = = EGL_TRUE ) ;
glGenFramebuffers ( 1 , & m_impl - > framebuffer ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , m_impl - > framebuffer ) ;
2024-12-20 17:44:43 -07:00
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , texture_target_name = = EGL_TEXTURE_RECTANGLE_ANGLE ? GL_TEXTURE_RECTANGLE_ANGLE : GL_TEXTURE_2D , texture , 0 ) ;
2024-11-29 22:15:02 +01:00
// NOTE: ANGLE doesn't allocate depth buffer for us, so we need to do it manually
// FIXME: Depth buffer only needs to be allocated if it's configured in WebGL context attributes
glGenRenderbuffers ( 1 , & m_impl - > depth_buffer ) ;
glBindRenderbuffer ( GL_RENDERBUFFER , m_impl - > depth_buffer ) ;
glRenderbufferStorage ( GL_RENDERBUFFER , GL_DEPTH_COMPONENT16 , width , height ) ;
glFramebufferRenderbuffer ( GL_FRAMEBUFFER , GL_DEPTH_ATTACHMENT , GL_RENDERBUFFER , m_impl - > depth_buffer ) ;
2025-06-27 04:39:16 +02:00
m_painting_surface = Gfx : : PaintingSurface : : create_from_iosurface ( move ( iosurface ) , m_skia_backend_context , Gfx : : PaintingSurface : : Origin : : BottomLeft ) ;
2024-11-29 22:15:02 +01:00
# endif
}
void OpenGLContext : : set_size ( Gfx : : IntSize const & size )
{
if ( m_size ! = size ) {
m_painting_surface = nullptr ;
}
m_size = size ;
}
void OpenGLContext : : make_current ( )
{
# ifdef AK_OS_MACOS
allocate_painting_surface_if_needed ( ) ;
eglMakeCurrent ( m_impl - > display , m_impl - > surface , m_impl - > surface , m_impl - > context ) ;
# endif
}
2025-03-23 11:27:39 +00:00
void OpenGLContext : : present ( bool preserve_drawing_buffer )
{
make_current ( ) ;
// "Before the drawing buffer is presented for compositing the implementation shall ensure that all rendering operations have been flushed to the drawing buffer."
// With Metal, glFlush flushes the command buffer, but without waiting for it to be scheduled or completed.
// eglWaitUntilWorkScheduledANGLE flushes the command buffer, and waits until it has been scheduled, hence the name.
// eglWaitUntilWorkScheduledANGLE only has an effect on CGL and Metal backends, so we only use it on macOS.
# ifdef AK_OS_MACOS
eglWaitUntilWorkScheduledANGLE ( m_impl - > display ) ;
# else
// FIXME: When enabling WebGL for Linux, we need to use glFlush() here.
# endif
// "By default, after compositing the contents of the drawing buffer shall be cleared to their default values, as shown in the table above.
// This default behavior can be changed by setting the preserveDrawingBuffer attribute of the WebGLContextAttributes object.
// If this flag is true, the contents of the drawing buffer shall be preserved until the author either clears or overwrites them."
if ( ! preserve_drawing_buffer ) {
clear_buffer_to_default_values ( ) ;
}
}
2024-11-29 22:15:02 +01:00
RefPtr < Gfx : : PaintingSurface > OpenGLContext : : surface ( )
{
return m_painting_surface ;
}
2025-01-08 13:00:12 +00:00
u32 OpenGLContext : : default_renderbuffer ( ) const
{
# ifdef AK_OS_MACOS
return m_impl - > depth_buffer ;
# else
return 0 ;
# endif
}
u32 OpenGLContext : : default_framebuffer ( ) const
{
# ifdef AK_OS_MACOS
return m_impl - > framebuffer ;
# else
return 0 ;
# endif
}
2025-01-17 15:42:17 +00:00
struct Extension {
String webgl_extension_name ;
Vector < StringView > required_angle_extensions ;
2025-03-23 10:38:00 +00:00
Optional < OpenGLContext : : WebGLVersion > only_for_webgl_version { OptionalNone { } } ;
2025-01-17 15:42:17 +00:00
} ;
Vector < Extension > s_available_webgl_extensions {
2024-12-10 05:49:33 +01:00
// Khronos ratified WebGL Extensions
2025-03-23 10:38:00 +00:00
{ " ANGLE_instanced_arrays " _string , { " GL_ANGLE_instanced_arrays " sv } , OpenGLContext : : WebGLVersion : : WebGL1 } ,
{ " EXT_blend_minmax " _string , { " GL_EXT_blend_minmax " sv } , OpenGLContext : : WebGLVersion : : WebGL1 } ,
{ " EXT_frag_depth " _string , { " GL_EXT_frag_depth " sv } , OpenGLContext : : WebGLVersion : : WebGL1 } ,
{ " EXT_shader_texture_lod " _string , { " GL_EXT_shader_texture_lod " sv } , OpenGLContext : : WebGLVersion : : WebGL1 } ,
2025-01-17 15:42:17 +00:00
{ " EXT_texture_filter_anisotropic " _string , { " GL_EXT_texture_filter_anisotropic " sv } } ,
2025-03-23 10:38:00 +00:00
{ " OES_element_index_uint " _string , { " GL_OES_element_index_uint " sv } , OpenGLContext : : WebGLVersion : : WebGL1 } ,
{ " OES_standard_derivatives " _string , { " GL_OES_standard_derivatives " sv } , OpenGLContext : : WebGLVersion : : WebGL1 } ,
{ " OES_texture_float " _string , { " GL_OES_texture_float " sv } , OpenGLContext : : WebGLVersion : : WebGL1 } ,
2025-01-17 15:42:17 +00:00
{ " OES_texture_float_linear " _string , { " GL_OES_texture_float_linear " sv } } ,
2025-03-23 10:38:00 +00:00
{ " OES_texture_half_float " _string , { " GL_OES_texture_half_float " sv } , OpenGLContext : : WebGLVersion : : WebGL1 } ,
{ " OES_texture_half_float_linear " _string , { " GL_OES_texture_half_float_linear " sv } , OpenGLContext : : WebGLVersion : : WebGL1 } ,
{ " OES_vertex_array_object " _string , { " GL_OES_vertex_array_object " sv } , OpenGLContext : : WebGLVersion : : WebGL1 } ,
2025-01-17 15:42:17 +00:00
{ " WEBGL_compressed_texture_s3tc " _string , { " GL_EXT_texture_compression_dxt1 " sv , " GL_ANGLE_texture_compression_dxt3 " sv , " GL_ANGLE_texture_compression_dxt5 " sv } } ,
{ " WEBGL_debug_renderer_info " _string , { } } ,
{ " WEBGL_debug_shaders " _string , { } } ,
2025-03-23 10:38:00 +00:00
{ " WEBGL_depth_texture " _string , { " GL_ANGLE_depth_texture " sv } , OpenGLContext : : WebGLVersion : : WebGL1 } ,
{ " WEBGL_draw_buffers " _string , { " GL_EXT_draw_buffers " sv } , OpenGLContext : : WebGLVersion : : WebGL1 } ,
2025-01-17 15:42:17 +00:00
{ " WEBGL_lose_context " _string , { } } ,
2024-12-10 05:49:33 +01:00
// Community approved WebGL Extensions
2025-01-17 15:42:17 +00:00
{ " EXT_clip_control " _string , { " GL_EXT_clip_control " sv } } ,
2025-03-23 10:38:00 +00:00
{ " EXT_color_buffer_float " _string , { " GL_EXT_color_buffer_float " sv } , OpenGLContext : : WebGLVersion : : WebGL2 } ,
2025-01-17 15:42:17 +00:00
{ " EXT_color_buffer_half_float " _string , { " GL_EXT_color_buffer_half_float " sv } } ,
2025-03-23 10:38:00 +00:00
{ " EXT_conservative_depth " _string , { " GL_EXT_conservative_depth " sv } , OpenGLContext : : WebGLVersion : : WebGL2 } ,
2025-01-17 15:42:17 +00:00
{ " EXT_depth_clamp " _string , { " GL_EXT_depth_clamp " sv } } ,
2025-03-23 10:38:00 +00:00
{ " EXT_disjoint_timer_query " _string , { " GL_EXT_disjoint_timer_query " sv } , OpenGLContext : : WebGLVersion : : WebGL1 } ,
{ " EXT_disjoint_timer_query_webgl2 " _string , { " GL_EXT_disjoint_timer_query " sv } , OpenGLContext : : WebGLVersion : : WebGL2 } ,
2025-01-17 15:42:17 +00:00
{ " EXT_float_blend " _string , { " GL_EXT_float_blend " sv } } ,
{ " EXT_polygon_offset_clamp " _string , { " GL_EXT_polygon_offset_clamp " sv } } ,
2025-03-23 10:38:00 +00:00
{ " EXT_render_snorm " _string , { " GL_EXT_render_snorm " sv } , OpenGLContext : : WebGLVersion : : WebGL2 } ,
{ " EXT_sRGB " _string , { " GL_EXT_sRGB " sv } , OpenGLContext : : WebGLVersion : : WebGL1 } ,
2025-01-17 15:42:17 +00:00
{ " EXT_texture_compression_bptc " _string , { " GL_EXT_texture_compression_bptc " sv } } ,
{ " EXT_texture_compression_rgtc " _string , { " GL_EXT_texture_compression_rgtc " sv } } ,
{ " EXT_texture_mirror_clamp_to_edge " _string , { " GL_EXT_texture_mirror_clamp_to_edge " sv } } ,
2025-03-23 10:38:00 +00:00
{ " EXT_texture_norm16 " _string , { " GL_EXT_texture_norm16 " sv } , OpenGLContext : : WebGLVersion : : WebGL2 } ,
2025-01-17 15:42:17 +00:00
{ " KHR_parallel_shader_compile " _string , { " GL_KHR_parallel_shader_compile " sv } } ,
2025-03-23 10:38:00 +00:00
{ " NV_shader_noperspective_interpolation " _string , { " GL_NV_shader_noperspective_interpolation " sv } , OpenGLContext : : WebGLVersion : : WebGL2 } ,
2025-01-17 15:42:17 +00:00
{ " OES_draw_buffers_indexed " _string , { " GL_OES_draw_buffers_indexed " sv } } ,
2025-03-23 10:38:00 +00:00
{ " OES_fbo_render_mipmap " _string , { " GL_OES_fbo_render_mipmap " sv } , OpenGLContext : : WebGLVersion : : WebGL1 } ,
{ " OES_sample_variables " _string , { " GL_OES_sample_variables " sv } , OpenGLContext : : WebGLVersion : : WebGL2 } ,
{ " OES_shader_multisample_interpolation " _string , { " GL_OES_shader_multisample_interpolation " sv } , OpenGLContext : : WebGLVersion : : WebGL2 } ,
{ " OVR_multiview2 " _string , { " GL_OVR_multiview2 " sv } , OpenGLContext : : WebGLVersion : : WebGL2 } ,
2025-01-17 15:42:17 +00:00
{ " WEBGL_blend_func_extended " _string , { " GL_EXT_blend_func_extended " sv } } ,
2025-03-23 10:38:00 +00:00
{ " WEBGL_clip_cull_distance " _string , { " GL_EXT_clip_cull_distance " sv } , OpenGLContext : : WebGLVersion : : WebGL2 } ,
{ " WEBGL_color_buffer_float " _string , { " EXT_color_buffer_half_float " sv , " OES_texture_float " sv } , OpenGLContext : : WebGLVersion : : WebGL1 } ,
2025-01-17 15:42:17 +00:00
{ " WEBGL_compressed_texture_astc " _string , { " KHR_texture_compression_astc_hdr " sv , " KHR_texture_compression_astc_ldr " sv } } ,
{ " WEBGL_compressed_texture_etc " _string , { " GL_ANGLE_compressed_texture_etc " sv } } ,
{ " WEBGL_compressed_texture_etc1 " _string , { " GL_OES_compressed_ETC1_RGB8_texture " sv } } ,
{ " WEBGL_compressed_texture_pvrtc " _string , { " GL_IMG_texture_compression_pvrtc " sv } } ,
{ " WEBGL_compressed_texture_s3tc_srgb " _string , { " GL_EXT_texture_compression_s3tc_srgb " sv } } ,
{ " WEBGL_multi_draw " _string , { " GL_ANGLE_multi_draw " sv } } ,
{ " WEBGL_polygon_mode " _string , { " GL_ANGLE_polygon_mode " sv } } ,
2025-03-23 10:38:00 +00:00
{ " WEBGL_provoking_vertex " _string , { " GL_ANGLE_provoking_vertex " sv } , OpenGLContext : : WebGLVersion : : WebGL2 } ,
{ " WEBGL_render_shared_exponent " _string , { " GL_QCOM_render_shared_exponent " sv } , OpenGLContext : : WebGLVersion : : WebGL2 } ,
{ " WEBGL_stencil_texturing " _string , { " GL_ANGLE_stencil_texturing " sv } , OpenGLContext : : WebGLVersion : : WebGL2 } ,
2024-12-10 05:49:33 +01:00
} ;
Vector < String > OpenGLContext : : get_supported_extensions ( )
{
# ifdef AK_OS_MACOS
2025-01-17 15:42:17 +00:00
if ( m_requestable_extensions . has_value ( ) )
return m_requestable_extensions . value ( ) ;
2024-12-10 05:49:33 +01:00
make_current ( ) ;
2025-01-17 15:42:17 +00:00
auto const * requestable_extensions_string = reinterpret_cast < char const * > ( glGetString ( GL_REQUESTABLE_EXTENSIONS_ANGLE ) ) ;
StringView requestable_extensions_view ( requestable_extensions_string , strlen ( requestable_extensions_string ) ) ;
auto requestable_extensions = requestable_extensions_view . split_view ( ' ' ) ;
2024-12-10 05:49:33 +01:00
Vector < String > extensions ;
2025-01-17 15:42:17 +00:00
for ( auto const & available_extension : s_available_webgl_extensions ) {
2025-03-23 10:38:00 +00:00
bool supported = ! available_extension . only_for_webgl_version . has_value ( )
| | m_webgl_version = = available_extension . only_for_webgl_version ;
if ( supported ) {
for ( auto const & required_extension : available_extension . required_angle_extensions ) {
auto maybe_required_extension = requestable_extensions . find_if ( [ & ] ( StringView requestable_extension ) {
return required_extension = = requestable_extension ;
} ) ;
if ( maybe_required_extension = = requestable_extensions . end ( ) ) {
supported = false ;
break ;
}
2025-01-17 15:42:17 +00:00
}
}
if ( supported )
extensions . append ( available_extension . webgl_extension_name ) ;
2024-12-10 05:49:33 +01:00
}
2025-01-17 15:42:17 +00:00
// We must cache this, because once extensions have been requested, they're no longer requestable extensions and would
// not appear in this list. However, we must always report every supported extension, regardless of what has already
// been requested.
m_requestable_extensions = extensions ;
2024-12-10 05:49:33 +01:00
return extensions ;
# else
2025-03-23 10:38:00 +00:00
( void ) m_webgl_version ;
2024-12-10 05:49:33 +01:00
return { } ;
# endif
}
2025-01-10 12:55:47 +00:00
void OpenGLContext : : request_extension ( char const * extension_name )
{
# ifdef AK_OS_MACOS
make_current ( ) ;
glRequestExtensionANGLE ( extension_name ) ;
# else
( void ) extension_name ;
# endif
}
2024-01-18 20:29:09 +01:00
}