Add support for accelerated alpha blending under X11.

git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@10628 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
Lauri Kasanen
2015-03-16 18:12:28 +00:00
parent 4798d70ded
commit c91e48149b
6 changed files with 105 additions and 17 deletions
+2
View File
@@ -25,6 +25,8 @@ CHANGES IN FLTK 1.3.4 RELEASED: ??? ?? ????
is quite smaller due to use of lossless compression techniques.
- The Linux/Unix printer dialog now uses BSD-style printing commands
(lpr/lpq) when SystemV-style commands (lp/lpstat) are not available.
- Drawing alpha-blended images under X11 is now accelerated with
Xrender.
Bug fixes
+3
View File
@@ -525,6 +525,9 @@ public:
int height();
int descent();
void copy_offscreen(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy);
#if ! defined(FL_DOXYGEN)
void copy_offscreen_with_alpha(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy);
#endif
};
#endif
+1
View File
@@ -84,6 +84,7 @@ extern FL_EXPORT ulong fl_event_time;
// off-screen pixmaps: create, destroy, draw into, copy to window:
typedef ulong Fl_Offscreen;
# define fl_create_offscreen(w,h) XCreatePixmap(fl_display, RootWindow(fl_display, fl_screen), w, h, fl_visual->depth)
# define fl_create_offscreen_with_alpha(w,h) XCreatePixmap(fl_display, RootWindow(fl_display, fl_screen), w, h, 32)
// begin/end are macros that save the old state in local variables:
# define fl_begin_offscreen(pixmap) \
Window _sw=fl_window; fl_window=pixmap; \
+32 -2
View File
@@ -129,14 +129,44 @@ void Fl_Graphics_Driver::copy_offscreen(int x, int y, int w, int h, Fl_Offscreen
#if defined(USE_X11)
#ifdef HAVE_XRENDER
#include <X11/extensions/Xrender.h>
#endif
void Fl_Xlib_Graphics_Driver::copy_offscreen(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy) {
XCopyArea(fl_display, pixmap, fl_window, fl_gc, srcx, srcy, w, h, x, y);
}
void Fl_Xlib_Graphics_Driver::copy_offscreen_with_alpha(int x, int y, int w, int h,
Fl_Offscreen pixmap, int srcx, int srcy) {
#ifdef HAVE_XRENDER
XRenderPictureAttributes srcattr;
memset(&srcattr, 0, sizeof(XRenderPictureAttributes));
XRenderPictFormat *srcfmt = XRenderFindStandardFormat(fl_display, PictStandardARGB32);
XRenderPictFormat *dstfmt = XRenderFindStandardFormat(fl_display, PictStandardRGB24);
Picture src = XRenderCreatePicture(fl_display, pixmap, srcfmt, 0, &srcattr);
Picture dst = XRenderCreatePicture(fl_display, fl_window, dstfmt, 0, &srcattr);
if (!src || !dst) {
fprintf(stderr, "Failed to create Render pictures (%lu %lu)\n", src, dst);
return;
}
const Fl_Region clipr = fl_clip_region();
if (clipr)
XRenderSetPictureClipRegion(fl_display, dst, clipr);
XRenderComposite(fl_display, PictOpOver, src, None, dst, srcx, srcy, 0, 0,
x, y, w, h);
XRenderFreePicture(fl_display, src);
XRenderFreePicture(fl_display, dst);
#endif
}
// maybe someone feels inclined to implement alpha blending on X11?
char fl_can_do_alpha_blending() {
return 0;
return Fl_X::xrender_supported();
}
#elif defined(WIN32)
+9
View File
@@ -711,6 +711,12 @@ void Fl_Xlib_Graphics_Driver::draw(Fl_RGB_Image *img, int XP, int YP, int WP, in
fl_begin_offscreen((Fl_Offscreen)img->id_);
fl_draw_image(img->array, 0, 0, img->w(), img->h(), img->d(), img->ld());
fl_end_offscreen();
} else if (img->d() == 4 && fl_can_do_alpha_blending()) {
img->id_ = fl_create_offscreen_with_alpha(img->w(), img->h());
fl_begin_offscreen((Fl_Offscreen)img->id_);
fl_draw_image(img->array, 0, 0, img->w(), img->h(), img->d() | FL_IMAGE_WITH_ALPHA,
img->ld());
fl_end_offscreen();
}
}
if (img->id_) {
@@ -727,6 +733,9 @@ void Fl_Xlib_Graphics_Driver::draw(Fl_RGB_Image *img, int XP, int YP, int WP, in
XSetClipOrigin(fl_display, fl_gc, X-cx, Y-cy);
}
if (img->d() == 4 && fl_can_do_alpha_blending())
copy_offscreen_with_alpha(X, Y, W, H, img->id_, cx, cy);
else
copy_offscreen(X, Y, W, H, img->id_, cx, cy);
if (img->mask_) {
+49 -6
View File
@@ -316,6 +316,13 @@ static void xrgb_converter(const uchar *from, uchar *to, int w, int delta) {
INNARDS32((from[0]<<16)+(from[1]<<8)+(from[2]));
}
static void argb_premul_converter(const uchar *from, uchar *to, int w, int delta) {
INNARDS32((from[3] << 24) +
(((from[0] * from[3]) / 255) << 16) +
(((from[1] * from[3]) / 255) << 8) +
((from[2] * from[3]) / 255));
}
static void bgrx_converter(const uchar *from, uchar *to, int w, int delta) {
INNARDS32((from[0]<<8)+(from[1]<<16)+(unsigned(from[2])<<24));
}
@@ -451,7 +458,8 @@ static void figure_out_visual() {
static void innards(const uchar *buf, int X, int Y, int W, int H,
int delta, int linedelta, int mono,
Fl_Draw_Image_Cb cb, void* userdata)
Fl_Draw_Image_Cb cb, void* userdata,
const bool alpha)
{
if (!linedelta) linedelta = W*delta;
@@ -462,11 +470,28 @@ static void innards(const uchar *buf, int X, int Y, int W, int H,
dy -= Y;
if (!bytes_per_pixel) figure_out_visual();
const unsigned oldbpp = bytes_per_pixel;
const GC oldgc = fl_gc;
static GC gc32 = None;
xi.width = w;
xi.height = h;
void (*conv)(const uchar *from, uchar *to, int w, int delta) = converter;
if (mono) conv = mono_converter;
if (alpha) {
// This flag states the destination format is ARGB32 (big-endian), pre-multiplied.
bytes_per_pixel = 4;
conv = argb_premul_converter;
xi.depth = 32;
xi.bits_per_pixel = 32;
// Do we need a new GC?
if (fl_visual->depth != 32) {
if (gc32 == None)
gc32 = XCreateGC(fl_display, fl_window, 0, NULL);
fl_gc = gc32;
}
}
// See if the data is already in the right format. Unfortunately
// some 32-bit x servers (XFree86) care about the unknown 8 bits
@@ -534,21 +559,39 @@ static void innards(const uchar *buf, int X, int Y, int W, int H,
delete[] linebuf;
}
}
if (alpha) {
bytes_per_pixel = oldbpp;
xi.depth = fl_visual->depth;
xi.bits_per_pixel = oldbpp * 8;
if (fl_visual->depth != 32) {
fl_gc = oldgc;
}
}
}
void Fl_Xlib_Graphics_Driver::draw_image(const uchar* buf, int x, int y, int w, int h, int d, int l){
innards(buf,x,y,w,h,d,l,(d<3&&d>-3),0,0);
const bool alpha = !!(d & FL_IMAGE_WITH_ALPHA);
d &= ~FL_IMAGE_WITH_ALPHA;
innards(buf,x,y,w,h,d,l,(d<3&&d>-3),0,0,alpha);
}
void Fl_Xlib_Graphics_Driver::draw_image(Fl_Draw_Image_Cb cb, void* data,
int x, int y, int w, int h,int d) {
innards(0,x,y,w,h,d,0,(d<3&&d>-3),cb,data);
const bool alpha = !!(d & FL_IMAGE_WITH_ALPHA);
d &= ~FL_IMAGE_WITH_ALPHA;
innards(0,x,y,w,h,d,0,(d<3&&d>-3),cb,data,alpha);
}
void Fl_Xlib_Graphics_Driver::draw_image_mono(const uchar* buf, int x, int y, int w, int h, int d, int l){
innards(buf,x,y,w,h,d,l,1,0,0);
innards(buf,x,y,w,h,d,l,1,0,0,0);
}
void Fl_Xlib_Graphics_Driver::draw_image_mono(Fl_Draw_Image_Cb cb, void* data,
int x, int y, int w, int h,int d) {
innards(0,x,y,w,h,d,0,1,cb,data);
innards(0,x,y,w,h,d,0,1,cb,data,0);
}
void fl_rectf(int x, int y, int w, int h, uchar r, uchar g, uchar b) {
@@ -558,7 +601,7 @@ void fl_rectf(int x, int y, int w, int h, uchar r, uchar g, uchar b) {
} else {
uchar c[3];
c[0] = r; c[1] = g; c[2] = b;
innards(c,x,y,w,h,0,0,0,0,0);
innards(c,x,y,w,h,0,0,0,0,0,0);
}
}