mirror of
https://github.com/VincentWei/MiniGUI.git
synced 2026-09-25 02:33:59 +08:00
initial implementation of concurrent blitting
This commit is contained in:
+36
-5
@@ -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}
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user