From 4ea138ef190d33111ef2625fdd9d673310b9e3fa Mon Sep 17 00:00:00 2001 From: Vincent Wei Date: Sat, 14 Mar 2020 19:01:49 +0800 Subject: [PATCH] implement methods for compositing schema and PROCS runmode --- src/newgal/drm/drmvideo.c | 2258 +++++++++++++++++++++---------------- 1 file changed, 1295 insertions(+), 963 deletions(-) diff --git a/src/newgal/drm/drmvideo.c b/src/newgal/drm/drmvideo.c index ede2278f..9f2718e0 100644 --- a/src/newgal/drm/drmvideo.c +++ b/src/newgal/drm/drmvideo.c @@ -57,6 +57,7 @@ #include #include #include +#include #include #include #include @@ -80,13 +81,14 @@ static void DRM_VideoQuit(_THIS); static int DRM_Suspend(_THIS); static int DRM_Resume(_THIS); -/* DRM engine operators for dumb buffer */ +/* DRM engine methods 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); -/* DRM engine operators accelerated */ +static int DRM_AllocDumbSurface(_THIS, GAL_Surface *surface); +static void DRM_FreeDumbSurface(_THIS, GAL_Surface *surface); + +/* DRM engine methods accelerated */ static GAL_Surface *DRM_SetVideoMode_Accl(_THIS, GAL_Surface *current, int width, int height, int bpp, Uint32 flags); static int DRM_AllocHWSurface_Accl(_THIS, GAL_Surface *surface); @@ -98,740 +100,87 @@ static void DRM_UpdateRects_Accl (_THIS, int numrects, GAL_Rect *rects); static int DRM_SetHWColorKey_Accl(_THIS, GAL_Surface *surface, Uint32 key); static int DRM_SetHWAlpha_Accl(_THIS, GAL_Surface *surface, Uint8 value); +#if IS_SHAREDFB_SCHEMA_PROCS +/* DRM engine methods for clients under sharedfb schema and MiniGUI-Processes */ +static GAL_Surface *DRM_SetVideoMode_Client(_THIS, GAL_Surface *current, + int width, int height, int bpp, Uint32 flags); +#endif /* IS_SHAREDFB_SCHEMA_PROCS */ + +#if IS_COMPOSITING_SCHEMA +/* DRM engine methods for compositing schema */ +static int DRM_AllocSharedHWSurface(_THIS, GAL_Surface *surface, + size_t* pixels_size, off_t* pixels_off, Uint32 rw_modes); +static int DRM_FreeSharedHWSurface(_THIS, GAL_Surface *surface); +static int DRM_AttachSharedHWSurface(_THIS, GAL_Surface *surface, + int prime_fd, size_t mapsize, BOOL with_rw); +static int DRM_DettachSharedHWSurface(_THIS, GAL_Surface *surface); + +static int DRM_SetCursor(_THIS, GAL_Surface *surface, int hot_x, int hot_y); +static int DRM_MoveCursor(_THIS, int x, int y); +#endif /* IS_COMPOSITING_SCHEMA */ + /* DRM driver bootstrap functions */ static int DRM_Available(void) { return drmAvailable(); } -/* - * The following helpers derived from DRM HOWTO by David Herrmann. - * - * drm_prepare - * drm_find_crtc - * drm_setup_connector - * drm_create_dumb_fb - * drm_cleanup - * - * Copyright 2012-2017 David Herrmann - * - * 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. - */ - -struct drm_mode_info { - struct drm_mode_info *next; - - uint32_t width; - uint32_t height; - uint32_t conn; - uint32_t crtc; - - drmModeModeInfo mode; -}; - -/* - * drm_cleanup(vdata): This cleans up all the devices we created during - * drm_prepare(). It resets the CRTCs to their saved states and deallocates - * all memory. - */ -static void drm_cleanup(DrmVideoData* vdata) +/* format conversion helpers */ +static int drm_format_to_bpp(uint32_t drm_format, + int* bpp, int* cpp) { - if (vdata->saved_crtc) { - /* restore saved CRTC configuration */ - int 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); - if (ret) { - _ERR_PRINTF ("NEWGAL>DRM: failed to restore CRTC for connector %u (%d): %m\n", - vdata->saved_info->conn, errno); - } - - drmModeFreeCrtc(vdata->saved_crtc); - } - - if (vdata->scanout_fb) { - if (vdata->driver_ops) { - // do nothing for hardware surface. - } - else { - /* dumb buffer */ - struct drm_mode_destroy_dumb dreq; - - /* unmap buffer */ - munmap(vdata->scanout_fb, vdata->size); - - /* 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); - } - - close (vdata->dev_fd); -} - -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); - } - - if (device->hidden->exdrv_handle) - dlclose(device->hidden->exdrv_handle); - - free(device->hidden); - free(device); -} - -static char* find_driver_for_device (const char *dev_name) -{ - char *driver; - int major_number, minor_number; - struct stat file_attrs; - char *device_path; - char device_link_path[PATH_MAX + 1] = ""; - int ret; - - if (stat (dev_name, &file_attrs) < 0) { - _ERR_PRINTF("NEWGAL>DRM: failed to call stat on %s\n", dev_name); - return NULL; - } - - if (!S_ISCHR (file_attrs.st_mode)) { - _ERR_PRINTF("NEWGAL>DRM: %s is not a character device\n", dev_name); - return NULL; - } - - major_number = major (file_attrs.st_rdev); - minor_number = minor (file_attrs.st_rdev); - - ret = asprintf (&device_path, "/sys/dev/char/%d:%d/device/driver", - major_number, minor_number); - if (ret < 0) { - _ERR_PRINTF("NEWGAL>DRM: failed to call asprintf to build device path\n"); - return NULL; - } - - if (readlink (device_path, device_link_path, - sizeof (device_link_path) - 1) < 0) { - free (device_path); - return NULL; - } - - _DBG_PRINTF("device link path: %s\n", device_link_path); - - free (device_path); - driver = strrchr (device_link_path, '/'); - if (driver == NULL) - return NULL; - - return strdup (driver + strlen ("/")); -} - -static DrmDriverOps* load_external_driver (DrmVideoData* vdata, - const char* driver_name, int device_fd) -{ - const char* filename = NULL; - char buff[LEN_SO_NAME + 1]; - DrmDriverOps* (*get_exdrv) (const char* driver_name, int device_fd); - char* error; - - filename = getenv ("MG_GAL_DRM_DRIVER"); - if (filename == NULL) { - memset (buff, 0, sizeof (buff)); - if (GetMgEtcValue ("drm", "exdriver", buff, LEN_SO_NAME) < 0) - return NULL; - - filename = buff; - } - - vdata->exdrv_handle = dlopen (filename, RTLD_LAZY); - if (!vdata->exdrv_handle) { - _WRN_PRINTF("Failed to open specified external DRM driver: %s (%s)\n", - filename, dlerror()); - return NULL; - } - - dlerror(); /* Clear any existing error */ - get_exdrv = dlsym (vdata->exdrv_handle, "__drm_ex_driver_get"); - error = dlerror(); - if (error) { - _WRN_PRINTF("Failed to get symbol: %s\n", error); - dlclose (vdata->exdrv_handle); - vdata->exdrv_handle = NULL; - return NULL; - } - - return get_exdrv (driver_name, device_fd); -} - -static int open_drm_device(GAL_VideoDevice *device) -{ - char *driver_name; - int device_fd; - - driver_name = find_driver_for_device(device->hidden->dev_name); - - _DBG_PRINTF("Try to load DRM driver: %s\n", driver_name); - - device_fd = drmOpen(driver_name, NULL); - if (device_fd < 0) { - _ERR_PRINTF("NEWGAL>DRM: drmOpen failed\n"); - free(driver_name); - return -errno; - } - - device->hidden->driver_ops = load_external_driver (device->hidden, - driver_name, device_fd); - - free (driver_name); - - if (device->hidden->driver_ops == NULL) { - uint64_t has_dumb; - - /* check whether supports dumb buffer */ - if (drmGetCap(device_fd, DRM_CAP_DUMB_BUFFER, &has_dumb) < 0 || - !has_dumb) { - _ERR_PRINTF("NEWGAL>DRM: the DRM device '%s' does not support dumb buffers\n", - device->hidden->dev_name); - close(device_fd); - return -EOPNOTSUPP; - } - - device->hidden->dev_fd = device_fd; - device->hidden->driver = NULL; - return 0; - } - - device->hidden->dev_fd = device_fd; - device->hidden->driver = device->hidden->driver_ops->create_driver(device_fd); - if (device->hidden->driver == NULL) { - _WRN_PRINTF("NEWGAL>DRM: failed to create DRM driver\n"); - device->hidden->driver_ops = NULL; - } - - return 0; -} - -static GAL_VideoDevice *DRM_CreateDevice(int devindex) -{ - GAL_VideoDevice *device; - - /* Initialize all variables that we clean on shutdown */ - device = (GAL_VideoDevice *)malloc(sizeof(GAL_VideoDevice)); - if ( device ) { - memset(device, 0, (sizeof (*device))); - device->hidden = (struct GAL_PrivateVideoData *) - calloc(1, (sizeof (*device->hidden))); - } - if ((device == NULL) || (device->hidden == NULL)) { - GAL_OutOfMemory(); - if (device) { - free(device); - } - return NULL; - } - - memset(device->hidden, 0, (sizeof (*device->hidden))); - if (GetMgEtcValue ("drm", "device", - device->hidden->dev_name, LEN_DEVICE_NAME) < 0) { - strcpy(device->hidden->dev_name, "/dev/dri/card0"); - _WRN_PRINTF("NEWGAL>DRM: No dri.device defined, use the default '/dev/dri/card0'\n"); - } - - device->hidden->dev_fd = -1; - open_drm_device(device); - if (device->hidden->dev_fd < 0) { - return NULL; - } - - device->VideoInit = DRM_VideoInit; - device->ListModes = DRM_ListModes; - device->SetColors = DRM_SetColors; - device->VideoQuit = DRM_VideoQuit; - if (device->hidden->driver) { - /* Use accelerated driver */ - device->SetVideoMode = DRM_SetVideoMode_Accl; -#if IS_SHAREDFB_SCHEMA - device->RequestHWSurface = NULL; -#endif - device->AllocHWSurface = DRM_AllocHWSurface_Accl; - device->FreeHWSurface = DRM_FreeHWSurface_Accl; - device->UpdateRects = DRM_UpdateRects_Accl; - } - else { - /* Use DUMB buffer */ - device->SetVideoMode = DRM_SetVideoMode_Dumb; -#if IS_SHAREDFB_SCHEMA - device->RequestHWSurface = NULL; -#endif - device->AllocHWSurface = DRM_AllocHWSurface_Dumb; - device->FreeHWSurface = DRM_FreeHWSurface_Dumb; - device->UpdateRects = NULL; - } - - /* set accelerated methods in DRM_VideoInit */ - device->CheckHWBlit = NULL; - device->FillHWRect = NULL; - device->SetHWColorKey = NULL; - device->SetHWAlpha = NULL; - device->Suspend = DRM_Suspend; - device->Resume = DRM_Resume; - device->free = DRM_DeleteDevice; - - return device; -} - -VideoBootStrap DRM_bootstrap = { - DRM_DRIVER_NAME, "Linux DRI video driver", - DRM_Available, DRM_CreateDevice -}; - -/* - * drm_find_crtc(vdata, res, conn, info): - * This small helper tries to find a suitable CRTC for the given connector. - */ -static int drm_find_crtc(DrmVideoData* vdata, - drmModeRes *res, drmModeConnector *conn, struct drm_mode_info *info) -{ - drmModeEncoder *enc; - unsigned int i, j; - int32_t crtc; - struct drm_mode_info *iter; - - /* first try the currently conected encoder+crtc */ - if (conn->encoder_id) - enc = drmModeGetEncoder(vdata->dev_fd, conn->encoder_id); - else - enc = NULL; - - if (enc) { - if (enc->crtc_id) { - crtc = enc->crtc_id; - for (iter = vdata->mode_list; iter; iter = iter->next) { - if (iter->crtc == crtc) { - crtc = -1; - break; - } - } - - if (crtc >= 0) { - drmModeFreeEncoder(enc); - info->crtc = crtc; - return 0; - } - } - - drmModeFreeEncoder(enc); - } - - /* If the connector is not currently bound to an encoder or if the - * encoder+crtc is already used by another connector (actually unlikely - * but lets be safe), iterate all other available encoders to find a - * matching CRTC. */ - for (i = 0; i < conn->count_encoders; ++i) { - enc = drmModeGetEncoder(vdata->dev_fd, conn->encoders[i]); - if (!enc) { - _ERR_PRINTF("NEWGAL>DRM: cannot retrieve encoder %u:%u (%d): %m\n", - i, conn->encoders[i], errno); - continue; - } - - /* iterate all global CRTCs */ - for (j = 0; j < res->count_crtcs; ++j) { - /* check whether this CRTC works with the encoder */ - if (!(enc->possible_crtcs & (1 << j))) - continue; - - /* check that no other device already uses this CRTC */ - crtc = res->crtcs[j]; - for (iter = vdata->mode_list; iter; iter = iter->next) { - if (iter->crtc == crtc) { - crtc = -1; - break; - } - } - - /* we have found a CRTC, so save it and return */ - if (crtc >= 0) { - drmModeFreeEncoder(enc); - info->crtc = crtc; - return 0; - } - } - - drmModeFreeEncoder(enc); - } - - _ERR_PRINTF("NEWGAL>DRM: cannot find suitable CRTC for connector %u\n", - conn->connector_id); - return -ENOENT; -} - -/* - * drm_setup_connector: - * Set up a single connector. - */ -static int drm_setup_connector(DrmVideoData* vdata, - drmModeRes *res, drmModeConnector *conn, struct drm_mode_info *info) -{ - int ret; - - /* check if a monitor is connected */ - if (conn->connection != DRM_MODE_CONNECTED) { - _ERR_PRINTF("NEWGAL>DRM: ignoring unused connector %u\n", - conn->connector_id); - return -ENOENT; - } - - /* check if there is at least one valid mode */ - if (conn->count_modes == 0) { - _ERR_PRINTF("NEWGAL>DRM: no valid mode for connector %u\n", - conn->connector_id); - return -EFAULT; - } - - /* copy the mode information into our device structure */ - memcpy(&info->mode, &conn->modes[0], sizeof(info->mode)); - info->width = conn->modes[0].hdisplay; - info->height = conn->modes[0].vdisplay; - _DBG_PRINTF("NEWGAL>DRM: mode for connector %u is %ux%u\n", - conn->connector_id, info->width, info->height); - - /* find a crtc for this connector */ - ret = drm_find_crtc(vdata, res, conn, info); - if (ret) { - _ERR_PRINTF("NEWGAL>DRM: no valid crtc for connector %u\n", - conn->connector_id); - return ret; - } - - return 0; -} - -/* - * drm_prepare: - * Collect the connnectors and mode information. - */ -static int drm_prepare(DrmVideoData* vdata) -{ - drmModeRes *res; - drmModeConnector *conn; - unsigned int i; - struct drm_mode_info *info; - int ret; - - /* retrieve resources */ - res = drmModeGetResources(vdata->dev_fd); - if (!res) { - _ERR_PRINTF("NEWGAL>DRM: cannot retrieve DRM resources (%d): %m\n", - errno); - return -errno; - } - - /* iterate all connectors */ - for (i = 0; i < res->count_connectors; ++i) { - /* get information for each connector */ - conn = drmModeGetConnector(vdata->dev_fd, res->connectors[i]); - if (!conn) { - _ERR_PRINTF("NEWGAL>DRM: cannot retrieve DRM connector %u:%u(%d): %m\n", - i, res->connectors[i], errno); - continue; - } - - /* create a device structure */ - info = malloc(sizeof(*info)); - memset(info, 0, sizeof(*info)); - info->conn = conn->connector_id; - - /* call helper function to prepare this connector */ - ret = drm_setup_connector(vdata, res, conn, info); - if (ret) { - if (ret != -ENOENT) { - errno = -ret; - _ERR_PRINTF("NEWGAL>DRM: cannot setup device for connector" - " %u:%u (%d): %m\n", - i, res->connectors[i], errno); - } - free(info); - drmModeFreeConnector(conn); - continue; - } - - /* free connector vdata and link device into global list */ - drmModeFreeConnector(conn); - info->next = vdata->mode_list; - vdata->mode_list = info; - } - - /* free resources again */ - drmModeFreeResources(res); - return 0; -} - -/* DRM engine methods for both dumb buffer and acclerated buffers */ -static int DRM_VideoInit(_THIS, GAL_PixelFormat *vformat) -{ - int n = 0; - struct drm_mode_info *iter; - - drm_prepare(this->hidden); - - for (iter = this->hidden->mode_list; iter; iter = iter->next) { - _DBG_PRINTF("mode #%d: %ux%u, conn: %u, crtc: %u\n", n, - iter->width, iter->height, iter->conn, iter->crtc); - n++; - } - - if (n == 0) { + switch (drm_format) { + case DRM_FORMAT_RGB332: + case DRM_FORMAT_BGR233: + *bpp = 8; + *cpp = 1; + break; + + case DRM_FORMAT_XRGB4444: + case DRM_FORMAT_XBGR4444: + case DRM_FORMAT_RGBX4444: + case DRM_FORMAT_BGRX4444: + case DRM_FORMAT_ARGB4444: + case DRM_FORMAT_ABGR4444: + case DRM_FORMAT_RGBA4444: + case DRM_FORMAT_BGRA4444: + case DRM_FORMAT_XRGB1555: + case DRM_FORMAT_XBGR1555: + case DRM_FORMAT_RGBX5551: + case DRM_FORMAT_BGRX5551: + case DRM_FORMAT_ARGB1555: + case DRM_FORMAT_ABGR1555: + case DRM_FORMAT_RGBA5551: + case DRM_FORMAT_BGRA5551: + case DRM_FORMAT_RGB565: + case DRM_FORMAT_BGR565: + *bpp = 16; + *cpp = 2; + break; + + case DRM_FORMAT_RGB888: + case DRM_FORMAT_BGR888: + *bpp = 24; + *cpp = 3; + break; + + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_RGBX8888: + case DRM_FORMAT_BGRX8888: + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_RGBA8888: + case DRM_FORMAT_BGRA8888: + *bpp = 32; + *cpp = 4; + break; + + default: return -1; } - this->hidden->modes = calloc(n + 1, sizeof(GAL_Rect*)); - if (this->hidden->modes == NULL) { - _ERR_PRINTF("NEWGAL>DRM: failed to allocate memory for modes (%d)\n", - n); - return -1; - } - - n = 0; - for (iter = this->hidden->mode_list; iter; iter = iter->next) { - this->hidden->modes[n] = malloc(sizeof(GAL_Rect)); - this->hidden->modes[n]->x = 0; - this->hidden->modes[n]->y = 0; - this->hidden->modes[n]->w = iter->width; - this->hidden->modes[n]->h = iter->height; - n++; - } - - vformat->BitsPerPixel = 32; - vformat->BytesPerPixel = 4; - - if (this->hidden->driver) { - if (this->hidden->driver_ops->clear_buffer) { - this->info.blit_fill = 1; - this->FillHWRect = DRM_FillHWRect_Accl; - } - else - this->FillHWRect = NULL; - - if (this->hidden->driver_ops->check_blit) { - this->CheckHWBlit = DRM_CheckHWBlit_Accl; - this->SetHWColorKey = DRM_SetHWColorKey_Accl; - this->SetHWAlpha = DRM_SetHWAlpha_Accl; - - this->info.blit_hw = 1; - if (this->hidden->driver_ops->alpha_blit) - this->info.blit_hw_A = 1; - if (this->hidden->driver_ops->key_blit) - this->info.blit_hw_CC = 1; - } - else { - this->CheckHWBlit = NULL; - this->SetHWColorKey = NULL; - this->SetHWAlpha = NULL; - } - } - - /* We're done! */ - return(0); -} - -static GAL_Rect **DRM_ListModes(_THIS, GAL_PixelFormat *format, Uint32 flags) -{ - if (format->BitsPerPixel != 32) { - return NULL; - } - - return this->hidden->modes; -} - -static int DRM_SetColors(_THIS, int firstcolor, int ncolors, GAL_Color *colors) -{ - /* do nothing of note. */ - return(1); -} - -static void DRM_VideoQuit(_THIS) -{ - if (this->screen->pixels != NULL) { - this->screen->pixels = NULL; - } -} - -static int DRM_Resume(_THIS) -{ - DrmVideoData* vdata = this->hidden; - int ret = -1; - - _DBG_PRINTF ("%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 ("%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". - * We can use it for unaccelerated software rendering on the CPU. - */ -static int drm_create_dumb_fb(DrmVideoData* vdata, const DrmModeInfo* info, - uint32_t format, int bpp) -{ - struct drm_mode_create_dumb creq; - struct drm_mode_destroy_dumb dreq; - struct drm_mode_map_dumb mreq; - uint32_t handles[4], pitches[4], offsets[4]; - int ret; - - /* create dumb buffer */ - memset(&creq, 0, sizeof(creq)); - creq.width = info->width; - creq.height = info->height; - creq.bpp = bpp; - ret = drmIoctl(vdata->dev_fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq); - if (ret < 0) { - _ERR_PRINTF("NEWGAL>DRM: cannot create dumb buffer (%d): %m\n", - errno); - return -errno; - } - - vdata->width = creq.width; - vdata->height = creq.height; - vdata->bpp = creq.bpp; - vdata->pitch = creq.pitch; - vdata->size = creq.size; - vdata->handle = creq.handle; - - /* create framebuffer object for the dumb-buffer */ - handles[0] = vdata->handle; - pitches[0] = vdata->pitch; - offsets[0] = 0; - - ret = drmModeAddFB2(vdata->dev_fd, vdata->width, vdata->height, format, - handles, pitches, offsets, &vdata->scanout_buff_id, 0); - if (ret) { - _ERR_PRINTF("NEWGAL>DRM: cannot create framebuffer (%d): %m\n", - errno); - ret = -errno; - goto err_destroy; - } - - /* prepare buffer for memory mapping */ - memset(&mreq, 0, sizeof(mreq)); - mreq.handle = vdata->handle; - ret = drmIoctl(vdata->dev_fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq); - if (ret) { - _ERR_PRINTF("NEWGAL>DRM: cannot map dumb buffer (%d): %m\n", errno); - ret = -errno; - goto err_fb; - } - - /* perform actual memory mapping */ - vdata->scanout_fb = mmap(0, vdata->size, PROT_READ | PROT_WRITE, MAP_SHARED, - vdata->dev_fd, mreq.offset); - if (vdata->scanout_fb == MAP_FAILED) { - _ERR_PRINTF("NEWGAL>DRM: cannot mmap dumb buffer (%d): %m\n", errno); - ret = -errno; - goto err_fb; - } - return 0; - -err_fb: - drmModeRmFB(vdata->dev_fd, vdata->scanout_buff_id); - -err_destroy: - memset(&dreq, 0, sizeof(dreq)); - dreq.handle = vdata->handle; - drmIoctl(vdata->dev_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq); - return ret; -} - -static DrmModeInfo* find_mode(DrmVideoData* vdata, int width, int height) -{ - DrmModeInfo *iter; - - for (iter = vdata->mode_list; iter; iter = iter->next) { - if (iter->width >= width && iter->height >= height) - return iter; - } - - return NULL; } static inline uint32_t get_def_drm_format(int bpp) @@ -1324,6 +673,884 @@ static int translate_drm_format(uint32_t drm_format, Uint32* RGBAmasks) return bpp; } +/* + * The following helpers derived from DRM HOWTO by David Herrmann. + * + * drm_prepare + * drm_find_crtc + * drm_setup_connector + * drm_create_dumb_fb + * drm_cleanup + * + * Copyright 2012-2017 David Herrmann + * + * 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. + */ + +struct drm_mode_info { + struct drm_mode_info *next; + + int width; + int height; + int pitch; + + uint32_t conn; + uint32_t crtc; + + drmModeModeInfo mode; +}; + +/* + * drm_cleanup(vdata): This cleans up all the devices we created during + * drm_prepare(). It resets the CRTCs to their saved states and deallocates + * all memory. + */ +static void drm_cleanup(DrmVideoData* vdata) +{ + if (vdata->saved_crtc) { + /* restore saved CRTC configuration */ + int 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); + if (ret) { + _ERR_PRINTF ("NEWGAL>DRM: failed to restore CRTC for " + "connector %u (%d): %m\n", + vdata->saved_info->conn, errno); + } + + drmModeFreeCrtc(vdata->saved_crtc); + } + + if (vdata->scanout_fb) { + if (vdata->driver_ops) { + // do nothing for hardware surface. + } + else { + /* dumb buffer */ + struct drm_mode_destroy_dumb dreq; + + /* unmap buffer */ + munmap(vdata->scanout_fb, vdata->size); + + /* 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); + } + + close (vdata->dev_fd); +} + +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); + } + + if (device->hidden->exdrv_handle) + dlclose(device->hidden->exdrv_handle); + + free(device->hidden); + free(device); +} + +static char* find_driver_for_device (const char *dev_name) +{ + char *driver; + int major_number, minor_number; + struct stat file_attrs; + char *device_path; + char device_link_path[PATH_MAX + 1] = ""; + int ret; + + if (stat (dev_name, &file_attrs) < 0) { + _ERR_PRINTF("NEWGAL>DRM: failed to call stat on %s\n", dev_name); + return NULL; + } + + if (!S_ISCHR (file_attrs.st_mode)) { + _ERR_PRINTF("NEWGAL>DRM: %s is not a character device\n", dev_name); + return NULL; + } + + major_number = major (file_attrs.st_rdev); + minor_number = minor (file_attrs.st_rdev); + + ret = asprintf (&device_path, "/sys/dev/char/%d:%d/device/driver", + major_number, minor_number); + if (ret < 0) { + _ERR_PRINTF("NEWGAL>DRM: failed to call asprintf to build device path\n"); + return NULL; + } + + if (readlink (device_path, device_link_path, + sizeof (device_link_path) - 1) < 0) { + free (device_path); + return NULL; + } + + _DBG_PRINTF("device link path: %s\n", device_link_path); + + free (device_path); + driver = strrchr (device_link_path, '/'); + if (driver == NULL) + return NULL; + + return strdup (driver + strlen ("/")); +} + +static DrmDriverOps* load_external_driver (DrmVideoData* vdata, + const char* driver_name, int device_fd) +{ + const char* filename = NULL; + char buff[LEN_SO_NAME + 1]; + DrmDriverOps* (*get_exdrv) (const char* driver_name, int device_fd); + char* error; + + filename = getenv ("MG_GAL_DRM_DRIVER"); + if (filename == NULL) { + memset (buff, 0, sizeof (buff)); + if (GetMgEtcValue ("drm", "exdriver", buff, LEN_SO_NAME) < 0) + return NULL; + + filename = buff; + } + + vdata->exdrv_handle = dlopen (filename, RTLD_LAZY); + if (!vdata->exdrv_handle) { + _WRN_PRINTF("failed to open specified external DRM driver: %s (%s)\n", + filename, dlerror()); + return NULL; + } + + dlerror(); /* Clear any existing error */ + get_exdrv = dlsym (vdata->exdrv_handle, "__drm_ex_driver_get"); + error = dlerror(); + if (error) { + _WRN_PRINTF("failed to get symbol: %s\n", error); + dlclose (vdata->exdrv_handle); + vdata->exdrv_handle = NULL; + return NULL; + } + + return get_exdrv (driver_name, device_fd); +} + +static int open_drm_device(GAL_VideoDevice *device) +{ + char *driver_name; + int device_fd; + + driver_name = find_driver_for_device(device->hidden->dev_name); + + _DBG_PRINTF("Try to load DRM driver: %s\n", driver_name); + + device_fd = drmOpen(driver_name, NULL); + if (device_fd < 0) { + _ERR_PRINTF("NEWGAL>DRM: drmOpen failed\n"); + free(driver_name); + return -errno; + } + + device->hidden->driver_ops = load_external_driver (device->hidden, + driver_name, device_fd); + + free (driver_name); + + if (device->hidden->driver_ops == NULL) { + uint64_t has_dumb; + + /* check whether supports dumb buffer */ + if (drmGetCap(device_fd, DRM_CAP_DUMB_BUFFER, &has_dumb) < 0 || + !has_dumb) { + _ERR_PRINTF("NEWGAL>DRM: the DRM device '%s' does not support " + "dumb buffers\n", + device->hidden->dev_name); + close(device_fd); + return -EOPNOTSUPP; + } + + device->hidden->dev_fd = device_fd; + device->hidden->driver = NULL; + return 0; + } + + device->hidden->dev_fd = device_fd; + device->hidden->driver = device->hidden->driver_ops->create_driver(device_fd); + if (device->hidden->driver == NULL) { + _WRN_PRINTF("failed to create DRM driver\n"); + device->hidden->driver_ops = NULL; + } + + return 0; +} + +static GAL_VideoDevice *DRM_CreateDevice(int devindex) +{ + GAL_VideoDevice *device; + + /* Initialize all variables that we clean on shutdown */ + device = (GAL_VideoDevice *)malloc(sizeof(GAL_VideoDevice)); + if ( device ) { + memset(device, 0, (sizeof (*device))); + device->hidden = (struct GAL_PrivateVideoData *) + calloc(1, (sizeof (*device->hidden))); + } + if ((device == NULL) || (device->hidden == NULL)) { + GAL_OutOfMemory(); + if (device) { + free(device); + } + return NULL; + } + + memset(device->hidden, 0, (sizeof (*device->hidden))); + if (GetMgEtcValue ("drm", "device", + device->hidden->dev_name, LEN_DEVICE_NAME) < 0) { + strcpy(device->hidden->dev_name, "/dev/dri/card0"); + _WRN_PRINTF("No drm.device defined, use the default '/dev/dri/card0'\n"); + } + + device->hidden->dev_fd = -1; + open_drm_device(device); + if (device->hidden->dev_fd < 0) { + return NULL; + } + + device->VideoInit = DRM_VideoInit; + device->ListModes = DRM_ListModes; + device->SetColors = DRM_SetColors; + device->VideoQuit = DRM_VideoQuit; + if (device->hidden->driver) { + /* Use accelerated driver */ +#ifdef _MGRM_PROCESSES +# ifdef _MGSCHEMA_COMPOSITING + if (mgIsServer) { + device->SetVideoMode = DRM_SetVideoMode_Accl; + } + else + device->SetVideoMode = NULL; // client never calls this method. +# else /* defined _MGSCHEMA_COMPOSITING */ + if (mgIsServer) { + device->SetVideoMode = DRM_SetVideoMode_Accl; + } + else { + device->SetVideoMode = DRM_SetVideoMode_Client; + } +# endif /* not defined _MGSCHEMA_COMPOSITING */ + device->RequestHWSurface = NULL; // always be NULL +#endif /* defined _MGRM_PROCESSES */ + + device->AllocHWSurface = DRM_AllocHWSurface_Accl; + device->FreeHWSurface = DRM_FreeHWSurface_Accl; + device->UpdateRects = DRM_UpdateRects_Accl; + } + else { + /* Use DUMB buffer */ +#ifdef _MGRM_PROCESSES +# ifdef _MGSCHEMA_COMPOSITING + if (mgIsServer) { + device->SetVideoMode = DRM_SetVideoMode_Dumb; + } + else + device->SetVideoMode = NULL; // client never calls this method. +# else /* defined _MGSCHEMA_COMPOSITING */ + if (mgIsServer) { + device->SetVideoMode = DRM_SetVideoMode_Dumb; + } + else { + device->SetVideoMode = DRM_SetVideoMode_Client; + } +# endif /* not defined _MGSCHEMA_COMPOSITING */ + device->RequestHWSurface = NULL; // always be NULL +#endif /* defined _MGRM_PROCESSES */ + device->AllocHWSurface = DRM_AllocDumbSurface; + device->FreeHWSurface = DRM_FreeDumbSurface; + device->UpdateRects = NULL; + } + +#if IS_COMPOSITING_SCHEMA + device->AllocSharedHWSurface = DRM_AllocSharedHWSurface; + device->FreeSharedHWSurface = DRM_FreeSharedHWSurface; + device->AttachSharedHWSurface = DRM_AttachSharedHWSurface; + device->DettachSharedHWSurface = DRM_DettachSharedHWSurface; + device->AllocDumbSurface = DRM_AllocDumbSurface; + device->FreeDumbSurface = DRM_FreeDumbSurface; + device->SetCursor = DRM_SetCursor; + device->MoveCursor = DRM_MoveCursor; +#endif + + /* set accelerated methods in DRM_VideoInit */ + device->CheckHWBlit = NULL; + device->FillHWRect = NULL; + device->SetHWColorKey = NULL; + device->SetHWAlpha = NULL; + device->Suspend = DRM_Suspend; + device->Resume = DRM_Resume; + device->free = DRM_DeleteDevice; + + return device; +} + +VideoBootStrap DRM_bootstrap = { + DRM_DRIVER_NAME, "Linux DRI video driver", + DRM_Available, DRM_CreateDevice +}; + +/* + * drm_find_crtc(vdata, res, conn, info): + * This small helper tries to find a suitable CRTC for the given connector. + */ +static int drm_find_crtc(DrmVideoData* vdata, + drmModeRes *res, drmModeConnector *conn, struct drm_mode_info *info) +{ + drmModeEncoder *enc; + unsigned int i, j; + int32_t crtc; + struct drm_mode_info *iter; + + /* first try the currently conected encoder+crtc */ + if (conn->encoder_id) + enc = drmModeGetEncoder(vdata->dev_fd, conn->encoder_id); + else + enc = NULL; + + if (enc) { + if (enc->crtc_id) { + crtc = enc->crtc_id; + for (iter = vdata->mode_list; iter; iter = iter->next) { + if (iter->crtc == crtc) { + crtc = -1; + break; + } + } + + if (crtc >= 0) { + drmModeFreeEncoder(enc); + info->crtc = crtc; + return 0; + } + } + + drmModeFreeEncoder(enc); + } + + /* If the connector is not currently bound to an encoder or if the + * encoder+crtc is already used by another connector (actually unlikely + * but lets be safe), iterate all other available encoders to find a + * matching CRTC. */ + for (i = 0; i < conn->count_encoders; ++i) { + enc = drmModeGetEncoder(vdata->dev_fd, conn->encoders[i]); + if (!enc) { + _ERR_PRINTF("NEWGAL>DRM: cannot retrieve encoder %u:%u (%d): %m\n", + i, conn->encoders[i], errno); + continue; + } + + /* iterate all global CRTCs */ + for (j = 0; j < res->count_crtcs; ++j) { + /* check whether this CRTC works with the encoder */ + if (!(enc->possible_crtcs & (1 << j))) + continue; + + /* check that no other device already uses this CRTC */ + crtc = res->crtcs[j]; + for (iter = vdata->mode_list; iter; iter = iter->next) { + if (iter->crtc == crtc) { + crtc = -1; + break; + } + } + + /* we have found a CRTC, so save it and return */ + if (crtc >= 0) { + drmModeFreeEncoder(enc); + info->crtc = crtc; + return 0; + } + } + + drmModeFreeEncoder(enc); + } + + _ERR_PRINTF("NEWGAL>DRM: cannot find suitable CRTC for connector %u\n", + conn->connector_id); + return -ENOENT; +} + +/* + * drm_setup_connector: + * Set up a single connector. + */ +static int drm_setup_connector(DrmVideoData* vdata, + drmModeRes *res, drmModeConnector *conn, struct drm_mode_info *info) +{ + int ret; + + /* check if a monitor is connected */ + if (conn->connection != DRM_MODE_CONNECTED) { + _ERR_PRINTF("NEWGAL>DRM: ignoring unused connector %u\n", + conn->connector_id); + return -ENOENT; + } + + /* check if there is at least one valid mode */ + if (conn->count_modes == 0) { + _ERR_PRINTF("NEWGAL>DRM: no valid mode for connector %u\n", + conn->connector_id); + return -EFAULT; + } + + /* copy the mode information into our device structure */ + memcpy(&info->mode, &conn->modes[0], sizeof(info->mode)); + info->width = conn->modes[0].hdisplay; + info->height = conn->modes[0].vdisplay; + _DBG_PRINTF("NEWGAL>DRM: mode for connector %u is %ux%u\n", + conn->connector_id, info->width, info->height); + + /* find a crtc for this connector */ + ret = drm_find_crtc(vdata, res, conn, info); + if (ret) { + _ERR_PRINTF("NEWGAL>DRM: no valid crtc for connector %u\n", + conn->connector_id); + return ret; + } + + return 0; +} + +/* + * drm_prepare: + * Collect the connnectors and mode information. + */ +static int drm_prepare(DrmVideoData* vdata) +{ + drmModeRes *res; + drmModeConnector *conn; + unsigned int i; + struct drm_mode_info *info; + int ret; + + /* retrieve resources */ + res = drmModeGetResources(vdata->dev_fd); + if (!res) { + _ERR_PRINTF("NEWGAL>DRM: cannot retrieve DRM resources (%d): %m\n", + errno); + return -errno; + } + + /* iterate all connectors */ + for (i = 0; i < res->count_connectors; ++i) { + /* get information for each connector */ + conn = drmModeGetConnector(vdata->dev_fd, res->connectors[i]); + if (!conn) { + _ERR_PRINTF("NEWGAL>DRM: cannot retrieve DRM connector %u:%u(%d): %m\n", + i, res->connectors[i], errno); + continue; + } + + /* create a device structure */ + info = malloc(sizeof(*info)); + memset(info, 0, sizeof(*info)); + info->conn = conn->connector_id; + + /* call helper function to prepare this connector */ + ret = drm_setup_connector(vdata, res, conn, info); + if (ret) { + if (ret != -ENOENT) { + errno = -ret; + _ERR_PRINTF("NEWGAL>DRM: cannot setup device for connector" + " %u:%u (%d): %m\n", + i, res->connectors[i], errno); + } + free(info); + drmModeFreeConnector(conn); + continue; + } + + /* free connector vdata and link device into global list */ + drmModeFreeConnector(conn); + info->next = vdata->mode_list; + vdata->mode_list = info; + } + + /* free resources again */ + drmModeFreeResources(res); + return 0; +} + +/* DRM engine methods for both dumb buffer and acclerated buffers */ +static int DRM_VideoInit(_THIS, GAL_PixelFormat *vformat) +{ + int n = 0; + struct drm_mode_info *iter; + + drm_prepare(this->hidden); + + for (iter = this->hidden->mode_list; iter; iter = iter->next) { + _DBG_PRINTF("mode #%d: %ux%u, conn: %u, crtc: %u\n", n, + iter->width, iter->height, iter->conn, iter->crtc); + n++; + } + + if (n == 0) { + return -1; + } + + this->hidden->modes = calloc(n + 1, sizeof(GAL_Rect*)); + if (this->hidden->modes == NULL) { + _ERR_PRINTF("NEWGAL>DRM: failed to allocate memory for modes (%d)\n", + n); + return -1; + } + + n = 0; + for (iter = this->hidden->mode_list; iter; iter = iter->next) { + this->hidden->modes[n] = malloc(sizeof(GAL_Rect)); + this->hidden->modes[n]->x = 0; + this->hidden->modes[n]->y = 0; + this->hidden->modes[n]->w = iter->width; + this->hidden->modes[n]->h = iter->height; + n++; + } + + vformat->BitsPerPixel = 32; + vformat->BytesPerPixel = 4; + + if (this->hidden->driver) { + if (this->hidden->driver_ops->clear_buffer) { + this->info.blit_fill = 1; + this->FillHWRect = DRM_FillHWRect_Accl; + } + else + this->FillHWRect = NULL; + + if (this->hidden->driver_ops->check_blit) { + this->CheckHWBlit = DRM_CheckHWBlit_Accl; + this->SetHWColorKey = DRM_SetHWColorKey_Accl; + this->SetHWAlpha = DRM_SetHWAlpha_Accl; + + this->info.blit_hw = 1; + if (this->hidden->driver_ops->alpha_blit) + this->info.blit_hw_A = 1; + if (this->hidden->driver_ops->key_blit) + this->info.blit_hw_CC = 1; + } + else { + this->CheckHWBlit = NULL; + this->SetHWColorKey = NULL; + this->SetHWAlpha = NULL; + } + } + + /* We're done! */ + return(0); +} + +static GAL_Rect **DRM_ListModes(_THIS, GAL_PixelFormat *format, Uint32 flags) +{ + if (format->BitsPerPixel != 32) { + return NULL; + } + + return this->hidden->modes; +} + +static int DRM_SetColors(_THIS, int firstcolor, int ncolors, GAL_Color *colors) +{ + /* do nothing of note. */ + return(1); +} + +static void DRM_VideoQuit(_THIS) +{ + if (this->screen->pixels != NULL) { + this->screen->pixels = NULL; + } +} + +static int DRM_Resume(_THIS) +{ + DrmVideoData* vdata = this->hidden; + int ret = -1; + + _DBG_PRINTF ("%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 ("%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, width, height, bpp): + * Call this function to create a so called "dumb buffer". + * We can use it for unaccelerated software rendering on the CPU. + */ +static int drm_create_dumb_fb(DrmVideoData* vdata, + uint32_t width, uint32_t height, uint32_t drm_format, int bpp) +{ + struct drm_mode_create_dumb creq; + struct drm_mode_destroy_dumb dreq; + struct drm_mode_map_dumb mreq; + uint32_t handles[4], pitches[4], offsets[4]; + int ret; + + /* create dumb buffer */ + memset(&creq, 0, sizeof(creq)); + creq.width = width; + creq.height = height; + creq.bpp = bpp; + ret = drmIoctl(vdata->dev_fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq); + if (ret < 0) { + _ERR_PRINTF("NEWGAL>DRM: cannot create dumb buffer (%d): %m\n", + errno); + return -errno; + } + + vdata->width = creq.width; + vdata->height = creq.height; + vdata->bpp = creq.bpp; + vdata->pitch = creq.pitch; + vdata->size = creq.size; + vdata->handle = creq.handle; + + /* create framebuffer object for the dumb-buffer */ + handles[0] = vdata->handle; + pitches[0] = vdata->pitch; + offsets[0] = 0; + + ret = drmModeAddFB2(vdata->dev_fd, vdata->width, vdata->height, drm_format, + handles, pitches, offsets, &vdata->scanout_buff_id, 0); + if (ret) { + _ERR_PRINTF("NEWGAL>DRM: cannot create framebuffer (%d): %m\n", + errno); + ret = -errno; + goto err_destroy; + } + + /* prepare buffer for memory mapping */ + memset(&mreq, 0, sizeof(mreq)); + mreq.handle = vdata->handle; + ret = drmIoctl(vdata->dev_fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq); + if (ret) { + _ERR_PRINTF("NEWGAL>DRM: cannot map dumb buffer (%d): %m\n", errno); + ret = -errno; + goto err_fb; + } + + /* perform actual memory mapping */ + vdata->scanout_fb = mmap(0, vdata->size, PROT_READ | PROT_WRITE, MAP_SHARED, + vdata->dev_fd, mreq.offset); + if (vdata->scanout_fb == MAP_FAILED) { + _ERR_PRINTF("NEWGAL>DRM: cannot mmap dumb buffer (%d): %m\n", errno); + ret = -errno; + goto err_fb; + } + + return 0; + +err_fb: + drmModeRmFB(vdata->dev_fd, vdata->scanout_buff_id); + +err_destroy: + memset(&dreq, 0, sizeof(dreq)); + dreq.handle = vdata->handle; + drmIoctl(vdata->dev_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq); + return ret; +} + +static inline uint32_t nr_lines_for_header (uint32_t header_size, + uint32_t width, uint32_t height, int cpp) +{ + uint32_t min_pitch = width * cpp; + uint32_t nr_lines = header_size / min_pitch; + + if (nr_lines == 0) + nr_lines = 1; + + return nr_lines; +} + +static DrmSurfaceBuffer *drm_create_dumb_buffer(DrmVideoData* vdata, + uint32_t drm_format, uint32_t hdr_size, + int width, int height, int *pitch) +{ + struct drm_mode_create_dumb creq; + struct drm_mode_destroy_dumb dreq; + struct drm_mode_map_dumb mreq; + int bpp, cpp, ret; + int nr_header_lines = 0; // the number of lines reserved for header + DrmSurfaceBuffer *surface_buffer = NULL; + + ret = drm_format_to_bpp (drm_format, &bpp, &cpp); + assert (ret == 0); + + /* create dumb buffer */ + memset(&creq, 0, sizeof(creq)); + if (hdr_size) { + creq.width = width; + nr_header_lines = nr_lines_for_header (hdr_size, width, height, cpp); + creq.height += nr_header_lines; + } + else { + creq.width = width; + creq.height = height; + } + creq.bpp = bpp; + ret = drmIoctl(vdata->dev_fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq); + if (ret < 0) { + _WRN_PRINTF("Failed to create dumb buffer (%d): %m\n", errno); + return NULL; + } + + if ((surface_buffer = malloc (sizeof (DrmSurfaceBuffer))) == NULL) { + _WRN_PRINTF("Failed to allocate memory\n"); + goto err_destroy; + } + + surface_buffer->handle = creq.handle; + //surface_buffer->width = creq.width; + //surface_buffer->height = creq.height - nr_header_lines; + //surface_buffer->drm_format = drm_format; + //surface_buffer->bpp = bpp; + //surface_buffer->cpp = cpp; + //surface_buffer->foreign = 0; + //surface_buffer->dumb = 0; + + surface_buffer->offset = creq.pitch * nr_header_lines; + surface_buffer->size = creq.size; + *pitch = creq.pitch; + + /* prepare buffer for memory mapping */ + memset(&mreq, 0, sizeof(mreq)); + mreq.handle = surface_buffer->handle; + ret = drmIoctl(vdata->dev_fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq); + if (ret) { + _WRN_PRINTF("NEWGAL>DRM: cannot map dumb buffer (%d): %m\n", errno); + goto err_fb; + } + + /* perform actual memory mapping */ + surface_buffer->buff = mmap(0, surface_buffer->size, + PROT_READ | PROT_WRITE, MAP_SHARED, + vdata->dev_fd, mreq.offset); + if (surface_buffer->buff == MAP_FAILED) { + _ERR_PRINTF("NEWGAL>DRM: cannot mmap dumb buffer (%d): %m\n", errno); + goto err_fb; + } + + return surface_buffer; + +err_fb: + free (surface_buffer); + +err_destroy: + memset(&dreq, 0, sizeof(dreq)); + dreq.handle = vdata->handle; + drmIoctl(vdata->dev_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq); + return NULL; +} + +static void drm_destroy_dumb_buffer(DrmVideoData* vdata, + DrmSurfaceBuffer *surface_buffer) +{ + struct drm_mode_destroy_dumb dreq; + + if (surface_buffer->buff) + munmap (surface_buffer->buff, surface_buffer->size); + + memset (&dreq, 0, sizeof(dreq)); + dreq.handle = surface_buffer->handle; + drmIoctl(vdata->dev_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq); + free (surface_buffer); +} + +static DrmModeInfo* find_mode(DrmVideoData* vdata, int width, int height) +{ + DrmModeInfo *iter; + + for (iter = vdata->mode_list; iter; iter = iter->next) { + if (iter->width >= width && iter->height >= height) + return iter; + } + + return NULL; +} + /* DRM engine methods for dumb buffers */ static GAL_Surface *DRM_SetVideoMode_Dumb(_THIS, GAL_Surface *current, int width, int height, int bpp, Uint32 flags) @@ -1351,7 +1578,8 @@ static GAL_Surface *DRM_SetVideoMode_Dumb(_THIS, GAL_Surface *current, info->width, info->height, bpp); /* create a dumb framebuffer for current CRTC */ - ret = drm_create_dumb_fb(this->hidden, info, drm_format, bpp); + ret = drm_create_dumb_fb(this->hidden, info->width, info->height, + drm_format, bpp); if (ret) { _ERR_PRINTF("NEWGAL>DRM: cannot create dumb framebuffer\n"); return NULL; @@ -1400,23 +1628,228 @@ static GAL_Surface *DRM_SetVideoMode_Dumb(_THIS, GAL_Surface *current, return(current); } -static int DRM_AllocHWSurface_Dumb(_THIS, GAL_Surface *surface) +static int DRM_AllocDumbSurface (_THIS, GAL_Surface *surface) { - return(-1); + DrmVideoData* vdata = this->hidden; + uint32_t drm_format; + DrmSurfaceBuffer* surface_buffer; + + drm_format = translate_gal_format(surface->format); + if (drm_format == 0) { + _ERR_PRINTF("NEWGAL>DRM: not supported pixel format, " + "RGBA masks (0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", + surface->format->Rmask, surface->format->Gmask, + surface->format->Bmask, surface->format->Amask); + return -1; + } + + surface_buffer = drm_create_dumb_buffer(vdata, drm_format, 0, + surface->w, surface->h, &surface->pitch); + if (surface_buffer == NULL) { + return -1; + } + + surface->pixels = surface_buffer->buff + surface_buffer->offset; + surface->flags |= GAL_HWSURFACE; + surface->hwdata = (struct private_hwdata *)surface_buffer; + return 0; } -static void DRM_FreeHWSurface_Dumb(_THIS, GAL_Surface *surface) +static void DRM_FreeDumbSurface (_THIS, GAL_Surface *surface) { + DrmVideoData* vdata = this->hidden; + DrmSurfaceBuffer* surface_buffer; + + surface_buffer = (DrmSurfaceBuffer*)surface->hwdata; + if (surface_buffer) { + drm_destroy_dumb_buffer (vdata, surface_buffer); + } + surface->pixels = NULL; + surface->hwdata = NULL; } +#if IS_COMPOSITING_SCHEMA +static int DRM_AllocSharedHWSurface(_THIS, GAL_Surface *surface, + size_t* pixels_size, off_t* pixels_off, Uint32 rw_modes) +{ + DrmVideoData* vdata = this->hidden; + uint32_t drm_format; + size_t hdr_size; + DrmSurfaceBuffer* surface_buffer; + int prime_fd; + + drm_format = translate_gal_format(surface->format); + if (drm_format == 0) { + _WRN_PRINTF("not supported pixel format, " + "RGBA masks (0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", + surface->format->Rmask, surface->format->Gmask, + surface->format->Bmask, surface->format->Amask); + return -1; + } + + hdr_size = sizeof (GAL_SharedSurfaceHeader); + if (vdata->driver_ops) { + surface_buffer = vdata->driver_ops->create_buffer(vdata->driver, + drm_format, hdr_size, surface->w, surface->h, &surface->pitch); + } + else { + surface_buffer = drm_create_dumb_buffer(vdata, + drm_format, hdr_size, surface->w, surface->h, &surface->pitch); + } + + if (surface_buffer == NULL) { + _WRN_PRINTF("Failed to create shared hardware surface: size (%d x %d)\n", + surface->w, surface->h); + return -1; + } + + /* get the prime fd */ + if (drmPrimeHandleToFD (vdata->dev_fd, surface_buffer->handle, DRM_CLOEXEC, + &prime_fd)) { + _WRN_PRINTF ("cannot get prime fd: %m\n"); + goto error; + } + + *pixels_size = surface->h * surface->pitch; + *pixels_off = surface_buffer->offset; + + /* go for success */ + /* the caller will set the pixels and flags + surface->pixels = surface_buffer->buff + surface_buffer->offset; + surface->flags |= GAL_HWSURFACE; + */ + surface->hwdata = (struct private_hwdata *)surface_buffer; + + return prime_fd; + +error: + if (surface_buffer) { + if (vdata->driver_ops) + vdata->driver_ops->destroy_buffer(vdata->driver, surface_buffer); + else + drm_destroy_dumb_buffer(vdata, surface_buffer); + } + + return -1; +} + +static int DRM_FreeSharedHWSurface(_THIS, GAL_Surface *surface) +{ + int retval = -1; + DrmVideoData* vdata = this->hidden; + DrmSurfaceBuffer* surface_buffer; + + surface_buffer = (DrmSurfaceBuffer*)surface->hwdata; + if (surface_buffer) { + if (vdata->driver_ops) + vdata->driver_ops->destroy_buffer(vdata->driver, surface_buffer); + else + drm_destroy_dumb_buffer(vdata, surface_buffer); + + retval = 0; + } + + return retval; +} + +static int DRM_AttachSharedHWSurface(_THIS, GAL_Surface *surface, + int prime_fd, size_t mapsize, BOOL with_rw) +{ + int retval = -1; + DrmVideoData* vdata = this->hidden; + DrmSurfaceBuffer* surface_buffer = NULL; + + if (vdata->driver_ops) { + surface_buffer = vdata->driver_ops->create_buffer_from_prime_fd ( + vdata->driver, prime_fd, mapsize); + if (surface_buffer == NULL) { + _WRN_PRINTF ("failed to create buffer from prime fd: %d!\n", + prime_fd); + goto error; + } + + if (vdata->driver_ops->map_buffer (vdata->driver, + surface_buffer) == NULL) { + _WRN_PRINTF ("cannot map hardware buffer: %m\n"); + goto error; + } + + surface->shared_header = (GAL_SharedSurfaceHeader*)surface_buffer->buff; + surface->hwdata = (struct private_hwdata *)surface_buffer; + retval = 0; + } + + /* for shared dumb buffer, the caller uses mmap directly */ + + return retval; + +error: + if (surface_buffer) { + vdata->driver_ops->destroy_buffer (vdata->driver, surface_buffer); + } + + return retval; +} + +static int DRM_DettachSharedHWSurface(_THIS, GAL_Surface *surface) +{ + int retval = -1; + DrmVideoData* vdata = this->hidden; + DrmSurfaceBuffer* surface_buffer; + + surface_buffer = (DrmSurfaceBuffer*)surface->hwdata; + if (surface_buffer) { + assert (vdata->driver_ops); + vdata->driver_ops->unmap_buffer(vdata->driver, surface_buffer); + vdata->driver_ops->destroy_buffer(vdata->driver, surface_buffer); + surface->pixels = NULL; + surface->hwdata = NULL; + + retval = 0; + } + + return retval; +} + +static int DRM_SetCursor(_THIS, GAL_Surface *surface, int hot_x, int hot_y) +{ + int retval = -1; + DrmVideoData* vdata = this->hidden; + DrmSurfaceBuffer* surface_buffer; + + surface_buffer = (DrmSurfaceBuffer*)surface->hwdata; + if (surface_buffer) { + retval = drmModeSetCursor2 (vdata->dev_fd, vdata->saved_crtc->crtc_id, + surface_buffer->handle, surface->w, surface->h, hot_x, hot_y); + if (retval) + _WRN_PRINTF ("failed to call drmModeSetCursor2: %m\n"); + } + + return retval; +} + +static int DRM_MoveCursor(_THIS, int x, int y) +{ + int retval = -1; + DrmVideoData* vdata = this->hidden; + + retval = drmModeMoveCursor (vdata->dev_fd, vdata->saved_crtc->crtc_id, x, y); + if (retval) { + _WRN_PRINTF ("failed to call drmModeMoveCursor: %m\n"); + } + + return retval; +} +#endif /* IS_COMPOSITING_SCHEMA */ + /* 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; - uint32_t drm_format; + uint32_t drm_format, buff_id; Uint32 RGBAmasks[4]; DrmSurfaceBuffer* scanout_buff = NULL; @@ -1428,7 +1861,7 @@ static GAL_Surface *DRM_SetVideoMode_Accl(_THIS, GAL_Surface *current, /* 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", + _ERR_PRINTF("NEWGAL>DRM: cannot find a CRTC for video mode: %dx%d-%d\n", width, height, bpp); return NULL; } @@ -1445,7 +1878,7 @@ static GAL_Surface *DRM_SetVideoMode_Accl(_THIS, GAL_Surface *current, /* create the scanout buffer */ scanout_buff = vdata->driver_ops->create_buffer(vdata->driver, drm_format, - info->width, info->height); + 0, info->width, info->height, &info->pitch); if (scanout_buff == NULL) { _ERR_PRINTF ("NEWGAL>DRM: cannot create scanout buffer: %m\n"); goto error; @@ -1455,20 +1888,17 @@ static GAL_Surface *DRM_SetVideoMode_Accl(_THIS, GAL_Surface *current, { uint32_t handles[4], pitches[4], offsets[4]; handles[0] = scanout_buff->handle; - pitches[0] = scanout_buff->pitch; - offsets[0] = 0; + pitches[0] = info->pitch; + offsets[0] = scanout_buff->offset; if (drmModeAddFB2(vdata->dev_fd, info->width, info->height, drm_format, - handles, pitches, offsets, &scanout_buff->id, 0) != 0) { + handles, pitches, offsets, &buff_id, 0) != 0) { _ERR_PRINTF ("NEWGAL>DRM: cannot set up scanout frame buffer: %m\n"); goto error; } } - /* not a foreign surface */ - scanout_buff->foreign = 0; - if (NULL == vdata->driver_ops->map_buffer(vdata->driver, scanout_buff)) { _ERR_PRINTF ("NEWGAL>DRM: cannot map scanout frame buffer: %m\n"); goto error; @@ -1477,11 +1907,11 @@ static GAL_Surface *DRM_SetVideoMode_Accl(_THIS, GAL_Surface *current, vdata->width = info->width; vdata->height = info->height; vdata->bpp = bpp; - vdata->pitch = scanout_buff->pitch; - vdata->size = scanout_buff->pitch * info->height; + vdata->pitch = info->pitch; + vdata->size = info->pitch * info->height; vdata->handle = 0; - vdata->scanout_buff_id = scanout_buff->id; - vdata->scanout_fb = scanout_buff->pixels; + vdata->scanout_buff_id = buff_id; + vdata->scanout_fb = scanout_buff->buff + scanout_buff->offset; _DBG_PRINTF("scanout frame buffer: size (%dx%d), pitch(%d)\n", vdata->width, vdata->height, vdata->pitch); @@ -1548,6 +1978,23 @@ error: return NULL; } +#if IS_SHAREDFB_SCHEMA_PROCS + +#include "client.h" + +int __drm_get_shared_screen_surface (GHANDLE handle, SHAREDSURFINFO* info) +{ + return 0; +} + +/* DRM engine method for clients under sharedfb schema and MiniGUI-Processes */ +static GAL_Surface *DRM_SetVideoMode_Client(_THIS, GAL_Surface *current, + int width, int height, int bpp, Uint32 flags) +{ + return NULL; +} +#endif /* IS_SHAREDFB_SCHEMA_PROCS */ + static int DRM_AllocHWSurface_Accl(_THIS, GAL_Surface *surface) { DrmVideoData* vdata = this->hidden; @@ -1556,28 +2003,26 @@ static int DRM_AllocHWSurface_Accl(_THIS, GAL_Surface *surface) drm_format = translate_gal_format(surface->format); if (drm_format == 0) { - _ERR_PRINTF("NEWGAL>DRM: not supported pixel format, RGBA masks (0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", - surface->format->Rmask, surface->format->Gmask, - surface->format->Bmask, surface->format->Amask); + _ERR_PRINTF("NEWGAL>DRM: not supported pixel format, " + "RGBA masks (0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", + surface->format->Rmask, surface->format->Gmask, + surface->format->Bmask, surface->format->Amask); return -1; } surface_buffer = vdata->driver_ops->create_buffer(vdata->driver, drm_format, - surface->w, surface->h); + 0, surface->w, surface->h, &surface->pitch); if (surface_buffer == NULL) { return -1; } - /* not a foreign surface */ - surface_buffer->foreign = 0; if (vdata->driver_ops->map_buffer(vdata->driver, surface_buffer) == NULL) { _ERR_PRINTF ("NEWGAL>DRM: cannot map hardware buffer: %m\n"); goto error; } - surface->pixels = surface_buffer->pixels; + surface->pixels = surface_buffer->buff + surface_buffer->offset; surface->flags |= GAL_HWSURFACE; - surface->pitch = surface_buffer->pitch; surface->hwdata = (struct private_hwdata *)surface_buffer; return 0; @@ -1595,7 +2040,7 @@ static void DRM_FreeHWSurface_Accl(_THIS, GAL_Surface *surface) surface_buffer = (DrmSurfaceBuffer*)surface->hwdata; if (surface_buffer) { - if (surface_buffer->pixels) + if (surface_buffer->buff) vdata->driver_ops->unmap_buffer(vdata->driver, surface_buffer); vdata->driver_ops->destroy_buffer(vdata->driver, surface_buffer); } @@ -1732,14 +2177,11 @@ BOOL __drm_get_surface_info (GAL_Surface *surface, DrmSurfaceInfo* info) DrmSurfaceBuffer* surface_buffer = (DrmSurfaceBuffer*)surface->hwdata; if (surface_buffer) { - info->prime_fd = surface_buffer->prime_fd; - info->name = surface_buffer->name; info->handle = surface_buffer->handle; - info->id = surface_buffer->id; - info->width = surface_buffer->width; - info->height = surface_buffer->height; - info->pitch = surface_buffer->pitch; - info->drm_format = surface_buffer->drm_format; + info->width = surface->w; + info->height = surface->h; + info->pitch = surface->pitch; + //info->drm_format = surface_buffer->drm_format; info->size = surface_buffer->size; return TRUE; } @@ -1748,48 +2190,18 @@ BOOL __drm_get_surface_info (GAL_Surface *surface, DrmSurfaceInfo* info) return FALSE; } -/* called by drmCreateDCFromName */ -GAL_Surface* __drm_create_surface_from_name (GHANDLE video, - uint32_t name, uint32_t drm_format, - unsigned int width, unsigned int height, uint32_t pitch) +static GAL_Surface* create_surface_from_buffer (_THIS, + DrmSurfaceBuffer* surface_buffer, int depth, Uint32 *RGBAmasks, + uint32_t width, uint32_t height, uint32_t pitch) { - GAL_VideoDevice *this = (GAL_VideoDevice *)video; DrmVideoData* vdata = this->hidden; - DrmSurfaceBuffer* surface_buffer; GAL_Surface* surface = NULL; - Uint32 RGBAmasks[4]; - int depth; + size_t pixels_size = height * pitch; - if (this && this->VideoInit != DRM_VideoInit) { - return NULL; + if (surface_buffer->size < surface_buffer->offset + pixels_size) { + _WRN_PRINTF ("NEWGAL>DRM: the buffer size is not large enought!\n"); } - if (vdata->driver_ops == NULL) { - _ERR_PRINTF ("NEWGAL>DRM: not hardware accelerated!\n"); - return NULL; - } - - if (vdata->driver_ops->create_buffer_from_name == NULL) { - _ERR_PRINTF ("NEWGAL>DRM: not implemented method: create_buffer_from_name!\n"); - return NULL; - } - - depth = translate_drm_format(drm_format, RGBAmasks); - if (depth == 0) { - _ERR_PRINTF("NEWGAL>DRM: not supported drm format: %u\n", - drm_format); - return NULL; - } - - surface_buffer = vdata->driver_ops->create_buffer_from_name(vdata->driver, - name, drm_format, width, height, pitch); - if (surface_buffer == NULL) { - _ERR_PRINTF ("NEWGAL>DRM: create_buffer_from_name failed!\n"); - return NULL; - } - /* not a foreign surface */ - surface_buffer->foreign = 0; - if (vdata->driver_ops->map_buffer(vdata->driver, surface_buffer) == NULL) { _ERR_PRINTF ("NEWGAL>DRM: cannot map hardware buffer: %m\n"); goto error; @@ -1801,105 +2213,6 @@ GAL_Surface* __drm_create_surface_from_name (GHANDLE video, goto error; } - /* Allocate the format */ - surface->format = GAL_AllocFormat(depth, RGBAmasks[0], RGBAmasks[1], - RGBAmasks[2], RGBAmasks[3]); - if (surface->format == NULL) { - goto error; - } - - /* Allocate an empty mapping */ - surface->map = GAL_AllocBlitMap(); - if (surface->map == NULL) { - goto error; - } - - surface->format_version = 0; - surface->video = this; - surface->flags = GAL_HWSURFACE; - surface->dpi = GDCAP_DPI_DEFAULT; - surface->w = width; - surface->h = height; - surface->pitch = pitch; - surface->offset = 0; - surface->pixels = surface_buffer->pixels; - surface->hwdata = (struct private_hwdata *)surface_buffer; - - /* The surface is ready to go */ - surface->refcount = 1; - - GAL_SetClipRect(surface, NULL); - -#ifdef _MGUSE_UPDATE_REGION - /* Initialize update region */ - InitClipRgn (&surface->update_region, &__mg_free_update_region_list); -#endif - - return(surface); - -error: - if (surface) - GAL_FreeSurface(surface); - - if (surface_buffer) - vdata->driver_ops->destroy_buffer(vdata->driver, surface_buffer); - - return NULL; -} - -/* called by drmCreateDCFromHandle */ -GAL_Surface* __drm_create_surface_from_handle (GHANDLE video, - uint32_t handle, unsigned long size, uint32_t drm_format, - unsigned int width, unsigned int height, uint32_t pitch) -{ - GAL_VideoDevice *this = (GAL_VideoDevice *)video; - DrmVideoData* vdata = this->hidden; - DrmSurfaceBuffer* surface_buffer; - GAL_Surface* surface = NULL; - Uint32 RGBAmasks[4]; - int depth; - - if (this && this->VideoInit != DRM_VideoInit) { - return NULL; - } - - if (vdata->driver_ops == NULL) { - _ERR_PRINTF ("NEWGAL>DRM: not hardware accelerated!\n"); - return NULL; - } - - if (vdata->driver_ops->create_buffer_from_handle == NULL) { - _ERR_PRINTF ("NEWGAL>DRM: not implemented method: create_buffer_from_handle!\n"); - return NULL; - } - - depth = translate_drm_format (drm_format, RGBAmasks); - if (depth == 0) { - _ERR_PRINTF ("NEWGAL>DRM: not supported drm format: %u\n", - drm_format); - return NULL; - } - - surface_buffer = vdata->driver_ops->create_buffer_from_handle (vdata->driver, - handle, size, drm_format, width, height, pitch); - if (surface_buffer == NULL) { - _ERR_PRINTF ("NEWGAL>DRM: create_buffer_from_handle failed!\n"); - return NULL; - } - /* this is a foreign surface */ - surface_buffer->foreign = 1; - - if (vdata->driver_ops->map_buffer (vdata->driver, surface_buffer) == NULL) { - _ERR_PRINTF ("NEWGAL>DRM: cannot map hardware buffer: %m\n"); - goto error; - } - - /* Allocate the surface */ - surface = (GAL_Surface *)malloc (sizeof(*surface)); - if (surface == NULL) { - goto error; - } - /* Allocate the format */ surface->format = GAL_AllocFormat (depth, RGBAmasks[0], RGBAmasks[1], RGBAmasks[2], RGBAmasks[3]); @@ -1921,7 +2234,7 @@ GAL_Surface* __drm_create_surface_from_handle (GHANDLE video, surface->h = height; surface->pitch = pitch; surface->offset = 0; - surface->pixels = surface_buffer->pixels; + surface->pixels = surface_buffer->buff + surface_buffer->offset; surface->hwdata = (struct private_hwdata *)surface_buffer; /* The surface is ready to go */ @@ -1946,15 +2259,14 @@ error: return NULL; } -/* called by drmCreateDCFromPrimeFd */ -GAL_Surface* __drm_create_surface_from_prime_fd (GHANDLE video, - int prime_fd, unsigned long size, uint32_t drm_format, +/* called by drmCreateDCFromName */ +GAL_Surface* __drm_create_surface_from_name (GHANDLE video, + uint32_t name, uint32_t drm_format, uint32_t pixels_off, unsigned int width, unsigned int height, uint32_t pitch) { GAL_VideoDevice *this = (GAL_VideoDevice *)video; DrmVideoData* vdata = this->hidden; DrmSurfaceBuffer* surface_buffer; - GAL_Surface* surface = NULL; Uint32 RGBAmasks[4]; int depth; @@ -1962,13 +2274,87 @@ GAL_Surface* __drm_create_surface_from_prime_fd (GHANDLE video, return NULL; } - if (vdata->driver_ops == NULL) { - _ERR_PRINTF ("NEWGAL>DRM: not hardware accelerated!\n"); + if (vdata->driver_ops == NULL || + vdata->driver_ops->create_buffer_from_name == NULL) { + _WRN_PRINTF ("not hardware accelerated or not implemented method!\n"); return NULL; } - if (vdata->driver_ops->create_buffer_from_prime_fd == NULL) { - _ERR_PRINTF ("NEWGAL>DRM: not implemented method: create_buffer_from_prime_fd.\n"); + depth = translate_drm_format(drm_format, RGBAmasks); + if (depth == 0) { + _WRN_PRINTF("not supported DRM format: %u\n", drm_format); + return NULL; + } + + surface_buffer = vdata->driver_ops->create_buffer_from_name(vdata->driver, + name); + if (surface_buffer == NULL) { + _ERR_PRINTF ("NEWGAL>DRM: create_buffer_from_name failed: %u!\n", name); + return NULL; + } + surface_buffer->offset = pixels_off; + + return create_surface_from_buffer (this, surface_buffer, depth, + RGBAmasks, width, height, pitch); +} + +/* called by drmCreateDCFromHandle */ +GAL_Surface* __drm_create_surface_from_handle (GHANDLE video, uint32_t handle, + unsigned long size, uint32_t drm_format, uint32_t pixels_off, + unsigned int width, unsigned int height, uint32_t pitch) +{ + GAL_VideoDevice *this = (GAL_VideoDevice *)video; + DrmVideoData* vdata = this->hidden; + DrmSurfaceBuffer* surface_buffer; + Uint32 RGBAmasks[4]; + int depth; + + if (this && this->VideoInit != DRM_VideoInit) { + return NULL; + } + + if (vdata->driver_ops == NULL || + vdata->driver_ops->create_buffer_from_handle == NULL) { + _WRN_PRINTF ("not implemented method!\n"); + return NULL; + } + + depth = translate_drm_format (drm_format, RGBAmasks); + if (depth == 0) { + _ERR_PRINTF ("NEWGAL>DRM: not supported drm format: %u\n", drm_format); + return NULL; + } + + surface_buffer = vdata->driver_ops->create_buffer_from_handle (vdata->driver, + handle, size); + if (surface_buffer == NULL) { + _ERR_PRINTF ("NEWGAL>DRM: create_buffer_from_handle failed!\n"); + return NULL; + } + surface_buffer->offset = pixels_off; + + return create_surface_from_buffer (this, surface_buffer, depth, + RGBAmasks, width, height, pitch); +} + +/* called by drmCreateDCFromPrimeFd */ +GAL_Surface* __drm_create_surface_from_prime_fd (GHANDLE video, + int prime_fd, size_t size, uint32_t drm_format, uint32_t pixels_off, + uint32_t width, uint32_t height, uint32_t pitch) +{ + GAL_VideoDevice *this = (GAL_VideoDevice *)video; + DrmVideoData* vdata = this->hidden; + DrmSurfaceBuffer* surface_buffer; + Uint32 RGBAmasks[4]; + int depth; + + if (this && this->VideoInit != DRM_VideoInit) { + return NULL; + } + + if (vdata->driver_ops == NULL || + vdata->driver_ops->create_buffer_from_prime_fd) { + _ERR_PRINTF ("NEWGAL>DRM: not implemented method!\n"); return NULL; } @@ -1979,70 +2365,16 @@ GAL_Surface* __drm_create_surface_from_prime_fd (GHANDLE video, return NULL; } - surface_buffer = vdata->driver_ops->create_buffer_from_prime_fd (vdata->driver, - prime_fd, size, drm_format, width, height, pitch); + surface_buffer = vdata->driver_ops->create_buffer_from_prime_fd ( + vdata->driver, prime_fd, size); if (surface_buffer == NULL) { _ERR_PRINTF ("NEWGAL>DRM: create_buffer_from_prime_fd failed!\n"); return NULL; } - /* not a foreign surface */ - surface_buffer->foreign = 1; + surface_buffer->offset = pixels_off; - if (vdata->driver_ops->map_buffer (vdata->driver, surface_buffer) == NULL) { - _ERR_PRINTF ("NEWGAL>DRM: cannot map hardware buffer: %m\n"); - goto error; - } - - /* Allocate the surface */ - surface = (GAL_Surface *)malloc (sizeof(*surface)); - if (surface == NULL) { - goto error; - } - - /* Allocate the format */ - surface->format = GAL_AllocFormat(depth, RGBAmasks[0], RGBAmasks[1], - RGBAmasks[2], RGBAmasks[3]); - if (surface->format == NULL) { - goto error; - } - - /* Allocate an empty mapping */ - surface->map = GAL_AllocBlitMap(); - if (surface->map == NULL) { - goto error; - } - - surface->format_version = 0; - surface->video = this; - surface->flags = GAL_HWSURFACE; - surface->dpi = GDCAP_DPI_DEFAULT; - surface->w = width; - surface->h = height; - surface->pitch = pitch; - surface->offset = 0; - surface->pixels = surface_buffer->pixels; - surface->hwdata = (struct private_hwdata *)surface_buffer; - - /* The surface is ready to go */ - surface->refcount = 1; - - GAL_SetClipRect(surface, NULL); - -#ifdef _MGUSE_UPDATE_REGION - /* Initialize update region */ - InitClipRgn (&surface->update_region, &__mg_free_update_region_list); -#endif - - return(surface); - -error: - if (surface) - GAL_FreeSurface(surface); - - if (surface_buffer) - vdata->driver_ops->destroy_buffer(vdata->driver, surface_buffer); - - return NULL; + return create_surface_from_buffer (this, surface_buffer, depth, + RGBAmasks, width, height, pitch); } #endif /* _MGGAL_DRM */