Subversion Repositories Kolibri OS

Rev

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

  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 <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. 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 ? " <swap>":"");
  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. };
  698.