use async. update for shadow engine

This commit is contained in:
Vincent Wei
2023-07-13 18:37:56 +08:00
parent e98aeab8dc
commit fef311f0b2
4 changed files with 306 additions and 55 deletions
+75 -48
View File
@@ -1157,7 +1157,6 @@ static int open_drm_device(GAL_VideoDevice *device)
device->hidden->driver_ops = load_external_driver (device->hidden,
driver_name, fd);
free (driver_name);
/* get capabilities */
{
@@ -1206,10 +1205,12 @@ static int open_drm_device(GAL_VideoDevice *device)
device->hidden->dev_fd = fd;
if (device->hidden->driver_ops) {
device->hidden->driver = device->hidden->driver_ops->create_driver(fd);
if (device->hidden->driver == NULL)
_WRN_PRINTF("Failed to create DRM driver: %s\n", driver_name);
}
free(driver_name);
if (device->hidden->driver == NULL) {
_WRN_PRINTF("failed to create DRM driver\n");
device->hidden->driver_ops = NULL;
/* check whether supports dumb buffer */
@@ -1272,6 +1273,15 @@ static GAL_VideoDevice *DRM_CreateDevice(int devindex)
if (mgIsServer)
#endif /* defined _MGRM_PROCESSES */
{
if (GetMgEtcIntValue("drm", "update_interval",
&device->hidden->update_interval) < 0) {
device->hidden->update_interval = 20;
}
else if (device->hidden->update_interval < 0 ||
device->hidden->update_interval > 50) {
device->hidden->update_interval = 20;
}
char tmp [8];
if (GetMgEtcValue ("drm", "double_buffering", tmp, 8) < 0) {
device->hidden->dbl_buff = 0;
@@ -1491,19 +1501,6 @@ static int drm_find_crtc(DrmVideoData* vdata,
return -ENOENT;
}
static int get_crtc_index(drmModeRes *res, uint32_t id)
{
int i;
for (i = 0; i < res->count_crtcs; ++i) {
if (res->crtcs[i] == id)
return i;
}
return -1;
}
/*
* drm_setup_connector:
* Set up a single connector.
@@ -1542,9 +1539,6 @@ static int drm_setup_connector(DrmVideoData* vdata,
return ret;
}
vdata->crtc_idx = get_crtc_index(res, info->crtc);
_DBG_PRINTF("CRTC found: id: %u; idx: %d\n",
info->crtc, vdata->crtc_idx);
return 0;
}
@@ -1810,6 +1804,40 @@ static void DRM_CopyVideoInfoToSharedRes(_THIS)
}
#endif /* _MGRM_PROCESSES */
static int get_crtc_index(DrmVideoData* vdata)
{
#if 1
int pipe = -1;
drmModeRes *res;
res = drmModeGetResources(vdata->dev_fd);
if (!res)
goto done;
for (int i = 0; i < res->count_crtcs; i++) {
if (vdata->saved_info->crtc == res->crtcs[i]) {
pipe = i;
break;
}
}
drmModeFreeResources(res);
done:
vdata->crtc_idx = pipe;
return pipe;
#else
int i;
for (i = 0; i < res->count_crtcs; ++i) {
if (res->crtcs[i] == id)
return i;
}
return -1;
#endif
}
static int drm_setup_scanout_buffer (DrmVideoData* vdata,
uint32_t handle, uint32_t drm_format,
uint32_t width, uint32_t height, uint32_t pitch, uint32_t offset)
@@ -1847,6 +1875,14 @@ static int drm_setup_scanout_buffer (DrmVideoData* vdata,
drmModeFreeCrtc(vdata->saved_crtc);
vdata->saved_crtc = NULL;
}
else {
if (get_crtc_index(vdata) < 0) {
_WRN_PRINTF("Invalid return value of get_crtc_index()\n");
}
else {
_DBG_PRINTF("CRTC index: %d\n", vdata->crtc_idx);
}
}
return ret;
}
@@ -1931,22 +1967,6 @@ static int drm_setup_cursor_plane (DrmVideoData* vdata, uint32_t drm_format,
}
}
#if 0
int pipe = -1;
drmModeRes *res;
res = drmModeGetResources(vdata->dev_fd);
if (!res) return ret;
for (i = 0; i < res->count_crtcs; i++) {
if (vdata->saved_info->crtc == res->crtcs[i]) {
pipe = i;
break;
}
}
drmModeFreeResources(res);
assert (pipe >= 0);
#endif
plane_res = drmModeGetPlaneResources (vdata->dev_fd);
if (!plane_res) {
_WRN_PRINTF( "drmModeGetPlaneResources failed: %m\n");
@@ -2540,19 +2560,21 @@ static void* task_do_update(void *data)
}
}
#else
memset(&vbl, 0, sizeof(vbl));
vbl.request.type = DRM_VBLANK_RELATIVE;
if (this->hidden->cap_vblank_high_crtc)
vbl.request.type |=
(this->hidden->crtc_idx << DRM_VBLANK_HIGH_CRTC_SHIFT);
vbl.request.sequence = 1;
vbl.request.signal = 0;
_DBG_PRINTF("VBL type: 0x%08x\n", vbl.request.type);
if (drmWaitVBlank(this->hidden->dev_fd, &vbl)) {
_WRN_PRINTF("Failed drmWaitVBlank(%d): %m\n", this->hidden->crtc_idx);
}
else {
vbl_ok = TRUE;
if (this->hidden->crtc_idx >= 0) {
memset(&vbl, 0, sizeof(vbl));
vbl.request.type = DRM_VBLANK_RELATIVE;
if (this->hidden->cap_vblank_high_crtc)
vbl.request.type |=
(this->hidden->crtc_idx << DRM_VBLANK_HIGH_CRTC_SHIFT);
vbl.request.sequence = 1;
vbl.request.signal = 0;
_DBG_PRINTF("VBL type: 0x%08x\n", vbl.request.type);
if (drmWaitVBlank(this->hidden->dev_fd, &vbl)) {
_WRN_PRINTF("Failed drmWaitVBlank(%d): %m\n", this->hidden->crtc_idx);
}
else {
vbl_ok = TRUE;
}
}
#endif
@@ -2573,12 +2595,13 @@ static void* task_do_update(void *data)
vbl.reply.tval_sec, vbl.reply.tval_usec);
}
else {
usleep(20 * 1000); // 20ms
usleep(this->hidden->update_interval * 1000);
}
sem_wait(this->hidden->update_lock);
if (RECTH(this->hidden->update_rect)) {
update_real_screen_memcpy(this);
/* TODO: update cursor under compositing schema */
drmModeClip clip = {
this->hidden->update_rect.left,
this->hidden->update_rect.top,
@@ -3754,6 +3777,10 @@ static BOOL DRM_SyncUpdate(_THIS)
this->hidden->driver_ops->flush_driver(this->hidden->driver);
}
_DBG_PRINTF("called: %d, %d, %d, %d\n",
bound.left, bound.top,
bound.right, bound.bottom);
{
drmModeClip clip = { bound.left, bound.top,
bound.right, bound.bottom };
+1
View File
@@ -104,6 +104,7 @@ typedef struct GAL_PrivateVideoData {
uint32_t cap_vblank_high_crtc:1;
uint32_t dbl_buff:1;
uint32_t scanout_buff_id;
int update_interval;
int crtc_idx;
void* exdrv_handle;
+223
View File
@@ -54,6 +54,10 @@
#include <stdlib.h>
#include <string.h>
#include <error.h>
#include <time.h>
#include <unistd.h>
#define _DEBUG
#include "common.h"
@@ -143,8 +147,28 @@ static void refresh_by_using_pixman(ShadowFBHeader *shadowfb_header,
pixman_image_set_transform(realfb_info->src_img, NULL);
pixman_image_set_clip_region32(realfb_info->dst_img, NULL);
}
#else
#ifdef _DEBUG
static double get_elapsed_seconds(const struct timespec *ts_from,
const struct timespec *ts_to)
{
struct timespec ts_curr;
time_t ds;
long dns;
if (ts_to == NULL) {
clock_gettime(CLOCK_REALTIME, &ts_curr);
ts_to = &ts_curr;
}
ds = ts_to->tv_sec - ts_from->tv_sec;
dns = ts_to->tv_nsec - ts_from->tv_nsec;
return ds + dns * 1.0E-9;
}
#endif
static void refresh_ccw_32bpp(ShadowFBHeader* shadowfb_header,
RealFBInfo* realfb_info, void* update)
{
@@ -155,6 +179,11 @@ static void refresh_ccw_32bpp(ShadowFBHeader* shadowfb_header,
int dst_width, dst_height;
int x, y;
#ifdef _DEBUG
struct timespec ts_start;
clock_gettime(CLOCK_REALTIME, &ts_start);
#endif
_get_dst_rect_ccw(&dst_update, &src_update, realfb_info);
dst_width = RECTW(dst_update);
dst_height = RECTH(dst_update);
@@ -183,6 +212,11 @@ static void refresh_ccw_32bpp(ShadowFBHeader* shadowfb_header,
src_bits += 4;
dst_line -= realfb_info->pitch;
}
#ifdef _DEBUG
double elapsed = get_elapsed_seconds(&ts_start, NULL);
_MG_PRINTF("Cosumed time to rotate dirty rect (ccw): %f (seconds)\n", elapsed);
#endif
}
static void refresh_cw_32bpp(ShadowFBHeader* shadowfb_header,
@@ -195,6 +229,11 @@ static void refresh_cw_32bpp(ShadowFBHeader* shadowfb_header,
int dst_width, dst_height;
int x, y;
#ifdef _DEBUG
struct timespec ts_start;
clock_gettime(CLOCK_REALTIME, &ts_start);
#endif
_get_dst_rect_cw(&dst_update, &src_update, realfb_info);
dst_width = RECTW(dst_update);
dst_height = RECTH(dst_update);
@@ -223,6 +262,11 @@ static void refresh_cw_32bpp(ShadowFBHeader* shadowfb_header,
src_bits += 4;
dst_line += realfb_info->pitch;
}
#ifdef _DEBUG
double elapsed = get_elapsed_seconds(&ts_start, NULL);
_MG_PRINTF("Cosumed time to rotate dirty rect (cw): %f (seconds)\n", elapsed);
#endif
}
#endif
@@ -255,6 +299,7 @@ static GAL_Surface *SHADOW_SetVideoMode (_THIS, GAL_Surface *current, int width,
static int SHADOW_SetColors (_THIS, int firstcolor, int ncolors, GAL_Color *colors);
static void SHADOW_VideoQuit (_THIS);
static BOOL SHADOW_SyncUpdate (_THIS);
static BOOL SHADOW_SyncUpdateAsync (_THIS);
static BOOL SHADOW_SyncUpdateConcurrently (_THIS);
/* Hardware surface functions */
@@ -307,6 +352,10 @@ static void SHADOW_UpdateRects (_THIS, int numrects, GAL_Rect *rects)
#ifdef _MGRM_PROCESSES
_sysvipc_sem_op (this->hidden->semid, 0, -1);
#endif
if (this->hidden->async_update) {
pthread_mutex_lock(&this->hidden->update_lock);
}
bound = _shadowfbheader->dirty_rect;
for (i = 0; i < numrects; i++) {
@@ -328,6 +377,9 @@ static void SHADOW_UpdateRects (_THIS, int numrects, GAL_Rect *rects)
}
}
if (this->hidden->async_update) {
pthread_mutex_unlock(&this->hidden->update_lock);
}
#ifdef _MGRM_PROCESSES
_sysvipc_sem_op (this->hidden->semid, 0, 1);
#endif
@@ -539,6 +591,140 @@ static int RealEngine_Init(void)
return 0;
}
static BOOL SHADOW_SyncUpdateAsync (_THIS)
{
if (this->hidden->async_update) {
pthread_mutex_lock(&this->hidden->update_lock);
}
if (_shadowfbheader->dirty || _shadowfbheader->palette_changed) {
GAL_VideoDevice *real_device;
real_device = this->hidden->realfb_info->real_device;
assert(real_device);
if (_shadowfbheader->palette_changed) {
real_device->SetColors(real_device, _shadowfbheader->firstcolor,
_shadowfbheader->ncolors,
(GAL_Color*)((char*)_shadowfbheader +
_shadowfbheader->palette_offset));
SetRect(&_shadowfbheader->dirty_rect, 0, 0,
_shadowfbheader->width, _shadowfbheader->height);
}
GetBoundRect (&this->hidden->update_rect,
&this->hidden->update_rect, &_shadowfbheader->dirty_rect);
SetRect(&_shadowfbheader->dirty_rect, 0, 0, 0, 0);
_shadowfbheader->dirty = FALSE;
_shadowfbheader->palette_changed = FALSE;
}
if (this->hidden->async_update) {
pthread_mutex_unlock(&this->hidden->update_lock);
}
return TRUE;
}
static void *task_do_update(void *data)
{
_THIS = data;
if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL))
goto error;
this->hidden->async_update = 1;
sem_post(&this->hidden->sync_sem);
do {
usleep(this->hidden->update_interval * 1000);
pthread_mutex_lock(&this->hidden->update_lock);
if (RECTH(this->hidden->update_rect)) {
shadow_fb_ops.refresh(_shadowfbheader,
this->hidden->realfb_info, &this->hidden->update_rect);
RECT dirty_rect;
if (this->hidden->realfb_info->flags & _ROT_DIR_CW) {
_get_dst_rect_cw(&dirty_rect, &(this->hidden->update_rect),
this->hidden->realfb_info);
}
else if (this->hidden->realfb_info->flags & _ROT_DIR_CCW) {
_get_dst_rect_ccw(&dirty_rect, &(this->hidden->update_rect),
this->hidden->realfb_info);
}
else if (this->hidden->realfb_info->flags & _ROT_DIR_HFLIP) {
dirty_rect = this->hidden->update_rect;
_get_dst_rect_hflip (&dirty_rect, this->hidden->realfb_info);
}
else if (this->hidden->realfb_info->flags & _ROT_DIR_VFLIP) {
dirty_rect = this->hidden->update_rect;
_get_dst_rect_vflip (&dirty_rect, this->hidden->realfb_info);
}
else {
dirty_rect = this->hidden->update_rect;
}
GAL_Rect update_rect;
update_rect.x = dirty_rect.left;
update_rect.y = dirty_rect.top;
update_rect.w = RECTW(dirty_rect);
update_rect.h = RECTH(dirty_rect);
GAL_VideoDevice *real_device;
real_device = this->hidden->realfb_info->real_device;
if (real_device->UpdateRects)
real_device->UpdateRects(real_device, 1, &update_rect);
if (real_device->SyncUpdate)
real_device->SyncUpdate(real_device);
SetRectEmpty(&this->hidden->update_rect);
}
pthread_mutex_unlock(&this->hidden->update_lock);
} while (1);
return NULL;
error:
this->hidden->async_update = 0;
sem_post(&this->hidden->sync_sem);
return NULL;
}
static int create_async_updater(_THIS)
{
if (sem_init(&this->hidden->sync_sem, 0, 0))
return -1;
pthread_attr_t attr;
pthread_attr_init(&attr);
struct sched_param sp = { 90 };
pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
pthread_attr_setschedparam(&attr, &sp);
if (pthread_create(&this->hidden->update_thd, &attr,
task_do_update, this))
return -1;
sem_wait(&this->hidden->sync_sem);
pthread_attr_destroy(&attr);
return this->hidden->async_update ? 0 : -1;
}
static void cancel_async_updater(_THIS)
{
if (this->hidden->async_update) {
pthread_cancel(this->hidden->update_thd);
pthread_join(this->hidden->update_thd, NULL);
sem_destroy(&this->hidden->sync_sem);
}
}
#if 0 /* multiple updaters */
struct update_thd_args {
_THIS;
int number;
@@ -727,6 +913,7 @@ static int create_extra_updaters(_THIS)
return 0;
}
#endif
static int SHADOW_VideoInit (_THIS, GAL_PixelFormat *vformat)
{
@@ -760,6 +947,35 @@ static int SHADOW_VideoInit (_THIS, GAL_PixelFormat *vformat)
}
#endif
char tmp[8];
if (GetMgEtcValue ("shadow", "async_update", tmp, sizeof(tmp)) < 0) {
this->hidden->async_update = 0;
}
else if (strcasecmp(tmp, "true") == 0 ||
strcasecmp(tmp, "yes") == 0) {
this->hidden->async_update = 1;
}
else {
this->hidden->async_update = 0;
}
if (this->hidden->async_update) {
if (GetMgEtcIntValue("shadow", "update_interval",
&this->hidden->update_interval) < 0) {
this->hidden->update_interval = 20;
}
else if (this->hidden->update_interval < 0 ||
this->hidden->update_interval > 50) {
this->hidden->update_interval = 20;
}
create_async_updater(this);
if (this->hidden->async_update) {
this->SyncUpdate = SHADOW_SyncUpdateAsync;
}
}
#if 0 /* code for multiple updaters */
char nr_updaters[LEN_MODE+1] = "0";
if (GetMgEtcValue ("shadow", "nr_updaters",
nr_updaters, LEN_MODE) < 0) {
@@ -777,6 +993,7 @@ static int SHADOW_VideoInit (_THIS, GAL_PixelFormat *vformat)
perror ("NEWGAL>SHADOW: create_updaters");
}
}
#endif
/* We're done! */
return 0;
@@ -979,9 +1196,11 @@ static GAL_Surface *SHADOW_SetVideoMode(_THIS, GAL_Surface *current,
current->pitch = _shadowfbheader->pitch;
current->pixels = (char *)_shadowfbheader + _shadowfbheader->fb_offset;
#if 0 /* Code for multiple updaters */
if (this->hidden->nr_updaters > 0) {
this->SyncUpdate = SHADOW_SyncUpdateConcurrently;
}
#endif
#ifdef _MGUSE_PIXMAN
GAL_CreatePixmanImage(current);
@@ -1052,6 +1271,7 @@ static GAL_Surface *SHADOW_SetVideoMode(_THIS, GAL_Surface *current,
static void SHADOW_VideoQuit (_THIS)
{
#if 0 /* Code for multiple updaters */
if (this->hidden->nr_updaters > 0) {
for (int i = 0; i < this->hidden->nr_updaters; i++) {
pthread_cancel(this->hidden->update_thds[i]);
@@ -1062,6 +1282,9 @@ static void SHADOW_VideoQuit (_THIS)
sem_destroy(&this->hidden->sync_sem);
}
#endif
cancel_async_updater(this);
if (_shadowfbheader) {
_shadowfbheader->dirty = FALSE;
+7 -7
View File
@@ -120,13 +120,13 @@ struct GAL_PrivateVideoData {
int semid;
#endif
int nr_updaters;
/* only valid when nr_updaters > 0 */
RECT dirty_rcs[MAX_NR_UPDATERS];
sem_t update_sems[MAX_NR_UPDATERS];
pthread_t update_thds[MAX_NR_UPDATERS];
sem_t sync_sem;
/* async updater */
int async_update;
int update_interval;
RECT update_rect;
pthread_t update_thd;
pthread_mutex_t update_lock;
sem_t sync_sem;
};
typedef struct _ShadowFBOps {