new function: concurrentTask_Do

This commit is contained in:
Vincent Wei
2021-05-21 17:17:46 +08:00
parent 9befaeb68a
commit 4e6809618a
8 changed files with 158 additions and 326 deletions

View File

@@ -56,6 +56,9 @@
#include <assert.h>
#include "common.h"
#ifdef _MGRM_PROCESSES
#include "minigui.h"
#include "constants.h"
#include "newgal.h"
@@ -63,6 +66,8 @@
#include <pthread.h>
#include <semaphore.h>
#include "concurrent-tasks.h"
typedef void (*task_proc)(void* context, int loop_idx);
typedef struct _ConcurrentTasksInfo {
@@ -71,9 +76,9 @@ typedef struct _ConcurrentTasksInfo {
sem_t sem_lock;
sem_t sem_sync;
int nr_loops;
task_proc proc;
void* ctxt;
int nr_loops;
CCTaskProc proc;
void* ctxt;
} ConcurrentTasksInfo;
static ConcurrentTasksInfo *cctasks_info;
@@ -128,7 +133,7 @@ static void* cc_task_entry (void* data)
return NULL;
}
static void split_rect (GAL_Rect* rcs, const GAL_Rect* rc, int count)
int concurrentTasks_SplitRect (GAL_Rect* rcs, const GAL_Rect* rc, int count)
{
if (count == 1) {
rcs[0] = *rc;
@@ -151,63 +156,76 @@ static void split_rect (GAL_Rect* rcs, const GAL_Rect* rc, int count)
rcs[0].h = rc->h >> 2;
rcs[1].x = rc->x;
rcs[1].y = rcs[0].y+ rcs[0].h;
rcs[1].y = rcs[0].y + rcs[0].h;
rcs[1].w = rc->w;
rcs[1].h = rc->h >> 2;
rcs[2].x = rc->x;
rcs[2].y = rcs[1].y+ rcs[1].h;
rcs[2].y = rcs[1].y + rcs[1].h;
rcs[2].w = rc->w;
rcs[2].h = rc->h >> 2;
rcs[3].x = rc->x;
rcs[3].y = rcs[2].y+ rcs[2].h;
rcs[3].y = rcs[2].y + rcs[2].h;
rcs[3].w = rc->w;
rcs[3].h = rc->h - rcs[0].h - rcs[1].h - rcs[2].h;
rcs[3].h = rc->h - rcs[0].h * 3;
}
else if (count == 8) {
rcs[0].x = rc->x;
rcs[0].y = rc->y;
rcs[0].w = rc->w;
rcs[0].h = rc->h >> 3;
rcs[1].x = rc->x;
rcs[1].y = rcs[0].y + rcs[0].h;
rcs[1].w = rc->w;
rcs[1].h = rc->h >> 3;
rcs[2].x = rc->x;
rcs[2].y = rcs[1].y + rcs[1].h;
rcs[2].w = rc->w;
rcs[2].h = rc->h >> 3;
rcs[3].x = rc->x;
rcs[3].y = rcs[2].y + rcs[2].h;
rcs[3].w = rc->w;
rcs[3].h = rc->h >> 3;
rcs[4].x = rc->x;
rcs[4].y = rcs[3].y + rcs[3].h;
rcs[4].w = rc->w;
rcs[4].h = rc->h >> 3;
rcs[5].x = rc->x;
rcs[5].y = rcs[4].y + rcs[4].h;
rcs[5].w = rc->w;
rcs[5].h = rc->h >> 3;
rcs[6].x = rc->x;
rcs[6].y = rcs[5].y + rcs[5].h;
rcs[6].w = rc->w;
rcs[6].h = rc->h >> 3;
rcs[7].x = rc->x;
rcs[7].y = rcs[6].y + rcs[6].h;
rcs[7].w = rc->w;
rcs[7].h = rc->h - rcs[0].h * 7;
}
else {
assert (0);
return -1;
}
return 0;
}
typedef struct _ContextBlit {
GAL_Surface *src;
GAL_Surface *dst;
GAL_blit real_blit;
GAL_Rect src_rects [_MGNR_CONCURRENT_TASKS + 1];
GAL_Rect dst_rects [_MGNR_CONCURRENT_TASKS + 1];
} ContextBlit;
static void blit_proc (void* context, int loop_idx)
{
ContextBlit *ctxt = context;
if (ctxt->src_rects[loop_idx].h > 0) {
ctxt->real_blit (ctxt->src, ctxt->src_rects + loop_idx,
ctxt->dst, ctxt->dst_rects + loop_idx);
}
}
int concurrentTasks_Blit (GAL_blit real_blit,
struct GAL_Surface *src, GAL_Rect *srcrect,
struct GAL_Surface *dst, GAL_Rect *dstrect)
int concurrentTasks_Do (void* context, CCTaskProc proc)
{
int i;
ContextBlit ctxt;
ctxt.src = src;
ctxt.dst = dst;
ctxt.real_blit = real_blit;
split_rect (ctxt.src_rects, srcrect, _MGNR_CONCURRENT_TASKS + 1);
split_rect (ctxt.dst_rects, dstrect, _MGNR_CONCURRENT_TASKS + 1);
if (_MGNR_CONCURRENT_TASKS > 0) {
cctasks_info->nr_loops = 1; // reserve 0 for the current thread
cctasks_info->proc = blit_proc;
cctasks_info->ctxt = &ctxt;
cctasks_info->proc = proc;
cctasks_info->ctxt = context;
}
// wake up the concurrent task threads
@@ -215,7 +233,7 @@ int concurrentTasks_Blit (GAL_blit real_blit,
sem_post (&cctasks_info->sem_loop);
}
blit_proc (&ctxt, 0);
proc (context, 0);
// wait for finish of concurrent task threads
for (i = 0; i < _MGNR_CONCURRENT_TASKS; i++) {
@@ -284,7 +302,7 @@ int concurrentTasks_Term (void)
{
int i;
if (_MGNR_CONCURRENT_TASKS <= 0)
if (_MGNR_CONCURRENT_TASKS <= 0 && cctasks_info == NULL)
return 0;
for (i = 0; i < _MGNR_CONCURRENT_TASKS; i++) {
@@ -302,3 +320,5 @@ int concurrentTasks_Term (void)
return 0;
}
#endif /* _MGRM_PROCESSES */

View File

@@ -58,11 +58,12 @@
extern "C" {
#endif /* __cplusplus */
typedef void (*CCTaskProc)(void* context, int loop_idx);
int concurrentTasks_Init (void);
int concurrentTasks_Term (void);
int concurrentTasks_Blit (GAL_blit real_blit,
struct GAL_Surface *src, GAL_Rect *srcrect,
struct GAL_Surface *dst, GAL_Rect *dstrect);
int concurrentTasks_SplitRect (GAL_Rect* rcs, const GAL_Rect* rc, int count);
int concurrentTasks_Do (void* context, CCTaskProc proc);
#ifdef __cplusplus
}

View File

@@ -765,10 +765,6 @@ 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;
}
@@ -832,7 +828,6 @@ 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

View File

@@ -230,18 +230,6 @@ 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)
{
@@ -297,261 +285,3 @@ 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_loop;
sem_t sem_lock;
sem_t sem_sync;
pthread_t pths[_MGNR_UPDATE_THREADS];
int nr_loops;
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 task_idx = (int)(intptr_t)data;
if (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL))
return NULL;
do {
int loop_idx;
if (my_sem_wait (&cuth_info.sem_loop)) {
_ERR_PRINTF ("Update thread %d failed on sem_wait\n", task_idx);
return NULL;
}
my_sem_wait (&cuth_info.sem_lock);
loop_idx = cuth_info.nr_loops++;
sem_post (&cuth_info.sem_lock);
pthread_testcancel ();
copy_lines (cuth_info.device->hidden->shadow_screen,
cuth_info.device->hidden->real_screen,
&cuth_info.bound, loop_idx);
if (sem_post (&cuth_info.sem_sync)) {
_ERR_PRINTF ("Update thread %d failed on sem_post\n", task_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);
if (sem_init (&cuth_info.sem_loop, 0, 0)) {
_ERR_PRINTF ("NEWGAL>DBLBUFF: failed to create loop 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;
}
if (sem_init (&cuth_info.sem_lock, 0, 1)) {
_ERR_PRINTF ("NEWGAL>DBLBUFF: failed to create lock semaphore: %s\n",
strerror (errno));
goto failed_sem_lock;
}
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_lock);
failed_sem_lock:
sem_destroy (&cuth_info.sem_sync);
failed_sem_sync:
sem_destroy (&cuth_info.sem_loop);
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);
sem_destroy (&cuth_info.sem_loop);
sem_destroy (&cuth_info.sem_lock);
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.nr_loops = 1; // reserve 0 for the current thread
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_loop);
}
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 */

View File

@@ -64,8 +64,6 @@ 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);

View File

@@ -49,6 +49,7 @@
#include "common.h"
#include "newgal.h"
#include "blit.h"
#include "concurrent-tasks.h"
#define DEFINE_COPY_ROW(name, type) \
static void name(type *src, int src_w, type *dst, int dst_w) \
@@ -377,6 +378,31 @@ int GAL_CleanupStretchBlit (GAL_Surface *src, GAL_Surface *dst)
return 0;
}
#ifdef _MGRM_PROCESSES
typedef struct _ContextStretch {
pixman_op_t op;
pixman_image_t *src_img;
pixman_image_t *msk_img;
pixman_image_t *dst_img;
GAL_Rect dst_rects [_MGNR_CONCURRENT_TASKS + 1];
} ContextStretch;
static void stretch_proc (void* context, int loop_idx)
{
ContextStretch *ctxt = context;
if (ctxt->dst_rects[loop_idx].h > 0) {
GAL_Rect* dstrect = ctxt->dst_rects + loop_idx;
pixman_image_composite32 (ctxt->op, ctxt->src_img, ctxt->msk_img, ctxt->dst_img,
dstrect->x, dstrect->y,
0, 0,
dstrect->x, dstrect->y,
dstrect->w, dstrect->h);
}
}
#endif
int GAL_StretchBlt (GAL_Surface *src, GAL_Rect *srcrect,
GAL_Surface *dst, GAL_Rect *dstrect,
const STRETCH_EXTRA_INFO* sei, DWORD ops)
@@ -409,11 +435,27 @@ int GAL_StretchBlt (GAL_Surface *src, GAL_Rect *srcrect,
dst->clip_rect.x, dst->clip_rect.y, dst->clip_rect.w, dst->clip_rect.h);
pixman_image_set_clip_region32 (dst_img, &clip_region);
#ifdef _MGRM_PROCESSES
// we use concurrent tasks only under MiniGUI-Processes.
{
ContextStretch ctxt;
ctxt.op = op;
ctxt.src_img = src_img;
ctxt.msk_img = msk_img;
ctxt.dst_img = dst_img;
concurrentTasks_SplitRect (ctxt.dst_rects, dstrect, _MGNR_CONCURRENT_TASKS + 1);
concurrentTasks_Do (&ctxt, stretch_proc);
}
#else
pixman_image_composite32 (op, src_img, msk_img, dst_img,
dstrect->x, dstrect->y,
0, 0,
dstrect->x, dstrect->y,
dstrect->w, dstrect->h);
#endif
pixman_region32_fini (&clip_region);
return 0;

View File

@@ -56,10 +56,10 @@
#include "pixels_c.h"
#include "memops.h"
#include "leaks.h"
#include "concurrent-tasks.h"
#ifdef _MGRM_PROCESSES
#include <sys/mman.h> /* for munmap */
#include "concurrent-tasks.h"
#endif /* _MGRM_PROCESSES */
/* Public routines */
@@ -494,6 +494,28 @@ static int own_overlapped_bitblit(GAL_blit real_blit, struct GAL_Surface *src, G
}
#endif
#ifdef _MGRM_PROCESSES
typedef struct _ContextBlit {
GAL_Surface *src;
GAL_Surface *dst;
GAL_blit real_blit;
GAL_Rect src_rects [_MGNR_CONCURRENT_TASKS + 1];
GAL_Rect dst_rects [_MGNR_CONCURRENT_TASKS + 1];
} ContextBlit;
static void blit_proc (void* context, int loop_idx)
{
ContextBlit *ctxt = context;
if (ctxt->src_rects[loop_idx].h > 0) {
ctxt->real_blit (ctxt->src, ctxt->src_rects + loop_idx,
ctxt->dst, ctxt->dst_rects + loop_idx);
}
}
#endif
/*
* Set up a blit between two surfaces -- split into three parts:
* The upper part, GAL_UpperBlit(), performs clipping and rectangle
@@ -541,7 +563,18 @@ int GAL_LowerBlit (GAL_Surface *src, GAL_Rect *srcrect,
#ifdef _MGRM_PROCESSES
// we use concurrent tasks only under MiniGUI-Processes.
concurrentTasks_Blit (do_blit, src, srcrect, dst, dstrect);
{
ContextBlit ctxt;
ctxt.src = src;
ctxt.dst = dst;
ctxt.real_blit = do_blit;
concurrentTasks_SplitRect (ctxt.src_rects, srcrect, _MGNR_CONCURRENT_TASKS + 1);
concurrentTasks_SplitRect (ctxt.dst_rects, dstrect, _MGNR_CONCURRENT_TASKS + 1);
concurrentTasks_Do (&ctxt, blit_proc);
}
#else
# ifdef MG_CONFIG_USE_OWN_OVERLAPPED_BITBLIT
ret = own_overlapped_bitblit(do_blit, src, srcrect, dst, dstrect);

View File

@@ -58,6 +58,7 @@
#include "pixels_c.h"
#include "license.h"
#include "debug.h"
#include "concurrent-tasks.h"
/* Available video drivers */
static VideoBootStrap *bootstrap[] = {
@@ -288,6 +289,12 @@ int GAL_VideoInit (const char *driver_name, Uint32 flags)
video->info.vfmt = GAL_VideoSurface->format;
#ifdef _MGRM_PROCESSES
// we use concurrent tasks only under MiniGUI-Processes.
if (concurrentTasks_Init ())
return -1;
#endif
return(0);
}
@@ -1154,6 +1161,12 @@ void GAL_VideoQuit (void)
DestroyFreeClipRectList (&__mg_free_update_region_list);
#endif
}
#ifdef _MGRM_PROCESSES
// we use concurrent tasks only under MiniGUI-Processes.
concurrentTasks_Term ();
#endif
return;
}