Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4680 right-hear 1
/*
2
 * Blit RGBA images to X with X(Shm)Images
3
 */
4
 
5
#ifndef _XOPEN_SOURCE
6
# define _XOPEN_SOURCE 1
7
#endif
8
 
9
#ifndef _XOPEN_SOURCE
10
# define _XOPEN_SOURCE 1
11
#endif
12
 
13
#define noSHOWINFO
14
 
15
#include "fitz.h"
16
 
17
#include 
18
#include 
19
#include 
20
#include 
21
#include 
22
 
23
extern int ffs(int);
24
 
25
typedef void (*ximage_convert_func_t)
26
(
27
	const unsigned char *src,
28
	int srcstride,
29
	unsigned char *dst,
30
	int dststride,
31
	int w,
32
	int h
33
	);
34
 
35
#define POOLSIZE 4
36
#define WIDTH 256
37
#define HEIGHT 256
38
 
39
enum {
40
	ARGB8888,
41
	BGRA8888,
42
	RGBA8888,
43
	ABGR8888,
44
	RGB888,
45
	BGR888,
46
	RGB565,
47
	RGB565_BR,
48
	RGB555,
49
	RGB555_BR,
50
	BGR233,
51
	UNKNOWN
52
};
53
 
54
#ifdef SHOWINFO
55
static char *modename[] = {
56
	"ARGB8888",
57
	"BGRA8888",
58
	"RGBA8888",
59
	"ABGR8888",
60
	"RGB888",
61
	"BGR888",
62
	"RGB565",
63
	"RGB565_BR",
64
	"RGB555",
65
	"RGB555_BR",
66
	"BGR233",
67
	"UNKNOWN"
68
};
69
#endif
70
 
71
extern ximage_convert_func_t ximage_convert_funcs[];
72
 
73
static struct
74
{
75
	Display *display;
76
	int screen;
77
	XVisualInfo visual;
78
	Colormap colormap;
79
 
80
	int bitsperpixel;
81
	int mode;
82
 
83
	XColor rgbcube[256];
84
 
85
	ximage_convert_func_t convert_func;
86
 
87
	int useshm;
88
	int shmcode;
89
	XImage *pool[POOLSIZE];
90
	/* MUST exist during the lifetime of the shared ximage according to the
91
	xc/doc/hardcopy/Xext/mit-shm.PS.gz */
92
	XShmSegmentInfo shminfo[POOLSIZE];
93
	int lastused;
94
} info;
95
 
96
static XImage *
97
createximage(Display *dpy, Visual *vis, XShmSegmentInfo *xsi, int depth, int w, int h)
98
{
99
	XImage *img;
100
	Status status;
101
 
102
	if (!XShmQueryExtension(dpy))
103
		goto fallback;
104
	if (!info.useshm)
105
		goto fallback;
106
 
107
	img = XShmCreateImage(dpy, vis, depth, ZPixmap, NULL, xsi, w, h);
108
	if (!img)
109
	{
110
		fprintf(stderr, "warn: could not XShmCreateImage\n");
111
		goto fallback;
112
	}
113
 
114
	xsi->shmid = shmget(IPC_PRIVATE,
115
		img->bytes_per_line * img->height,
116
		IPC_CREAT | 0777);
117
	if (xsi->shmid < 0)
118
	{
119
		XDestroyImage(img);
120
		fprintf(stderr, "warn: could not shmget\n");
121
		goto fallback;
122
	}
123
 
124
	img->data = xsi->shmaddr = shmat(xsi->shmid, NULL, 0);
125
	if (img->data == (char*)-1)
126
	{
127
		XDestroyImage(img);
128
		fprintf(stderr, "warn: could not shmat\n");
129
		goto fallback;
130
	}
131
 
132
	xsi->readOnly = False;
133
	status = XShmAttach(dpy, xsi);
134
	if (!status)
135
	{
136
		shmdt(xsi->shmaddr);
137
		XDestroyImage(img);
138
		fprintf(stderr, "warn: could not XShmAttach\n");
139
		goto fallback;
140
	}
141
 
142
	XSync(dpy, False);
143
 
144
	shmctl(xsi->shmid, IPC_RMID, NULL);
145
 
146
	return img;
147
 
148
fallback:
149
	info.useshm = 0;
150
 
151
	img = XCreateImage(dpy, vis, depth, ZPixmap, 0, NULL, w, h, 32, 0);
152
	if (!img)
153
	{
154
		fprintf(stderr, "fail: could not XCreateImage");
155
		abort();
156
	}
157
 
158
	img->data = malloc(h * img->bytes_per_line);
159
	if (!img->data)
160
	{
161
		fprintf(stderr, "fail: could not malloc");
162
		abort();
163
	}
164
 
165
	return img;
166
}
167
 
168
static void
169
make_colormap(void)
170
{
171
	if (info.visual.class == PseudoColor && info.visual.depth == 8)
172
	{
173
		int i, r, g, b;
174
		i = 0;
175
		for (b = 0; b < 4; b++) {
176
			for (g = 0; g < 8; g++) {
177
				for (r = 0; r < 8; r++) {
178
					info.rgbcube[i].pixel = i;
179
					info.rgbcube[i].red = (r * 36) << 8;
180
					info.rgbcube[i].green = (g * 36) << 8;
181
					info.rgbcube[i].blue = (b * 85) << 8;
182
					info.rgbcube[i].flags =
183
					DoRed | DoGreen | DoBlue;
184
					i++;
185
				}
186
			}
187
		}
188
		info.colormap = XCreateColormap(info.display,
189
			RootWindow(info.display, info.screen),
190
			info.visual.visual,
191
			AllocAll);
192
		XStoreColors(info.display, info.colormap, info.rgbcube, 256);
193
		return;
194
	}
195
	else if (info.visual.class == TrueColor)
196
	{
197
		info.colormap = 0;
198
		return;
199
	}
200
	fprintf(stderr, "Cannot handle visual class %d with depth: %d\n",
201
		info.visual.class, info.visual.depth);
202
	return;
203
}
204
 
205
static void
206
select_mode(void)
207
{
208
 
209
	int byteorder;
210
	int byterev;
211
	unsigned long rm, gm, bm;
212
	unsigned long rs, gs, bs;
213
 
214
	byteorder = ImageByteOrder(info.display);
215
	if (fz_is_big_endian())
216
		byterev = byteorder != MSBFirst;
217
	else
218
		byterev = byteorder != LSBFirst;
219
 
220
	rm = info.visual.red_mask;
221
	gm = info.visual.green_mask;
222
	bm = info.visual.blue_mask;
223
 
224
	rs = ffs(rm) - 1;
225
	gs = ffs(gm) - 1;
226
	bs = ffs(bm) - 1;
227
 
228
#ifdef SHOWINFO
229
	printf("ximage: mode %d/%d %08lx %08lx %08lx (%ld,%ld,%ld) %s%s\n",
230
		info.visual.depth,
231
		info.bitsperpixel,
232
		rm, gm, bm, rs, gs, bs,
233
		byteorder == MSBFirst ? "msb" : "lsb",
234
		byterev ? " ":"");
235
#endif
236
 
237
	info.mode = UNKNOWN;
238
	if (info.bitsperpixel == 8) {
239
		/* Either PseudoColor with BGR233 colormap, or TrueColor */
240
		info.mode = BGR233;
241
	}
242
	else if (info.bitsperpixel == 16) {
243
		if (rm == 0xF800 && gm == 0x07E0 && bm == 0x001F)
244
			info.mode = !byterev ? RGB565 : RGB565_BR;
245
		if (rm == 0x7C00 && gm == 0x03E0 && bm == 0x001F)
246
			info.mode = !byterev ? RGB555 : RGB555_BR;
247
	}
248
	else if (info.bitsperpixel == 24) {
249
		if (rs == 0 && gs == 8 && bs == 16)
250
			info.mode = byteorder == MSBFirst ? RGB888 : BGR888;
251
		if (rs == 16 && gs == 8 && bs == 0)
252
			info.mode = byteorder == MSBFirst ? BGR888 : RGB888;
253
	}
254
	else if (info.bitsperpixel == 32) {
255
		if (rs == 0 && gs == 8 && bs == 16)
256
			info.mode = byteorder == MSBFirst ? ABGR8888 : RGBA8888;
257
		if (rs == 8 && gs == 16 && bs == 24)
258
			info.mode = byteorder == MSBFirst ? BGRA8888 : ARGB8888;
259
		if (rs == 16 && gs == 8 && bs == 0)
260
			info.mode = byteorder == MSBFirst ? ARGB8888 : BGRA8888;
261
		if (rs == 24 && gs == 16 && bs == 8)
262
			info.mode = byteorder == MSBFirst ? RGBA8888 : ABGR8888;
263
	}
264
 
265
#ifdef SHOWINFO
266
	printf("ximage: RGBA8888 to %s\n", modename[info.mode]);
267
#endif
268
 
269
	/* select conversion function */
270
	info.convert_func = ximage_convert_funcs[info.mode];
271
}
272
 
273
static int
274
create_pool(void)
275
{
276
	int i;
277
 
278
	info.lastused = 0;
279
 
280
	for (i = 0; i < POOLSIZE; i++) {
281
		info.pool[i] = NULL;
282
	}
283
 
284
	for (i = 0; i < POOLSIZE; i++) {
285
		info.pool[i] = createximage(info.display,
286
			info.visual.visual, &info.shminfo[i], info.visual.depth,
287
			WIDTH, HEIGHT);
288
		if (info.pool[i] == NULL) {
289
			return 0;
290
		}
291
	}
292
 
293
	return 1;
294
}
295
 
296
static XImage *
297
next_pool_image(void)
298
{
299
	if (info.lastused + 1 >= POOLSIZE) {
300
		if (info.useshm)
301
			XSync(info.display, False);
302
		else
303
			XFlush(info.display);
304
		info.lastused = 0;
305
	}
306
	return info.pool[info.lastused ++];
307
}
308
 
309
static int
310
ximage_error_handler(Display *display, XErrorEvent *event)
311
{
312
	/* Turn off shared memory images if we get an error from the MIT-SHM extension */
313
	if (event->request_code == info.shmcode)
314
	{
315
		char buf[80];
316
		XGetErrorText(display, event->error_code, buf, sizeof buf);
317
		fprintf(stderr, "ximage: disabling shared memory extension: %s\n", buf);
318
		info.useshm = 0;
319
		return 0;
320
	}
321
 
322
	XSetErrorHandler(NULL);
323
	return (XSetErrorHandler(ximage_error_handler))(display, event);
324
}
325
 
326
int
327
ximage_init(Display *display, int screen, Visual *visual)
328
{
329
	XVisualInfo template;
330
	XVisualInfo *visuals;
331
	int nvisuals;
332
	XPixmapFormatValues *formats;
333
	int nformats;
334
	int ok;
335
	int i;
336
	int major;
337
	int event;
338
	int error;
339
 
340
	info.display = display;
341
	info.screen = screen;
342
	info.colormap = 0;
343
 
344
	/* Get XVisualInfo for this visual */
345
	template.visualid = XVisualIDFromVisual(visual);
346
	visuals = XGetVisualInfo(display, VisualIDMask, &template, &nvisuals);
347
	if (nvisuals != 1) {
348
		fprintf(stderr, "Visual not found!\n");
349
		XFree(visuals);
350
		return 0;
351
	}
352
	memcpy(&info.visual, visuals, sizeof (XVisualInfo));
353
	XFree(visuals);
354
 
355
	/* Get appropriate PixmapFormat for this visual */
356
	formats = XListPixmapFormats(info.display, &nformats);
357
	for (i = 0; i < nformats; i++) {
358
		if (formats[i].depth == info.visual.depth) {
359
			info.bitsperpixel = formats[i].bits_per_pixel;
360
			break;
361
		}
362
	}
363
	XFree(formats);
364
	if (i == nformats) {
365
		fprintf(stderr, "PixmapFormat not found!\n");
366
		return 0;
367
	}
368
 
369
	/* extract mode */
370
	select_mode();
371
 
372
	/* prepare colormap */
373
	make_colormap();
374
 
375
	/* identify code for MIT-SHM extension */
376
	if (XQueryExtension(display, "MIT-SHM", &major, &event, &error) &&
377
		XShmQueryExtension(display))
378
		info.shmcode = major;
379
 
380
	/* intercept errors looking for SHM code */
381
	XSetErrorHandler(ximage_error_handler);
382
 
383
	/* prepare pool of XImages */
384
	info.useshm = 1;
385
	ok = create_pool();
386
	if (!ok)
387
		return 0;
388
 
389
#ifdef SHOWINFO
390
	printf("ximage: %sPutImage\n", info.useshm ? "XShm" : "X");
391
#endif
392
 
393
	return 1;
394
}
395
 
396
int
397
ximage_get_depth(void)
398
{
399
	return info.visual.depth;
400
}
401
 
402
Visual *
403
ximage_get_visual(void)
404
{
405
	return info.visual.visual;
406
}
407
 
408
Colormap
409
ximage_get_colormap(void)
410
{
411
	return info.colormap;
412
}
413
 
414
void
415
ximage_blit(Drawable d, GC gc,
416
	int dstx, int dsty,
417
	unsigned char *srcdata,
418
	int srcx, int srcy,
419
	int srcw, int srch,
420
	int srcstride)
421
{
422
	XImage *image;
423
	int ax, ay;
424
	int w, h;
425
	unsigned char *srcptr;
426
 
427
	for (ay = 0; ay < srch; ay += HEIGHT)
428
	{
429
		h = MIN(srch - ay, HEIGHT);
430
		for (ax = 0; ax < srcw; ax += WIDTH)
431
		{
432
			w = MIN(srcw - ax, WIDTH);
433
 
434
			image = next_pool_image();
435
 
436
			srcptr = srcdata +
437
			(ay + srcy) * srcstride +
438
			(ax + srcx) * 4;
439
 
440
			info.convert_func(srcptr, srcstride,
441
				(unsigned char *) image->data,
442
				image->bytes_per_line, w, h);
443
 
444
			if (info.useshm)
445
			{
446
				XShmPutImage(info.display, d, gc, image,
447
					0, 0, dstx + ax, dsty + ay,
448
					w, h, False);
449
			}
450
			else
451
			{
452
				XPutImage(info.display, d, gc, image,
453
					0, 0,
454
					dstx + ax,
455
					dsty + ay,
456
					w, h);
457
			}
458
		}
459
	}
460
}
461
 
462
/*
463
 * Primitive conversion functions
464
 */
465
 
466
#ifndef restrict
467
#ifndef _C99
468
#ifdef __GNUC__
469
#define restrict __restrict__
470
#else
471
#define restrict
472
#endif
473
#endif
474
#endif
475
 
476
#define PARAMS \
477
	const unsigned char * restrict src, \
478
	int srcstride, \
479
	unsigned char * restrict dst, \
480
	int dststride, \
481
	int w, \
482
	int h
483
 
484
/*
485
 * Convert byte:RGBA8888 to various formats
486
 */
487
 
488
static void
489
ximage_convert_argb8888(PARAMS)
490
{
491
	int x, y;
492
	for (y = 0; y < h; y++) {
493
		for (x = 0; x < w; x ++) {
494
			dst[x * 4 + 0] = src[x * 4 + 3]; /* a */
495
			dst[x * 4 + 1] = src[x * 4 + 0]; /* r */
496
			dst[x * 4 + 2] = src[x * 4 + 1]; /* g */
497
			dst[x * 4 + 3] = src[x * 4 + 2]; /* b */
498
		}
499
		dst += dststride;
500
		src += srcstride;
501
	}
502
}
503
 
504
static void
505
ximage_convert_bgra8888(PARAMS)
506
{
507
	int x, y;
508
	for (y = 0; y < h; y++) {
509
		for (x = 0; x < w; x++) {
510
			dst[x * 4 + 0] = src[x * 4 + 2];
511
			dst[x * 4 + 1] = src[x * 4 + 1];
512
			dst[x * 4 + 2] = src[x * 4 + 0];
513
			dst[x * 4 + 3] = src[x * 4 + 3];
514
		}
515
		dst += dststride;
516
		src += srcstride;
517
	}
518
}
519
 
520
static void
521
ximage_convert_abgr8888(PARAMS)
522
{
523
	int x, y;
524
	for (y = 0; y < h; y++) {
525
		for (x = 0; x < w; x++) {
526
			dst[x * 4 + 0] = src[x * 4 + 3];
527
			dst[x * 4 + 1] = src[x * 4 + 2];
528
			dst[x * 4 + 2] = src[x * 4 + 1];
529
			dst[x * 4 + 3] = src[x * 4 + 0];
530
		}
531
		dst += dststride;
532
		src += srcstride;
533
	}
534
}
535
 
536
static void
537
ximage_convert_rgba8888(PARAMS)
538
{
539
	int x, y;
540
	for (y = 0; y < h; y++) {
541
		for (x = 0; x < w; x++) {
542
			dst[x] = src[x];
543
		}
544
		dst += dststride;
545
		src += srcstride;
546
	}
547
}
548
 
549
static void
550
ximage_convert_bgr888(PARAMS)
551
{
552
	int x, y;
553
	for (y = 0; y < h; y++) {
554
		for (x = 0; x < w; x++) {
555
			dst[3*x + 0] = src[4*x + 2];
556
			dst[3*x + 1] = src[4*x + 1];
557
			dst[3*x + 2] = src[4*x + 0];
558
		}
559
		src += srcstride;
560
		dst += dststride;
561
	}
562
}
563
 
564
static void
565
ximage_convert_rgb888(PARAMS)
566
{
567
	int x, y;
568
	for (y = 0; y < h; y++) {
569
		for (x = 0; x < w; x++) {
570
			dst[3*x + 0] = src[4*x + 0];
571
			dst[3*x + 1] = src[4*x + 1];
572
			dst[3*x + 2] = src[4*x + 2];
573
		}
574
		src += srcstride;
575
		dst += dststride;
576
	}
577
}
578
 
579
static void
580
ximage_convert_rgb565(PARAMS)
581
{
582
	unsigned char r, g, b;
583
	int x, y;
584
	for (y = 0; y < h; y++) {
585
		for (x = 0; x < w; x++) {
586
			r = src[4*x + 0];
587
			g = src[4*x + 1];
588
			b = src[4*x + 2];
589
			((unsigned short *)dst)[x] =
590
			((r & 0xF8) << 8) |
591
			((g & 0xFC) << 3) |
592
			(b >> 3);
593
		}
594
		src += srcstride;
595
		dst += dststride;
596
	}
597
}
598
 
599
static void
600
ximage_convert_rgb565_br(PARAMS)
601
{
602
	unsigned char r, g, b;
603
	int x, y;
604
	for (y = 0; y < h; y++) {
605
		for (x = 0; x < w; x++) {
606
			r = src[4*x + 0];
607
			g = src[4*x + 1];
608
			b = src[4*x + 2];
609
			/* final word is:
610
			g4 g3 g2 b7 b6 b5 b4 b3 : r7 r6 r5 r4 r3 g7 g6 g5
611
			*/
612
			((unsigned short *)dst)[x] =
613
			(r & 0xF8) |
614
			((g & 0xE0) >> 5) |
615
			((g & 0x1C) << 11) |
616
			((b & 0xF8) << 5);
617
		}
618
		src += srcstride;
619
		dst += dststride;
620
	}
621
}
622
 
623
static void
624
ximage_convert_rgb555(PARAMS)
625
{
626
	unsigned char r, g, b;
627
	int x, y;
628
	for (y = 0; y < h; y++) {
629
		for (x = 0; x < w; x++) {
630
			r = src[4*x + 0];
631
			g = src[4*x + 1];
632
			b = src[4*x + 2];
633
			((unsigned short *)dst)[x] =
634
			((r & 0xF8) << 7) |
635
			((g & 0xF8) << 2) |
636
			(b >> 3);
637
		}
638
		src += srcstride;
639
		dst += dststride;
640
	}
641
}
642
 
643
static void
644
ximage_convert_rgb555_br(PARAMS)
645
{
646
	unsigned char r, g, b;
647
	int x, y;
648
	for (y = 0; y < h; y++) {
649
		for (x = 0; x < w; x++) {
650
			r = src[4*x + 0];
651
			g = src[4*x + 1];
652
			b = src[4*x + 2];
653
			/* final word is:
654
			g5 g4 g3 b7 b6 b5 b4 b3 : 0 r7 r6 r5 r4 r3 g7 g6
655
			*/
656
			((unsigned short *)dst)[x] =
657
			((r & 0xF8) >> 1) |
658
			((g & 0xC0) >> 6) |
659
			((g & 0x38) << 10) |
660
			((b & 0xF8) << 5);
661
		}
662
		src += srcstride;
663
		dst += dststride;
664
	}
665
}
666
 
667
static void
668
ximage_convert_bgr233(PARAMS)
669
{
670
	unsigned char r, g, b;
671
	int x,y;
672
	for(y = 0; y < h; y++) {
673
		for(x = 0; x < w; x++) {
674
			r = src[4*x + 0];
675
			g = src[4*x + 1];
676
			b = src[4*x + 2];
677
			/* format: b7 b6 g7 g6 g5 r7 r6 r5 */
678
			dst[x] = (b&0xC0) | ((g>>2)&0x38) | ((r>>5)&0x7);
679
		}
680
		src += srcstride;
681
		dst += dststride;
682
	}
683
}
684
 
685
ximage_convert_func_t ximage_convert_funcs[] = {
686
	ximage_convert_argb8888,
687
	ximage_convert_bgra8888,
688
	ximage_convert_rgba8888,
689
	ximage_convert_abgr8888,
690
	ximage_convert_rgb888,
691
	ximage_convert_bgr888,
692
	ximage_convert_rgb565,
693
	ximage_convert_rgb565_br,
694
	ximage_convert_rgb555,
695
	ximage_convert_rgb555_br,
696
	ximage_convert_bgr233,
697
};