From 06b90939c428b7a79098790239fc13b0cd057bcd Mon Sep 17 00:00:00 2001 From: Vincent Wei Date: Wed, 3 Jul 2019 12:17:21 +0800 Subject: [PATCH] tune drm video engine for acclerated graphics --- include/exstubs.h | 7 +- src/newgal/drm/drmvideo.c | 315 +++++++++++++++++++++++++------------- src/newgal/drm/drmvideo.h | 11 +- 3 files changed, 221 insertions(+), 112 deletions(-) diff --git a/include/exstubs.h b/include/exstubs.h index 48297570..9c7c220d 100644 --- a/include/exstubs.h +++ b/include/exstubs.h @@ -99,20 +99,21 @@ typedef struct _DrmDriverOps { void (*destroy_driver) (DrmDriver *driver); uint32_t (* create_buffer) (DrmDriver *driver, + int depth, int bpp, unsigned int width, unsigned int height, - unsigned int *pitch, BOOL as_fb); + unsigned int *pitch); BOOL (* fetch_buffer) (DrmDriver *driver, uint32_t buffer_id, unsigned int *width, unsigned int *height, unsigned int *pitch); - BOOL (* map_buffer) (DrmDriver *driver, + uint8_t* (* map_buffer) (DrmDriver *driver, uint32_t buffer_id); void (* unmap_buffer) (DrmDriver *driver, uint32_t buffer_id); - char * (* begin_flush) (DrmDriver *driver, + uint8_t * (* begin_flush) (DrmDriver *driver, uint32_t buffer_id); void (* end_flush) (DrmDriver *driver, diff --git a/src/newgal/drm/drmvideo.c b/src/newgal/drm/drmvideo.c index a59bff49..0d762650 100644 --- a/src/newgal/drm/drmvideo.c +++ b/src/newgal/drm/drmvideo.c @@ -63,14 +63,14 @@ static int DRM_VideoInit(_THIS, GAL_PixelFormat *vformat); static GAL_Rect **DRM_ListModes(_THIS, GAL_PixelFormat *format, Uint32 flags); static int DRM_SetColors(_THIS, int firstcolor, int ncolors, GAL_Color *colors); static void DRM_VideoQuit(_THIS); +static int DRM_Suspend(_THIS); +static int DRM_Resume(_THIS); /* DRM engine operators for dumb buffer */ static GAL_Surface *DRM_SetVideoMode_Dumb(_THIS, GAL_Surface *current, int width, int height, int bpp, Uint32 flags); static int DRM_AllocHWSurface_Dumb(_THIS, GAL_Surface *surface); static void DRM_FreeHWSurface_Dumb(_THIS, GAL_Surface *surface); -static int DRM_Suspend_Dumb(_THIS); -static int DRM_Resume_Dumb(_THIS); /* DRM engine operators accelerated */ static GAL_Surface *DRM_SetVideoMode_Accl(_THIS, GAL_Surface *current, @@ -103,15 +103,6 @@ static int DRM_Available(void) * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the * above copyright notice and this permission notice appear in all copies. - - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS - * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, - * OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING - * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION - * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ struct drm_mode_info { @@ -132,28 +123,6 @@ struct drm_mode_info { */ static void drm_cleanup(DrmVideoData* vdata) { - struct drm_mode_info *iter; - struct drm_mode_destroy_dumb dreq; - - if (vdata->modes) { - int i = 0; - while (vdata->modes[i]) { - free (vdata->modes[i]); - i++; - } - - free(vdata->modes); - } - - while (vdata->mode_list) { - /* remove from global list */ - iter = vdata->mode_list; - vdata->mode_list = iter->next; - - /* free allocated memory */ - free(iter); - } - if (vdata->saved_crtc) { /* restore saved CRTC configuration */ int ret = drmModeSetCrtc(vdata->dev_fd, @@ -171,28 +140,59 @@ static void drm_cleanup(DrmVideoData* vdata) drmModeFreeCrtc(vdata->saved_crtc); } - if (vdata->fb) { - /* unmap buffer */ - munmap(vdata->fb, vdata->size); + if (vdata->scanout_fb) { + if (vdata->driver_ops) { + vdata->driver_ops->unmap_buffer(vdata->driver, vdata->scanout_buff_id); + vdata->driver_ops->destroy_buffer(vdata->driver, vdata->scanout_buff_id); + } + else { + /* dumb buffer */ + struct drm_mode_destroy_dumb dreq; - /* delete framebuffer */ - drmModeRmFB(vdata->dev_fd, vdata->buff); + /* unmap buffer */ + munmap(vdata->scanout_fb, vdata->size); - /* delete dumb buffer */ - memset(&dreq, 0, sizeof(dreq)); - dreq.handle = vdata->handle; - drmIoctl(vdata->dev_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq); + /* delete framebuffer */ + drmModeRmFB(vdata->dev_fd, vdata->scanout_buff_id); + + /* delete dumb buffer */ + memset(&dreq, 0, sizeof(dreq)); + dreq.handle = vdata->handle; + drmIoctl(vdata->dev_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq); + } } + + if (vdata->modes) { + int i = 0; + while (vdata->modes[i]) { + free (vdata->modes[i]); + i++; + } + + free(vdata->modes); + } + + while (vdata->mode_list) { + struct drm_mode_info *iter; + + /* remove from global list */ + iter = vdata->mode_list; + vdata->mode_list = iter->next; + + /* free allocated memory */ + free(iter); + } + } static void DRM_DeleteDevice(GAL_VideoDevice *device) { + drm_cleanup(device->hidden); + if (device->hidden->driver && device->hidden->driver_ops) { device->hidden->driver_ops->destroy_driver(device->hidden->driver); } - drm_cleanup(device->hidden); - free(device->hidden); free(device); } @@ -276,6 +276,7 @@ static int open_drm_device(GAL_VideoDevice *device) } device->hidden->dev_fd = device_fd; + device->hidden->driver = NULL; return 0; } @@ -298,7 +299,7 @@ static GAL_VideoDevice *DRM_CreateDevice(int devindex) if ( device ) { memset(device, 0, (sizeof (*device))); device->hidden = (struct GAL_PrivateVideoData *) - malloc((sizeof (*device->hidden))); + calloc(1, (sizeof (*device->hidden))); } if ((device == NULL) || (device->hidden == NULL)) { GAL_OutOfMemory(); @@ -337,6 +338,8 @@ static GAL_VideoDevice *DRM_CreateDevice(int devindex) device->SetHWColorKey = DRM_SetHWColorKey_Accl; device->SetHWAlpha = DRM_SetHWAlpha_Accl; device->FreeHWSurface = DRM_FreeHWSurface_Accl; + device->Suspend = DRM_Suspend; + device->Resume = DRM_Resume; } else { /* Use DUMB buffer */ @@ -350,8 +353,8 @@ static GAL_VideoDevice *DRM_CreateDevice(int devindex) device->SetHWColorKey = NULL; device->SetHWAlpha = NULL; device->FreeHWSurface = DRM_FreeHWSurface_Dumb; - device->Suspend = DRM_Suspend_Dumb; - device->Resume = DRM_Resume_Dumb; + device->Suspend = DRM_Suspend; + device->Resume = DRM_Resume; } device->free = DRM_DeleteDevice; @@ -609,6 +612,59 @@ static void DRM_VideoQuit(_THIS) } } +static int DRM_Resume(_THIS) +{ + DrmVideoData* vdata = this->hidden; + int ret = -1; + + _DBG_PRINTF ("NEWGAL>DRM: %s called\n", __FUNCTION__); + + if (vdata->saved_info) { + vdata->saved_crtc = drmModeGetCrtc(vdata->dev_fd, + vdata->saved_info->crtc); + ret = drmModeSetCrtc(vdata->dev_fd, + vdata->saved_info->crtc, + vdata->scanout_buff_id, 0, 0, + &vdata->saved_info->conn, 1, + &vdata->saved_info->mode); + } + + if (ret) { + _ERR_PRINTF ("NEWGAL>DRM: Failed to resume dumb frame buffer: %d.\n", + ret); + } + + return ret; +} + +static int DRM_Suspend(_THIS) +{ + DrmVideoData* vdata = this->hidden; + int ret = -1; + + _DBG_PRINTF ("NEWGAL>DRM: %s called\n", __FUNCTION__); + + if (vdata->saved_crtc) { + /* restore saved CRTC configuration */ + ret = drmModeSetCrtc(vdata->dev_fd, + vdata->saved_crtc->crtc_id, + vdata->saved_crtc->buffer_id, + vdata->saved_crtc->x, + vdata->saved_crtc->y, + &vdata->saved_info->conn, 1, + &vdata->saved_crtc->mode); + + drmModeFreeCrtc(vdata->saved_crtc); + vdata->saved_crtc = NULL; + } + + if (ret) { + _ERR_PRINTF ("NEWGAL>DRM: Failed to suspend dumb frame buffer: %m.\n"); + } + + return ret; +} + /* * drm_create_dumb_fb(vdata, info): * Call this function to create a so called "dumb buffer". @@ -643,7 +699,7 @@ static int drm_create_dumb_fb(DrmVideoData* vdata, const DrmModeInfo* info, /* create framebuffer object for the dumb-buffer */ ret = drmModeAddFB(vdata->dev_fd, vdata->width, vdata->height, depth, bpp, - vdata->pitch, vdata->handle, &vdata->buff); + vdata->pitch, vdata->handle, &vdata->scanout_buff_id); if (ret) { _ERR_PRINTF("NEWGAL>DRM: cannot create framebuffer (%d): %m\n", errno); @@ -662,9 +718,9 @@ static int drm_create_dumb_fb(DrmVideoData* vdata, const DrmModeInfo* info, } /* perform actual memory mapping */ - vdata->fb = mmap(0, vdata->size, PROT_READ | PROT_WRITE, MAP_SHARED, + vdata->scanout_fb = mmap(0, vdata->size, PROT_READ | PROT_WRITE, MAP_SHARED, vdata->dev_fd, mreq.offset); - if (vdata->fb == MAP_FAILED) { + if (vdata->scanout_fb == MAP_FAILED) { _ERR_PRINTF("NEWGAL>DRM: cannot mmap dumb buffer (%d): %m\n", errno); ret = -errno; goto err_fb; @@ -673,7 +729,7 @@ static int drm_create_dumb_fb(DrmVideoData* vdata, const DrmModeInfo* info, return 0; err_fb: - drmModeRmFB(vdata->dev_fd, vdata->buff); + drmModeRmFB(vdata->dev_fd, vdata->scanout_buff_id); err_destroy: memset(&dreq, 0, sizeof(dreq)); @@ -729,7 +785,7 @@ static GAL_Surface *DRM_SetVideoMode_Dumb(_THIS, GAL_Surface *current, /* perform actual modesetting on the found connector+CRTC */ this->hidden->saved_crtc = drmModeGetCrtc(vdata->dev_fd, info->crtc); - ret = drmModeSetCrtc(vdata->dev_fd, info->crtc, vdata->buff, 0, 0, + ret = drmModeSetCrtc(vdata->dev_fd, info->crtc, vdata->scanout_buff_id, 0, 0, &info->conn, 1, &info->mode); if (ret) { _ERR_PRINTF ("NEWGAL>DRM: cannot set CRTC for connector %u (%d): %m\n", @@ -755,7 +811,7 @@ static GAL_Surface *DRM_SetVideoMode_Dumb(_THIS, GAL_Surface *current, current->w = width; current->h = height; current->pitch = this->hidden->pitch; - current->pixels = this->hidden->fb; + current->pixels = this->hidden->scanout_fb; /* We're done */ return(current); @@ -771,63 +827,110 @@ static void DRM_FreeHWSurface_Dumb(_THIS, GAL_Surface *surface) surface->pixels = NULL; } -static int DRM_Resume_Dumb(_THIS) -{ - DrmVideoData* vdata = this->hidden; - int ret = -1; - - _DBG_PRINTF ("NEWGAL>DRM: %s called\n", __FUNCTION__); - - if (vdata->saved_info) { - vdata->saved_crtc = drmModeGetCrtc(vdata->dev_fd, - vdata->saved_info->crtc); - ret = drmModeSetCrtc(vdata->dev_fd, - vdata->saved_info->crtc, - vdata->buff, 0, 0, - &vdata->saved_info->conn, 1, - &vdata->saved_info->mode); - } - - if (ret) { - _ERR_PRINTF ("NEWGAL>DRM: Failed to resume dumb frame buffer: %d.\n", - ret); - } - - return ret; -} - -static int DRM_Suspend_Dumb(_THIS) -{ - DrmVideoData* vdata = this->hidden; - int ret = -1; - - _DBG_PRINTF ("NEWGAL>DRM: %s called\n", __FUNCTION__); - - if (vdata->saved_crtc) { - /* restore saved CRTC configuration */ - ret = drmModeSetCrtc(vdata->dev_fd, - vdata->saved_crtc->crtc_id, - vdata->saved_crtc->buffer_id, - vdata->saved_crtc->x, - vdata->saved_crtc->y, - &vdata->saved_info->conn, 1, - &vdata->saved_crtc->mode); - - drmModeFreeCrtc(vdata->saved_crtc); - vdata->saved_crtc = NULL; - } - - if (ret) { - _ERR_PRINTF ("NEWGAL>DRM: Failed to suspend dumb frame buffer: %m.\n"); - } - - return ret; -} - /* DRM engine methods for accelerated buffers */ static GAL_Surface *DRM_SetVideoMode_Accl(_THIS, GAL_Surface *current, int width, int height, int bpp, Uint32 flags) { + DrmVideoData* vdata = this->hidden; + DrmModeInfo* info; + int depth; + unsigned int pitch; + + if (bpp != 32) { + _DBG_PRINTF("NEWGAL>DRM: force bpp (%d) to be 32\n", bpp); + bpp = 32; + } + depth = 24; + + /* find the connector+CRTC suitable for the resolution requested */ + info = find_mode(vdata, width, height); + if (info == NULL) { + _ERR_PRINTF("NEWGAL>DRM: cannot find a CRTC for video mode: %dx%d-%dbpp\n", + width, height, bpp); + return NULL; + } + + _DBG_PRINTF("NEWGAL>DRM: going setting video mode: %dx%d-%dbpp\n", + info->width, info->height, bpp); + +#if 0 + if (drmSetMaster(this->hidden->dev_fd)) { + _ERR_PRINTF("NEWGAL>DRM: failed to call drmSetMaster: %m\n"); + return NULL; + } +#endif + + /* create the scanout buffer and set up it as frame buffer */ + vdata->scanout_buff_id = + vdata->driver_ops->create_buffer(vdata->driver, depth, bpp, + info->width, info->height, &pitch); + if (vdata->scanout_buff_id == 0) { + goto error; + } + + vdata->width = info->width; + vdata->height = info->height; + vdata->bpp = bpp; + vdata->pitch = pitch; + vdata->size = pitch * info->height; + vdata->handle = 0; + vdata->scanout_fb = vdata->driver_ops->map_buffer(vdata->driver, vdata->scanout_buff_id); + if (vdata->scanout_fb == NULL) { + _ERR_PRINTF ("NEWGAL>DRM: cannot map scanout frame buffer: %m\n"); + goto error; + } + + _DBG_PRINTF("NEWGAL>DRM: scanout frame buffer: size (%dx%d), pitch(%d)\n", + vdata->width, vdata->height, vdata->pitch); + + /* get console buffer id */ + vdata->saved_crtc = drmModeGetCrtc(vdata->dev_fd, info->crtc); + vdata->console_buff_id = vdata->saved_crtc->buffer_id; + + /* perform actual modesetting on the found connector+CRTC */ + if (drmModeSetCrtc(vdata->dev_fd, info->crtc, vdata->scanout_buff_id, 0, 0, + &info->conn, 1, &info->mode)) { + _ERR_PRINTF ("NEWGAL>DRM: cannot set CRTC for connector %u (%d): %m\n", + info->conn, errno); + + goto error; + } + + this->hidden->saved_info = info; + + /* Allocate the new pixel format for the screen */ + if (!GAL_ReallocFormat (current, bpp, 0, 0, 0, 0)) { + goto error; + } + + _DBG_PRINTF("NEWGAL>DRM: real screen mode: %dx%d-%dbpp\n", width, height, bpp); + + current->flags = flags & GAL_FULLSCREEN; + current->w = width; + current->h = height; + current->pitch = this->hidden->pitch; + current->pixels = this->hidden->scanout_fb; + + /* We're done */ + return(current); + +error: + + if (vdata->saved_crtc) { + drmModeFreeCrtc(vdata->saved_crtc); + vdata->saved_crtc = NULL; + } + + if (vdata->scanout_fb) { + vdata->driver_ops->unmap_buffer(vdata->driver, vdata->scanout_buff_id); + vdata->scanout_fb = NULL; + } + + if (vdata->scanout_buff_id) { + vdata->driver_ops->destroy_buffer(vdata->driver, vdata->scanout_buff_id); + vdata->scanout_buff_id = 0; + } + return NULL; } diff --git a/src/newgal/drm/drmvideo.h b/src/newgal/drm/drmvideo.h index 33caf665..c1754b5e 100644 --- a/src/newgal/drm/drmvideo.h +++ b/src/newgal/drm/drmvideo.h @@ -63,12 +63,17 @@ typedef struct GAL_PrivateVideoData { uint32_t pitch; uint32_t size; - uint32_t buff; - uint32_t handle; + uint32_t scanout_buff_id; + uint8_t* scanout_fb; DrmModeInfo* saved_info; drmModeCrtc* saved_crtc; - uint8_t* fb; + + /* only valid when using DUMB frame buffer */ + uint32_t handle; + + /* only valid when using DRM driver */ + uint32_t console_buff_id; } DrmVideoData; #endif /* _NEWGAL_DRMVIDEO_H */