@ -76,12 +76,16 @@ struct virgl_egl {
EGLContext egl_ctx ;
EGLContext egl_ctx ;
uint32_t extension_bits ;
uint32_t extension_bits ;
EGLSyncKHR signaled_fence ;
EGLSyncKHR signaled_fence ;
bool different_gpu ;
} ;
} ;
static bool virgl_egl_has_extension_in_string ( const char * haystack , const char * needle )
static bool virgl_egl_has_extension_in_string ( const char * haystack , const char * needle )
{
{
const unsigned needle_len = strlen ( needle ) ;
const unsigned needle_len = strlen ( needle ) ;
if ( ! haystack )
return false ;
if ( needle_len = = 0 )
if ( needle_len = = 0 )
return false ;
return false ;
@ -122,6 +126,148 @@ static int virgl_egl_init_extensions(struct virgl_egl *egl, const char *extensio
return 0 ;
return 0 ;
}
}
# ifdef ENABLE_MINIGBM_ALLOCATION
struct egl_funcs {
PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplay ;
PFNEGLQUERYDEVICESEXTPROC eglQueryDevices ;
PFNEGLQUERYDEVICESTRINGEXTPROC eglQueryDeviceString ;
} ;
static bool virgl_egl_get_interface ( struct egl_funcs * funcs )
{
const char * client_extensions = eglQueryString ( NULL , EGL_EXTENSIONS ) ;
assert ( funcs ) ;
if ( virgl_egl_has_extension_in_string ( client_extensions , " EGL_KHR_platform_base " ) ) {
funcs - > eglGetPlatformDisplay =
( PFNEGLGETPLATFORMDISPLAYEXTPROC ) eglGetProcAddress ( " eglGetPlatformDisplay " ) ;
} else if ( virgl_egl_has_extension_in_string ( client_extensions , " EGL_EXT_platform_base " ) ) {
funcs - > eglGetPlatformDisplay =
( PFNEGLGETPLATFORMDISPLAYEXTPROC ) eglGetProcAddress ( " eglGetPlatformDisplayEXT " ) ;
}
if ( ! funcs - > eglGetPlatformDisplay )
return false ;
if ( ! virgl_egl_has_extension_in_string ( client_extensions , " EGL_EXT_platform_device " ) )
return false ;
if ( ! virgl_egl_has_extension_in_string ( client_extensions , " EGL_EXT_device_enumeration " ) )
return false ;
funcs - > eglQueryDevices = ( PFNEGLQUERYDEVICESEXTPROC ) eglGetProcAddress ( " eglQueryDevicesEXT " ) ;
if ( ! funcs - > eglQueryDevices )
return false ;
if ( ! virgl_egl_has_extension_in_string ( client_extensions , " EGL_EXT_device_query " ) )
return false ;
funcs - > eglQueryDeviceString = ( PFNEGLQUERYDEVICESTRINGEXTPROC ) eglGetProcAddress ( " eglQueryDeviceStringEXT " ) ;
if ( ! funcs - > eglQueryDeviceString )
return false ;
return true ;
}
static EGLint virgl_egl_find_3d_device ( struct gbm_device_info * dev_infos , EGLint num_devices , uint32_t flags )
{
EGLint d ;
for ( d = 0 ; d < num_devices ; d + + ) {
if ( ( dev_infos [ d ] . dev_type_flags & flags ) = = flags
& & dev_infos [ d ] . dev_type_flags & GBM_DEV_TYPE_FLAG_3D )
return d ;
}
return - 1 ;
}
static EGLint virgl_egl_find_matching_device ( struct gbm_device_info * dev_infos , EGLint num_devices , int dri_node_num )
{
EGLint d ;
for ( d = 0 ; d < num_devices ; d + + ) {
if ( dev_infos [ d ] . dri_node_num = = dri_node_num )
return d ;
}
return - 1 ;
}
static EGLDeviceEXT virgl_egl_get_device ( struct virgl_egl * egl , struct egl_funcs * funcs ) {
EGLint num_devices = 0 ;
EGLint max_devices = 64 ;
EGLDeviceEXT devices [ 64 ] ;
struct gbm_device_info dev_infos [ 64 ] ;
struct gbm_device_info gbm_dev_info ;
EGLint device_num = - 1 ;
EGLint d ;
if ( gbm_detect_device_info ( 0 , gbm_device_get_fd ( egl - > gbm - > device ) , & gbm_dev_info ) < 0 )
return EGL_NO_DEVICE_EXT ;
if ( ! funcs - > eglQueryDevices ( max_devices , devices , & num_devices ) )
return EGL_NO_DEVICE_EXT ;
/* We query EGL_DRM_DEVICE_FILE_EXT without checking EGL_EXT_device_drm extension,
* we just get NULL when it is not available . Otherwise we would have to query it
* after initializing display for every device .
*/
for ( d = 0 ; d < num_devices ; d + + ) {
const char * dev_node = funcs - > eglQueryDeviceString ( devices [ d ] , EGL_DRM_DEVICE_FILE_EXT ) ;
memset ( & dev_infos [ d ] , 0 , sizeof ( dev_infos [ d ] ) ) ;
if ( dev_node ) {
if ( gbm_detect_device_info_path ( 0 , dev_node , dev_infos + d ) < 0 )
return false ;
} else {
dev_infos [ d ] . dri_node_num = - 1 ;
}
}
if ( getenv ( " VIRGL_PREFER_DGPU " ) )
/* Find a discrete GPU. */
device_num = virgl_egl_find_3d_device ( dev_infos , num_devices , GBM_DEV_TYPE_FLAG_DISCRETE ) ;
if ( device_num > = 0 ) {
egl - > different_gpu = dev_infos [ device_num ] . dri_node_num ! = gbm_dev_info . dri_node_num ;
} else if ( gbm_dev_info . dev_type_flags & GBM_DEV_TYPE_FLAG_ARMSOC ) {
/* Find 3D device on ARM SOC. */
device_num = virgl_egl_find_3d_device ( dev_infos , num_devices , GBM_DEV_TYPE_FLAG_ARMSOC ) ;
}
if ( device_num < 0 ) {
/* Try to match GBM device. */
device_num = virgl_egl_find_matching_device ( dev_infos , num_devices , gbm_dev_info . dri_node_num ) ;
}
if ( device_num < 0 )
return EGL_NO_DEVICE_EXT ;
return devices [ device_num ] ;
}
static bool virgl_egl_get_display ( struct virgl_egl * egl )
{
struct egl_funcs funcs = { 0 } ;
EGLDeviceEXT device ;
if ( ! egl - > gbm )
return false ;
if ( ! virgl_egl_get_interface ( & funcs ) )
return false ;
device = virgl_egl_get_device ( egl , & funcs ) ;
if ( device = = EGL_NO_DEVICE_EXT )
return false ;
egl - > egl_display = funcs . eglGetPlatformDisplay ( EGL_PLATFORM_DEVICE_EXT , device , NULL ) ;
return true ;
}
# endif /* ENABLE_MINIGBM_ALLOCATION */
struct virgl_egl * virgl_egl_init ( struct virgl_gbm * gbm , bool surfaceless , bool gles )
struct virgl_egl * virgl_egl_init ( struct virgl_gbm * gbm , bool surfaceless , bool gles )
{
{
static EGLint conf_att [ ] = {
static EGLint conf_att [ ] = {
@ -156,9 +302,15 @@ struct virgl_egl *virgl_egl_init(struct virgl_gbm *gbm, bool surfaceless, bool g
goto fail ;
goto fail ;
egl - > gbm = gbm ;
egl - > gbm = gbm ;
egl - > different_gpu = false ;
const char * client_extensions = eglQueryString ( NULL , EGL_EXTENSIONS ) ;
const char * client_extensions = eglQueryString ( NULL , EGL_EXTENSIONS ) ;
if ( client_extensions & & strstr ( client_extensions , " EGL_KHR_platform_base " ) ) {
# ifdef ENABLE_MINIGBM_ALLOCATION
if ( virgl_egl_get_display ( egl ) ) {
/* Make -Wdangling-else happy. */
} else /* Fallback to surfaceless. */
# endif
if ( virgl_egl_has_extension_in_string ( client_extensions , " EGL_KHR_platform_base " ) ) {
PFNEGLGETPLATFORMDISPLAYEXTPROC get_platform_display =
PFNEGLGETPLATFORMDISPLAYEXTPROC get_platform_display =
( PFNEGLGETPLATFORMDISPLAYEXTPROC ) eglGetProcAddress ( " eglGetPlatformDisplay " ) ;
( PFNEGLGETPLATFORMDISPLAYEXTPROC ) eglGetProcAddress ( " eglGetPlatformDisplay " ) ;
@ -171,7 +323,7 @@ struct virgl_egl *virgl_egl_init(struct virgl_gbm *gbm, bool surfaceless, bool g
} else
} else
egl - > egl_display = get_platform_display ( EGL_PLATFORM_GBM_KHR ,
egl - > egl_display = get_platform_display ( EGL_PLATFORM_GBM_KHR ,
( EGLNativeDisplayType ) egl - > gbm - > device , NULL ) ;
( EGLNativeDisplayType ) egl - > gbm - > device , NULL ) ;
} else if ( client_extensions & & strstr ( client_extensions , " EGL_EXT_platform_base " ) ) {
} else if ( virgl_egl_has_extension_in_string ( client_extensions , " EGL_EXT_platform_base " ) ) {
PFNEGLGETPLATFORMDISPLAYEXTPROC get_platform_display =
PFNEGLGETPLATFORMDISPLAYEXTPROC get_platform_display =
( PFNEGLGETPLATFORMDISPLAYEXTPROC ) eglGetProcAddress ( " eglGetPlatformDisplayEXT " ) ;
( PFNEGLGETPLATFORMDISPLAYEXTPROC ) eglGetProcAddress ( " eglGetPlatformDisplayEXT " ) ;
@ -584,3 +736,8 @@ bool virgl_egl_export_fence(struct virgl_egl *egl, EGLSyncKHR fence, int *out_fd
* out_fd = eglDupNativeFenceFDANDROID ( egl - > egl_display , fence ) ;
* out_fd = eglDupNativeFenceFDANDROID ( egl - > egl_display , fence ) ;
return * out_fd ! = EGL_NO_NATIVE_FENCE_FD_ANDROID ;
return * out_fd ! = EGL_NO_NATIVE_FENCE_FD_ANDROID ;
}
}
bool virgl_egl_different_gpu ( struct virgl_egl * egl )
{
return egl - > different_gpu ;
}