initial implementation of concurrent blitting

This commit is contained in:
Vincent Wei
2021-05-20 22:14:28 +08:00
parent ad49fe0e0e
commit 87b9facc84
6 changed files with 303 additions and 8 deletions
+36 -5
View File
@@ -95,6 +95,7 @@ message_string="no"
osname="unspecified"
runtime_mode="procs"
compositing_schema="yes"
nr_update_threads=0
virtual_window="no"
use_shmopen="no"
mgslice_use_fallback="no"
@@ -853,12 +854,16 @@ build_ctrl_animation=$enableval)
if test "x$runtime_mode" == "xprocs"; then
AC_ARG_ENABLE(compositing,
[ --enable-compositing enable compositing schema (MiniGUI-Processes runmode only) <default=yes>],
compositing_schema=$enableval)
[ --enable-compositing enable compositing schema (MiniGUI-Processes runmode only) <default=yes>],
compositing_schema=$enableval)
AC_ARG_ENABLE(shmopen,
[ --enable-shmopen use shm_open <default=no>],
use_shmopen=$enableval)
[ --enable-shmopen use shm_open <default=no>],
use_shmopen=$enableval)
AC_ARG_WITH(update_threads,
[ --with-update-threads=[0/1/2/4/8]],
nr_update_threads=$withval)
fi
if test "x$runtime_mode" != "xths"; then
@@ -1755,7 +1760,7 @@ case "$runtime_mode" in
[Define if build MiniGUI-Processes])
MINIGUI_RUNMODE="procs"
if test "x$compositing_schema" = "xyes"; then
surface_schema="compositing"
surface_schema="compositing"
fi
if test "x$use_shmopen" = "xyes"; then
@@ -1777,9 +1782,34 @@ esac
if test "x$surface_schema" = "xcompositing"; then
AC_DEFINE(_MGSCHEMA_COMPOSITING, 1,
[Define if use compositing schema for the current runmode])
case "$nr_update_threads" in
1)
AC_DEFINE(_MGNR_UPDATE_THREADS, 1,
[The number of concurrent update threads.])
;;
2)
AC_DEFINE(_MGNR_UPDATE_THREADS, 2,
[The number of concurrent update threads.])
;;
4)
AC_DEFINE(_MGNR_UPDATE_THREADS, 4,
[The number of concurrent update threads.])
;;
8)
AC_DEFINE(_MGNR_UPDATE_THREADS, 8,
[The number of concurrent update threads.])
;;
*)
AC_DEFINE(_MGNR_UPDATE_THREADS, 0,
[The number of concurrent update threads.])
;;
esac
else
AC_DEFINE(_MGSCHEMA_SHAREDFB, 1,
[Define if use legacy schema (shared frame buffer) for the current runmode])
AC_DEFINE(_MGNR_UPDATE_THREADS, 0,
[The number of asynchronous update threads.])
fi
if test "x$virtual_window" = "xyes"; then
@@ -2794,6 +2824,7 @@ AC_MSG_NOTICE([
* Runtime mode: ${runtime_mode}
* Virtual Window: ${virtual_window}
* Surface schema: ${surface_schema}
* Update Threads: ${nr_update_threads}
* Use shm_open: ${use_shmopen}
* Incore resource: ${incore_res}
* Fallback mgslice: ${mgslice_use_fallback}
+1 -1
View File
@@ -1303,7 +1303,7 @@ static void transit_to_layer (CompositorCtxt* ctxt, MG_Layer* to_layer)
}
}
_DBG_PRINTF ("Average time to composite the layers: %u (times: %u)\n", total_time_ms / total_times, total_times);
_WRN_PRINTF ("Average time to composite the layers: %u (times: %u)\n", total_time_ms / total_times, total_times);
}
CompositorOps __mg_fallback_compositor = {
+2 -2
View File
@@ -77,13 +77,13 @@ static int GAL_SoftBlit(GAL_Surface *src, GAL_Rect *srcrect,
GAL_loblit RunBlit;
/* Set up the blit information */
info.s_pixels = (Uint8 *)src->pixels +
info.s_pixels = (Uint8 *)src->pixels + src->pixels_off +
(Uint16)srcrect->y*src->pitch +
(Uint16)srcrect->x*src->format->BytesPerPixel;
info.s_width = srcrect->w;
info.s_height = srcrect->h;
info.s_skip=src->pitch-info.s_width*src->format->BytesPerPixel;
info.d_pixels = (Uint8 *)dst->pixels +
info.d_pixels = (Uint8 *)dst->pixels + dst->pixels_off +
(Uint16)dstrect->y*dst->pitch +
(Uint16)dstrect->x*dst->format->BytesPerPixel;
info.d_width = dstrect->w;
+5
View File
@@ -765,6 +765,10 @@ static GAL_Surface *PCXVFB_SetVideoMode (_THIS, GAL_Surface *current,
this->hidden->shadow_screen = NULL;
}
if (this->hidden->real_screen) {
shadowScreen_InitUpdateThreads(this);
}
/* We're done */
return current;
}
@@ -828,6 +832,7 @@ static void PCXVFB_VideoQuit (_THIS)
/* Since 5.0.0 */
if (this->hidden->real_screen) {
GAL_FreeSurface (this->hidden->real_screen);
shadowScreen_TermUpdateThreads(this);
}
#ifdef WIN32 // windows
+257
View File
@@ -230,6 +230,18 @@ void shadowScreen_UpdateRects (_THIS, int numrects, GAL_Rect *rects)
this->hidden->dirty_rc = bound;
}
#if _MGNR_UPDATE_THREADS <= 0
int shadowScreen_InitUpdateThreads (_THIS)
{
return 0;
}
int shadowScreen_TermUpdateThreads (_THIS)
{
return 0;
}
/* Blit dirty content from shadow surface to ultimate surface */
int shadowScreen_BlitToReal (_THIS)
{
@@ -285,3 +297,248 @@ int shadowScreen_BlitToReal (_THIS)
return 0;
}
#else /* _MGNR_UPDATE_THREADS <= 0 */
#include <pthread.h>
#include <semaphore.h>
static struct UpdateThreadsInfo {
GAL_VideoDevice *device;
sem_t sem_tasks[_MGNR_UPDATE_THREADS];
sem_t sem_sync;
pthread_t pths[_MGNR_UPDATE_THREADS];
RECT bound;
} cuth_info;
static inline void copy_lines (GAL_Surface* src_surf, GAL_Surface* dst_surf,
const RECT *rc, int idx)
{
int y, h = RECTHP (rc);
uint8_t *src, *dst;
size_t count = src_surf->format->BytesPerPixel * RECTWP (rc);
if (h <= 0 || count == 0)
return;
src = src_surf->pixels + src_surf->pixels_off;
src += src_surf->pitch * (rc->top + idx);
src += src_surf->format->BytesPerPixel * rc->left;
dst = dst_surf->pixels + dst_surf->pixels_off;
dst += dst_surf->pitch * (rc->top + idx);
dst += dst_surf->format->BytesPerPixel * rc->left;
for (y = idx; y < h; y += (_MGNR_UPDATE_THREADS + 1)) {
memcpy (dst, src, count);
src += src_surf->pitch * (_MGNR_UPDATE_THREADS + 1);
dst += dst_surf->pitch * (_MGNR_UPDATE_THREADS + 1);
}
}
static inline int my_sem_wait (sem_t *sem)
{
try_again:
if (sem_wait (sem) < 0) {
if (errno == EINTR)
goto try_again;
else {
_WRN_PRINTF ("NEWGAL>DBLBUFF: failed sem_wait: %s\n", strerror (errno));
return -1;
}
}
return 0;
}
static void* task_do_update (void* data)
{
int idx = (int)(intptr_t)data;
if (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL))
return NULL;
do {
if (my_sem_wait (cuth_info.sem_tasks + idx - 1)) {
_ERR_PRINTF ("Update thread %d failed on sem_wait\n", idx);
return NULL;
}
pthread_testcancel ();
copy_lines (cuth_info.device->hidden->shadow_screen,
cuth_info.device->hidden->real_screen,
&cuth_info.bound, idx);
if (sem_post (&cuth_info.sem_sync)) {
_ERR_PRINTF ("Update thread %d failed on sem_post\n", idx);
return NULL;
}
pthread_testcancel ();
} while (1);
return NULL;
}
int shadowScreen_InitUpdateThreads (_THIS)
{
int i;
CHECK_VERSION_RETVAL (this, -1);
assert (this->real_screen && this->shadow_screen);
for (i = 0; i < _MGNR_UPDATE_THREADS; i++) {
if (sem_init (cuth_info.sem_tasks + i, 0, 0)) {
_ERR_PRINTF ("NEWGAL>DBLBUFF: failed to create task semaphore: %s\n",
strerror (errno));
goto failed_sem_update;
}
}
if (sem_init (&cuth_info.sem_sync, 0, 0)) {
_ERR_PRINTF ("NEWGAL>DBLBUFF: failed to create sync semaphore: %s\n",
strerror (errno));
goto failed_sem_sync;
}
for (i = 0; i < _MGNR_UPDATE_THREADS; i++) {
if (pthread_create (cuth_info.pths + i, NULL, task_do_update,
(void*)(intptr_t)(i + 1))) {
_ERR_PRINTF ("NEWGAL>DBLBUFF: failed to create update thread (%d): %s\n",
i, strerror (errno));
goto failed_threads;
}
}
cuth_info.device = this;
return 0;
failed_threads:
sem_destroy (&cuth_info.sem_sync);
failed_sem_sync:
for (i = 0; i < _MGNR_UPDATE_THREADS; i++) {
sem_destroy (cuth_info.sem_tasks + i);
}
failed_sem_update:
return -1;
}
int shadowScreen_TermUpdateThreads (_THIS)
{
int i;
for (i = 0; i < _MGNR_UPDATE_THREADS; i++) {
_WRN_PRINTF ("Cancelling update thread: %d\n", i);
/* send cancel request */
pthread_cancel (cuth_info.pths [i]);
pthread_join (cuth_info.pths [i], NULL);
}
sem_destroy (&cuth_info.sem_sync);
for (i = 0; i < _MGNR_UPDATE_THREADS; i++) {
sem_destroy (cuth_info.sem_tasks + i);
}
return 0;
}
#if 0
static void split_rect (RECT* rcs, const RECT* rc)
{
if (_MGNR_UPDATE_THREADS == 1) {
rcs[0] = *rc;
}
else if (_MGNR_UPDATE_THREADS == 2) {
rcs[0] = *rc;
rcs[0].bottom -= RECTHP (rc) >> 1;
rcs[1] = *rc;
rcs[1].top = rcs[0].bottom;
}
else if (_MGNR_UPDATE_THREADS == 4) {
rcs[0] = *rc;
rcs[0].right -= RECTWP (rc) >> 1;
rcs[0].bottom -= RECTHP (rc) >> 1;
rcs[1].top = rcs[0].top;
rcs[1].left = rcs[0].right;
rcs[1].right = rc->right;
rcs[1].bottom = rcs[0].bottom;
rcs[2].top = rcs[0].bottom;
rcs[2].left = rcs[0].left;
rcs[2].right = rcs[0].right;
rcs[2].bottom = rc->bottom;
rcs[3].top = rcs[0].bottom;
rcs[3].left = rcs[2].right;
rcs[3].right = rc->right;
rcs[3].bottom = rc->bottom;
}
else {
assert (0);
}
}
#endif
int shadowScreen_BlitToReal (_THIS)
{
int i, value;
CHECK_VERSION_RETVAL (this, -1);
cuth_info.bound = this->hidden->dirty_rc;
// wake up the concurrent update threads
for (i = 0; i < _MGNR_UPDATE_THREADS; i++) {
sem_post (cuth_info.sem_tasks + i);
}
copy_lines (cuth_info.device->hidden->shadow_screen,
cuth_info.device->hidden->real_screen,
&cuth_info.bound, 0);
// wait for finish of concurrent update threads
for (i = 0; i < _MGNR_UPDATE_THREADS; i++) {
if (my_sem_wait (&cuth_info.sem_sync) < 0)
return -1;
}
#ifdef _MGSCHEMA_COMPOSITING
if (this->hidden->cursor) {
RECT csr_rc, eff_rc;
csr_rc.left = boxleft (this);
csr_rc.top = boxtop (this);
csr_rc.right = csr_rc.left + CURSORWIDTH;
csr_rc.bottom = csr_rc.top + CURSORHEIGHT;
if (IntersectRect (&eff_rc, &csr_rc, &cuth_info.bound)) {
GAL_Rect src_rect, dst_rect;
src_rect.x = eff_rc.left - csr_rc.left;
src_rect.y = eff_rc.top - csr_rc.top;
src_rect.w = RECTW (eff_rc);
src_rect.h = RECTH (eff_rc);
dst_rect.x = eff_rc.left;
dst_rect.y = eff_rc.top;
dst_rect.w = src_rect.w;
dst_rect.h = src_rect.h;
GAL_SetupBlitting (this->hidden->cursor,
this->hidden->real_screen, 0);
GAL_BlitSurface (this->hidden->cursor, &src_rect,
this->hidden->real_screen, &dst_rect);
GAL_CleanupBlitting (this->hidden->cursor,
this->hidden->real_screen);
}
}
#endif /* _MGSCHEMA_COMPOSITING */
return 0;
}
#endif /* _MGNR_UPDATE_THREADS > 0 */
+2
View File
@@ -64,6 +64,8 @@ extern "C" {
# define _THIS GAL_VideoDevice *this
#endif
int shadowScreen_InitUpdateThreads (_THIS);
int shadowScreen_TermUpdateThreads (_THIS);
int shadowScreen_SetCursor (_THIS, GAL_Surface *surface, int hot_x, int hot_y);
int shadowScreen_MoveCursor (_THIS, int x, int y);
void shadowScreen_UpdateRects (_THIS, int numrects, GAL_Rect *rects);