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