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

14
CHANGES
View File

@ -5,10 +5,10 @@ CHANGES IN FLTK 1.3.4 RELEASED: ??? ?? ????
- Added full support of true subwindows to the Mac OS X platform.
Window nesting to any depth is possible. An Fl_Gl_Window window or
subwindow can contain Fl_Window's as subwindows.
- Added the Fl_Shared_Image::scale(width, height) function which gives
a shared image its own drawing size, independently of the size of the
underlying image. This improves much image drawing on high resolution
surfaces such as Laser printers, PDF files, or Apple retina displays.
- Added the Fl_Shared_Image::scale(width, height) function which gives
a shared image its own drawing size, independently of the size of the
underlying image. This improves much image drawing on high resolution
surfaces such as Laser printers, PDF files, or Apple retina displays.
Other improvements
@ -23,8 +23,10 @@ CHANGES IN FLTK 1.3.4 RELEASED: ??? ?? ????
(i.e. when called) - only destruction is delayed as before.
- The PostScript code output when printing images under Linux/Unix
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.
- 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

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
FL/x.H
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; \

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)

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_) {
@ -726,9 +732,12 @@ void Fl_Xlib_Graphics_Driver::draw(Fl_RGB_Image *img, int XP, int YP, int WP, in
int oy = Y-cy; if (oy < 0) oy += img->h();
XSetClipOrigin(fl_display, fl_gc, X-cx, Y-cy);
}
copy_offscreen(X, Y, W, H, img->id_, cx, 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_) {
// put the old clip region back
XSetClipOrigin(fl_display, fl_gc, 0, 0);

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);
}
}