src/video/x11/SDL_x11image.c
author Ryan C. Gordon <icculus@icculus.org>
Wed, 22 Mar 2006 05:00:59 +0000
changeset 1575 3ba88cb7eb1b
parent 1402 d910939febfa
child 1658 e49147870aac
child 1895 c121d94672cb
child 4159 a1b03ba2fcd0
permissions -rw-r--r--
Updated dynamic X11 code. See details in Bugzilla #170.
slouken@0
     1
/*
slouken@0
     2
    SDL - Simple DirectMedia Layer
slouken@1312
     3
    Copyright (C) 1997-2006 Sam Lantinga
slouken@0
     4
slouken@0
     5
    This library is free software; you can redistribute it and/or
slouken@1312
     6
    modify it under the terms of the GNU Lesser General Public
slouken@0
     7
    License as published by the Free Software Foundation; either
slouken@1312
     8
    version 2.1 of the License, or (at your option) any later version.
slouken@0
     9
slouken@0
    10
    This library is distributed in the hope that it will be useful,
slouken@0
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@0
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@1312
    13
    Lesser General Public License for more details.
slouken@0
    14
slouken@1312
    15
    You should have received a copy of the GNU Lesser General Public
slouken@1312
    16
    License along with this library; if not, write to the Free Software
slouken@1312
    17
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
slouken@0
    18
slouken@0
    19
    Sam Lantinga
slouken@252
    20
    slouken@libsdl.org
slouken@0
    21
*/
slouken@1402
    22
#include "SDL_config.h"
slouken@0
    23
slouken@1338
    24
#include <stdio.h>
slouken@166
    25
#include <unistd.h>
slouken@0
    26
slouken@0
    27
#include "SDL_endian.h"
slouken@1361
    28
#include "../../events/SDL_events_c.h"
slouken@0
    29
#include "SDL_x11image_c.h"
slouken@0
    30
slouken@0
    31
#ifndef NO_SHARED_MEMORY
slouken@0
    32
slouken@0
    33
/* Shared memory error handler routine */
slouken@0
    34
static int shm_error;
slouken@0
    35
static int (*X_handler)(Display *, XErrorEvent *) = NULL;
slouken@0
    36
static int shm_errhandler(Display *d, XErrorEvent *e)
slouken@0
    37
{
slouken@0
    38
        if ( e->error_code == BadAccess ) {
slouken@810
    39
        	shm_error = True;
slouken@0
    40
        	return(0);
slouken@0
    41
        } else
slouken@0
    42
		return(X_handler(d,e));
slouken@0
    43
}
slouken@270
    44
slouken@270
    45
static void try_mitshm(_THIS, SDL_Surface *screen)
slouken@270
    46
{
icculus@1575
    47
	/* Dynamic X11 may not have SHM entry points on this box. */
icculus@1575
    48
	if ((use_mitshm) && (!SDL_X11_HAVE_SHM))
icculus@1575
    49
		use_mitshm = 0;
icculus@1575
    50
slouken@270
    51
	if(!use_mitshm)
slouken@270
    52
		return;
slouken@270
    53
	shminfo.shmid = shmget(IPC_PRIVATE, screen->h*screen->pitch,
slouken@270
    54
			       IPC_CREAT | 0777);
slouken@270
    55
	if ( shminfo.shmid >= 0 ) {
slouken@270
    56
		shminfo.shmaddr = (char *)shmat(shminfo.shmid, 0, 0);
slouken@270
    57
		shminfo.readOnly = False;
slouken@270
    58
		if ( shminfo.shmaddr != (char *)-1 ) {
slouken@270
    59
			shm_error = False;
icculus@1575
    60
			X_handler = XSetErrorHandler(shm_errhandler);
icculus@1575
    61
			XShmAttach(SDL_Display, &shminfo);
icculus@1575
    62
			XSync(SDL_Display, True);
icculus@1575
    63
			XSetErrorHandler(X_handler);
slouken@810
    64
			if ( shm_error )
slouken@270
    65
				shmdt(shminfo.shmaddr);
slouken@270
    66
		} else {
slouken@270
    67
			shm_error = True;
slouken@270
    68
		}
slouken@270
    69
		shmctl(shminfo.shmid, IPC_RMID, NULL);
slouken@270
    70
	} else {
slouken@270
    71
		shm_error = True;
slouken@270
    72
	}
slouken@270
    73
	if ( shm_error )
slouken@270
    74
		use_mitshm = 0;
slouken@270
    75
	if ( use_mitshm )
slouken@270
    76
		screen->pixels = shminfo.shmaddr;
slouken@270
    77
}
slouken@0
    78
#endif /* ! NO_SHARED_MEMORY */
slouken@0
    79
slouken@0
    80
/* Various screen update functions available */
slouken@0
    81
static void X11_NormalUpdate(_THIS, int numrects, SDL_Rect *rects);
slouken@0
    82
static void X11_MITSHMUpdate(_THIS, int numrects, SDL_Rect *rects);
slouken@0
    83
slouken@0
    84
int X11_SetupImage(_THIS, SDL_Surface *screen)
slouken@0
    85
{
slouken@270
    86
#ifndef NO_SHARED_MEMORY
slouken@270
    87
	try_mitshm(this, screen);
slouken@270
    88
	if(use_mitshm) {
icculus@1575
    89
		SDL_Ximage = XShmCreateImage(SDL_Display, SDL_Visual,
slouken@270
    90
					     this->hidden->depth, ZPixmap,
slouken@270
    91
					     shminfo.shmaddr, &shminfo, 
slouken@270
    92
					     screen->w, screen->h);
slouken@270
    93
		if(!SDL_Ximage) {
icculus@1575
    94
			XShmDetach(SDL_Display, &shminfo);
icculus@1575
    95
			XSync(SDL_Display, False);
slouken@270
    96
			shmdt(shminfo.shmaddr);
slouken@270
    97
			screen->pixels = NULL;
slouken@270
    98
			goto error;
slouken@0
    99
		}
slouken@270
   100
		this->UpdateRects = X11_MITSHMUpdate;
slouken@0
   101
	}
slouken@551
   102
	if(!use_mitshm)
slouken@270
   103
#endif /* not NO_SHARED_MEMORY */
slouken@551
   104
	{
slouken@270
   105
		int bpp;
slouken@1336
   106
		screen->pixels = SDL_malloc(screen->h*screen->pitch);
slouken@270
   107
		if ( screen->pixels == NULL ) {
slouken@270
   108
			SDL_OutOfMemory();
slouken@270
   109
			return -1;
slouken@270
   110
		}
slouken@270
   111
 	        bpp = screen->format->BytesPerPixel;
icculus@1575
   112
		SDL_Ximage = XCreateImage(SDL_Display, SDL_Visual,
slouken@0
   113
					  this->hidden->depth, ZPixmap, 0,
slouken@0
   114
					  (char *)screen->pixels, 
slouken@0
   115
					  screen->w, screen->h,
slouken@270
   116
					  32, 0);
slouken@270
   117
		if ( SDL_Ximage == NULL )
slouken@270
   118
			goto error;
slouken@270
   119
		/* XPutImage will convert byte sex automatically */
slouken@270
   120
		SDL_Ximage->byte_order = (SDL_BYTEORDER == SDL_BIG_ENDIAN)
slouken@270
   121
			                 ? MSBFirst : LSBFirst;
slouken@270
   122
		this->UpdateRects = X11_NormalUpdate;
slouken@0
   123
	}
slouken@0
   124
	screen->pitch = SDL_Ximage->bytes_per_line;
slouken@270
   125
	return(0);
slouken@0
   126
slouken@270
   127
error:
slouken@270
   128
	SDL_SetError("Couldn't create XImage");
slouken@270
   129
	return 1;
slouken@0
   130
}
slouken@0
   131
slouken@0
   132
void X11_DestroyImage(_THIS, SDL_Surface *screen)
slouken@0
   133
{
slouken@0
   134
	if ( SDL_Ximage ) {
icculus@1575
   135
		XDestroyImage(SDL_Ximage);
slouken@0
   136
#ifndef NO_SHARED_MEMORY
slouken@0
   137
		if ( use_mitshm ) {
icculus@1575
   138
			XShmDetach(SDL_Display, &shminfo);
icculus@1575
   139
			XSync(SDL_Display, False);
slouken@0
   140
			shmdt(shminfo.shmaddr);
slouken@0
   141
		}
slouken@0
   142
#endif /* ! NO_SHARED_MEMORY */
slouken@0
   143
		SDL_Ximage = NULL;
slouken@0
   144
	}
slouken@0
   145
	if ( screen ) {
slouken@0
   146
		screen->pixels = NULL;
slouken@0
   147
	}
slouken@0
   148
}
slouken@0
   149
slouken@166
   150
/* Determine the number of CPUs in the system */
slouken@0
   151
static int num_CPU(void)
slouken@0
   152
{
slouken@0
   153
       static int num_cpus = 0;
slouken@0
   154
slouken@0
   155
       if(!num_cpus) {
slouken@1402
   156
#if defined(__LINUX__)
slouken@0
   157
           char line[BUFSIZ];
slouken@0
   158
           FILE *pstat = fopen("/proc/stat", "r");
slouken@0
   159
           if ( pstat ) {
slouken@0
   160
               while ( fgets(line, sizeof(line), pstat) ) {
slouken@1336
   161
                   if (SDL_memcmp(line, "cpu", 3) == 0 && line[3] != ' ') {
slouken@0
   162
                       ++num_cpus;
slouken@0
   163
                   }
slouken@0
   164
               }
slouken@0
   165
               fclose(pstat);
slouken@0
   166
           }
slouken@1402
   167
#elif defined(__IRIX__)
slouken@605
   168
	   num_cpus = sysconf(_SC_NPROC_ONLN);
slouken@166
   169
#elif defined(_SC_NPROCESSORS_ONLN)
slouken@166
   170
	   /* number of processors online (SVR4.0MP compliant machines) */
slouken@166
   171
           num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
slouken@166
   172
#elif defined(_SC_NPROCESSORS_CONF)
slouken@166
   173
	   /* number of processors configured (SVR4.0MP compliant machines) */
slouken@166
   174
           num_cpus = sysconf(_SC_NPROCESSORS_CONF);
slouken@0
   175
#endif
slouken@0
   176
           if ( num_cpus <= 0 ) {
slouken@0
   177
               num_cpus = 1;
slouken@0
   178
           }
slouken@0
   179
       }
slouken@0
   180
       return num_cpus;
slouken@0
   181
}
slouken@0
   182
slouken@0
   183
int X11_ResizeImage(_THIS, SDL_Surface *screen, Uint32 flags)
slouken@0
   184
{
slouken@0
   185
	int retval;
slouken@0
   186
slouken@0
   187
	X11_DestroyImage(this, screen);
slouken@0
   188
        if ( flags & SDL_OPENGL ) {  /* No image when using GL */
slouken@0
   189
        	retval = 0;
slouken@0
   190
        } else {
slouken@0
   191
		retval = X11_SetupImage(this, screen);
slouken@0
   192
		/* We support asynchronous blitting on the display */
slouken@0
   193
		if ( flags & SDL_ASYNCBLIT ) {
slouken@0
   194
			/* This is actually slower on single-CPU systems,
slouken@0
   195
			   probably because of CPU contention between the
slouken@0
   196
			   X server and the application.
slouken@0
   197
			   Note: Is this still true with XFree86 4.0?
slouken@0
   198
			*/
slouken@0
   199
			if ( num_CPU() > 1 ) {
slouken@0
   200
				screen->flags |= SDL_ASYNCBLIT;
slouken@0
   201
			}
slouken@0
   202
		}
slouken@0
   203
	}
slouken@0
   204
	return(retval);
slouken@0
   205
}
slouken@0
   206
slouken@0
   207
/* We don't actually allow hardware surfaces other than the main one */
slouken@0
   208
int X11_AllocHWSurface(_THIS, SDL_Surface *surface)
slouken@0
   209
{
slouken@0
   210
	return(-1);
slouken@0
   211
}
slouken@0
   212
void X11_FreeHWSurface(_THIS, SDL_Surface *surface)
slouken@0
   213
{
slouken@0
   214
	return;
slouken@0
   215
}
slouken@0
   216
slouken@0
   217
int X11_LockHWSurface(_THIS, SDL_Surface *surface)
slouken@0
   218
{
slouken@0
   219
	if ( (surface == SDL_VideoSurface) && blit_queued ) {
icculus@1575
   220
		XSync(GFX_Display, False);
slouken@0
   221
		blit_queued = 0;
slouken@0
   222
	}
slouken@0
   223
	return(0);
slouken@0
   224
}
slouken@0
   225
void X11_UnlockHWSurface(_THIS, SDL_Surface *surface)
slouken@0
   226
{
slouken@0
   227
	return;
slouken@0
   228
}
slouken@0
   229
slouken@0
   230
int X11_FlipHWSurface(_THIS, SDL_Surface *surface)
slouken@0
   231
{
slouken@0
   232
	return(0);
slouken@0
   233
}
slouken@0
   234
slouken@0
   235
static void X11_NormalUpdate(_THIS, int numrects, SDL_Rect *rects)
slouken@0
   236
{
slouken@0
   237
	int i;
slouken@270
   238
	
slouken@270
   239
	for (i = 0; i < numrects; ++i) {
slouken@270
   240
		if ( rects[i].w == 0 || rects[i].h == 0 ) { /* Clipped? */
slouken@270
   241
			continue;
slouken@0
   242
		}
icculus@1575
   243
		XPutImage(GFX_Display, SDL_Window, SDL_GC, SDL_Ximage,
slouken@270
   244
			  rects[i].x, rects[i].y,
slouken@270
   245
			  rects[i].x, rects[i].y, rects[i].w, rects[i].h);
slouken@0
   246
	}
slouken@0
   247
	if ( SDL_VideoSurface->flags & SDL_ASYNCBLIT ) {
icculus@1575
   248
		XFlush(GFX_Display);
slouken@270
   249
		blit_queued = 1;
slouken@0
   250
	} else {
icculus@1575
   251
		XSync(GFX_Display, False);
slouken@0
   252
	}
slouken@0
   253
}
slouken@0
   254
slouken@0
   255
static void X11_MITSHMUpdate(_THIS, int numrects, SDL_Rect *rects)
slouken@0
   256
{
slouken@0
   257
#ifndef NO_SHARED_MEMORY
slouken@0
   258
	int i;
slouken@0
   259
slouken@0
   260
	for ( i=0; i<numrects; ++i ) {
slouken@270
   261
		if ( rects[i].w == 0 || rects[i].h == 0 ) { /* Clipped? */
slouken@0
   262
			continue;
slouken@0
   263
		}
icculus@1575
   264
		XShmPutImage(GFX_Display, SDL_Window, SDL_GC, SDL_Ximage,
slouken@0
   265
				rects[i].x, rects[i].y,
slouken@0
   266
				rects[i].x, rects[i].y, rects[i].w, rects[i].h,
slouken@0
   267
									False);
slouken@0
   268
	}
slouken@0
   269
	if ( SDL_VideoSurface->flags & SDL_ASYNCBLIT ) {
icculus@1575
   270
		XFlush(GFX_Display);
slouken@270
   271
		blit_queued = 1;
slouken@0
   272
	} else {
icculus@1575
   273
		XSync(GFX_Display, False);
slouken@0
   274
	}
slouken@0
   275
#endif /* ! NO_SHARED_MEMORY */
slouken@0
   276
}
slouken@0
   277
slouken@0
   278
/* There's a problem with the automatic refreshing of the display.
slouken@0
   279
   Even though the XVideo code uses the GFX_Display to update the
slouken@0
   280
   video memory, it appears that updating the window asynchronously
slouken@0
   281
   from a different thread will cause "blackouts" of the window.
slouken@0
   282
   This is a sort of a hacked workaround for the problem.
slouken@0
   283
*/
slouken@0
   284
static int enable_autorefresh = 1;
slouken@0
   285
slouken@0
   286
void X11_DisableAutoRefresh(_THIS)
slouken@0
   287
{
slouken@0
   288
	--enable_autorefresh;
slouken@0
   289
}
slouken@0
   290
slouken@0
   291
void X11_EnableAutoRefresh(_THIS)
slouken@0
   292
{
slouken@0
   293
	++enable_autorefresh;
slouken@0
   294
}
slouken@0
   295
slouken@0
   296
void X11_RefreshDisplay(_THIS)
slouken@0
   297
{
slouken@161
   298
	/* Don't refresh a display that doesn't have an image (like GL)
slouken@161
   299
	   Instead, post an expose event so the application can refresh.
slouken@161
   300
	 */
slouken@0
   301
	if ( ! SDL_Ximage || (enable_autorefresh <= 0) ) {
slouken@161
   302
		SDL_PrivateExpose();
slouken@0
   303
		return;
slouken@0
   304
	}
slouken@0
   305
#ifndef NO_SHARED_MEMORY
slouken@0
   306
	if ( this->UpdateRects == X11_MITSHMUpdate ) {
icculus@1575
   307
		XShmPutImage(SDL_Display, SDL_Window, SDL_GC, SDL_Ximage,
slouken@0
   308
				0, 0, 0, 0, this->screen->w, this->screen->h,
slouken@0
   309
				False);
slouken@270
   310
	} else
slouken@270
   311
#endif /* ! NO_SHARED_MEMORY */
slouken@0
   312
	{
icculus@1575
   313
		XPutImage(SDL_Display, SDL_Window, SDL_GC, SDL_Ximage,
slouken@270
   314
			  0, 0, 0, 0, this->screen->w, this->screen->h);
slouken@0
   315
	}
icculus@1575
   316
	XSync(SDL_Display, False);
slouken@0
   317
}
icculus@1575
   318