Dumb buffer is almost ok

This commit is contained in:
Vincent Wei
2019-06-11 15:33:30 +08:00
parent 046353b9cb
commit bbbff5bd8c
2 changed files with 186 additions and 159 deletions
+172 -157
View File
@@ -91,6 +91,7 @@ static int DRM_Available(void)
* The following helpers derived from DRM HOWTO by David Herrmann.
*
* drm_prepare
* drm_find_crtc
* drm_setup_dev
* drm_create_dumb_fb
* drm_cleanup
@@ -114,18 +115,12 @@ static int DRM_Available(void)
struct drm_mode_info {
struct drm_mode_info *next;
uint32_t width;
uint32_t height;
uint32_t stride;
uint32_t size;
uint32_t handle;
uint8_t *map;
uint32_t width;
uint32_t height;
uint32_t conn;
uint32_t crtc;
drmModeModeInfo mode;
uint32_t fb;
uint32_t conn;
uint32_t crtc;
drmModeCrtc *saved_crtc;
};
/*
@@ -143,31 +138,31 @@ static void drm_cleanup(DrmVideoData* vdata)
iter = vdata->mode_list;
vdata->mode_list = iter->next;
/* restore saved CRTC configuration */
drmModeSetCrtc(vdata->dev_fd,
iter->saved_crtc->crtc_id,
iter->saved_crtc->buffer_id,
iter->saved_crtc->x,
iter->saved_crtc->y,
&iter->conn,
1,
&iter->saved_crtc->mode);
drmModeFreeCrtc(iter->saved_crtc);
/* unmap buffer */
munmap(iter->map, iter->size);
/* delete framebuffer */
drmModeRmFB(vdata->dev_fd, iter->fb);
/* delete dumb buffer */
memset(&dreq, 0, sizeof(dreq));
dreq.handle = iter->handle;
drmIoctl(vdata->dev_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
/* free allocated memory */
free(iter);
}
/* restore saved CRTC configuration */
drmModeSetCrtc(vdata->dev_fd,
vdata->saved_crtc->crtc_id,
vdata->saved_crtc->buffer_id,
vdata->saved_crtc->x,
vdata->saved_crtc->y,
&vdata->conn,
1,
&vdata->saved_crtc->mode);
drmModeFreeCrtc(vdata->saved_crtc);
/* unmap buffer */
munmap(vdata->fb, vdata->size);
/* delete framebuffer */
drmModeRmFB(vdata->dev_fd, vdata->buff);
/* delete dumb buffer */
memset(&dreq, 0, sizeof(dreq));
dreq.handle = vdata->handle;
drmIoctl(vdata->dev_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
}
static void DRM_DeleteDevice(GAL_VideoDevice *device)
@@ -353,11 +348,11 @@ VideoBootStrap DRM_bootstrap = {
};
/*
* modeset_find_crtc(vdata, res, conn, dev):
* modeset_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 *dev)
drmModeRes *res, drmModeConnector *conn, struct drm_mode_info *info)
{
drmModeEncoder *enc;
unsigned int i, j;
@@ -382,7 +377,7 @@ static int drm_find_crtc(DrmVideoData* vdata,
if (crtc >= 0) {
drmModeFreeEncoder(enc);
dev->crtc = crtc;
info->crtc = crtc;
return 0;
}
}
@@ -420,7 +415,7 @@ static int drm_find_crtc(DrmVideoData* vdata,
/* we have found a CRTC, so save it and return */
if (crtc >= 0) {
drmModeFreeEncoder(enc);
dev->crtc = crtc;
info->crtc = crtc;
return 0;
}
}
@@ -433,84 +428,12 @@ static int drm_find_crtc(DrmVideoData* vdata,
return -ENOENT;
}
/*
* drm_create_dumb_fb(vdata, dev):
* 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, struct drm_mode_info *dev)
{
struct drm_mode_create_dumb creq;
struct drm_mode_destroy_dumb dreq;
struct drm_mode_map_dumb mreq;
int ret;
/* create dumb buffer */
memset(&creq, 0, sizeof(creq));
creq.width = dev->width;
creq.height = dev->height;
creq.bpp = 32;
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;
}
dev->stride = creq.pitch;
dev->size = creq.size;
dev->handle = creq.handle;
/* create framebuffer object for the dumb-buffer */
ret = drmModeAddFB(vdata->dev_fd, dev->width, dev->height, 24, 32, dev->stride,
dev->handle, &dev->fb);
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 = dev->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 */
dev->map = mmap(0, dev->size, PROT_READ | PROT_WRITE, MAP_SHARED,
vdata->dev_fd, mreq.offset);
if (dev->map == MAP_FAILED) {
_ERR_PRINTF("NEWGAL>DRM: cannot mmap dumb buffer (%d): %m\n",
errno);
ret = -errno;
goto err_fb;
}
/* clear the framebuffer to 0 */
memset(dev->map, 0, dev->size);
return 0;
err_fb:
drmModeRmFB(vdata->dev_fd, dev->fb);
err_destroy:
memset(&dreq, 0, sizeof(dreq));
dreq.handle = dev->handle;
drmIoctl(vdata->dev_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
return ret;
}
/*
* drm_setup_dev:
* Set up a single connector.
*/
static int drm_setup_dev(DrmVideoData* vdata,
drmModeRes *res, drmModeConnector *conn, struct drm_mode_info *dev)
drmModeRes *res, drmModeConnector *conn, struct drm_mode_info *info)
{
int ret;
@@ -529,28 +452,20 @@ static int drm_setup_dev(DrmVideoData* vdata,
}
/* copy the mode information into our device structure */
memcpy(&dev->mode, &conn->modes[0], sizeof(dev->mode));
dev->width = conn->modes[0].hdisplay;
dev->height = conn->modes[0].vdisplay;
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, dev->width, dev->height);
conn->connector_id, info->width, info->height);
/* find a crtc for this connector */
ret = drm_find_crtc(vdata, res, conn, dev);
ret = drm_find_crtc(vdata, res, conn, info);
if (ret) {
_DBG_PRINTF("NEWGAL>DRM: no valid crtc for connector %u\n",
conn->connector_id);
return ret;
}
/* create a framebuffer for this CRTC */
ret = drm_create_dumb_fb(vdata, dev);
if (ret) {
_DBG_PRINTF("NEWGAL>DRM: cannot create framebuffer for connector %u\n",
conn->connector_id);
return ret;
}
return 0;
}
@@ -559,7 +474,7 @@ static int drm_prepare(DrmVideoData* vdata)
drmModeRes *res;
drmModeConnector *conn;
unsigned int i;
struct drm_mode_info *dev;
struct drm_mode_info *info;
int ret;
/* retrieve resources */
@@ -581,12 +496,12 @@ static int drm_prepare(DrmVideoData* vdata)
}
/* create a device structure */
dev = malloc(sizeof(*dev));
memset(dev, 0, sizeof(*dev));
dev->conn = conn->connector_id;
info = malloc(sizeof(*info));
memset(info, 0, sizeof(*info));
info->conn = conn->connector_id;
/* call helper function to prepare this connector */
ret = drm_setup_dev(vdata, res, conn, dev);
ret = drm_setup_dev(vdata, res, conn, info);
if (ret) {
if (ret != -ENOENT) {
errno = -ret;
@@ -594,15 +509,15 @@ static int drm_prepare(DrmVideoData* vdata)
" %u:%u (%d): %m\n",
i, res->connectors[i], errno);
}
free(dev);
free(info);
drmModeFreeConnector(conn);
continue;
}
/* free connector vdata and link device into global list */
drmModeFreeConnector(conn);
dev->next = vdata->mode_list;
vdata->mode_list = dev;
info->next = vdata->mode_list;
vdata->mode_list = info;
}
/* free resources again */
@@ -620,9 +535,8 @@ static int DRM_VideoInit(_THIS, GAL_PixelFormat *vformat)
struct drm_mode_info *iter;
int i = 0;
for (iter = this->hidden->mode_list; iter; iter = iter->next) {
_MG_PRINTF("mode #%d: %ux%u(%u), fb: %u, conn: %u, crtc: %u\n", i,
iter->width, iter->height, iter->stride,
iter->fb, iter->conn, iter->crtc);
_MG_PRINTF("mode #%d: %ux%u, conn: %u, crtc: %u\n", i,
iter->width, iter->height, iter->conn, iter->crtc);
i++;
}
@@ -656,43 +570,144 @@ static void DRM_VideoQuit(_THIS)
}
}
/*
* 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,
int depth, int bpp)
{
struct drm_mode_create_dumb creq;
struct drm_mode_destroy_dumb dreq;
struct drm_mode_map_dumb mreq;
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 */
ret = drmModeAddFB(vdata->dev_fd, vdata->width, vdata->height, depth, bpp,
vdata->pitch, vdata->handle, &vdata->buff);
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->fb = mmap(0, vdata->size, PROT_READ | PROT_WRITE, MAP_SHARED,
vdata->dev_fd, mreq.offset);
if (vdata->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->buff);
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)
{
return vdata->mode_list;
}
/* DRM engine methods for dumb buffers */
static GAL_Surface *DRM_SetVideoMode_Dumb(_THIS, GAL_Surface *current,
int width, int height, int bpp, Uint32 flags)
{
int pitch;
DrmVideoData* vdata = this->hidden;
DrmModeInfo* info;
int depth;
int ret;
if (this->hidden->buffer) {
free (this->hidden->buffer);
}
pitch = width * ((bpp + 7) / 8);
pitch = (pitch + 3) & ~3;
this->hidden->buffer = malloc (pitch * height);
if (!this->hidden->buffer) {
_ERR_PRINTF ("NEWGAL>DRM: "
"Couldn't allocate buffer for requested mode\n");
if (bpp < 16) {
_ERR_PRINTF("NEWGAL>DRM: bpp (%d) are too small for DRM\n", bpp);
return NULL;
}
memset (this->hidden->buffer, 0, pitch * height);
bpp = ((bpp + 7) / 8) * 8;
if (bpp > 24)
depth = 24;
else
depth = bpp;
/* Allocate the new pixel format for the screen */
if (!GAL_ReallocFormat (current, bpp, 0, 0, 0, 0)) {
free(this->hidden->buffer);
this->hidden->buffer = NULL;
_ERR_PRINTF ("NEWGAL>DRM: "
"Couldn't allocate new pixel format for requested mode\n");
return(NULL);
/* 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",
width, height, bpp);
/* create a dumb framebuffer for current CRTC */
ret = drm_create_dumb_fb(this->hidden, info, depth, bpp);
if (ret) {
_ERR_PRINTF("NEWGAL>DRM: cannot create dumb framebuffer\n");
return NULL;
}
/* 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,
&info->conn, 1, &info->mode);
if (ret) {
_ERR_PRINTF ("NEWGAL>DRM: cannot set CRTC for connector %u (%d): %m\n",
info->conn, errno);
return NULL;
}
/* Set up the new mode framebuffer */
/* Allocate the new pixel format for the screen */
if (!GAL_ReallocFormat (current, bpp, 0, 0, 0, 0)) {
_ERR_PRINTF ("NEWGAL>DRM: allocate new pixel format for requested mode\n");
return NULL;
}
current->flags = flags & GAL_FULLSCREEN;
this->hidden->w = current->w = width;
this->hidden->h = current->h = height;
current->pitch = pitch;
current->pixels = this->hidden->buffer;
current->w = this->hidden->width;
current->h = this->hidden->height;
current->pitch = this->hidden->pitch;
current->pixels = this->hidden->fb;
/* We're done */
return(current);
+14 -2
View File
@@ -34,6 +34,8 @@
#ifndef _NEWGAL_DRMVIDEO_H
#define _NEWGAL_DRMVIDEO_H
#include <stdint.h>
#include "sysvideo.h"
/* Hidden "this" pointer for the video functions */
@@ -54,8 +56,18 @@ typedef struct GAL_PrivateVideoData {
DrmModeInfo* mode_list;
int w, h;
void *buffer;
int bpp;
uint32_t width;
uint32_t height;
uint32_t pitch;
uint32_t size;
uint32_t conn;
uint32_t buff;
uint32_t handle;
drmModeCrtc* saved_crtc;
uint8_t* fb;
} DrmVideoData;
#endif /* _NEWGAL_DRMVIDEO_H */