aboutsummaryrefslogtreecommitdiffstats
path: root/src/xlib.c
diff options
context:
space:
mode:
authorJohn Hawthorn <jhawthor@uvic.ca>2008-09-13 00:02:38 -0700
committerJohn Hawthorn <jhawthor@uvic.ca>2008-09-13 00:02:38 -0700
commitd9e9f33c3210b71c07c4268415ff9b1555819b3f (patch)
tree1574715591b8ae6cb08771ff19670b56a5c887a9 /src/xlib.c
parent219d3d9d9c17db046755327054be8061bdb2bb7a (diff)
downloadmirror-meh-d9e9f33c3210b71c07c4268415ff9b1555819b3f.tar.gz
mirror-meh-d9e9f33c3210b71c07c4268415ff9b1555819b3f.tar.bz2
mirror-meh-d9e9f33c3210b71c07c4268415ff9b1555819b3f.zip
Major changes. Optional XShm support, bilinear scaling, caching WIP
Diffstat (limited to 'src/xlib.c')
-rw-r--r--src/xlib.c182
1 files changed, 130 insertions, 52 deletions
diff --git a/src/xlib.c b/src/xlib.c
index d36a931..511e740 100644
--- a/src/xlib.c
+++ b/src/xlib.c
@@ -7,6 +7,9 @@
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
+#include <X11/extensions/XShm.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
#include "meh.h"
@@ -16,80 +19,139 @@ int screen;
Window window;
GC gc;
-static unsigned int getshift(unsigned int mask){
-#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
- return __builtin_ctz(mask);
-#else
- int i = 0;
- while((mask & 1) == 0){
- i++;
- mask >>= 1;
+int xshm = 0;
+
+#define GETVAL(x, c) (ibuf[(x) * 3 + (c)])
+#define GETLVAL(x, y, u, v, c) (( \
+ (GETVAL((x), (c)) * (1023^(u)) + GETVAL((x)+1, (c)) * (u)) * (1023^(v)) + \
+ (GETVAL((x)+img->bufwidth, (c)) * (1023^(u)) + GETVAL((x)+img->bufwidth+1, (c)) * (u)) * (v)) >> 20)
+
+void scale(struct image *img, XImage *ximg){
+ int x, y;
+ unsigned char * __restrict__ ibuf;
+ char* __restrict__ newBuf = ximg->data;
+ unsigned int jdy = ximg->bytes_per_line / 4 - ximg->width;
+ unsigned int dx = (img->bufwidth << 10) / ximg->width;
+
+ struct timeval t0;
+ struct timeval t1;
+ gettimeofday(&t0, NULL);
+
+ for(y = 0; y < ximg->height; y++){
+ unsigned int bufy = (y << 10) * img->bufheight / ximg->height;
+ unsigned int v_ratio = (bufy & 1023);
+ unsigned int bufx = img->bufwidth / ximg->width;
+ unsigned char *ibuf = &img->buf[y * img->bufheight / ximg->height * img->bufwidth * 3];
+ for(x = ximg->width; x; x--){
+ unsigned int u_ratio = (bufx & 1023);
+
+ *newBuf++ = GETLVAL(bufx >> 10, bufy >> 10, u_ratio, v_ratio, 2);
+ *newBuf++ = GETLVAL(bufx >> 10, bufy >> 10, u_ratio, v_ratio, 1);
+ *newBuf++ = GETLVAL(bufx >> 10, bufy >> 10, u_ratio, v_ratio, 0);
+ newBuf++;
+
+ bufx += dx;
+ }
+ newBuf += jdy;
}
- return i;
-#endif
+
+ gettimeofday(&t1, NULL);
+ printf("%i ms\n", ((t1.tv_sec - t0.tv_sec) * 1000000 + t1.tv_usec - t0.tv_usec) / 1000);
}
+
+void linearscale(struct image *img, XImage *ximg){
+ unsigned int i;
+ int x, y;
+ unsigned int dx;
+ unsigned char * __restrict__ ibuf;
+ char* __restrict__ newBuf = ximg->data;
+ unsigned int jdy = ximg->bytes_per_line / 4 - ximg->width;
+ dx = (img->bufwidth << 10) / ximg->width;
+
+ struct timeval t0;
+ struct timeval t1;
+ gettimeofday(&t0, NULL);
+
+ for(y = 0; y < ximg->height; y++){
+ i = 0;
+ ibuf = &img->buf[y * img->bufheight / ximg->height * img->bufwidth * 3];
+ for(x = 0; x < ximg->width; x++){
+ *newBuf++ = (ibuf[(i >> 10)*3+2]);
+ *newBuf++ = (ibuf[(i >> 10)*3+1]);
+ *newBuf++ = (ibuf[(i >> 10)*3]);
+ newBuf++;
+
+ i += dx;
+ }
+ newBuf += jdy;
+ }
+
+ gettimeofday(&t1, NULL);
+ printf("%i ms\n", ((t1.tv_sec - t0.tv_sec) * 1000000 + t1.tv_usec - t0.tv_usec) / 1000);
+}
+
+XShmSegmentInfo *shminfo;
XImage *ximage(struct image *img, unsigned int width, unsigned int height) {
int depth;
XImage *ximg = NULL;
Visual *vis;
- unsigned int rshift, gshift, bshift;
- unsigned int i;
- unsigned int x,y;
- unsigned int j = 0;
depth = DefaultDepth(display, screen);
vis = DefaultVisual(display, screen);
- rshift = getshift(vis->red_mask);
- gshift = getshift(vis->green_mask);
- bshift = getshift(vis->blue_mask);
-
- if (depth >= 24) {
- unsigned char *ibuf;
- unsigned int dx;
- size_t numNewBufBytes = ((sizeof(u_int32_t)) * (width) * (height));
- u_int32_t *newBuf = malloc(numNewBufBytes);
-
- dx = 1024 * img->width / width;
- for(y = 0; y < height; y++){
- i = 0;
- ibuf = &img->buf[y * img->height / height * img->width * 3];
- for(x = 0; x < width; x++){
- unsigned int r, g, b;
- r = (ibuf[(i >> 10)*3] << rshift) & vis->red_mask;
- g = (ibuf[(i >> 10)*3+1] << gshift) & vis->green_mask;
- b = (ibuf[(i >> 10)*3+2] << bshift) & vis->blue_mask;
-
- newBuf[j++] = r | g | b;
- i += dx;
+ if(depth >= 24){
+ if(xshm){
+ shminfo = malloc(sizeof(XShmSegmentInfo));
+ if(!(ximg = XShmCreateImage(display,
+ CopyFromParent, depth,
+ ZPixmap,
+ NULL,
+ shminfo,
+ width, height
+ ))){
+ }
+ if((shminfo->shmid = shmget(IPC_PRIVATE, ximg->bytes_per_line * ximg->height, IPC_CREAT|0777)) == -1){
+ fprintf(stderr, "XShm problems\n");
+ exit(1);
+ }
+ if((shminfo->shmaddr = ximg->data = shmat(shminfo->shmid, 0, 0)) == (void *)-1){
+ fprintf(stderr, "XShm problems\n");
+ exit(1);
+ }
+ shminfo->readOnly = False;
+ if(!XShmAttach(display, shminfo)){
+ fprintf(stderr, "XShm problems, falling back to to XImage\n");
+ xshm = 0;
}
}
-
- ximg = XCreateImage (display,
- CopyFromParent, depth,
- ZPixmap, 0,
- (char *) newBuf,
- width, height,
- 32, 0
- );
+ if(!xshm){
+ ximg = XCreateImage(display,
+ CopyFromParent, depth,
+ ZPixmap, 0,
+ NULL,
+ width, height,
+ 32, 0
+ );
+ ximg->data = malloc(ximg->bytes_per_line * ximg->height + /*HACK*/(ximg->bytes_per_line+1));
+ XInitImage(ximg);
+ }
+ scale(img, ximg);
}else{
/* TODO other depths */
- fprintf(stderr, "This program does not support display depths less than 24.\n");
+ fprintf(stderr, "This program does not yet support display depths <24.\n");
exit(1);
return NULL;
}
- XInitImage(ximg);
-
return ximg;
}
XImage *getimage(struct image *img, unsigned int width, unsigned int height){
- if(width * img->height > height * img->width){
- return ximage(img, img->width * height / img->height, height);
+ if(width * img->bufheight > height * img->bufwidth){
+ return ximage(img, img->bufwidth * height / img->bufheight, height);
}else{
- return ximage(img, width, img->height * width / img->width);
+ return ximage(img, width, img->bufheight * width / img->bufwidth);
}
}
@@ -103,7 +165,7 @@ void drawimage(XImage *ximg, unsigned int width, unsigned int height){
if(xoffset){
rects[0].width = rects[1].width = xoffset;
rects[0].height = rects[1].height = height;
- rects[1].x = width-xoffset;
+ rects[1].x = width - xoffset;
rects[1].y = 0;
}else if(yoffset){
rects[0].width = rects[1].width = width;
@@ -113,10 +175,26 @@ void drawimage(XImage *ximg, unsigned int width, unsigned int height){
}
XFillRectangles(display, window, gc, rects, 2);
}
- XPutImage(display, window, gc, ximg, 0, 0, xoffset, yoffset, ximg->width, ximg->height);
+ if(xshm){
+ XShmPutImage(display, window, gc, ximg, 0, 0, xoffset, yoffset, ximg->width, ximg->height, False);
+ }else{
+ XPutImage(display, window, gc, ximg, 0, 0, xoffset, yoffset, ximg->width, ximg->height);
+ }
XFlush(display);
}
+void freeXImg(XImage *ximg){
+ if(xshm){
+ XShmDetach(display, shminfo);
+ XDestroyImage(ximg);
+ shmdt(shminfo->shmaddr);
+ shmctl(shminfo->shmid, IPC_RMID, 0);
+ free(shminfo);
+ }else{
+ XDestroyImage(ximg);
+ }
+}
+
void setaspect(unsigned int w, unsigned int h){
XSizeHints *hints = XAllocSizeHints();