2023-04-27 19:35:18 +08:00
# include <stdio.h>
2023-07-16 01:34:58 +08:00
# include <assert.h>
2023-04-27 19:35:18 +08:00
# include <errno.h>
# include <fcntl.h>
# include <sys/mman.h>
# include <string.h>
# include <stdlib.h>
# include <sys/ioctl.h>
2023-04-29 02:05:13 +08:00
# include <libdrm/drm_fourcc.h>
2023-04-27 19:35:18 +08:00
# include "drm.h"
2023-04-29 02:05:13 +08:00
# include "va.h"
2023-08-11 00:25:26 +08:00
# include "drm_master.h"
2023-04-27 19:35:18 +08:00
extern struct kmsvnc_data * kmsvnc ;
2023-05-07 17:57:53 +08:00
static int check_pixfmt_non_vaapi ( ) {
if (
kmsvnc - > drm - > mfb - > pixel_format ! = KMSVNC_FOURCC_TO_INT ( ' X ' , ' R ' , ' 2 ' , ' 4 ' ) & &
kmsvnc - > drm - > mfb - > pixel_format ! = KMSVNC_FOURCC_TO_INT ( ' A ' , ' R ' , ' 2 ' , ' 4 ' )
)
{
KMSVNC_FATAL ( " Unsupported pixfmt %s, please create an issue with your pixfmt. \n " , kmsvnc - > drm - > pixfmt_name ) ;
}
return 0 ;
}
2023-07-16 01:34:58 +08:00
static void convert_copy ( const char * in , int width , int height , char * buff )
{
memcpy ( buff , in , width * height * BYTES_PER_PIXEL ) ;
2023-04-27 19:35:18 +08:00
}
2023-07-16 01:34:58 +08:00
static void convert_bgra_to_rgba ( const char * in , int width , int height , char * buff )
2023-04-27 19:35:18 +08:00
{
2023-07-16 01:34:58 +08:00
memcpy ( buff , in , width * height * BYTES_PER_PIXEL ) ;
for ( int i = 0 ; i < width * height * BYTES_PER_PIXEL ; i + = BYTES_PER_PIXEL ) {
uint32_t pixdata = htonl ( * ( ( uint32_t * ) ( kmsvnc - > drm - > kms_convert_buf + i ) ) ) ;
buff [ i + 0 ] = ( pixdata & 0x0000ff00 ) > > 8 ;
buff [ i + 2 ] = ( pixdata & 0xff000000 ) > > 24 ;
2023-04-27 19:35:18 +08:00
}
}
2023-04-29 15:17:06 +08:00
static inline char convert_buf_allocate ( size_t len ) {
2023-07-16 01:34:58 +08:00
if ( kmsvnc - > drm - > kms_convert_buf_len < len )
2023-04-29 15:17:06 +08:00
{
2023-07-16 01:34:58 +08:00
if ( kmsvnc - > drm - > kms_convert_buf )
free ( kmsvnc - > drm - > kms_convert_buf ) ;
kmsvnc - > drm - > kms_convert_buf = malloc ( len ) ;
if ( ! kmsvnc - > drm - > kms_convert_buf ) return 1 ;
kmsvnc - > drm - > kms_convert_buf_len = len ;
2023-04-29 15:17:06 +08:00
}
return 0 ;
}
2023-04-27 23:42:41 +08:00
static inline void convert_x_tiled ( const int tilex , const int tiley , const char * in , int width , int height , char * buff )
2023-04-27 19:35:18 +08:00
{
2023-04-27 23:42:41 +08:00
if ( width % tilex )
2023-04-27 19:35:18 +08:00
{
return ;
}
2023-04-27 23:42:41 +08:00
if ( height % tiley )
2023-04-27 19:35:18 +08:00
{
2023-04-27 23:42:41 +08:00
int sno = ( width / tilex ) + ( height / tiley ) * ( width / tilex ) ;
int ord = ( width % tilex ) + ( height % tiley ) * tilex ;
int max_offset = sno * tilex * tiley + ord ;
2023-07-16 01:34:58 +08:00
if ( kmsvnc - > drm - > kms_cpy_tmp_buf_len < max_offset * 4 + 4 )
2023-04-27 19:35:18 +08:00
{
2023-07-16 01:34:58 +08:00
if ( kmsvnc - > drm - > kms_cpy_tmp_buf )
free ( kmsvnc - > drm - > kms_convert_buf ) ;
kmsvnc - > drm - > kms_cpy_tmp_buf = malloc ( max_offset * 4 + 4 ) ;
if ( ! kmsvnc - > drm - > kms_cpy_tmp_buf ) return ;
kmsvnc - > drm - > kms_cpy_tmp_buf_len = max_offset * 4 + 4 ;
2023-04-27 19:35:18 +08:00
}
2023-07-16 01:34:58 +08:00
memcpy ( kmsvnc - > drm - > kms_cpy_tmp_buf , in , max_offset * 4 + 4 ) ;
in = ( const char * ) kmsvnc - > drm - > kms_cpy_tmp_buf ;
2023-04-27 19:35:18 +08:00
}
2023-04-29 15:17:06 +08:00
if ( convert_buf_allocate ( width * height * 4 ) ) return ;
2023-04-27 19:35:18 +08:00
for ( int y = 0 ; y < height ; y + + )
{
for ( int x = 0 ; x < width ; x + + )
{
2023-04-27 23:42:41 +08:00
int sno = ( x / tilex ) + ( y / tiley ) * ( width / tilex ) ;
int ord = ( x % tilex ) + ( y % tiley ) * tilex ;
int offset = sno * tilex * tiley + ord ;
2023-07-16 01:34:58 +08:00
memcpy ( kmsvnc - > drm - > kms_convert_buf + ( x + y * width ) * 4 , in + offset * 4 , 4 ) ;
2023-04-27 19:35:18 +08:00
}
}
2023-07-16 01:34:58 +08:00
convert_bgra_to_rgba ( kmsvnc - > drm - > kms_convert_buf , width , height , buff ) ;
2023-04-27 19:35:18 +08:00
}
2023-04-27 23:42:41 +08:00
void convert_nvidia_x_tiled_kmsbuf ( const char * in , int width , int height , char * buff )
2023-04-27 19:35:18 +08:00
{
2023-04-27 23:42:41 +08:00
convert_x_tiled ( 16 , 128 , in , width , height , buff ) ;
2023-04-27 19:35:18 +08:00
}
2023-04-27 23:42:41 +08:00
void convert_intel_x_tiled_kmsbuf ( const char * in , int width , int height , char * buff )
2023-04-27 19:35:18 +08:00
{
2023-04-27 23:42:41 +08:00
convert_x_tiled ( 128 , 8 , in , width , height , buff ) ;
2023-04-27 19:35:18 +08:00
}
2023-04-29 15:17:06 +08:00
static void convert_vaapi ( const char * in , int width , int height , char * buff ) {
2023-05-07 17:57:53 +08:00
if ( KMSVNC_FOURCC_TO_INT ( ' R ' , ' G ' , ' B ' , 0 ) & kmsvnc - > va - > image - > format . fourcc = = KMSVNC_FOURCC_TO_INT ( ' R ' , ' G ' , ' B ' , 0 ) ) {
va_hwframe_to_vaapi ( buff ) ;
}
else {
2023-04-29 15:17:06 +08:00
if ( convert_buf_allocate ( width * height * BYTES_PER_PIXEL ) ) return ;
2023-07-16 01:34:58 +08:00
va_hwframe_to_vaapi ( kmsvnc - > drm - > kms_convert_buf ) ;
2023-05-07 17:57:53 +08:00
// is 30 depth?
if ( kmsvnc - > va - > image - > format . depth = = 30 ) {
for ( int i = 0 ; i < width * height * BYTES_PER_PIXEL ; i + = BYTES_PER_PIXEL ) {
2023-07-16 01:34:58 +08:00
// ensure little endianess
uint32_t pixdata = __builtin_bswap32 ( htonl ( * ( ( uint32_t * ) ( kmsvnc - > drm - > kms_convert_buf + i ) ) ) ) ;
kmsvnc - > drm - > kms_convert_buf [ i ] = ( pixdata & 0x3ff00000 ) > > 20 > > 2 ;
kmsvnc - > drm - > kms_convert_buf [ i + 1 ] = ( pixdata & 0xffc00 ) > > 10 > > 2 ;
kmsvnc - > drm - > kms_convert_buf [ i + 2 ] = ( pixdata & 0x3ff ) > > 2 ;
2023-05-07 17:57:53 +08:00
}
}
// is xrgb?
if ( ( kmsvnc - > va - > image - > format . blue_mask | kmsvnc - > va - > image - > format . red_mask ) < 0x1000000 ) {
2023-04-29 15:17:06 +08:00
for ( int i = 0 ; i < width * height * BYTES_PER_PIXEL ; i + = BYTES_PER_PIXEL ) {
2023-07-16 01:34:58 +08:00
uint32_t * pixdata = ( uint32_t * ) ( kmsvnc - > drm - > kms_convert_buf + i ) ;
* pixdata = ntohl ( htonl ( * pixdata ) < < 8 ) ;
2023-04-29 15:17:06 +08:00
}
}
2023-07-16 01:34:58 +08:00
// is bgrx?
2023-05-07 17:57:53 +08:00
if ( kmsvnc - > va - > image - > format . blue_mask > kmsvnc - > va - > image - > format . red_mask ) {
2023-07-16 01:34:58 +08:00
for ( int i = 0 ; i < width * height * BYTES_PER_PIXEL ; i + = BYTES_PER_PIXEL ) {
uint32_t pixdata = htonl ( * ( ( uint32_t * ) ( kmsvnc - > drm - > kms_convert_buf + i ) ) ) ;
buff [ i + 0 ] = ( pixdata & 0x0000ff00 ) > > 8 ;
buff [ i + 2 ] = ( pixdata & 0xff000000 ) > > 24 ;
}
2023-05-07 17:57:53 +08:00
}
2023-07-16 01:34:58 +08:00
// rgbx now
memcpy ( buff , kmsvnc - > drm - > kms_convert_buf , width * height * BYTES_PER_PIXEL ) ;
2023-04-29 15:17:06 +08:00
}
}
2023-04-27 19:35:18 +08:00
static inline void drm_sync ( int drmfd , uint64_t flags )
{
struct dma_buf_sync sync = {
. flags = flags ,
} ;
2023-04-29 02:05:13 +08:00
DRM_R_IOCTL_MAY ( drmfd , DMA_BUF_IOCTL_SYNC , & sync ) ;
2023-04-27 19:35:18 +08:00
}
void drm_sync_start ( int drmfd )
{
drm_sync ( drmfd , DMA_BUF_SYNC_START | DMA_BUF_SYNC_READ ) ;
}
void drm_sync_end ( int drmfd )
{
drm_sync ( drmfd , DMA_BUF_SYNC_END | DMA_BUF_SYNC_READ ) ;
}
void drm_sync_noop ( int drmfd )
{
}
void drm_cleanup ( ) {
if ( kmsvnc - > drm ) {
2023-08-11 00:25:26 +08:00
if ( kmsvnc - > drm - > gamma & & kmsvnc - > drm - > gamma - > size & & kmsvnc - > drm - > gamma - > red & & kmsvnc - > drm - > gamma - > green & & kmsvnc - > drm - > gamma - > blue ) {
if ( drmModeCrtcSetGamma ( kmsvnc - > drm - > drm_master_fd ? : kmsvnc - > drm - > drm_fd , kmsvnc - > drm - > plane - > crtc_id , kmsvnc - > drm - > gamma - > size , kmsvnc - > drm - > gamma - > red , kmsvnc - > drm - > gamma - > green , kmsvnc - > drm - > gamma - > blue ) ) perror ( " Failed to restore gamma " ) ;
}
2023-08-11 01:27:08 +08:00
if ( kmsvnc - > drm - > gamma & & kmsvnc - > drm - > gamma - > red ) {
2023-08-11 00:25:26 +08:00
free ( kmsvnc - > drm - > gamma - > red ) ;
kmsvnc - > drm - > gamma - > red = kmsvnc - > drm - > gamma - > green = kmsvnc - > drm - > gamma - > blue = NULL ;
}
if ( kmsvnc - > drm - > gamma ) {
free ( kmsvnc - > drm - > gamma ) ;
kmsvnc - > drm - > gamma = NULL ;
}
2023-04-27 19:35:18 +08:00
if ( kmsvnc - > drm - > drm_ver ) {
drmFreeVersion ( kmsvnc - > drm - > drm_ver ) ;
kmsvnc - > drm - > drm_ver = NULL ;
}
2023-04-29 02:05:13 +08:00
if ( kmsvnc - > drm - > pixfmt_name ) {
free ( kmsvnc - > drm - > pixfmt_name ) ;
kmsvnc - > drm - > pixfmt_name = NULL ;
}
if ( kmsvnc - > drm - > mod_vendor ) {
free ( kmsvnc - > drm - > mod_vendor ) ;
kmsvnc - > drm - > mod_vendor = NULL ;
}
if ( kmsvnc - > drm - > mod_name ) {
free ( kmsvnc - > drm - > mod_name ) ;
kmsvnc - > drm - > mod_name = NULL ;
}
2023-04-27 19:35:18 +08:00
if ( kmsvnc - > drm - > plane ) {
drmModeFreePlane ( kmsvnc - > drm - > plane ) ;
kmsvnc - > drm - > plane = NULL ;
}
2023-07-16 01:34:58 +08:00
if ( kmsvnc - > drm - > cursor_plane ) {
drmModeFreePlane ( kmsvnc - > drm - > cursor_plane ) ;
kmsvnc - > drm - > cursor_plane = NULL ;
}
2023-04-27 19:35:18 +08:00
if ( kmsvnc - > drm - > mfb ) {
2023-04-27 23:42:41 +08:00
drmModeFreeFB2 ( kmsvnc - > drm - > mfb ) ;
2023-04-27 19:35:18 +08:00
kmsvnc - > drm - > mfb = NULL ;
}
2023-07-16 01:34:58 +08:00
if ( kmsvnc - > drm - > cursor_mfb ) {
drmModeFreeFB2 ( kmsvnc - > drm - > cursor_mfb ) ;
kmsvnc - > drm - > cursor_mfb = NULL ;
}
if ( kmsvnc - > drm - > mapped & & kmsvnc - > drm - > mapped ! = MAP_FAILED ) {
2023-04-27 19:35:18 +08:00
munmap ( kmsvnc - > drm - > mapped , kmsvnc - > drm - > mmap_size ) ;
kmsvnc - > drm - > mapped = NULL ;
}
2023-07-16 01:34:58 +08:00
if ( kmsvnc - > drm - > cursor_mapped & & kmsvnc - > drm - > cursor_mapped ! = MAP_FAILED ) {
munmap ( kmsvnc - > drm - > cursor_mapped , kmsvnc - > drm - > cursor_mmap_size ) ;
kmsvnc - > drm - > cursor_mapped = NULL ;
}
2023-04-27 19:35:18 +08:00
if ( kmsvnc - > drm - > prime_fd > 0 ) {
close ( kmsvnc - > drm - > prime_fd ) ;
kmsvnc - > drm - > prime_fd = 0 ;
}
if ( kmsvnc - > drm - > drm_fd > 0 ) {
close ( kmsvnc - > drm - > drm_fd ) ;
kmsvnc - > drm - > drm_fd = 0 ;
}
2023-08-11 00:25:26 +08:00
if ( kmsvnc - > drm - > drm_master_fd > 0 ) {
close ( kmsvnc - > drm - > drm_master_fd ) ;
kmsvnc - > drm - > drm_master_fd = 0 ;
}
2023-04-28 14:13:46 +08:00
if ( kmsvnc - > drm - > plane_res ) {
drmModeFreePlaneResources ( kmsvnc - > drm - > plane_res ) ;
kmsvnc - > drm - > plane_res = NULL ;
}
2023-07-16 01:34:58 +08:00
if ( kmsvnc - > drm - > kms_convert_buf ) {
free ( kmsvnc - > drm - > kms_convert_buf ) ;
kmsvnc - > drm - > kms_convert_buf = NULL ;
}
kmsvnc - > drm - > kms_convert_buf_len = 0 ;
if ( kmsvnc - > drm - > kms_cpy_tmp_buf ) {
free ( kmsvnc - > drm - > kms_cpy_tmp_buf ) ;
kmsvnc - > drm - > kms_cpy_tmp_buf = NULL ;
}
kmsvnc - > drm - > kms_cpy_tmp_buf_len = 0 ;
if ( kmsvnc - > drm - > kms_cursor_buf ) {
free ( kmsvnc - > drm - > kms_cursor_buf ) ;
kmsvnc - > drm - > kms_cursor_buf = NULL ;
}
kmsvnc - > drm - > kms_cursor_buf_len = 0 ;
2023-04-27 19:35:18 +08:00
free ( kmsvnc - > drm ) ;
kmsvnc - > drm = NULL ;
}
}
2023-07-16 01:34:58 +08:00
static const char * drm_get_plane_type_name ( uint64_t plane_type ) {
switch ( plane_type ) {
case DRM_PLANE_TYPE_OVERLAY :
return " overlay " ;
case DRM_PLANE_TYPE_PRIMARY :
return " primary " ;
case DRM_PLANE_TYPE_CURSOR :
return " cursor " ;
default :
return " unknown " ;
2023-04-27 19:35:18 +08:00
}
2023-07-16 01:34:58 +08:00
} ;
2023-04-27 23:42:41 +08:00
2023-07-16 01:34:58 +08:00
static int drm_refresh_planes ( char first_time ) {
struct kmsvnc_drm_data * drm = kmsvnc - > drm ;
if ( ! drm - > plane & & kmsvnc - > source_plane > 0 )
2023-04-27 19:35:18 +08:00
{
2023-04-28 14:13:46 +08:00
drm - > plane = drmModeGetPlane ( drm - > drm_fd , kmsvnc - > source_plane ) ;
2023-04-27 19:35:18 +08:00
if ( ! drm - > plane )
2023-04-29 02:05:13 +08:00
KMSVNC_FATAL ( " Failed to get plane %d: %s \n " , kmsvnc - > source_plane , strerror ( errno ) ) ;
2023-04-27 19:35:18 +08:00
if ( drm - > plane - > fb_id = = 0 )
2023-04-28 14:13:46 +08:00
fprintf ( stderr , " Place %d does not have an attached framebuffer \n " , kmsvnc - > source_plane ) ;
2023-04-27 19:35:18 +08:00
}
2023-07-16 01:34:58 +08:00
if ( ! drm - > plane | | ( kmsvnc - > capture_cursor & & ! drm - > cursor_plane ) ) {
drmModePlane * current_plane = NULL ;
2023-07-16 10:43:22 +08:00
if ( drm - > plane_res ) {
drmModeFreePlaneResources ( kmsvnc - > drm - > plane_res ) ;
drm - > plane_res = NULL ;
}
2023-04-27 19:35:18 +08:00
drm - > plane_res = drmModeGetPlaneResources ( drm - > drm_fd ) ;
if ( ! drm - > plane_res )
2023-04-29 02:05:13 +08:00
KMSVNC_FATAL ( " Failed to get plane resources: %s \n " , strerror ( errno ) ) ;
2023-04-27 19:35:18 +08:00
int i ;
for ( i = 0 ; i < drm - > plane_res - > count_planes ; i + + )
{
2023-07-16 01:34:58 +08:00
current_plane = drmModeGetPlane ( drm - > drm_fd , drm - > plane_res - > planes [ i ] ) ;
if ( ! current_plane )
2023-04-27 19:35:18 +08:00
{
fprintf ( stderr , " Failed to get plane %u: %s \n " , drm - > plane_res - > planes [ i ] , strerror ( errno ) ) ;
continue ;
}
2023-07-16 01:34:58 +08:00
// get plane type
uint64_t plane_type = 114514 ;
drmModeObjectPropertiesPtr plane_props = drmModeObjectGetProperties ( drm - > drm_fd , current_plane - > plane_id , DRM_MODE_OBJECT_PLANE ) ;
if ( ! plane_props ) {
fprintf ( stderr , " Failed to get plane prop %u: %s \n " , drm - > plane_res - > planes [ i ] , strerror ( errno ) ) ;
}
else {
for ( int i = 0 ; i < plane_props - > count_props ; i + + ) {
drmModePropertyPtr plane_prop = drmModeGetProperty ( drm - > drm_fd , plane_props - > props [ i ] ) ;
if ( strcmp ( plane_prop - > name , " type " ) = = 0 ) {
plane_type = plane_props - > prop_values [ i ] ;
}
drmModeFreeProperty ( plane_prop ) ;
}
drmModeFreeObjectProperties ( plane_props ) ;
}
assert ( drm - > plane_res - > planes [ i ] = = current_plane - > plane_id ) ;
if ( first_time ) {
printf ( " Plane %u CRTC %u FB %u Type %s \n " , current_plane - > plane_id , current_plane - > crtc_id , current_plane - > fb_id , drm_get_plane_type_name ( plane_type ) ) ;
2023-04-27 19:35:18 +08:00
}
2023-07-16 01:34:58 +08:00
// populate drm->plane and drm->cursor_plane
char nofree = 0 ;
if ( current_plane - > fb_id ! = 0 ) {
if ( ! drm - > plane ) {
if ( kmsvnc - > source_crtc = = 0 | | current_plane - > crtc_id = = kmsvnc - > source_crtc ) {
nofree = 1 ;
drm - > plane = current_plane ;
}
}
// assume cursor plane is always after primary plane
if ( ! drm - > cursor_plane ) {
if ( drm - > plane & & drm - > plane - > crtc_id = = current_plane - > crtc_id & & plane_type = = DRM_PLANE_TYPE_CURSOR ) {
nofree = 1 ;
drm - > cursor_plane = current_plane ;
}
}
}
if ( ( ! kmsvnc - > capture_cursor | | drm - > cursor_plane ) & & drm - > plane ) {
break ;
}
if ( ! nofree ) {
drmModeFreePlane ( current_plane ) ;
}
current_plane = NULL ;
2023-04-27 19:35:18 +08:00
}
2023-07-16 01:34:58 +08:00
if ( ! first_time ) return 0 ;
2023-04-27 19:35:18 +08:00
if ( i = = drm - > plane_res - > count_planes )
{
2023-07-16 01:34:58 +08:00
if ( ! drm - > plane ) {
if ( kmsvnc - > source_crtc ! = 0 )
{
KMSVNC_FATAL ( " No usable planes found on CRTC %d \n " , kmsvnc - > source_crtc ) ;
}
else
{
KMSVNC_FATAL ( " No usable planes found \n " ) ;
}
2023-04-27 19:35:18 +08:00
}
2023-07-16 01:34:58 +08:00
else if ( ! drm - > cursor_plane ) {
fprintf ( stderr , " No usable cursor plane found, cursor capture currently unavailable \n " ) ;
2023-04-27 19:35:18 +08:00
}
}
printf ( " Using plane %u to locate framebuffers \n " , drm - > plane - > plane_id ) ;
2023-07-16 01:34:58 +08:00
if ( drm - > cursor_plane ) {
printf ( " Using cursor plane %u \n " , drm - > cursor_plane - > plane_id ) ;
}
}
return 0 ;
}
int drm_dump_cursor_plane ( char * * data , int * width , int * height ) {
struct kmsvnc_drm_data * drm = kmsvnc - > drm ;
2023-07-16 10:43:22 +08:00
if ( ! drm - > cursor_plane ) {
drm_refresh_planes ( 0 ) ; // ignore error
if ( drm - > cursor_plane ) {
printf ( " Using cursor plane %u \n " , drm - > cursor_plane - > plane_id ) ;
}
}
else {
uint32_t plane_id = drm - > cursor_plane - > plane_id ;
2023-07-16 01:34:58 +08:00
drmModeFreePlane ( drm - > cursor_plane ) ;
drm - > cursor_plane = NULL ;
2023-07-16 10:43:22 +08:00
drm - > cursor_plane = drmModeGetPlane ( drm - > drm_fd , plane_id ) ;
2023-07-16 01:34:58 +08:00
}
if ( ! drm - > cursor_plane ) {
data = NULL ;
return 1 ;
}
if ( drm - > cursor_mfb ) drmModeFreeFB2 ( drm - > cursor_mfb ) ;
drm - > cursor_mfb = drmModeGetFB2 ( drm - > drm_fd , drm - > cursor_plane - > fb_id ) ;
if ( ! drm - > cursor_mfb ) {
KMSVNC_DEBUG ( " Cursor framebuffer missing \n " ) ;
return 1 ;
}
2023-07-16 10:43:22 +08:00
2023-07-16 01:34:58 +08:00
if ( drm - > cursor_mfb - > modifier ! = DRM_FORMAT_MOD_NONE & & drm - > cursor_mfb - > modifier ! = DRM_FORMAT_MOD_LINEAR ) {
//kmsvnc->capture_cursor = 0;
KMSVNC_DEBUG ( " Cursor plane modifier is not linear: %lu \n " , drm - > cursor_mfb - > modifier ) ;
return 1 ;
}
if (
drm - > cursor_mfb - > pixel_format ! = KMSVNC_FOURCC_TO_INT ( ' A ' , ' R ' , ' 2 ' , ' 4 ' ) & &
drm - > cursor_mfb - > pixel_format ! = KMSVNC_FOURCC_TO_INT ( ' A ' , ' R ' , ' 3 ' , ' 0 ' )
)
{
//kmsvnc->capture_cursor = 0;
char * fmtname = drmGetFormatName ( drm - > cursor_mfb - > pixel_format ) ;
KMSVNC_DEBUG ( " Cursor plane pixel format unsupported (%u, %s) \n " , drm - > cursor_mfb - > pixel_format , fmtname ) ;
free ( fmtname ) ;
return 1 ;
}
struct drm_gem_flink flink ;
flink . handle = drm - > cursor_mfb - > handles [ 0 ] ;
DRM_IOCTL_MUST ( drm - > drm_fd , DRM_IOCTL_GEM_FLINK , & flink ) ;
struct drm_gem_open open_arg ;
open_arg . name = flink . name ;
DRM_IOCTL_MUST ( drm - > drm_fd , DRM_IOCTL_GEM_OPEN , & open_arg ) ;
struct drm_mode_map_dumb mreq ;
memset ( & mreq , 0 , sizeof ( mreq ) ) ;
mreq . handle = open_arg . handle ;
DRM_IOCTL_MUST ( drm - > drm_fd , DRM_IOCTL_MODE_MAP_DUMB , & mreq ) ;
size_t mmap_size = open_arg . size ;
if ( mmap_size ! = drm - > cursor_mfb - > width * drm - > cursor_mfb - > height * BYTES_PER_PIXEL ) {
2023-07-16 10:50:07 +08:00
KMSVNC_DEBUG ( " Cursor plane mmap_size != calculated size (%ld, %d) \n " , mmap_size , drm - > cursor_mfb - > width * drm - > cursor_mfb - > height * BYTES_PER_PIXEL ) ;
2023-07-16 01:34:58 +08:00
return 1 ;
}
off_t mmap_offset = mreq . offset ;
if ( drm - > cursor_mapped & & drm - > cursor_mapped ! = MAP_FAILED ) munmap ( drm - > cursor_mapped , drm - > cursor_mmap_size ) ;
drm - > cursor_mapped = mmap ( NULL , mmap_size , PROT_READ , MAP_SHARED , drm - > drm_fd , mmap_offset ) ;
if ( drm - > cursor_mapped = = MAP_FAILED )
{
KMSVNC_DEBUG ( " Failed to mmap cursor: %s \n " , strerror ( errno ) ) ;
return 1 ;
}
else
{
if ( kmsvnc - > drm - > kms_cursor_buf_len < mmap_size )
{
if ( kmsvnc - > drm - > kms_cursor_buf )
free ( kmsvnc - > drm - > kms_cursor_buf ) ;
kmsvnc - > drm - > kms_cursor_buf = malloc ( mmap_size ) ;
if ( ! kmsvnc - > drm - > kms_cursor_buf ) return 1 ;
kmsvnc - > drm - > kms_cursor_buf_len = mmap_size ;
}
memcpy ( drm - > kms_cursor_buf , drm - > cursor_mapped , mmap_size ) ;
if ( drm - > cursor_mfb - > pixel_format = = KMSVNC_FOURCC_TO_INT ( ' X ' , ' R ' , ' 3 ' , ' 0 ' ) | |
drm - > cursor_mfb - > pixel_format = = KMSVNC_FOURCC_TO_INT ( ' A ' , ' R ' , ' 3 ' , ' 0 ' ) )
{
for ( int i = 0 ; i < drm - > cursor_mfb - > width * drm - > cursor_mfb - > height * BYTES_PER_PIXEL ; i + = BYTES_PER_PIXEL ) {
uint32_t pixdata = __builtin_bswap32 ( htonl ( * ( ( uint32_t * ) ( kmsvnc - > drm - > kms_cursor_buf + i ) ) ) ) ;
kmsvnc - > drm - > kms_cursor_buf [ i ] = ( pixdata & 0x3ff00000 ) > > 20 > > 2 ;
kmsvnc - > drm - > kms_cursor_buf [ i + 1 ] = ( pixdata & 0xffc00 ) > > 10 > > 2 ;
kmsvnc - > drm - > kms_cursor_buf [ i + 2 ] = ( pixdata & 0x3ff ) > > 2 ;
kmsvnc - > drm - > kms_cursor_buf [ i + 3 ] = ( pixdata & 0xc0000000 ) > > 30 < < 6 ;
}
}
if ( drm - > cursor_mfb - > pixel_format = = KMSVNC_FOURCC_TO_INT ( ' X ' , ' R ' , ' 2 ' , ' 4 ' ) | |
drm - > cursor_mfb - > pixel_format = = KMSVNC_FOURCC_TO_INT ( ' A ' , ' R ' , ' 2 ' , ' 4 ' ) )
{
// bgra to rgba
for ( int i = 0 ; i < drm - > cursor_mfb - > width * drm - > cursor_mfb - > height * BYTES_PER_PIXEL ; i + = BYTES_PER_PIXEL ) {
uint32_t pixdata = htonl ( * ( ( uint32_t * ) ( kmsvnc - > drm - > kms_cursor_buf + i ) ) ) ;
kmsvnc - > drm - > kms_cursor_buf [ i + 0 ] = ( pixdata & 0x0000ff00 ) > > 8 ;
kmsvnc - > drm - > kms_cursor_buf [ i + 2 ] = ( pixdata & 0xff000000 ) > > 24 ;
}
}
* width = drm - > cursor_mfb - > width ;
* height = drm - > cursor_mfb - > height ;
* data = drm - > kms_cursor_buf ;
}
return 0 ;
}
int drm_open ( ) {
struct kmsvnc_drm_data * drm = malloc ( sizeof ( struct kmsvnc_drm_data ) ) ;
if ( ! drm ) KMSVNC_FATAL ( " memory allocation error at %s:%d \n " , __FILE__ , __LINE__ ) ;
memset ( drm , 0 , sizeof ( struct kmsvnc_drm_data ) ) ;
kmsvnc - > drm = drm ;
drm - > drm_fd = open ( kmsvnc - > card , O_RDONLY ) ;
if ( drm - > drm_fd < 0 )
{
KMSVNC_FATAL ( " card %s open failed: %s \n " , kmsvnc - > card , strerror ( errno ) ) ;
}
2023-08-11 01:27:08 +08:00
if ( kmsvnc - > screen_blank & & ! drmIsMaster ( drm - > drm_fd ) ) {
drm - > drm_master_fd = drm_get_master_fd ( ) ;
drm - > drm_master_fd = drm - > drm_master_fd > 0 ? drm - > drm_master_fd : 0 ;
if ( kmsvnc - > debug_enabled ) {
fprintf ( stderr , " not master client, master fd %d \n " , drm - > drm_master_fd ) ;
}
}
2023-07-16 01:34:58 +08:00
drm - > drm_ver = drmGetVersion ( drm - > drm_fd ) ;
printf ( " drm driver is %s \n " , drm - > drm_ver - > name ) ;
int err = drmSetClientCap ( drm - > drm_fd , DRM_CLIENT_CAP_UNIVERSAL_PLANES , 1 ) ;
if ( err < 0 )
{
perror ( " Failed to set universal planes capability: primary planes will not be usable " ) ;
2023-04-27 19:35:18 +08:00
}
2023-07-16 01:34:58 +08:00
if ( drm_refresh_planes ( 1 ) ) return 1 ;
2023-04-27 23:42:41 +08:00
2023-08-11 01:27:08 +08:00
if ( kmsvnc - > screen_blank ) {
drm - > gamma = malloc ( sizeof ( struct kmsvnc_drm_gamma_data ) ) ;
if ( ! drm - > gamma ) KMSVNC_FATAL ( " memory allocation error at %s:%d \n " , __FILE__ , __LINE__ ) ;
memset ( drm - > gamma , 0 , sizeof ( struct kmsvnc_drm_gamma_data ) ) ;
drmModeCrtc * target_crtc = drmModeGetCrtc ( drm - > drm_fd , drm - > plane - > crtc_id ) ;
if ( target_crtc ) {
drm - > gamma - > size = ( uint32_t ) target_crtc - > gamma_size ;
drm - > gamma - > red = malloc ( drm - > gamma - > size * sizeof ( uint16_t ) * 3 ) ;
if ( ! drm - > gamma - > size ) {
fprintf ( stderr , " drm->gamma->size = %u, not setting gamma. \n " , drm - > gamma - > size ) ;
2023-08-11 00:25:26 +08:00
}
2023-08-11 01:27:08 +08:00
else if ( ! drm - > gamma - > red ) {
2023-08-11 00:25:26 +08:00
fprintf ( stderr , " memory allocation error at %s:%d \n " , __FILE__ , __LINE__ ) ;
fprintf ( stderr , " not setting gamma. \n " ) ;
}
else {
2023-08-11 01:27:08 +08:00
memset ( drm - > gamma - > red , 0 , drm - > gamma - > size * sizeof ( uint16_t ) * 3 ) ;
drm - > gamma - > green = drm - > gamma - > red + drm - > gamma - > size ;
drm - > gamma - > blue = drm - > gamma - > red + drm - > gamma - > size * 2 ;
if ( kmsvnc - > screen_blank_restore ) {
int step = 0x10000 / drm - > gamma - > size ;
for ( int i = 0 ; i < drm - > gamma - > size ; i + + ) {
drm - > gamma - > red [ i ] = drm - > gamma - > green [ i ] = drm - > gamma - > blue [ i ] = step * i ;
}
}
else {
// legacy api, but weston also uses this, so whatever
drmModeCrtcGetGamma ( drm - > drm_fd , drm - > plane - > crtc_id , drm - > gamma - > size , drm - > gamma - > red , drm - > gamma - > green , drm - > gamma - > blue ) ;
}
2023-08-11 00:25:26 +08:00
if ( kmsvnc - > debug_enabled ) {
2023-08-11 01:27:08 +08:00
for ( int i = 0 ; i < drm - > gamma - > size ; i + + ) {
fprintf ( stderr , " gamma: %05d %05hu %05hu %05hu \n " , i , drm - > gamma - > red [ i ] , drm - > gamma - > green [ i ] , drm - > gamma - > blue [ i ] ) ;
2023-08-11 00:25:26 +08:00
}
}
2023-08-11 01:27:08 +08:00
uint16_t * new_gamma_red = malloc ( drm - > gamma - > size * sizeof ( uint16_t ) * 3 ) ;
if ( ! new_gamma_red ) {
fprintf ( stderr , " memory allocation error at %s:%d \n " , __FILE__ , __LINE__ ) ;
fprintf ( stderr , " not setting gamma. \n " ) ;
}
else {
memset ( new_gamma_red , 0 , drm - > gamma - > size * sizeof ( uint16_t ) * 3 ) ;
uint16_t * new_gamma_green = new_gamma_red + drm - > gamma - > size ;
uint16_t * new_gamma_blue = new_gamma_red + drm - > gamma - > size * 2 ;
if ( drmModeCrtcSetGamma ( drm - > drm_master_fd ? : drm - > drm_fd , drm - > plane - > crtc_id , drm - > gamma - > size , new_gamma_red , new_gamma_green , new_gamma_blue ) ) perror ( " Failed to set gamma " ) ;
}
if ( new_gamma_red ) {
free ( new_gamma_red ) ;
new_gamma_red = NULL ;
}
2023-08-11 00:25:26 +08:00
}
}
2023-08-11 01:27:08 +08:00
else {
fprintf ( stderr , " Did not get a crtc structure, not setting gamma. \n " ) ;
}
if ( target_crtc ) {
drmModeFreeCrtc ( target_crtc ) ;
target_crtc = NULL ;
}
2023-08-11 00:25:26 +08:00
}
2023-04-27 23:42:41 +08:00
drm - > mfb = drmModeGetFB2 ( drm - > drm_fd , drm - > plane - > fb_id ) ;
if ( ! drm - > mfb ) {
2023-04-29 02:05:13 +08:00
KMSVNC_FATAL ( " Failed to get framebuffer %u: %s \n " , drm - > plane - > fb_id , strerror ( errno ) ) ;
2023-04-27 19:35:18 +08:00
}
2023-04-29 02:05:13 +08:00
drm - > pixfmt_name = drmGetFormatName ( drm - > mfb - > pixel_format ) ;
drm - > mod_vendor = drmGetFormatModifierVendor ( drm - > mfb - > modifier ) ;
drm - > mod_name = drmGetFormatModifierName ( drm - > mfb - > modifier ) ;
2023-04-30 16:32:31 +08:00
printf ( " Template framebuffer is %u: %ux%u fourcc:%u mod:%lu flags:%u \n " , drm - > mfb - > fb_id , drm - > mfb - > width , drm - > mfb - > height , drm - > mfb - > pixel_format , drm - > mfb - > modifier , drm - > mfb - > flags ) ;
2023-04-27 23:42:41 +08:00
printf ( " handles %u %u %u %u \n " , drm - > mfb - > handles [ 0 ] , drm - > mfb - > handles [ 1 ] , drm - > mfb - > handles [ 2 ] , drm - > mfb - > handles [ 3 ] ) ;
printf ( " offsets %u %u %u %u \n " , drm - > mfb - > offsets [ 0 ] , drm - > mfb - > offsets [ 1 ] , drm - > mfb - > offsets [ 2 ] , drm - > mfb - > offsets [ 3 ] ) ;
printf ( " pitches %u %u %u %u \n " , drm - > mfb - > pitches [ 0 ] , drm - > mfb - > pitches [ 1 ] , drm - > mfb - > pitches [ 2 ] , drm - > mfb - > pitches [ 3 ] ) ;
2023-04-29 02:05:13 +08:00
printf ( " format %s, modifier %s:%s \n " , drm - > pixfmt_name , drm - > mod_vendor , drm - > mod_name ) ;
2023-04-27 23:42:41 +08:00
if ( ! drm - > mfb - > handles [ 0 ] )
2023-04-27 19:35:18 +08:00
{
2023-04-29 02:05:13 +08:00
KMSVNC_FATAL ( " No handle set on framebuffer: maybe you need some additional capabilities? \n " ) ;
2023-04-27 19:35:18 +08:00
}
drm - > mmap_fd = drm - > drm_fd ;
drm - > mmap_size = drm - > mfb - > width * drm - > mfb - > height * BYTES_PER_PIXEL ;
drm - > funcs = malloc ( sizeof ( struct kmsvnc_drm_funcs ) ) ;
2023-04-29 02:05:13 +08:00
if ( ! drm - > funcs ) KMSVNC_FATAL ( " memory allocation error at %s:%d \n " , __FILE__ , __LINE__ ) ;
2023-07-16 01:34:58 +08:00
drm - > funcs - > convert = convert_bgra_to_rgba ;
2023-04-27 19:35:18 +08:00
drm - > funcs - > sync_start = drm_sync_noop ;
drm - > funcs - > sync_end = drm_sync_noop ;
if ( drm_vendors ( ) ) return 1 ;
return 0 ;
}
static int drm_kmsbuf_prime ( ) {
struct kmsvnc_drm_data * drm = kmsvnc - > drm ;
2023-04-27 23:42:41 +08:00
int err = drmPrimeHandleToFD ( drm - > drm_fd , drm - > mfb - > handles [ 0 ] , O_RDWR , & drm - > prime_fd ) ;
2023-04-27 19:35:18 +08:00
if ( err < 0 | | drm - > prime_fd < 0 )
{
2023-07-16 01:34:58 +08:00
KMSVNC_FATAL ( " Failed to get PRIME fd from framebuffer handle \n " ) ;
2023-04-27 19:35:18 +08:00
}
drm - > funcs - > sync_start = & drm_sync_start ;
drm - > funcs - > sync_end = & drm_sync_end ;
drm - > mmap_fd = drm - > prime_fd ;
return 0 ;
}
2023-04-29 02:05:13 +08:00
static int drm_kmsbuf_prime_vaapi ( ) {
struct kmsvnc_drm_data * drm = kmsvnc - > drm ;
int err = drmPrimeHandleToFD ( drm - > drm_fd , drm - > mfb - > handles [ 0 ] , O_RDWR , & drm - > prime_fd ) ;
if ( err < 0 | | drm - > prime_fd < 0 )
{
2023-07-16 01:34:58 +08:00
KMSVNC_FATAL ( " Failed to get PRIME fd from framebuffer handle \n " ) ;
2023-04-29 02:05:13 +08:00
}
if ( va_init ( ) ) return 1 ;
drm - > mmap_fd = drm - > prime_fd ;
2023-04-29 15:17:06 +08:00
drm - > skip_map = 1 ;
2023-04-29 02:05:13 +08:00
return 0 ;
}
2023-04-27 19:35:18 +08:00
static int drm_kmsbuf_dumb ( ) {
struct kmsvnc_drm_data * drm = kmsvnc - > drm ;
struct drm_gem_flink flink ;
2023-04-27 23:42:41 +08:00
flink . handle = drm - > mfb - > handles [ 0 ] ;
2023-04-27 19:35:18 +08:00
DRM_IOCTL_MUST ( drm - > drm_fd , DRM_IOCTL_GEM_FLINK , & flink ) ;
struct drm_gem_open open_arg ;
open_arg . name = flink . name ;
DRM_IOCTL_MUST ( drm - > drm_fd , DRM_IOCTL_GEM_OPEN , & open_arg ) ;
struct drm_mode_map_dumb mreq ;
memset ( & mreq , 0 , sizeof ( mreq ) ) ;
mreq . handle = open_arg . handle ;
DRM_IOCTL_MUST ( drm - > drm_fd , DRM_IOCTL_MODE_MAP_DUMB , & mreq ) ;
drm - > mmap_size = open_arg . size ;
drm - > mmap_offset = mreq . offset ;
return 0 ;
}
int drm_vendors ( ) {
struct kmsvnc_drm_data * drm = kmsvnc - > drm ;
char * driver_name ;
if ( kmsvnc - > force_driver ) {
printf ( " using %s instead of %s \n " , kmsvnc - > force_driver , drm - > drm_ver - > name ) ;
driver_name = kmsvnc - > force_driver ;
}
else {
driver_name = drm - > drm_ver - > name ;
}
2023-04-29 02:05:13 +08:00
if ( strcmp ( driver_name , " i915 " ) = = 0 | | strcmp ( driver_name , " amdgpu " ) = = 0 )
2023-04-27 19:35:18 +08:00
{
2023-04-29 02:05:13 +08:00
if ( fourcc_mod_is_vendor ( drm - > mfb - > modifier , INTEL ) ) {
if ( strstr ( drm - > mod_name , " CCS " ) ) {
printf ( " warn: intel with CCS modifier detected, please set INTEL_DEBUG=noccs \n " ) ;
}
} ;
drm - > funcs - > convert = & convert_vaapi ;
if ( drm_kmsbuf_prime_vaapi ( ) ) return 1 ;
2023-04-27 19:35:18 +08:00
}
else if ( strcmp ( driver_name , " nvidia-drm " ) = = 0 )
{
2023-05-07 17:57:53 +08:00
if ( check_pixfmt_non_vaapi ( ) ) return 1 ;
2023-04-29 02:05:13 +08:00
printf ( " warn: nvidia card detected. Currently only x-tiled framebuffer is supported. Performance may suffer. \n " ) ;
2023-05-24 14:41:22 +08:00
if ( drm - > mfb - > modifier ! = DRM_FORMAT_MOD_NONE & & drm - > mfb - > modifier ! = DRM_FORMAT_MOD_LINEAR ) {
drm - > funcs - > convert = & convert_nvidia_x_tiled_kmsbuf ;
}
2023-04-27 19:35:18 +08:00
if ( drm_kmsbuf_dumb ( ) ) return 1 ;
}
else if ( strcmp ( driver_name , " vmwgfx " ) = = 0 | |
strcmp ( driver_name , " vboxvideo " ) = = 0 | |
strcmp ( driver_name , " virtio_gpu " ) = = 0
)
{
2023-05-07 17:57:53 +08:00
if ( check_pixfmt_non_vaapi ( ) ) return 1 ;
2023-04-29 02:05:13 +08:00
if ( drm - > mfb - > modifier ! = DRM_FORMAT_MOD_NONE & & drm - > mfb - > modifier ! = DRM_FORMAT_MOD_LINEAR ) {
printf ( " warn: modifier is not LINEAR, please create an issue with your modifier. \n " ) ;
}
2023-04-27 19:35:18 +08:00
// virgl does not work
if ( drm_kmsbuf_dumb ( ) ) return 1 ;
}
else if ( strcmp ( driver_name , " test-prime " ) = = 0 )
{
2023-05-07 17:57:53 +08:00
if ( check_pixfmt_non_vaapi ( ) ) return 1 ;
2023-04-27 19:35:18 +08:00
if ( drm_kmsbuf_prime ( ) ) return 1 ;
}
else if ( strcmp ( driver_name , " test-map-dumb " ) = = 0 )
{
2023-05-07 17:57:53 +08:00
if ( check_pixfmt_non_vaapi ( ) ) return 1 ;
2023-04-27 19:35:18 +08:00
if ( drm_kmsbuf_dumb ( ) ) return 1 ;
}
2023-04-27 19:51:16 +08:00
else if ( strcmp ( driver_name , " test-i915-gem " ) = = 0 )
{
2023-05-07 17:57:53 +08:00
if ( check_pixfmt_non_vaapi ( ) ) return 1 ;
2023-04-27 19:51:16 +08:00
struct drm_gem_flink flink ;
2023-04-27 23:42:41 +08:00
flink . handle = drm - > mfb - > handles [ 0 ] ;
2023-04-27 19:51:16 +08:00
DRM_IOCTL_MUST ( drm - > drm_fd , DRM_IOCTL_GEM_FLINK , & flink ) ;
struct drm_gem_open open_arg ;
open_arg . name = flink . name ;
DRM_IOCTL_MUST ( drm - > drm_fd , DRM_IOCTL_GEM_OPEN , & open_arg ) ;
struct drm_i915_gem_mmap_gtt mmap_arg ;
mmap_arg . handle = open_arg . handle ;
DRM_IOCTL_MUST ( drm - > drm_fd , DRM_IOCTL_I915_GEM_MMAP_GTT , & mmap_arg ) ;
drm - > mmap_size = open_arg . size ;
drm - > mmap_offset = mmap_arg . offset ;
}
2023-04-29 02:05:13 +08:00
else if ( strcmp ( driver_name , " test-i915-prime-xtiled " ) = = 0 )
{
2023-05-07 17:57:53 +08:00
if ( check_pixfmt_non_vaapi ( ) ) return 1 ;
2023-04-29 02:05:13 +08:00
drm - > funcs - > convert = & convert_intel_x_tiled_kmsbuf ;
if ( drm_kmsbuf_prime ( ) ) return 1 ;
}
2023-04-27 19:35:18 +08:00
else
{
2023-05-07 17:57:53 +08:00
if ( check_pixfmt_non_vaapi ( ) ) return 1 ;
2023-04-27 19:35:18 +08:00
fprintf ( stderr , " Untested drm driver, use at your own risk! \n " ) ;
2023-04-29 02:05:13 +08:00
if ( drm - > mfb - > modifier ! = DRM_FORMAT_MOD_NONE & & drm - > mfb - > modifier ! = DRM_FORMAT_MOD_LINEAR ) {
printf ( " warn: modifier is not LINEAR, please create an issue with your driver and modifier. \n " ) ;
}
2023-04-27 19:35:18 +08:00
if ( drm_kmsbuf_dumb ( ) ) return 1 ;
}
2023-04-29 15:17:06 +08:00
if ( ! drm - > skip_map & & ! drm - > mapped )
2023-04-27 19:35:18 +08:00
{
2023-04-30 16:32:31 +08:00
printf ( " mapping with size = %lu, offset = %ld, fd = %d \n " , drm - > mmap_size , drm - > mmap_offset , drm - > mmap_fd ) ;
2023-04-27 19:35:18 +08:00
drm - > mapped = mmap ( NULL , drm - > mmap_size , PROT_READ , MAP_SHARED , drm - > mmap_fd , drm - > mmap_offset ) ;
if ( drm - > mapped = = MAP_FAILED )
{
2023-04-29 02:05:13 +08:00
KMSVNC_FATAL ( " Failed to mmap: %s \n " , strerror ( errno ) ) ;
2023-04-27 19:35:18 +08:00
}
}
return 0 ;
}