#include "surface.h" #include #include #include #include XRenderSurf * xrender_surf_new(Display *disp, Drawable draw, int format, int w, int h, Bool ca) { XRenderSurf *rs; XRenderPictFormat *fmt; XRenderPictureAttributes att = { .component_alpha = ca, }; Visual *vis = DefaultVisual(disp, DefaultScreen(disp)); rs = (XRenderSurf*)calloc(1, sizeof(XRenderSurf)); fmt = XRenderFindStandardFormat(disp, format); rs->w = w; rs->h = h; rs->depth = fmt->depth; rs->vis = vis; rs->draw = XCreatePixmap(disp, draw, w, h, fmt->depth); rs->pic = XRenderCreatePicture(disp, rs->draw, fmt, CPComponentAlpha, &att); rs->allocated = 1; return rs; } XRenderSurf * xrender_surf_adopt(Display *disp, Drawable draw, int w, int h) { XWindowAttributes win_attr; XRenderSurf *rs; XRenderPictFormat *fmt; XRenderPictureAttributes att; XGetWindowAttributes(disp, draw, &win_attr); Visual *vis = win_attr.visual; rs = (XRenderSurf*)calloc(1, sizeof(XRenderSurf)); fmt = XRenderFindVisualFormat(disp, vis); rs->w = w; rs->h = h; rs->depth = fmt->depth; rs->vis = vis; rs->draw = draw; rs->pic = XRenderCreatePicture(disp, rs->draw, fmt, 0, &att); rs->allocated = 0; return rs; } void xrender_surf_free(Display *disp, XRenderSurf *rs) { if (rs->allocated) XFreePixmap(disp, rs->draw); XRenderFreePicture(disp, rs->pic); free(rs); } void xrender_surf_populate(Display *disp, XRenderSurf *rs, int w, int h, char *img_data) { GC gc; XGCValues gcv; XImage *xim; int x, y; gc = XCreateGC(disp, rs->draw, 0, &gcv); xim = XCreateImage(disp, rs->vis, rs->depth, ZPixmap, 0, NULL, w, h, 32, w * 4); xim->data = img_data; XPutImage(disp, rs->draw, gc, xim, 0, 0, 0, 0, w, h); free(xim->data); xim->data = NULL; XDestroyImage(xim); XFreeGC(disp, gc); } /* this is similar to create_gaussian_kernel_1d() except for the fact that I use ** a naive (or let's call it: brute-force) 2d implementation of a gaussian-blur ** to be able to compare the performance... and the performance non-surprisingly ** sucks... 2 pass 1d gauss. blur is faster than 1 pass 2d gauss. blur */ static XFixed* create_gaussian_kernel_2d (int iRadius, int* piSize) { double fSigma = (double) iRadius / 2.0f; double fScale1; double fScale2; double* pTmpKernel = NULL; XFixed* pKernel = NULL; double fU; double fV; int iX; int iY; double fSum = 0.0f; assert (piSize != NULL); fScale2 = 2.0f * fSigma * fSigma; fScale1 = 1.0f / (M_PI * fScale2); *piSize = (2 * iRadius+1) * (2 * iRadius+1); pTmpKernel = (double*) calloc (*piSize, sizeof (double)); if (!pTmpKernel) return NULL; for (iX = 0; iX < 2 * iRadius+1; iX++) { for (iY = 0; iY < 2 * iRadius+1; iY++) { fU = (double) iX; fV = (double) iY; pTmpKernel[iX+iY*(2*iRadius+1)] = fScale1 * exp (-(fU*fU+fV*fV) / fScale2); } } for (iX = 0; iX < *piSize; iX++) fSum += pTmpKernel[iX]; for (iX = 0; iX < *piSize; iX++) pTmpKernel[iX] /= fSum; pKernel = (XFixed*) calloc (*piSize + 2, sizeof (XFixed)); if (!pKernel) { free (pTmpKernel); return NULL; } for (iX = 0; iX < *piSize; iX++) pKernel[iX + 2] = XDoubleToFixed (pTmpKernel[iX]); free (pTmpKernel); *piSize += 2; pKernel[0] = (2 * iRadius + 1) <<16; pKernel[1] = (2 * iRadius + 1) << 16; return pKernel; } static void set_convolution(Display *disp, XRenderSurf *rs) { int kernel_size; XFixed *blur_kernel = create_gaussian_kernel_2d(20, &kernel_size); XRenderSetPictureFilter(disp, rs->pic, FilterConvolution, blur_kernel, kernel_size); } void xrender_surf_prepare(Display *disp, XRenderSurf *src, int w, int h, int transformations, SurfaceFilter filter) { if (transformations) { XTransform xf; xf.matrix[0][0] = (65536 * src->w) / (w*2); xf.matrix[0][1] = 0; xf.matrix[0][2] = 0; xf.matrix[1][0] = 0; xf.matrix[1][1] = (65536 * src->h) / h; xf.matrix[1][2] = 0; xf.matrix[2][0] = 0; xf.matrix[2][1] = 0; xf.matrix[2][2] = 65536; XRenderSetPictureTransform(disp, src->pic, &xf); } switch(filter) { case SurfaceBilinear: XRenderSetPictureFilter(disp, src->pic, "bilinear", NULL, 0); break; case SurfaceNearest: XRenderSetPictureFilter(disp, src->pic, "nearest", NULL, 0); break; case SurfaceConvolution: set_convolution(disp, src); break; default: break; } } void xrender_surf_blend(Display *disp, int op, XRenderSurf *src, XRenderSurf *mask, XRenderSurf *dst, int src_x, int src_y, int mask_x, int mask_y, int dst_x, int dst_y, unsigned int width, unsigned int height) { XRenderComposite(disp, op, src->pic, mask ? mask->pic : None, dst->pic, src_x, src_y, mask_x, mask_y, dst_x, dst_y, width, height); }