319 lines
8.5 KiB
C
319 lines
8.5 KiB
C
/*
|
|
SDL - Simple DirectMedia Layer
|
|
Copyright (C) 1997-2006 Sam Lantinga
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with this library; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
Sam Lantinga
|
|
slouken@libsdl.org
|
|
*/
|
|
#include "SDL_config.h"
|
|
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
|
|
#include "SDL_endian.h"
|
|
#include "../../events/SDL_events_c.h"
|
|
#include "SDL_x11image_c.h"
|
|
|
|
#ifndef NO_SHARED_MEMORY
|
|
|
|
/* Shared memory error handler routine */
|
|
static int shm_error;
|
|
static int (*X_handler)(Display *, XErrorEvent *) = NULL;
|
|
static int shm_errhandler(Display *d, XErrorEvent *e)
|
|
{
|
|
if ( e->error_code == BadAccess ) {
|
|
shm_error = True;
|
|
return(0);
|
|
} else
|
|
return(X_handler(d,e));
|
|
}
|
|
|
|
static void try_mitshm(_THIS, SDL_Surface *screen)
|
|
{
|
|
/* Dynamic X11 may not have SHM entry points on this box. */
|
|
if ((use_mitshm) && (!SDL_X11_HAVE_SHM))
|
|
use_mitshm = 0;
|
|
|
|
if(!use_mitshm)
|
|
return;
|
|
shminfo.shmid = shmget(IPC_PRIVATE, screen->h*screen->pitch,
|
|
IPC_CREAT | 0777);
|
|
if ( shminfo.shmid >= 0 ) {
|
|
shminfo.shmaddr = (char *)shmat(shminfo.shmid, 0, 0);
|
|
shminfo.readOnly = False;
|
|
if ( shminfo.shmaddr != (char *)-1 ) {
|
|
shm_error = False;
|
|
X_handler = XSetErrorHandler(shm_errhandler);
|
|
XShmAttach(SDL_Display, &shminfo);
|
|
XSync(SDL_Display, True);
|
|
XSetErrorHandler(X_handler);
|
|
if ( shm_error )
|
|
shmdt(shminfo.shmaddr);
|
|
} else {
|
|
shm_error = True;
|
|
}
|
|
shmctl(shminfo.shmid, IPC_RMID, NULL);
|
|
} else {
|
|
shm_error = True;
|
|
}
|
|
if ( shm_error )
|
|
use_mitshm = 0;
|
|
if ( use_mitshm )
|
|
screen->pixels = shminfo.shmaddr;
|
|
}
|
|
#endif /* ! NO_SHARED_MEMORY */
|
|
|
|
/* Various screen update functions available */
|
|
static void X11_NormalUpdate(_THIS, int numrects, SDL_Rect *rects);
|
|
static void X11_MITSHMUpdate(_THIS, int numrects, SDL_Rect *rects);
|
|
|
|
int X11_SetupImage(_THIS, SDL_Surface *screen)
|
|
{
|
|
#ifndef NO_SHARED_MEMORY
|
|
try_mitshm(this, screen);
|
|
if(use_mitshm) {
|
|
SDL_Ximage = XShmCreateImage(SDL_Display, SDL_Visual,
|
|
this->hidden->depth, ZPixmap,
|
|
shminfo.shmaddr, &shminfo,
|
|
screen->w, screen->h);
|
|
if(!SDL_Ximage) {
|
|
XShmDetach(SDL_Display, &shminfo);
|
|
XSync(SDL_Display, False);
|
|
shmdt(shminfo.shmaddr);
|
|
screen->pixels = NULL;
|
|
goto error;
|
|
}
|
|
this->UpdateRects = X11_MITSHMUpdate;
|
|
}
|
|
if(!use_mitshm)
|
|
#endif /* not NO_SHARED_MEMORY */
|
|
{
|
|
int bpp;
|
|
screen->pixels = SDL_malloc(screen->h*screen->pitch);
|
|
if ( screen->pixels == NULL ) {
|
|
SDL_OutOfMemory();
|
|
return -1;
|
|
}
|
|
bpp = screen->format->BytesPerPixel;
|
|
SDL_Ximage = XCreateImage(SDL_Display, SDL_Visual,
|
|
this->hidden->depth, ZPixmap, 0,
|
|
(char *)screen->pixels,
|
|
screen->w, screen->h,
|
|
32, 0);
|
|
if ( SDL_Ximage == NULL )
|
|
goto error;
|
|
/* XPutImage will convert byte sex automatically */
|
|
SDL_Ximage->byte_order = (SDL_BYTEORDER == SDL_BIG_ENDIAN)
|
|
? MSBFirst : LSBFirst;
|
|
this->UpdateRects = X11_NormalUpdate;
|
|
}
|
|
screen->pitch = SDL_Ximage->bytes_per_line;
|
|
return(0);
|
|
|
|
error:
|
|
SDL_SetError("Couldn't create XImage");
|
|
return 1;
|
|
}
|
|
|
|
void X11_DestroyImage(_THIS, SDL_Surface *screen)
|
|
{
|
|
if ( SDL_Ximage ) {
|
|
XDestroyImage(SDL_Ximage);
|
|
#ifndef NO_SHARED_MEMORY
|
|
if ( use_mitshm ) {
|
|
XShmDetach(SDL_Display, &shminfo);
|
|
XSync(SDL_Display, False);
|
|
shmdt(shminfo.shmaddr);
|
|
}
|
|
#endif /* ! NO_SHARED_MEMORY */
|
|
SDL_Ximage = NULL;
|
|
}
|
|
if ( screen ) {
|
|
screen->pixels = NULL;
|
|
}
|
|
}
|
|
|
|
/* Determine the number of CPUs in the system */
|
|
static int num_CPU(void)
|
|
{
|
|
static int num_cpus = 0;
|
|
|
|
if(!num_cpus) {
|
|
#if defined(__LINUX__)
|
|
char line[BUFSIZ];
|
|
FILE *pstat = fopen("/proc/stat", "r");
|
|
if ( pstat ) {
|
|
while ( fgets(line, sizeof(line), pstat) ) {
|
|
if (SDL_memcmp(line, "cpu", 3) == 0 && line[3] != ' ') {
|
|
++num_cpus;
|
|
}
|
|
}
|
|
fclose(pstat);
|
|
}
|
|
#elif defined(__IRIX__)
|
|
num_cpus = sysconf(_SC_NPROC_ONLN);
|
|
#elif defined(_SC_NPROCESSORS_ONLN)
|
|
/* number of processors online (SVR4.0MP compliant machines) */
|
|
num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
|
|
#elif defined(_SC_NPROCESSORS_CONF)
|
|
/* number of processors configured (SVR4.0MP compliant machines) */
|
|
num_cpus = sysconf(_SC_NPROCESSORS_CONF);
|
|
#endif
|
|
if ( num_cpus <= 0 ) {
|
|
num_cpus = 1;
|
|
}
|
|
}
|
|
return num_cpus;
|
|
}
|
|
|
|
int X11_ResizeImage(_THIS, SDL_Surface *screen, Uint32 flags)
|
|
{
|
|
int retval;
|
|
|
|
X11_DestroyImage(this, screen);
|
|
if ( flags & SDL_OPENGL ) { /* No image when using GL */
|
|
retval = 0;
|
|
} else {
|
|
retval = X11_SetupImage(this, screen);
|
|
/* We support asynchronous blitting on the display */
|
|
if ( flags & SDL_ASYNCBLIT ) {
|
|
/* This is actually slower on single-CPU systems,
|
|
probably because of CPU contention between the
|
|
X server and the application.
|
|
Note: Is this still true with XFree86 4.0?
|
|
*/
|
|
if ( num_CPU() > 1 ) {
|
|
screen->flags |= SDL_ASYNCBLIT;
|
|
}
|
|
}
|
|
}
|
|
return(retval);
|
|
}
|
|
|
|
/* We don't actually allow hardware surfaces other than the main one */
|
|
int X11_AllocHWSurface(_THIS, SDL_Surface *surface)
|
|
{
|
|
return(-1);
|
|
}
|
|
void X11_FreeHWSurface(_THIS, SDL_Surface *surface)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int X11_LockHWSurface(_THIS, SDL_Surface *surface)
|
|
{
|
|
if ( (surface == SDL_VideoSurface) && blit_queued ) {
|
|
XSync(GFX_Display, False);
|
|
blit_queued = 0;
|
|
}
|
|
return(0);
|
|
}
|
|
void X11_UnlockHWSurface(_THIS, SDL_Surface *surface)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int X11_FlipHWSurface(_THIS, SDL_Surface *surface)
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
static void X11_NormalUpdate(_THIS, int numrects, SDL_Rect *rects)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < numrects; ++i) {
|
|
if ( rects[i].w == 0 || rects[i].h == 0 ) { /* Clipped? */
|
|
continue;
|
|
}
|
|
XPutImage(GFX_Display, SDL_Window, SDL_GC, SDL_Ximage,
|
|
rects[i].x, rects[i].y,
|
|
rects[i].x, rects[i].y, rects[i].w, rects[i].h);
|
|
}
|
|
if ( SDL_VideoSurface->flags & SDL_ASYNCBLIT ) {
|
|
XFlush(GFX_Display);
|
|
blit_queued = 1;
|
|
} else {
|
|
XSync(GFX_Display, False);
|
|
}
|
|
}
|
|
|
|
static void X11_MITSHMUpdate(_THIS, int numrects, SDL_Rect *rects)
|
|
{
|
|
#ifndef NO_SHARED_MEMORY
|
|
int i;
|
|
|
|
for ( i=0; i<numrects; ++i ) {
|
|
if ( rects[i].w == 0 || rects[i].h == 0 ) { /* Clipped? */
|
|
continue;
|
|
}
|
|
XShmPutImage(GFX_Display, SDL_Window, SDL_GC, SDL_Ximage,
|
|
rects[i].x, rects[i].y,
|
|
rects[i].x, rects[i].y, rects[i].w, rects[i].h,
|
|
False);
|
|
}
|
|
if ( SDL_VideoSurface->flags & SDL_ASYNCBLIT ) {
|
|
XFlush(GFX_Display);
|
|
blit_queued = 1;
|
|
} else {
|
|
XSync(GFX_Display, False);
|
|
}
|
|
#endif /* ! NO_SHARED_MEMORY */
|
|
}
|
|
|
|
/* There's a problem with the automatic refreshing of the display.
|
|
Even though the XVideo code uses the GFX_Display to update the
|
|
video memory, it appears that updating the window asynchronously
|
|
from a different thread will cause "blackouts" of the window.
|
|
This is a sort of a hacked workaround for the problem.
|
|
*/
|
|
static int enable_autorefresh = 1;
|
|
|
|
void X11_DisableAutoRefresh(_THIS)
|
|
{
|
|
--enable_autorefresh;
|
|
}
|
|
|
|
void X11_EnableAutoRefresh(_THIS)
|
|
{
|
|
++enable_autorefresh;
|
|
}
|
|
|
|
void X11_RefreshDisplay(_THIS)
|
|
{
|
|
/* Don't refresh a display that doesn't have an image (like GL)
|
|
Instead, post an expose event so the application can refresh.
|
|
*/
|
|
if ( ! SDL_Ximage || (enable_autorefresh <= 0) ) {
|
|
SDL_PrivateExpose();
|
|
return;
|
|
}
|
|
#ifndef NO_SHARED_MEMORY
|
|
if ( this->UpdateRects == X11_MITSHMUpdate ) {
|
|
XShmPutImage(SDL_Display, SDL_Window, SDL_GC, SDL_Ximage,
|
|
0, 0, 0, 0, this->screen->w, this->screen->h,
|
|
False);
|
|
} else
|
|
#endif /* ! NO_SHARED_MEMORY */
|
|
{
|
|
XPutImage(SDL_Display, SDL_Window, SDL_GC, SDL_Ximage,
|
|
0, 0, 0, 0, this->screen->w, this->screen->h);
|
|
}
|
|
XSync(SDL_Display, False);
|
|
}
|
|
|