From d12c9702a4428cdf83e6d0dc37b0b9e69fb19f80 Mon Sep 17 00:00:00 2001 From: Owen Taylor Date: Fri, 4 Jan 2002 05:58:01 +0000 Subject: [PATCH] Private function to tell if we have RENDER extension. Thu Jan 3 22:18:15 2002 Owen Taylor * gdk/x11/gdkdrawable-x11.c gdk/x11/gdkprivate-x11.h (_gdk_x11_have_render): Private function to tell if we have RENDER extension. * gdk/x11/gdkgc-x11.c (_gdk_x11_gc_get_fg_picture): Return None if we don't have RENDER extension. * gdk/x11/gdkpango-x11.c (gdk_pango_context_get): Don't use Xft unless we have render extension. * gdk/x11/gdkdrawable-x11.c (gdk_x11_drawable_get_picture): Handle missing render extension. * gdk/gdkdraw.c gdk/gdkdrawable.h gdk/gdkpixmap.c gdk/gdkwindow.c gdk/gdkinternals.h: Add a private copy_to_image() virtual function to the GdkDrawable vtable that extends get_image() to allow copying onto existing images. Make the default implementation of get_image() use this so that backends don't have to implement both. Add private wrapper _gdk_drawable_copy_to_image(). * gdk/x11/gdkimage-x11.c gdk/x11/gdkprivate-x11.c gdk/x11/gdkdrawable-x11.c (_gdk_x11_copy_to_image): Implement copy_to_image() semantics, speed up by using ShmPixmaps and XCopyArea when possible, XFlush() after ungrabbing the server, generally redo the logic once again. * gdk/gdkinternals.h gdk/x11/gdkimage-x11.c _gdk_windowing_bits_per_depth(): Function to convert from depth to bits-per-pixel. (We assume only one bpp per depth - X requires this.) * gdk/gdkinternals.h gdk/gdkrgb.c gdk/gdkimage.c: Move the GdkRGB scratch image code into a generic _gdk_image_get_scratch() chunk of code that we can use other places we need scratch images. * gdk/gdkimage.c gdk/x11/gdkimage.c gdk/gdkinternals.h: Add _gdk_image_new_for_depth() as the backend to _gdk_image_new() to allowing creating images with a depth and no visual. * gdk/gdkpixbuf-drawable.c: Fix so that getting parts of images not at 0,0 actually works. * gdk/gdkdrawable.h gdk/gdkinternals.h gdk/gdkdraw.c gdk/gdkwindow.c gdk/gdkpixmap.c gdk/gdkpixbuf-render.c: - Add a new GdkDrawableClass vfunc _draw_pixbuf, and _gdk_draw_pixbuf() [ will be made public later ], to allow backends to accelerate drawing pixbufs. - Move the implementation of gdk_pixbuf_render_to_drawable_alpha() to be the default implementation. - Update docs for gdk_pixbuf_render_to_drawable_alpha(). - Optimize the default implementation by using _gdk_image_copy_to_pixmap() and scratch shared images, and special casing the compositing. * gdk/x11/gdkdrawable-x11.c: Accelerate _gdk_draw_pixbuf() with alpha using the RENDER extension. * gdk/gdkpixbuf-drawable.c (gdk_pixbuf_get_from_drawable): Optimize by _gdk_image_copy_to_pixmap() and scratch images. * tests/testrgb.c: Add test for speed of alpha composition, reduce the number of iterations since alpha composition can be a bit slow. * gdk/x11/gdkimage-x11.c gdk/gdkprivate-x11.h (_gdk_x11_image_get_shm_pixmap): Private function to get a ShmPixmap for an image, if possible. --- ChangeLog | 70 +++++ ChangeLog.pre-2-0 | 70 +++++ ChangeLog.pre-2-10 | 70 +++++ ChangeLog.pre-2-2 | 70 +++++ ChangeLog.pre-2-4 | 70 +++++ ChangeLog.pre-2-6 | 70 +++++ ChangeLog.pre-2-8 | 70 +++++ gdk/gdkdraw.c | 555 ++++++++++++++++++++++++++++++++++++- gdk/gdkdrawable.h | 25 +- gdk/gdkimage.c | 263 ++++++++++++++++++ gdk/gdkinternals.h | 42 +++ gdk/gdkpixbuf-drawable.c | 85 +++--- gdk/gdkpixbuf-render.c | 191 +------------ gdk/gdkpixmap.c | 69 ++++- gdk/gdkrgb.c | 259 ++--------------- gdk/gdkwindow.c | 110 +++++++- gdk/x11/gdkdrawable-x11.c | 567 +++++++++++++++++++++++++++++++++++++- gdk/x11/gdkgc-x11.c | 8 +- gdk/x11/gdkimage-x11.c | 345 +++++++++++++++-------- gdk/x11/gdkpango-x11.c | 2 +- gdk/x11/gdkprivate-x11.h | 17 +- tests/testrgb.c | 48 +++- 22 files changed, 2446 insertions(+), 630 deletions(-) diff --git a/ChangeLog b/ChangeLog index 287f5a0f88..be56ec86c7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,73 @@ +Thu Jan 3 22:18:15 2002 Owen Taylor + + * gdk/x11/gdkdrawable-x11.c gdk/x11/gdkprivate-x11.h + (_gdk_x11_have_render): Private function to tell if we have RENDER + extension. + + * gdk/x11/gdkgc-x11.c (_gdk_x11_gc_get_fg_picture): Return + None if we don't have RENDER extension. + + * gdk/x11/gdkpango-x11.c (gdk_pango_context_get): Don't + use Xft unless we have render extension. + + * gdk/x11/gdkdrawable-x11.c (gdk_x11_drawable_get_picture): + Handle missing render extension. + + * gdk/gdkdraw.c gdk/gdkdrawable.h gdk/gdkpixmap.c gdk/gdkwindow.c + gdk/gdkinternals.h: Add a private copy_to_image() virtual function + to the GdkDrawable vtable that extends get_image() to allow + copying onto existing images. Make the default implementation of + get_image() use this so that backends don't have to implement + both. Add private wrapper _gdk_drawable_copy_to_image(). + + * gdk/x11/gdkimage-x11.c gdk/x11/gdkprivate-x11.c + gdk/x11/gdkdrawable-x11.c (_gdk_x11_copy_to_image): Implement + copy_to_image() semantics, speed up by using ShmPixmaps and + XCopyArea when possible, XFlush() after ungrabbing the server, + generally redo the logic once again. + + * gdk/gdkinternals.h gdk/x11/gdkimage-x11.c + _gdk_windowing_bits_per_depth(): Function to convert from depth to + bits-per-pixel. (We assume only one bpp per depth - X requires + this.) + + * gdk/gdkinternals.h gdk/gdkrgb.c gdk/gdkimage.c: Move the GdkRGB + scratch image code into a generic _gdk_image_get_scratch() chunk + of code that we can use other places we need scratch images. + + * gdk/gdkimage.c gdk/x11/gdkimage.c gdk/gdkinternals.h: + Add _gdk_image_new_for_depth() as the backend + to _gdk_image_new() to allowing creating images with + a depth and no visual. + + * gdk/gdkpixbuf-drawable.c: Fix so that getting + parts of images not at 0,0 actually works. + + * gdk/gdkdrawable.h gdk/gdkinternals.h gdk/gdkdraw.c + gdk/gdkwindow.c gdk/gdkpixmap.c gdk/gdkpixbuf-render.c: + - Add a new GdkDrawableClass vfunc _draw_pixbuf, and + _gdk_draw_pixbuf() [ will be made public later ], to allow + backends to accelerate drawing pixbufs. + - Move the implementation of gdk_pixbuf_render_to_drawable_alpha() + to be the default implementation. + - Update docs for gdk_pixbuf_render_to_drawable_alpha(). + - Optimize the default implementation by using + _gdk_image_copy_to_pixmap() and scratch shared images, and + special casing the compositing. + + * gdk/x11/gdkdrawable-x11.c: Accelerate _gdk_draw_pixbuf() + with alpha using the RENDER extension. + + * gdk/gdkpixbuf-drawable.c (gdk_pixbuf_get_from_drawable): + Optimize by _gdk_image_copy_to_pixmap() and scratch images. + + * tests/testrgb.c: Add test for speed of alpha composition, + reduce the number of iterations since alpha composition + can be a bit slow. + + * gdk/x11/gdkimage-x11.c gdk/gdkprivate-x11.h (_gdk_x11_image_get_shm_pixmap): + Private function to get a ShmPixmap for an image, if possible. + 2002-01-04 Anders Carlsson * tests/testtreesort.c: Add my cool list of integers. diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0 index 287f5a0f88..be56ec86c7 100644 --- a/ChangeLog.pre-2-0 +++ b/ChangeLog.pre-2-0 @@ -1,3 +1,73 @@ +Thu Jan 3 22:18:15 2002 Owen Taylor + + * gdk/x11/gdkdrawable-x11.c gdk/x11/gdkprivate-x11.h + (_gdk_x11_have_render): Private function to tell if we have RENDER + extension. + + * gdk/x11/gdkgc-x11.c (_gdk_x11_gc_get_fg_picture): Return + None if we don't have RENDER extension. + + * gdk/x11/gdkpango-x11.c (gdk_pango_context_get): Don't + use Xft unless we have render extension. + + * gdk/x11/gdkdrawable-x11.c (gdk_x11_drawable_get_picture): + Handle missing render extension. + + * gdk/gdkdraw.c gdk/gdkdrawable.h gdk/gdkpixmap.c gdk/gdkwindow.c + gdk/gdkinternals.h: Add a private copy_to_image() virtual function + to the GdkDrawable vtable that extends get_image() to allow + copying onto existing images. Make the default implementation of + get_image() use this so that backends don't have to implement + both. Add private wrapper _gdk_drawable_copy_to_image(). + + * gdk/x11/gdkimage-x11.c gdk/x11/gdkprivate-x11.c + gdk/x11/gdkdrawable-x11.c (_gdk_x11_copy_to_image): Implement + copy_to_image() semantics, speed up by using ShmPixmaps and + XCopyArea when possible, XFlush() after ungrabbing the server, + generally redo the logic once again. + + * gdk/gdkinternals.h gdk/x11/gdkimage-x11.c + _gdk_windowing_bits_per_depth(): Function to convert from depth to + bits-per-pixel. (We assume only one bpp per depth - X requires + this.) + + * gdk/gdkinternals.h gdk/gdkrgb.c gdk/gdkimage.c: Move the GdkRGB + scratch image code into a generic _gdk_image_get_scratch() chunk + of code that we can use other places we need scratch images. + + * gdk/gdkimage.c gdk/x11/gdkimage.c gdk/gdkinternals.h: + Add _gdk_image_new_for_depth() as the backend + to _gdk_image_new() to allowing creating images with + a depth and no visual. + + * gdk/gdkpixbuf-drawable.c: Fix so that getting + parts of images not at 0,0 actually works. + + * gdk/gdkdrawable.h gdk/gdkinternals.h gdk/gdkdraw.c + gdk/gdkwindow.c gdk/gdkpixmap.c gdk/gdkpixbuf-render.c: + - Add a new GdkDrawableClass vfunc _draw_pixbuf, and + _gdk_draw_pixbuf() [ will be made public later ], to allow + backends to accelerate drawing pixbufs. + - Move the implementation of gdk_pixbuf_render_to_drawable_alpha() + to be the default implementation. + - Update docs for gdk_pixbuf_render_to_drawable_alpha(). + - Optimize the default implementation by using + _gdk_image_copy_to_pixmap() and scratch shared images, and + special casing the compositing. + + * gdk/x11/gdkdrawable-x11.c: Accelerate _gdk_draw_pixbuf() + with alpha using the RENDER extension. + + * gdk/gdkpixbuf-drawable.c (gdk_pixbuf_get_from_drawable): + Optimize by _gdk_image_copy_to_pixmap() and scratch images. + + * tests/testrgb.c: Add test for speed of alpha composition, + reduce the number of iterations since alpha composition + can be a bit slow. + + * gdk/x11/gdkimage-x11.c gdk/gdkprivate-x11.h (_gdk_x11_image_get_shm_pixmap): + Private function to get a ShmPixmap for an image, if possible. + 2002-01-04 Anders Carlsson * tests/testtreesort.c: Add my cool list of integers. diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 287f5a0f88..be56ec86c7 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,73 @@ +Thu Jan 3 22:18:15 2002 Owen Taylor + + * gdk/x11/gdkdrawable-x11.c gdk/x11/gdkprivate-x11.h + (_gdk_x11_have_render): Private function to tell if we have RENDER + extension. + + * gdk/x11/gdkgc-x11.c (_gdk_x11_gc_get_fg_picture): Return + None if we don't have RENDER extension. + + * gdk/x11/gdkpango-x11.c (gdk_pango_context_get): Don't + use Xft unless we have render extension. + + * gdk/x11/gdkdrawable-x11.c (gdk_x11_drawable_get_picture): + Handle missing render extension. + + * gdk/gdkdraw.c gdk/gdkdrawable.h gdk/gdkpixmap.c gdk/gdkwindow.c + gdk/gdkinternals.h: Add a private copy_to_image() virtual function + to the GdkDrawable vtable that extends get_image() to allow + copying onto existing images. Make the default implementation of + get_image() use this so that backends don't have to implement + both. Add private wrapper _gdk_drawable_copy_to_image(). + + * gdk/x11/gdkimage-x11.c gdk/x11/gdkprivate-x11.c + gdk/x11/gdkdrawable-x11.c (_gdk_x11_copy_to_image): Implement + copy_to_image() semantics, speed up by using ShmPixmaps and + XCopyArea when possible, XFlush() after ungrabbing the server, + generally redo the logic once again. + + * gdk/gdkinternals.h gdk/x11/gdkimage-x11.c + _gdk_windowing_bits_per_depth(): Function to convert from depth to + bits-per-pixel. (We assume only one bpp per depth - X requires + this.) + + * gdk/gdkinternals.h gdk/gdkrgb.c gdk/gdkimage.c: Move the GdkRGB + scratch image code into a generic _gdk_image_get_scratch() chunk + of code that we can use other places we need scratch images. + + * gdk/gdkimage.c gdk/x11/gdkimage.c gdk/gdkinternals.h: + Add _gdk_image_new_for_depth() as the backend + to _gdk_image_new() to allowing creating images with + a depth and no visual. + + * gdk/gdkpixbuf-drawable.c: Fix so that getting + parts of images not at 0,0 actually works. + + * gdk/gdkdrawable.h gdk/gdkinternals.h gdk/gdkdraw.c + gdk/gdkwindow.c gdk/gdkpixmap.c gdk/gdkpixbuf-render.c: + - Add a new GdkDrawableClass vfunc _draw_pixbuf, and + _gdk_draw_pixbuf() [ will be made public later ], to allow + backends to accelerate drawing pixbufs. + - Move the implementation of gdk_pixbuf_render_to_drawable_alpha() + to be the default implementation. + - Update docs for gdk_pixbuf_render_to_drawable_alpha(). + - Optimize the default implementation by using + _gdk_image_copy_to_pixmap() and scratch shared images, and + special casing the compositing. + + * gdk/x11/gdkdrawable-x11.c: Accelerate _gdk_draw_pixbuf() + with alpha using the RENDER extension. + + * gdk/gdkpixbuf-drawable.c (gdk_pixbuf_get_from_drawable): + Optimize by _gdk_image_copy_to_pixmap() and scratch images. + + * tests/testrgb.c: Add test for speed of alpha composition, + reduce the number of iterations since alpha composition + can be a bit slow. + + * gdk/x11/gdkimage-x11.c gdk/gdkprivate-x11.h (_gdk_x11_image_get_shm_pixmap): + Private function to get a ShmPixmap for an image, if possible. + 2002-01-04 Anders Carlsson * tests/testtreesort.c: Add my cool list of integers. diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index 287f5a0f88..be56ec86c7 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -1,3 +1,73 @@ +Thu Jan 3 22:18:15 2002 Owen Taylor + + * gdk/x11/gdkdrawable-x11.c gdk/x11/gdkprivate-x11.h + (_gdk_x11_have_render): Private function to tell if we have RENDER + extension. + + * gdk/x11/gdkgc-x11.c (_gdk_x11_gc_get_fg_picture): Return + None if we don't have RENDER extension. + + * gdk/x11/gdkpango-x11.c (gdk_pango_context_get): Don't + use Xft unless we have render extension. + + * gdk/x11/gdkdrawable-x11.c (gdk_x11_drawable_get_picture): + Handle missing render extension. + + * gdk/gdkdraw.c gdk/gdkdrawable.h gdk/gdkpixmap.c gdk/gdkwindow.c + gdk/gdkinternals.h: Add a private copy_to_image() virtual function + to the GdkDrawable vtable that extends get_image() to allow + copying onto existing images. Make the default implementation of + get_image() use this so that backends don't have to implement + both. Add private wrapper _gdk_drawable_copy_to_image(). + + * gdk/x11/gdkimage-x11.c gdk/x11/gdkprivate-x11.c + gdk/x11/gdkdrawable-x11.c (_gdk_x11_copy_to_image): Implement + copy_to_image() semantics, speed up by using ShmPixmaps and + XCopyArea when possible, XFlush() after ungrabbing the server, + generally redo the logic once again. + + * gdk/gdkinternals.h gdk/x11/gdkimage-x11.c + _gdk_windowing_bits_per_depth(): Function to convert from depth to + bits-per-pixel. (We assume only one bpp per depth - X requires + this.) + + * gdk/gdkinternals.h gdk/gdkrgb.c gdk/gdkimage.c: Move the GdkRGB + scratch image code into a generic _gdk_image_get_scratch() chunk + of code that we can use other places we need scratch images. + + * gdk/gdkimage.c gdk/x11/gdkimage.c gdk/gdkinternals.h: + Add _gdk_image_new_for_depth() as the backend + to _gdk_image_new() to allowing creating images with + a depth and no visual. + + * gdk/gdkpixbuf-drawable.c: Fix so that getting + parts of images not at 0,0 actually works. + + * gdk/gdkdrawable.h gdk/gdkinternals.h gdk/gdkdraw.c + gdk/gdkwindow.c gdk/gdkpixmap.c gdk/gdkpixbuf-render.c: + - Add a new GdkDrawableClass vfunc _draw_pixbuf, and + _gdk_draw_pixbuf() [ will be made public later ], to allow + backends to accelerate drawing pixbufs. + - Move the implementation of gdk_pixbuf_render_to_drawable_alpha() + to be the default implementation. + - Update docs for gdk_pixbuf_render_to_drawable_alpha(). + - Optimize the default implementation by using + _gdk_image_copy_to_pixmap() and scratch shared images, and + special casing the compositing. + + * gdk/x11/gdkdrawable-x11.c: Accelerate _gdk_draw_pixbuf() + with alpha using the RENDER extension. + + * gdk/gdkpixbuf-drawable.c (gdk_pixbuf_get_from_drawable): + Optimize by _gdk_image_copy_to_pixmap() and scratch images. + + * tests/testrgb.c: Add test for speed of alpha composition, + reduce the number of iterations since alpha composition + can be a bit slow. + + * gdk/x11/gdkimage-x11.c gdk/gdkprivate-x11.h (_gdk_x11_image_get_shm_pixmap): + Private function to get a ShmPixmap for an image, if possible. + 2002-01-04 Anders Carlsson * tests/testtreesort.c: Add my cool list of integers. diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index 287f5a0f88..be56ec86c7 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,73 @@ +Thu Jan 3 22:18:15 2002 Owen Taylor + + * gdk/x11/gdkdrawable-x11.c gdk/x11/gdkprivate-x11.h + (_gdk_x11_have_render): Private function to tell if we have RENDER + extension. + + * gdk/x11/gdkgc-x11.c (_gdk_x11_gc_get_fg_picture): Return + None if we don't have RENDER extension. + + * gdk/x11/gdkpango-x11.c (gdk_pango_context_get): Don't + use Xft unless we have render extension. + + * gdk/x11/gdkdrawable-x11.c (gdk_x11_drawable_get_picture): + Handle missing render extension. + + * gdk/gdkdraw.c gdk/gdkdrawable.h gdk/gdkpixmap.c gdk/gdkwindow.c + gdk/gdkinternals.h: Add a private copy_to_image() virtual function + to the GdkDrawable vtable that extends get_image() to allow + copying onto existing images. Make the default implementation of + get_image() use this so that backends don't have to implement + both. Add private wrapper _gdk_drawable_copy_to_image(). + + * gdk/x11/gdkimage-x11.c gdk/x11/gdkprivate-x11.c + gdk/x11/gdkdrawable-x11.c (_gdk_x11_copy_to_image): Implement + copy_to_image() semantics, speed up by using ShmPixmaps and + XCopyArea when possible, XFlush() after ungrabbing the server, + generally redo the logic once again. + + * gdk/gdkinternals.h gdk/x11/gdkimage-x11.c + _gdk_windowing_bits_per_depth(): Function to convert from depth to + bits-per-pixel. (We assume only one bpp per depth - X requires + this.) + + * gdk/gdkinternals.h gdk/gdkrgb.c gdk/gdkimage.c: Move the GdkRGB + scratch image code into a generic _gdk_image_get_scratch() chunk + of code that we can use other places we need scratch images. + + * gdk/gdkimage.c gdk/x11/gdkimage.c gdk/gdkinternals.h: + Add _gdk_image_new_for_depth() as the backend + to _gdk_image_new() to allowing creating images with + a depth and no visual. + + * gdk/gdkpixbuf-drawable.c: Fix so that getting + parts of images not at 0,0 actually works. + + * gdk/gdkdrawable.h gdk/gdkinternals.h gdk/gdkdraw.c + gdk/gdkwindow.c gdk/gdkpixmap.c gdk/gdkpixbuf-render.c: + - Add a new GdkDrawableClass vfunc _draw_pixbuf, and + _gdk_draw_pixbuf() [ will be made public later ], to allow + backends to accelerate drawing pixbufs. + - Move the implementation of gdk_pixbuf_render_to_drawable_alpha() + to be the default implementation. + - Update docs for gdk_pixbuf_render_to_drawable_alpha(). + - Optimize the default implementation by using + _gdk_image_copy_to_pixmap() and scratch shared images, and + special casing the compositing. + + * gdk/x11/gdkdrawable-x11.c: Accelerate _gdk_draw_pixbuf() + with alpha using the RENDER extension. + + * gdk/gdkpixbuf-drawable.c (gdk_pixbuf_get_from_drawable): + Optimize by _gdk_image_copy_to_pixmap() and scratch images. + + * tests/testrgb.c: Add test for speed of alpha composition, + reduce the number of iterations since alpha composition + can be a bit slow. + + * gdk/x11/gdkimage-x11.c gdk/gdkprivate-x11.h (_gdk_x11_image_get_shm_pixmap): + Private function to get a ShmPixmap for an image, if possible. + 2002-01-04 Anders Carlsson * tests/testtreesort.c: Add my cool list of integers. diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index 287f5a0f88..be56ec86c7 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,73 @@ +Thu Jan 3 22:18:15 2002 Owen Taylor + + * gdk/x11/gdkdrawable-x11.c gdk/x11/gdkprivate-x11.h + (_gdk_x11_have_render): Private function to tell if we have RENDER + extension. + + * gdk/x11/gdkgc-x11.c (_gdk_x11_gc_get_fg_picture): Return + None if we don't have RENDER extension. + + * gdk/x11/gdkpango-x11.c (gdk_pango_context_get): Don't + use Xft unless we have render extension. + + * gdk/x11/gdkdrawable-x11.c (gdk_x11_drawable_get_picture): + Handle missing render extension. + + * gdk/gdkdraw.c gdk/gdkdrawable.h gdk/gdkpixmap.c gdk/gdkwindow.c + gdk/gdkinternals.h: Add a private copy_to_image() virtual function + to the GdkDrawable vtable that extends get_image() to allow + copying onto existing images. Make the default implementation of + get_image() use this so that backends don't have to implement + both. Add private wrapper _gdk_drawable_copy_to_image(). + + * gdk/x11/gdkimage-x11.c gdk/x11/gdkprivate-x11.c + gdk/x11/gdkdrawable-x11.c (_gdk_x11_copy_to_image): Implement + copy_to_image() semantics, speed up by using ShmPixmaps and + XCopyArea when possible, XFlush() after ungrabbing the server, + generally redo the logic once again. + + * gdk/gdkinternals.h gdk/x11/gdkimage-x11.c + _gdk_windowing_bits_per_depth(): Function to convert from depth to + bits-per-pixel. (We assume only one bpp per depth - X requires + this.) + + * gdk/gdkinternals.h gdk/gdkrgb.c gdk/gdkimage.c: Move the GdkRGB + scratch image code into a generic _gdk_image_get_scratch() chunk + of code that we can use other places we need scratch images. + + * gdk/gdkimage.c gdk/x11/gdkimage.c gdk/gdkinternals.h: + Add _gdk_image_new_for_depth() as the backend + to _gdk_image_new() to allowing creating images with + a depth and no visual. + + * gdk/gdkpixbuf-drawable.c: Fix so that getting + parts of images not at 0,0 actually works. + + * gdk/gdkdrawable.h gdk/gdkinternals.h gdk/gdkdraw.c + gdk/gdkwindow.c gdk/gdkpixmap.c gdk/gdkpixbuf-render.c: + - Add a new GdkDrawableClass vfunc _draw_pixbuf, and + _gdk_draw_pixbuf() [ will be made public later ], to allow + backends to accelerate drawing pixbufs. + - Move the implementation of gdk_pixbuf_render_to_drawable_alpha() + to be the default implementation. + - Update docs for gdk_pixbuf_render_to_drawable_alpha(). + - Optimize the default implementation by using + _gdk_image_copy_to_pixmap() and scratch shared images, and + special casing the compositing. + + * gdk/x11/gdkdrawable-x11.c: Accelerate _gdk_draw_pixbuf() + with alpha using the RENDER extension. + + * gdk/gdkpixbuf-drawable.c (gdk_pixbuf_get_from_drawable): + Optimize by _gdk_image_copy_to_pixmap() and scratch images. + + * tests/testrgb.c: Add test for speed of alpha composition, + reduce the number of iterations since alpha composition + can be a bit slow. + + * gdk/x11/gdkimage-x11.c gdk/gdkprivate-x11.h (_gdk_x11_image_get_shm_pixmap): + Private function to get a ShmPixmap for an image, if possible. + 2002-01-04 Anders Carlsson * tests/testtreesort.c: Add my cool list of integers. diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 287f5a0f88..be56ec86c7 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,73 @@ +Thu Jan 3 22:18:15 2002 Owen Taylor + + * gdk/x11/gdkdrawable-x11.c gdk/x11/gdkprivate-x11.h + (_gdk_x11_have_render): Private function to tell if we have RENDER + extension. + + * gdk/x11/gdkgc-x11.c (_gdk_x11_gc_get_fg_picture): Return + None if we don't have RENDER extension. + + * gdk/x11/gdkpango-x11.c (gdk_pango_context_get): Don't + use Xft unless we have render extension. + + * gdk/x11/gdkdrawable-x11.c (gdk_x11_drawable_get_picture): + Handle missing render extension. + + * gdk/gdkdraw.c gdk/gdkdrawable.h gdk/gdkpixmap.c gdk/gdkwindow.c + gdk/gdkinternals.h: Add a private copy_to_image() virtual function + to the GdkDrawable vtable that extends get_image() to allow + copying onto existing images. Make the default implementation of + get_image() use this so that backends don't have to implement + both. Add private wrapper _gdk_drawable_copy_to_image(). + + * gdk/x11/gdkimage-x11.c gdk/x11/gdkprivate-x11.c + gdk/x11/gdkdrawable-x11.c (_gdk_x11_copy_to_image): Implement + copy_to_image() semantics, speed up by using ShmPixmaps and + XCopyArea when possible, XFlush() after ungrabbing the server, + generally redo the logic once again. + + * gdk/gdkinternals.h gdk/x11/gdkimage-x11.c + _gdk_windowing_bits_per_depth(): Function to convert from depth to + bits-per-pixel. (We assume only one bpp per depth - X requires + this.) + + * gdk/gdkinternals.h gdk/gdkrgb.c gdk/gdkimage.c: Move the GdkRGB + scratch image code into a generic _gdk_image_get_scratch() chunk + of code that we can use other places we need scratch images. + + * gdk/gdkimage.c gdk/x11/gdkimage.c gdk/gdkinternals.h: + Add _gdk_image_new_for_depth() as the backend + to _gdk_image_new() to allowing creating images with + a depth and no visual. + + * gdk/gdkpixbuf-drawable.c: Fix so that getting + parts of images not at 0,0 actually works. + + * gdk/gdkdrawable.h gdk/gdkinternals.h gdk/gdkdraw.c + gdk/gdkwindow.c gdk/gdkpixmap.c gdk/gdkpixbuf-render.c: + - Add a new GdkDrawableClass vfunc _draw_pixbuf, and + _gdk_draw_pixbuf() [ will be made public later ], to allow + backends to accelerate drawing pixbufs. + - Move the implementation of gdk_pixbuf_render_to_drawable_alpha() + to be the default implementation. + - Update docs for gdk_pixbuf_render_to_drawable_alpha(). + - Optimize the default implementation by using + _gdk_image_copy_to_pixmap() and scratch shared images, and + special casing the compositing. + + * gdk/x11/gdkdrawable-x11.c: Accelerate _gdk_draw_pixbuf() + with alpha using the RENDER extension. + + * gdk/gdkpixbuf-drawable.c (gdk_pixbuf_get_from_drawable): + Optimize by _gdk_image_copy_to_pixmap() and scratch images. + + * tests/testrgb.c: Add test for speed of alpha composition, + reduce the number of iterations since alpha composition + can be a bit slow. + + * gdk/x11/gdkimage-x11.c gdk/gdkprivate-x11.h (_gdk_x11_image_get_shm_pixmap): + Private function to get a ShmPixmap for an image, if possible. + 2002-01-04 Anders Carlsson * tests/testtreesort.c: Add my cool list of integers. diff --git a/gdk/gdkdraw.c b/gdk/gdkdraw.c index e2d50121b3..c7882c5775 100644 --- a/gdk/gdkdraw.c +++ b/gdk/gdkdraw.c @@ -27,15 +27,34 @@ #include "gdkdrawable.h" #include "gdkinternals.h" #include "gdkwindow.h" +#include "gdk-pixbuf-private.h" +#include "gdkpixbuf.h" -static GdkDrawable* gdk_drawable_real_get_composite_drawable (GdkDrawable *drawable, - gint x, - gint y, - gint width, - gint height, - gint *composite_x_offset, - gint *composite_y_offset); -static GdkRegion * gdk_drawable_real_get_visible_region (GdkDrawable *drawable); +static GdkImage* gdk_drawable_real_get_image (GdkDrawable *drawable, + gint x, + gint y, + gint width, + gint height); +static GdkDrawable* gdk_drawable_real_get_composite_drawable (GdkDrawable *drawable, + gint x, + gint y, + gint width, + gint height, + gint *composite_x_offset, + gint *composite_y_offset); +static GdkRegion * gdk_drawable_real_get_visible_region (GdkDrawable *drawable); +static void gdk_drawable_real_draw_pixbuf (GdkDrawable *drawable, + GdkGC *gc, + GdkPixbuf *pixbuf, + gint src_x, + gint src_y, + gint dest_x, + gint dest_y, + gint width, + gint height, + GdkRgbDither dither, + gint x_dither, + gint y_dither); static void gdk_drawable_class_init (GdkDrawableClass *klass); @@ -70,10 +89,12 @@ gdk_drawable_get_type (void) static void gdk_drawable_class_init (GdkDrawableClass *klass) { + klass->get_image = gdk_drawable_real_get_image; klass->get_composite_drawable = gdk_drawable_real_get_composite_drawable; /* Default implementation for clip and visible region is the same */ klass->get_clip_region = gdk_drawable_real_get_visible_region; klass->get_visible_region = gdk_drawable_real_get_visible_region; + klass->_draw_pixbuf = gdk_drawable_real_draw_pixbuf; } /* Manipulation of drawables @@ -529,6 +550,57 @@ gdk_draw_image (GdkDrawable *drawable, xdest, ydest, width, height); } +/** + * _gdk_draw_pixbuf: + * @drawable: Destination drawable. + * @gc: a #GdkGC, used for clipping, or %NULL + * @pixbuf: a #GdkPixbuf + * @src_x: Source X coordinate within pixbuf. + * @src_y: Source Y coordinates within pixbuf. + * @dest_x: Destination X coordinate within drawable. + * @dest_y: Destination Y coordinate within drawable. + * @width: Width of region to render, in pixels, or -1 to use pixbuf width. + * @height: Height of region to render, in pixels, or -1 to use pixbuf height. + * @dither: Dithering mode for GdkRGB. + * @x_dither: X offset for dither. + * @y_dither: Y offset for dither. + * + * Renders a rectangular portion of a pixbuf to a drawable. The destination + * drawable must have a colormap. All windows have a colormap, however, pixmaps + * only have colormap by default if they were created with a non-NULL window argument. + * Otherwise a colormap must be set on them with gdk_drawable_set_colormap. + * + * On older X servers, rendering pixbufs with an alpha channel involves round trips + * to the X server, and may be somewhat slow. + **/ +void +_gdk_draw_pixbuf (GdkDrawable *drawable, + GdkGC *gc, + GdkPixbuf *pixbuf, + gint src_x, + gint src_y, + gint dest_x, + gint dest_y, + gint width, + gint height, + GdkRgbDither dither, + gint x_dither, + gint y_dither) +{ + g_return_if_fail (GDK_IS_DRAWABLE (drawable)); + g_return_if_fail (gc == NULL || GDK_IS_GC (gc)); + g_return_if_fail (GDK_IS_PIXBUF (pixbuf)); + + if (width == -1) + width = gdk_pixbuf_get_width (pixbuf); + if (height == -1) + height = gdk_pixbuf_get_height (pixbuf); + + GDK_DRAWABLE_GET_CLASS (drawable)->_draw_pixbuf (drawable, gc, pixbuf, + src_x, src_y, dest_x, dest_y, width, height, + dither, x_dither, y_dither); +} + void gdk_draw_points (GdkDrawable *drawable, GdkGC *gc, @@ -617,6 +689,80 @@ gdk_draw_glyphs (GdkDrawable *drawable, } +/** + * _gdk_drawable_copy_to_image: + * @drawable: a #GdkDrawable + * @image: a #GdkDrawable, or %NULL if a new @image should be created. + * @src_x: x coordinate on @drawable + * @src_y: y coordinate on @drawable + * @dest_x: x coordinate within @image. Must be 0 if @image is %NULL + * @dest_y: y coordinate within @image. Must be 0 if @image is %NULL + * @width: width of region to get + * @height: height or region to get + * + * Copies a portion of @drawable into the client side image structure + * @image. If @image is %NULL, creates a new image of size @width x @height + * and copies into that. See gdk_drawable_get_image() for further details. + * + * Return value: @image, or a new a #GdkImage containing the contents + of @drawable + **/ +GdkImage* +_gdk_drawable_copy_to_image (GdkDrawable *drawable, + GdkImage *image, + gint src_x, + gint src_y, + gint dest_x, + gint dest_y, + gint width, + gint height) +{ + GdkDrawable *composite; + gint composite_x_offset = 0; + gint composite_y_offset = 0; + GdkImage *retval; + GdkColormap *cmap; + + g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL); + g_return_val_if_fail (src_x >= 0, NULL); + g_return_val_if_fail (src_y >= 0, NULL); + + /* FIXME? Note race condition since we get the size then + * get the image, and the size may have changed. + */ + + if (width < 0 || height < 0) + gdk_drawable_get_size (drawable, + width < 0 ? &width : NULL, + height < 0 ? &height : NULL); + + composite = + GDK_DRAWABLE_GET_CLASS (drawable)->get_composite_drawable (drawable, + src_x, src_y, + width, height, + &composite_x_offset, + &composite_y_offset); + + retval = GDK_DRAWABLE_GET_CLASS (composite)->_copy_to_image (composite, + image, + src_x - composite_x_offset, + src_y - composite_y_offset, + dest_x, dest_y, + width, height); + + g_object_unref (G_OBJECT (composite)); + + if (!image && retval) + { + cmap = gdk_drawable_get_colormap (drawable); + + if (cmap) + gdk_image_set_colormap (retval, cmap); + } + + return retval; +} + /** * gdk_drawable_get_image: * @drawable: a #GdkDrawable @@ -705,6 +851,16 @@ gdk_drawable_get_image (GdkDrawable *drawable, return retval; } +static GdkImage* +gdk_drawable_real_get_image (GdkDrawable *drawable, + gint x, + gint y, + gint width, + gint height) +{ + return _gdk_drawable_copy_to_image (drawable, NULL, x, y, 0, 0, width, height); +} + static GdkDrawable* gdk_drawable_real_get_composite_drawable (GdkDrawable *drawable, gint x, @@ -776,3 +932,386 @@ gdk_drawable_real_get_visible_region (GdkDrawable *drawable) return gdk_region_rectangle (&rect); } + +static void +composite (guchar *src_buf, + gint src_rowstride, + guchar *dest_buf, + gint dest_rowstride, + gint width, + gint height) +{ + guchar *src = src_buf; + guchar *dest = dest_buf; + + while (height--) + { + gint twidth = width; + guchar *p = src; + guchar *q = dest; + + while (twidth--) + { + guchar a = p[3]; + guint t; + + t = a * p[0] + (255 - a) * q[0] + 0x80; + q[0] = (t + (t >> 8)) >> 8; + t = a * p[1] + (255 - a) * q[1] + 0x80; + q[1] = (t + (t >> 8)) >> 8; + t = a * p[2] + (255 - a) * q[2] + 0x80; + q[2] = (t + (t >> 8)) >> 8; + + p += 4; + q += 3; + } + + src += src_rowstride; + dest += dest_rowstride; + } +} + +static void +composite_0888 (guchar *src_buf, + gint src_rowstride, + guchar *dest_buf, + gint dest_rowstride, + GdkByteOrder dest_byte_order, + gint width, + gint height) +{ + guchar *src = src_buf; + guchar *dest = dest_buf; + + while (height--) + { + gint twidth = width; + guchar *p = src; + guchar *q = dest; + + if (dest_byte_order == GDK_LSB_FIRST) + { + while (twidth--) + { + guint t; + + t = p[3] * p[2] + (255 - p[3]) * q[0] + 0x80; + q[0] = (t + (t >> 8)) >> 8; + t = p[3] * p[1] + (255 - p[3]) * q[1] + 0x80; + q[1] = (t + (t >> 8)) >> 8; + t = p[3] * p[0] + (255 - p[3]) * q[2] + 0x80; + q[2] = (t + (t >> 8)) >> 8; + p += 4; + q += 4; + } + } + else + { + while (twidth--) + { + guint t; + + t = p[3] * p[0] + (255 - p[3]) * q[1] + 0x80; + q[1] = (t + (t >> 8)) >> 8; + t = p[3] * p[1] + (255 - p[3]) * q[2] + 0x80; + q[2] = (t + (t >> 8)) >> 8; + t = p[3] * p[2] + (255 - p[3]) * q[3] + 0x80; + q[3] = (t + (t >> 8)) >> 8; + p += 4; + q += 4; + } + } + + src += src_rowstride; + dest += dest_rowstride; + } +} + +static void +composite_565 (guchar *src_buf, + gint src_rowstride, + guchar *dest_buf, + gint dest_rowstride, + GdkByteOrder dest_byte_order, + gint width, + gint height) +{ + guchar *src = src_buf; + guchar *dest = dest_buf; + + while (height--) + { + gint twidth = width; + guchar *p = src; + gushort *q = (gushort *)dest; + + while (twidth--) + { + guchar a = p[3]; + guint tr, tg, tb; + guint tr1, tg1, tb1; + guint tmp = *q; + +#if 1 + /* This is fast, and corresponds to what composite() above does + * if we converted to 8-bit first. + */ + tr = (tmp & 0xf800); + tr1 = a * p[0] + (255 - a) * ((tr >> 8) + (tr >> 13)) + 0x80; + tg = (tmp & 0x07e0); + tg1 = a * p[1] + (255 - a) * ((tg >> 3) + (tg >> 9)) + 0x80; + tb = (tmp & 0x001f); + tb1 = a * p[2] + (255 - a) * ((tb << 3) + (tb >> 2)) + 0x80; + + *q = (((tr1 + (tr1 >> 8)) & 0xf800) | + (((tg1 + (tg1 >> 8)) & 0xfc00) >> 5) | + ((tb1 + (tb1 >> 8)) >> 11)); +#else + /* This version correspond to the result we get with XRENDER - + * a bit of precision is lost since we convert to 8 bit after premultiplying + * instead of at the end + */ + guint tr2, tg2, tb2; + guint tr3, tg3, tb3; + + tr = (tmp & 0xf800); + tr1 = (255 - a) * ((tr >> 8) + (tr >> 13)) + 0x80; + tr2 = a * p[0] + 0x80; + tr3 = ((tr1 + (tr1 >> 8)) >> 8) + ((tr2 + (tr2 >> 8)) >> 8); + + tg = (tmp & 0x07e0); + tg1 = (255 - a) * ((tg >> 3) + (tg >> 9)) + 0x80; + tg2 = a * p[0] + 0x80; + tg3 = ((tg1 + (tg1 >> 8)) >> 8) + ((tg2 + (tg2 >> 8)) >> 8); + + tb = (tmp & 0x001f); + tb1 = (255 - a) * ((tb << 3) + (tb >> 2)) + 0x80; + tb2 = a * p[0] + 0x80; + tb3 = ((tb1 + (tb1 >> 8)) >> 8) + ((tb2 + (tb2 >> 8)) >> 8); + + *q = (((tr3 & 0xf8) << 8) | + ((tg3 & 0xfc) << 3) | + ((tb3 >> 3))); +#endif + + p += 4; + q++; + } + + src += src_rowstride; + dest += dest_rowstride; + } +} + +static void +gdk_drawable_real_draw_pixbuf (GdkDrawable *drawable, + GdkGC *gc, + GdkPixbuf *pixbuf, + gint src_x, + gint src_y, + gint dest_x, + gint dest_y, + gint width, + gint height, + GdkRgbDither dither, + gint x_dither, + gint y_dither) +{ + gboolean free_gc = FALSE; + GdkPixbuf *composited = NULL; + gint dwidth, dheight; + GdkRegion *clip; + GdkRegion *drect; + GdkRectangle tmp_rect; + + g_return_if_fail (GDK_IS_PIXBUF (pixbuf)); + g_return_if_fail (pixbuf->colorspace == GDK_COLORSPACE_RGB); + g_return_if_fail (pixbuf->n_channels == 3 || pixbuf->n_channels == 4); + g_return_if_fail (pixbuf->bits_per_sample == 8); + + g_return_if_fail (drawable != NULL); + + if (width == -1) + width = pixbuf->width; + if (height == -1) + height = pixbuf->height; + + g_return_if_fail (width >= 0 && height >= 0); + g_return_if_fail (src_x >= 0 && src_x + width <= pixbuf->width); + g_return_if_fail (src_y >= 0 && src_y + height <= pixbuf->height); + + /* Clip to the drawable; this is required for get_from_drawable() so + * can't be done implicitly + */ + + if (dest_x < 0) + { + src_x -= dest_x; + width += dest_x; + dest_x = 0; + } + + if (dest_y < 0) + { + src_y -= dest_y; + height += dest_y; + dest_y = 0; + } + + gdk_drawable_get_size (drawable, &dwidth, &dheight); + + if ((dest_x + width) > dwidth) + width = dwidth - dest_x; + + if ((dest_y + height) > dheight) + height = dheight - dest_y; + + if (width <= 0 || height <= 0) + return; + + /* Clip to the clip region; this avoids getting more + * image data from the server than we need to. + */ + + tmp_rect.x = dest_x; + tmp_rect.y = dest_y; + tmp_rect.width = width; + tmp_rect.height = height; + + drect = gdk_region_rectangle (&tmp_rect); + clip = gdk_drawable_get_clip_region (drawable); + + gdk_region_intersect (drect, clip); + + gdk_region_get_clipbox (drect, &tmp_rect); + + gdk_region_destroy (drect); + gdk_region_destroy (clip); + + if (tmp_rect.width == 0 || + tmp_rect.height == 0) + return; + + /* Actually draw */ + + if (!gc) + { + gc = gdk_gc_new (drawable); + free_gc = TRUE; + } + + if (pixbuf->has_alpha) + { + GdkVisual *visual = gdk_drawable_get_visual (drawable); + void (*composite_func) (guchar *src_buf, + gint src_rowstride, + guchar *dest_buf, + gint dest_rowstride, + GdkByteOrder dest_byte_order, + gint width, + gint height) = NULL; + + /* First we see if we have a visual-specific composition function that can composite + * the pixbuf data directly onto the image + */ + if (visual) + { + gint bits_per_pixel = _gdk_windowing_get_bits_for_depth (visual->depth); + + if (visual->byte_order == (G_BYTE_ORDER == G_BIG_ENDIAN ? GDK_MSB_FIRST : GDK_LSB_FIRST) && + visual->depth == 16 && + visual->red_mask == 0xf800 && + visual->green_mask == 0x07e0 && + visual->blue_mask == 0x001f) + composite_func = composite_565; + else if (visual->depth == 24 && bits_per_pixel == 32 && + visual->red_mask == 0xff0000 && + visual->green_mask == 0x00ff00 && + visual->blue_mask == 0x0000ff) + composite_func = composite_0888; + } + + /* We can't use our composite func if we are required to dither + */ + if (composite_func && !(dither == GDK_RGB_DITHER_MAX && visual->depth != 24)) + { + gint x0, y0; + for (y0 = 0; y0 < height; y0 += GDK_SCRATCH_IMAGE_HEIGHT) + { + gint height1 = MIN (height - y0, GDK_SCRATCH_IMAGE_HEIGHT); + for (x0 = 0; x0 < width; x0 += GDK_SCRATCH_IMAGE_WIDTH) + { + gint xs0, ys0; + + gint width1 = MIN (width - x0, GDK_SCRATCH_IMAGE_WIDTH); + + GdkImage *image = _gdk_image_get_scratch (width1, height1, gdk_drawable_get_depth (drawable), &xs0, &ys0); + + _gdk_drawable_copy_to_image (drawable, image, + dest_x + x0, dest_y + y0, + xs0, ys0, + width1, height1); + (*composite_func) (pixbuf->pixels + (src_y + y0) * pixbuf->rowstride + (src_x + x0) * 4, + pixbuf->rowstride, + image->mem + ys0 * image->bpl + xs0 * image->bpp, + image->bpl, + visual->byte_order, + width1, height1); + gdk_draw_image (drawable, gc, image, + xs0, ys0, + dest_x + x0, dest_y + y0, + width1, height1); + } + } + + goto out; + } + else + { + /* No special composition func, convert dest to 24 bit RGB data, composite against + * that, and convert back. + */ + composited = gdk_pixbuf_get_from_drawable (NULL, + drawable, + NULL, + dest_x, dest_y, + 0, 0, + width, height); + + if (composited) + composite (pixbuf->pixels + src_y * pixbuf->rowstride + src_x * 4, + pixbuf->rowstride, + composited->pixels, + composited->rowstride, + width, height); + } + } + + if (composited) + { + gdk_pixbuf_render_to_drawable (composited, + drawable, gc, + 0, 0, + dest_x, dest_y, + width, height, + dither, + x_dither, y_dither); + } + else + { + gdk_pixbuf_render_to_drawable (pixbuf, + drawable, gc, + src_x, src_y, + dest_x, dest_y, + width, height, + dither, + x_dither, y_dither); + } + + out: + if (composited) + g_object_unref (G_OBJECT (composited)); + + if (free_gc) + gdk_gc_unref (gc); +} diff --git a/gdk/gdkdrawable.h b/gdk/gdkdrawable.h index e343d8ae62..6d2d4d9b7b 100644 --- a/gdk/gdkdrawable.h +++ b/gdk/gdkdrawable.h @@ -3,6 +3,8 @@ #include #include +#include +#include #ifdef __cplusplus extern "C" { @@ -130,7 +132,28 @@ struct _GdkDrawableClass gint height, gint *composite_x_offset, gint *composite_y_offset); - + + void (*_draw_pixbuf) (GdkDrawable *drawable, + GdkGC *gc, + GdkPixbuf *pixbuf, + gint src_x, + gint src_y, + gint dest_x, + gint dest_y, + gint width, + gint height, + GdkRgbDither dither, + gint x_dither, + gint y_dither); + GdkImage* (*_copy_to_image) (GdkDrawable *drawable, + GdkImage *image, + gint src_x, + gint src_y, + gint dest_x, + gint dest_y, + gint width, + gint height); + void (*_gdk_reserved1) (void); void (*_gdk_reserved2) (void); void (*_gdk_reserved3) (void); diff --git a/gdk/gdkimage.c b/gdk/gdkimage.c index fe913325fa..e748d8f527 100644 --- a/gdk/gdkimage.c +++ b/gdk/gdkimage.c @@ -27,8 +27,10 @@ #include #include +#include "gdk.h" /* For gdk_flush() */ #include "gdkimage.h" #include "gdkprivate.h" +#include "gdkinternals.h" /* For scratch_image code */ /** * gdk_image_ref: @@ -137,3 +139,264 @@ gdk_image_get_colormap (GdkImage *image) return image->colormap; } + +/* We have N_REGION GDK_SCRATCH_IMAGE_WIDTH x GDK_SCRATCH_IMAGE_HEIGHT regions divided + * up between n_images different images. possible_n_images gives + * various divisors of N_REGIONS. The reason for allowing this + * flexibility is that we want to create as few images as possible, + * but we want to deal with the abberant systems that have a SHMMAX + * limit less than + * + * GDK_SCRATCH_IMAGE_WIDTH * GDK_SCRATCH_IMAGE_HEIGHT * N_REGIONS * 4 (384k) + * + * (Are there any such?) + */ +#define N_REGIONS 6 +static const int possible_n_images[] = { 1, 2, 3, 6 }; + +/* We allocate one GdkScratchImageInfo structure for each + * depth where we are allocating scratch images. (Future: one + * per depth, per display) + */ +typedef struct _GdkScratchImageInfo GdkScratchImageInfo; + +struct _GdkScratchImageInfo { + gint depth; + + gint n_images; + GdkImage *static_image[N_REGIONS]; + gint static_image_idx; + + /* In order to optimize filling fractions, we simultaneously fill in up + * to three regions of size GDK_SCRATCH_IMAGE_WIDTH * GDK_SCRATCH_IMAGE_HEIGHT: one + * for images that are taller than GDK_SCRATCH_IMAGE_HEIGHT / 2, and must + * be tiled horizontally. One for images that are wider than + * GDK_SCRATCH_IMAGE_WIDTH / 2 and must be tiled vertically, and a third + * for images smaller than GDK_SCRATCH_IMAGE_HEIGHT / 2 x GDK_SCRATCH_IMAGE_WIDTH x 2 + * that we tile in horizontal rows. + */ + gint horiz_idx; + gint horiz_y; + gint vert_idx; + gint vert_x; + + /* tile_y1 and tile_y2 define the horizontal band into + * which we are tiling images. tile_x is the x extent to + * which that is filled + */ + gint tile_idx; + gint tile_x; + gint tile_y1; + gint tile_y2; +}; + +static GSList *scratch_image_infos = NULL; + +static gboolean +allocate_scratch_images (GdkScratchImageInfo *info, + gint n_images, + gboolean shared) +{ + gint i; + + for (i = 0; i < n_images; i++) + { + info->static_image[i] = _gdk_image_new_for_depth (shared ? GDK_IMAGE_SHARED : GDK_IMAGE_NORMAL, + NULL, + GDK_SCRATCH_IMAGE_WIDTH * (N_REGIONS / n_images), GDK_SCRATCH_IMAGE_HEIGHT, + info->depth); + + if (!info->static_image[i]) + { + gint j; + + for (j = 0; j < i; j++) + gdk_image_unref (info->static_image[i]); + + return FALSE; + } + } + + return TRUE; +} + +GdkScratchImageInfo * +scratch_image_info_for_depth (gint depth) +{ + GSList *tmp_list; + GdkScratchImageInfo *image_info; + gint i; + + tmp_list = scratch_image_infos; + while (tmp_list) + { + image_info = tmp_list->data; + if (image_info->depth == depth) + return image_info; + + tmp_list = tmp_list->next; + } + + image_info = g_new (GdkScratchImageInfo, 1); + + image_info->depth = depth; + + /* Try to allocate as few possible shared images */ + for (i=0; i < G_N_ELEMENTS (possible_n_images); i++) + { + if (allocate_scratch_images (image_info, possible_n_images[i], TRUE)) + { + image_info->n_images = possible_n_images[i]; + break; + } + } + + /* If that fails, just allocate N_REGIONS normal images */ + if (i == G_N_ELEMENTS (possible_n_images)) + { + allocate_scratch_images (image_info, N_REGIONS, FALSE); + image_info->n_images = N_REGIONS; + } + + image_info->static_image_idx = 0; + + image_info->horiz_y = GDK_SCRATCH_IMAGE_HEIGHT; + image_info->vert_x = GDK_SCRATCH_IMAGE_WIDTH; + image_info->tile_x = GDK_SCRATCH_IMAGE_WIDTH; + image_info->tile_y1 = image_info->tile_y2 = GDK_SCRATCH_IMAGE_HEIGHT; + + scratch_image_infos = g_slist_prepend (scratch_image_infos, image_info); + + return image_info; +} + +/* Defining NO_FLUSH can cause inconsistent screen updates, but is useful + for performance evaluation. */ + +#undef NO_FLUSH + +#ifdef VERBOSE +static gint sincelast; +#endif + +static gint +alloc_scratch_image (GdkScratchImageInfo *image_info) +{ + if (image_info->static_image_idx == N_REGIONS) + { +#ifndef NO_FLUSH + gdk_flush (); +#endif +#ifdef VERBOSE + g_print ("flush, %d puts since last flush\n", sincelast); + sincelast = 0; +#endif + image_info->static_image_idx = 0; + + /* Mark all regions that we might be filling in as completely + * full, to force new tiles to be allocated for subsequent + * images + */ + image_info->horiz_y = GDK_SCRATCH_IMAGE_HEIGHT; + image_info->vert_x = GDK_SCRATCH_IMAGE_WIDTH; + image_info->tile_x = GDK_SCRATCH_IMAGE_WIDTH; + image_info->tile_y1 = image_info->tile_y2 = GDK_SCRATCH_IMAGE_HEIGHT; + } + return image_info->static_image_idx++; +} + +/** + * _gdk_image_get_scratch: + * @width: desired width + * @height: desired height + * @depth: depth of image + * @x: X location within returned image of scratch image + * @y: Y location within returned image of scratch image + * + * Allocates an image of size width/height, up to a maximum + * of GDK_SCRATCH_IMAGE_WIDTHxGDK_SCRATCH_IMAGE_HEIGHT + * + * Return value: a scratch image. This must be used by a + * call to gdk_image_put() before any other calls to + * _gdk_image_get_scratch() + **/ +GdkImage * +_gdk_image_get_scratch (gint width, + gint height, + gint depth, + gint *x, + gint *y) +{ + GdkScratchImageInfo *image_info; + GdkImage *image; + gint idx; + + image_info = scratch_image_info_for_depth (depth); + + if (width >= (GDK_SCRATCH_IMAGE_WIDTH >> 1)) + { + if (height >= (GDK_SCRATCH_IMAGE_HEIGHT >> 1)) + { + idx = alloc_scratch_image (image_info); + *x = 0; + *y = 0; + } + else + { + if (height + image_info->horiz_y > GDK_SCRATCH_IMAGE_HEIGHT) + { + image_info->horiz_idx = alloc_scratch_image (image_info); + image_info->horiz_y = 0; + } + idx = image_info->horiz_idx; + *x = 0; + *y = image_info->horiz_y; + image_info->horiz_y += height; + } + } + else + { + if (height >= (GDK_SCRATCH_IMAGE_HEIGHT >> 1)) + { + if (width + image_info->vert_x > GDK_SCRATCH_IMAGE_WIDTH) + { + image_info->vert_idx = alloc_scratch_image (image_info); + image_info->vert_x = 0; + } + idx = image_info->vert_idx; + *x = image_info->vert_x; + *y = 0; + /* using 3 and -4 would be slightly more efficient on 32-bit machines + with > 1bpp displays */ + image_info->vert_x += (width + 7) & -8; + } + else + { + if (width + image_info->tile_x > GDK_SCRATCH_IMAGE_WIDTH) + { + image_info->tile_y1 = image_info->tile_y2; + image_info->tile_x = 0; + } + if (height + image_info->tile_y1 > GDK_SCRATCH_IMAGE_HEIGHT) + { + image_info->tile_idx = alloc_scratch_image (image_info); + image_info->tile_x = 0; + image_info->tile_y1 = 0; + image_info->tile_y2 = 0; + } + if (height + image_info->tile_y1 > image_info->tile_y2) + image_info->tile_y2 = height + image_info->tile_y1; + idx = image_info->tile_idx; + *x = image_info->tile_x; + *y = image_info->tile_y1; + image_info->tile_x += (width + 7) & -8; + } + } + image = image_info->static_image[idx * image_info->n_images / N_REGIONS]; + *x += GDK_SCRATCH_IMAGE_WIDTH * (idx % (N_REGIONS / image_info->n_images)); +#ifdef VERBOSE + g_print ("index %d, x %d, y %d (%d x %d)\n", idx, *x, *y, width, height); + sincelast++; +#endif + return image; +} diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h index aa557abd56..327d56560d 100644 --- a/gdk/gdkinternals.h +++ b/gdk/gdkinternals.h @@ -158,6 +158,43 @@ void _gdk_event_queue_append (GdkEvent *event); void _gdk_event_button_generate (GdkEvent *event); +#define GDK_SCRATCH_IMAGE_WIDTH 256 +#define GDK_SCRATCH_IMAGE_HEIGHT 64 + +GdkImage* _gdk_image_new_for_depth (GdkImageType type, + GdkVisual *visual, + gint width, + gint height, + gint depth); +GdkImage *_gdk_image_get_scratch (gint width, + gint height, + gint depth, + gint *x, + gint *y); + +/* Will most likely be exported in the future + */ +void _gdk_draw_pixbuf (GdkDrawable *drawable, + GdkGC *gc, + GdkPixbuf *pixbuf, + gint src_x, + gint src_y, + gint dest_x, + gint dest_y, + gint width, + gint height, + GdkRgbDither dither, + gint x_dither, + gint y_dither); +GdkImage *_gdk_drawable_copy_to_image (GdkDrawable *drawable, + GdkImage *image, + gint src_x, + gint src_y, + gint dest_x, + gint dest_y, + gint width, + gint height); + /************************************* * Interfaces used by windowing code * *************************************/ @@ -204,6 +241,11 @@ GdkWindow* _gdk_windowing_window_get_pointer (GdkWindow *window, gint *y, GdkModifierType *mask); +/* Return the number of bits-per-pixel for images of the specified depth. + * (Future: needs to be GdkDiplay specific.) + */ +gint _gdk_windowing_get_bits_for_depth (gint depth); + #define GDK_WINDOW_IS_MAPPED(window) ((((GdkWindowObject*)window)->state & GDK_WINDOW_STATE_WITHDRAWN) == 0) /* Called before processing updates for a window. This gives the windowing diff --git a/gdk/gdkpixbuf-drawable.c b/gdk/gdkpixbuf-drawable.c index f4a99cab70..bfb0d941d1 100644 --- a/gdk/gdkpixbuf-drawable.c +++ b/gdk/gdkpixbuf-drawable.c @@ -72,7 +72,7 @@ bitmap1 (GdkImage *image, int bpl; register guint8 data; guint8 *o; - guint8 *srow = image->mem, *orow = pixels; + guint8 *srow = image->mem + y1 * image->bpl, *orow = pixels; d (printf ("bitmap, no alpha\n")); @@ -128,7 +128,7 @@ bitmap1a (GdkImage *image, int bpl; register guint8 data; guint8 *o; - guint8 *srow = image->mem, *orow = pixels; + guint8 *srow = image->mem + y1 * image->bpl, *orow = pixels; d (printf ("bitmap, with alpha\n")); @@ -183,7 +183,7 @@ rgb1 (GdkImage *image, int bpl; register guint8 data; guint8 *o; - guint8 *srow = image->mem, *orow = pixels; + guint8 *srow = image->mem + y1 * image->bpl, *orow = pixels; d (printf ("1 bits/pixel\n")); @@ -231,7 +231,7 @@ rgb1a (GdkImage *image, int bpl; register guint8 data; guint8 *o; - guint8 *srow = image->mem, *orow = pixels; + guint8 *srow = image->mem + y1 * image->bpl, *orow = pixels; d (printf ("1 bits/pixel\n")); @@ -279,7 +279,7 @@ rgb8 (GdkImage *image, int bpl; guint32 mask; register guint32 data; - guint8 *srow = image->mem, *orow = pixels; + guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels; register guint8 *s; register guint8 *o; @@ -326,7 +326,7 @@ rgb8a (GdkImage *image, guint32 remap[256]; register guint8 *s; /* read 2 pixels at once */ register guint32 *o; - guint8 *srow = image->mem, *orow = pixels; + guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels; bpl = image->bpl; @@ -387,7 +387,7 @@ rgb565lsb (GdkImage *image, register guint8 *s; /* read 2 pixels at once */ #endif register guint16 *o; - guint8 *srow = image->mem, *orow = pixels; + guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels; bpl = image->bpl; @@ -490,7 +490,7 @@ rgb565msb (GdkImage *image, register guint32 *s; /* read 2 pixels at once */ #endif register guint16 *o; - guint8 *srow = image->mem, *orow = pixels; + guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels; bpl = image->bpl; @@ -596,7 +596,7 @@ rgb565alsb (GdkImage *image, #endif register guint32 *o; - guint8 *srow = image->mem, *orow = pixels; + guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels; bpl = image->bpl; @@ -659,7 +659,7 @@ rgb565amsb (GdkImage *image, #endif register guint32 *o; - guint8 *srow = image->mem, *orow = pixels; + guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels; bpl = image->bpl; @@ -717,7 +717,7 @@ rgb555lsb (GdkImage *image, register guint8 *s; /* read 2 pixels at once */ #endif register guint16 *o; - guint8 *srow = image->mem, *orow = pixels; + guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels; bpl = image->bpl; @@ -821,7 +821,7 @@ rgb555msb (GdkImage *image, register guint32 *s; /* read 2 pixels at once */ #endif register guint16 *o; - guint8 *srow = image->mem, *orow = pixels; + guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels; bpl = image->bpl; @@ -922,7 +922,7 @@ rgb555alsb (GdkImage *image, #endif register guint32 *o; - guint8 *srow = image->mem, *orow = pixels; + guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels; bpl = image->bpl; @@ -985,7 +985,7 @@ rgb555amsb (GdkImage *image, #endif register guint32 *o; - guint8 *srow = image->mem, *orow = pixels; + guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels; bpl = image->bpl; @@ -1039,7 +1039,7 @@ rgb888alsb (GdkImage *image, guint8 *s; /* for byte order swapping */ guint8 *o; - guint8 *srow = image->mem, *orow = pixels; + guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels; bpl = image->bpl; @@ -1076,7 +1076,7 @@ rgb888lsb (GdkImage *image, int xx, yy; int bpl; - guint8 *srow = image->mem, *orow = pixels; + guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels; guint8 *o, *s; bpl = image->bpl; @@ -1112,7 +1112,7 @@ rgb888amsb (GdkImage *image, int xx, yy; int bpl; - guint8 *srow = image->mem, *orow = pixels; + guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels; #ifdef LITTLE guint32 *o; guint32 *s; @@ -1166,7 +1166,7 @@ rgb888msb (GdkImage *image, int xx, yy; int bpl; - guint8 *srow = image->mem, *orow = pixels; + guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels; guint8 *s; guint8 *o; @@ -1207,8 +1207,7 @@ convert_real_slow (GdkImage *image, { int xx, yy; int bpl; - guint8 *srow = image->mem, *orow = pixels; - guint8 *s; + guint8 *orow = pixels; guint8 *o; guint32 pixel; GdkVisual *v; @@ -1225,7 +1224,6 @@ convert_real_slow (GdkImage *image, for (yy = y1; yy < y2; yy++) { - s = srow; o = orow; for (xx = x1; xx < x2; xx++) { @@ -1268,7 +1266,6 @@ convert_real_slow (GdkImage *image, if (alpha) *o++ = 0xff; } - srow += bpl; orow += rowstride; } } @@ -1481,6 +1478,7 @@ gdk_pixbuf_get_from_drawable (GdkPixbuf *dest, int src_width, src_height; GdkImage *image; int depth; + int x0, y0; /* General sanity checks */ @@ -1503,6 +1501,14 @@ gdk_pixbuf_get_from_drawable (GdkPixbuf *dest, g_return_val_if_fail (dest->bits_per_sample == 8, NULL); } + /* Create the pixbuf if needed */ + if (!dest) + { + dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, width, height); + if (dest == NULL) + return NULL; + } + if (cmap == NULL) cmap = gdk_drawable_get_colormap (src); @@ -1536,19 +1542,28 @@ gdk_pixbuf_get_from_drawable (GdkPixbuf *dest, g_return_val_if_fail (dest_x + width <= dest->width, NULL); g_return_val_if_fail (dest_y + height <= dest->height, NULL); } - - /* Get Image in ZPixmap format (packed bits). */ - image = gdk_image_get (src, src_x, src_y, width, height); - - if (image == NULL) - return NULL; - - dest = gdk_pixbuf_get_from_image (dest, image, cmap, - 0, 0, dest_x, dest_y, - width, height); - gdk_image_destroy (image); + for (y0 = 0; y0 < height; y0 += GDK_SCRATCH_IMAGE_HEIGHT) + { + gint height1 = MIN (height - y0, GDK_SCRATCH_IMAGE_HEIGHT); + for (x0 = 0; x0 < width; x0 += GDK_SCRATCH_IMAGE_WIDTH) + { + gint xs0, ys0; + + gint width1 = MIN (width - x0, GDK_SCRATCH_IMAGE_WIDTH); + + image = _gdk_image_get_scratch (width1, height1, depth, &xs0, &ys0); + _gdk_drawable_copy_to_image (src, image, + src_x + x0, src_y + y0, + xs0, ys0, width1, height1); + + gdk_pixbuf_get_from_image (dest, image, cmap, + xs0, ys0, dest_x + x0, dest_y + y0, + width1, height1); + } + } + return dest; } @@ -1638,8 +1653,8 @@ gdk_pixbuf_get_from_image (GdkPixbuf *dest, rowstride, alpha, src_x, src_y, - src_x + width, - src_y + height, + width, + height, cmap); return dest; diff --git a/gdk/gdkpixbuf-render.c b/gdk/gdkpixbuf-render.c index 23c75121b4..daaf6b31bb 100644 --- a/gdk/gdkpixbuf-render.c +++ b/gdk/gdkpixbuf-render.c @@ -237,30 +237,19 @@ gdk_pixbuf_render_to_drawable (GdkPixbuf *pixbuf, * @dest_y: Destination Y coordinate within drawable. * @width: Width of region to render, in pixels, or -1 to use pixbuf width. * @height: Height of region to render, in pixels, or -1 to use pixbuf height. - * @alpha_mode: If the image does not have opacity information, this is ignored. - * Otherwise, specifies how to handle transparency when rendering. - * @alpha_threshold: If the image does have opacity information and @alpha_mode - * is GDK_PIXBUF_ALPHA_BILEVEL, specifies the threshold value for opacity - * values. + * @alpha_mode: Ignored. Present for backwards compatibility. + * @alpha_threshold: Ignored. Present for backwards compatibility * @dither: Dithering mode for GdkRGB. * @x_dither: X offset for dither. * @y_dither: Y offset for dither. * - * Renders a rectangular portion of a pixbuf to a drawable. This is done using - * GdkRGB, so the specified drawable must have the GdkRGB visual and colormap. + * Renders a rectangular portion of a pixbuf to a drawable. The destination + * drawable must have a colormap. All windows have a colormap, however, pixmaps + * only have colormap by default if they were created with a non-NULL window argument. + * Otherwise a colormap must be set on them with gdk_drawable_set_colormap. * - * When used with #GDK_PIXBUF_ALPHA_BILEVEL, this function has to create a bitmap - * out of the thresholded alpha channel of the image and, it has to set this - * bitmap as the clipping mask for the GC used for drawing. This can be a - * significant performance penalty depending on the size and the complexity of - * the alpha channel of the image. If performance is crucial, consider handling - * the alpha channel yourself (possibly by caching it in your application) and - * using gdk_pixbuf_render_to_drawable() or GdkRGB directly instead. - * - * The #GDK_PIXBUF_ALPHA_FULL mode involves round trips to the X - * server, and may also be somewhat slow in its current implementation - * (though in the future it could be made significantly faster, in - * principle). + * On older X servers, rendering pixbufs with an alpha channel involves round trips + * to the X server, and may be somewhat slow. **/ void gdk_pixbuf_render_to_drawable_alpha (GdkPixbuf *pixbuf, @@ -273,165 +262,9 @@ gdk_pixbuf_render_to_drawable_alpha (GdkPixbuf *pixbuf, GdkRgbDither dither, int x_dither, int y_dither) { - GdkBitmap *bitmap = NULL; - GdkGC *gc; - GdkPixbuf *composited = NULL; - gint dwidth, dheight; - GdkRegion *clip; - GdkRegion *drect; - GdkRectangle tmp_rect; - - g_return_if_fail (GDK_IS_PIXBUF (pixbuf)); - g_return_if_fail (pixbuf->colorspace == GDK_COLORSPACE_RGB); - g_return_if_fail (pixbuf->n_channels == 3 || pixbuf->n_channels == 4); - g_return_if_fail (pixbuf->bits_per_sample == 8); - - g_return_if_fail (drawable != NULL); - - if (width == -1) - width = pixbuf->width; - if (height == -1) - height = pixbuf->height; - - g_return_if_fail (width >= 0 && height >= 0); - g_return_if_fail (src_x >= 0 && src_x + width <= pixbuf->width); - g_return_if_fail (src_y >= 0 && src_y + height <= pixbuf->height); - - /* Clip to the drawable; this is required for get_from_drawable() so - * can't be done implicitly - */ - - if (dest_x < 0) - { - src_x -= dest_x; - width += dest_x; - dest_x = 0; - } - - if (dest_y < 0) - { - src_y -= dest_y; - height += dest_y; - dest_y = 0; - } - - gdk_drawable_get_size (drawable, &dwidth, &dheight); - - if ((dest_x + width) > dwidth) - width = dwidth - dest_x; - - if ((dest_y + height) > dheight) - height = dheight - dest_y; - - if (width <= 0 || height <= 0) - return; - - /* Clip to the clip region; this avoids getting more - * image data from the server than we need to. - */ - - tmp_rect.x = dest_x; - tmp_rect.y = dest_y; - tmp_rect.width = width; - tmp_rect.height = height; - - drect = gdk_region_rectangle (&tmp_rect); - clip = gdk_drawable_get_clip_region (drawable); - - gdk_region_intersect (drect, clip); - - gdk_region_get_clipbox (drect, &tmp_rect); - - gdk_region_destroy (drect); - gdk_region_destroy (clip); - - if (tmp_rect.width == 0 || - tmp_rect.height == 0) - return; - - /* Actually draw */ - - gc = gdk_gc_new (drawable); - - if (pixbuf->has_alpha) - { - if (alpha_mode == GDK_PIXBUF_ALPHA_FULL) - { - GdkPixbuf *sub = NULL; - - composited = gdk_pixbuf_get_from_drawable (NULL, - drawable, - NULL, - dest_x, dest_y, - 0, 0, - width, height); - - if (composited) - { - if (src_x != 0 || src_y != 0) - { - sub = gdk_pixbuf_new_subpixbuf (pixbuf, src_x, src_y, - width, height); - } - - gdk_pixbuf_composite (sub ? sub : pixbuf, - composited, - 0, 0, - width, height, - 0, 0, - 1.0, 1.0, - GDK_INTERP_BILINEAR, - 255); - - if (sub) - g_object_unref (G_OBJECT (sub)); - } - else - alpha_mode = GDK_PIXBUF_ALPHA_BILEVEL; /* fall back */ - } - - if (alpha_mode == GDK_PIXBUF_ALPHA_BILEVEL) - { - bitmap = gdk_pixmap_new (NULL, width, height, 1); - gdk_pixbuf_render_threshold_alpha (pixbuf, bitmap, - src_x, src_y, - 0, 0, - width, height, - alpha_threshold); - - gdk_gc_set_clip_mask (gc, bitmap); - gdk_gc_set_clip_origin (gc, dest_x, dest_y); - } - } - - if (composited) - { - gdk_pixbuf_render_to_drawable (composited, - drawable, gc, - 0, 0, - dest_x, dest_y, - width, height, - dither, - x_dither, y_dither); - } - else - { - gdk_pixbuf_render_to_drawable (pixbuf, - drawable, gc, - src_x, src_y, - dest_x, dest_y, - width, height, - dither, - x_dither, y_dither); - } - - if (bitmap) - gdk_bitmap_unref (bitmap); - - if (composited) - g_object_unref (G_OBJECT (composited)); - - gdk_gc_unref (gc); + _gdk_draw_pixbuf (drawable, NULL, pixbuf, + src_x, src_y, dest_x, dest_y, width, height, + dither, x_dither, y_dither); } /** @@ -531,5 +364,3 @@ gdk_pixbuf_render_pixmap_and_mask_for_colormap (GdkPixbuf *pixbuf, *mask_return = NULL; } } - - diff --git a/gdk/gdkpixmap.c b/gdk/gdkpixmap.c index 088e181a5e..5e757246fb 100644 --- a/gdk/gdkpixmap.c +++ b/gdk/gdkpixmap.c @@ -102,16 +102,32 @@ static void gdk_pixmap_draw_image (GdkDrawable *drawable, gint ydest, gint width, gint height); +static void gdk_pixmap_draw_pixbuf (GdkDrawable *drawable, + GdkGC *gc, + GdkPixbuf *pixbuf, + gint src_x, + gint src_y, + gint dest_x, + gint dest_y, + gint width, + gint height, + GdkRgbDither dither, + gint x_dither, + gint y_dither); + static void gdk_pixmap_real_get_size (GdkDrawable *drawable, gint *width, gint *height); -static GdkImage* gdk_pixmap_get_image (GdkDrawable *drawable, - gint x, - gint y, - gint width, - gint height); +static GdkImage* gdk_pixmap_copy_to_image (GdkDrawable *drawable, + GdkImage *image, + gint src_x, + gint src_y, + gint dest_x, + gint dest_y, + gint width, + gint height); static GdkVisual* gdk_pixmap_real_get_visual (GdkDrawable *drawable); static gint gdk_pixmap_real_get_depth (GdkDrawable *drawable); @@ -182,12 +198,13 @@ gdk_pixmap_class_init (GdkPixmapObjectClass *klass) drawable_class->draw_lines = gdk_pixmap_draw_lines; drawable_class->draw_glyphs = gdk_pixmap_draw_glyphs; drawable_class->draw_image = gdk_pixmap_draw_image; + drawable_class->_draw_pixbuf = gdk_pixmap_draw_pixbuf; drawable_class->get_depth = gdk_pixmap_real_get_depth; drawable_class->get_size = gdk_pixmap_real_get_size; drawable_class->set_colormap = gdk_pixmap_real_set_colormap; drawable_class->get_colormap = gdk_pixmap_real_get_colormap; drawable_class->get_visual = gdk_pixmap_real_get_visual; - drawable_class->get_image = gdk_pixmap_get_image; + drawable_class->_copy_to_image = gdk_pixmap_copy_to_image; } static void @@ -366,6 +383,27 @@ gdk_pixmap_draw_image (GdkDrawable *drawable, width, height); } +static void +gdk_pixmap_draw_pixbuf (GdkDrawable *drawable, + GdkGC *gc, + GdkPixbuf *pixbuf, + gint src_x, + gint src_y, + gint dest_x, + gint dest_y, + gint width, + gint height, + GdkRgbDither dither, + gint x_dither, + gint y_dither) +{ + GdkPixmapObject *private = (GdkPixmapObject *)drawable; + + _gdk_draw_pixbuf (private->impl, gc, pixbuf, + src_x, src_y, dest_x, dest_y, width, height, + dither, x_dither, y_dither); +} + static void gdk_pixmap_real_get_size (GdkDrawable *drawable, gint *width, @@ -418,16 +456,21 @@ gdk_pixmap_real_get_colormap (GdkDrawable *drawable) } static GdkImage* -gdk_pixmap_get_image (GdkDrawable *drawable, - gint x, - gint y, - gint width, - gint height) +gdk_pixmap_copy_to_image (GdkDrawable *drawable, + GdkImage *image, + gint src_x, + gint src_y, + gint dest_x, + gint dest_y, + gint width, + gint height) { g_return_val_if_fail (GDK_IS_PIXMAP (drawable), NULL); - return gdk_drawable_get_image (((GdkPixmapObject*)drawable)->impl, - x, y, width, height); + return _gdk_drawable_copy_to_image (((GdkPixmapObject*)drawable)->impl, + image, + src_x, src_y, dest_x, dest_y, + width, height); } static GdkBitmap * diff --git a/gdk/gdkrgb.c b/gdk/gdkrgb.c index d7ce391cd2..042d4ca339 100644 --- a/gdk/gdkrgb.c +++ b/gdk/gdkrgb.c @@ -46,22 +46,10 @@ #define ENABLE_GRAYSCALE -#ifdef GDK_RGB_STANDALONE - -/* Compiling as a standalone module (i.e. with Gtk 1.0) */ -/* gtk/gtk.h is already included in gdkrgbstub.c */ -#include "config.h" -#include - -#else - -/* Compiling as a part of Gtk 1.1 or later */ #include "config.h" #include "gdkprivate.h" +#include "gdkinternals.h" /* _gdk_windowing_get_bits_for_depth() */ -#endif - -#include "gdk.h" /* For gdk_flush() */ #include "gdkrgb.h" typedef struct _GdkRgbInfo GdkRgbInfo; @@ -84,30 +72,10 @@ static const gchar* visual_names[] = "direct color", }; -#define REGION_WIDTH 256 -#define STAGE_ROWSTRIDE (REGION_WIDTH * 3) -#define REGION_HEIGHT 64 +#define STAGE_ROWSTRIDE (GDK_SCRATCH_IMAGE_WIDTH * 3) -/* We have N_REGION REGION_WIDTH x REGION_HEIGHT regions divided - * up between n_images different images. possible_n_images gives - * various divisors of N_REGIONS. The reason for allowing this - * flexibility is that we want to create as few images as possible, - * but we want to deal with the abberant systems that have a SHMMAX - * limit less than - * - * REGION_WIDTH * REGION_HEIGHT * N_REGIONS * 4 (384k) - * - * (Are there any such?) +/* Some of these fields should go, as they're not being used at all. (?) */ -#define N_REGIONS 6 -static const int possible_n_images[] = { 1, 2, 3, 6 }; - -/* Some of these fields should go, as they're not being used at all. - Globals should generally migrate into here - it's very likely that - we'll want to run more than one GdkRgbInfo context at the same time - (i.e. some but not all windows have privately installed - colormaps). */ - struct _GdkRgbInfo { GdkVisual *visual; @@ -147,32 +115,6 @@ struct _GdkRgbInfo GdkRgbConvFunc conv_indexed; GdkRgbConvFunc conv_indexed_d; - gint n_images; - GdkImage *static_image[N_REGIONS]; - gint static_image_idx; - - /* In order to optimize filling fractions, we simultaneously fill in up - * to three regions of size REGION_WIDTH * REGION_HEIGHT: one - * for images that are taller than REGION_HEIGHT / 2, and must - * be tiled horizontally. One for images that are wider than - * REGION_WIDTH / 2 and must be tiled vertically, and a third - * for images smaller than REGION_HEIGHT / 2 x REGION_WIDTH x 2 - * that we tile in horizontal rows. - */ - gint horiz_idx; - gint horiz_y; - gint vert_idx; - gint vert_x; - - /* tile_y1 and tile_y2 define the horizontal band into - * which we are tiling images. tile_x is the x extent to - * which that is filled - */ - gint tile_idx; - gint tile_x; - gint tile_y1; - gint tile_y2; - guchar *colorcube; guchar *colorcube_d; @@ -562,7 +504,7 @@ gdk_rgb_choose_visual (void) return best_visual; } -static void gdk_rgb_select_conv (GdkRgbInfo *image_info, GdkImage *image); +static void gdk_rgb_select_conv (GdkRgbInfo *image_info); static void gdk_rgb_set_gray_cmap (GdkRgbInfo *image_info, @@ -606,39 +548,10 @@ gdk_rgb_set_gray_cmap (GdkRgbInfo *image_info, } } -static gboolean -gdk_rgb_allocate_images (GdkRgbInfo *image_info, - gint n_images, - gboolean shared) -{ - gint i; - - for (i = 0; i < n_images; i++) - { - image_info->static_image[i] = gdk_image_new (shared ? GDK_IMAGE_SHARED : GDK_IMAGE_NORMAL, - image_info->visual, - REGION_WIDTH * (N_REGIONS / n_images), REGION_HEIGHT); - - if (!image_info->static_image[i]) - { - gint j; - - for (j = 0; j < i; j++) - gdk_image_unref (image_info->static_image[i]); - - return FALSE; - } - } - - return TRUE; -} - static void gdk_rgb_free_info (GdkRgbInfo *image_info) { - gint i; GSList *tmp_list; - if (image_info->stage_buf) g_free (image_info->stage_buf); @@ -649,9 +562,6 @@ gdk_rgb_free_info (GdkRgbInfo *image_info) if (image_info->own_gc) gdk_gc_unref (image_info->own_gc); - for (i = 0; i < image_info->n_images; i++) - gdk_image_unref (image_info->static_image[i]); - if (image_info->colorcube) g_free (image_info->colorcube); @@ -679,7 +589,6 @@ static GdkRgbInfo * gdk_rgb_create_info (GdkVisual *visual, GdkColormap *colormap) { GdkRgbInfo *image_info; - gint i; image_info = g_new0 (GdkRgbInfo, 1); @@ -765,33 +674,9 @@ gdk_rgb_create_info (GdkVisual *visual, GdkColormap *colormap) image_info->bitmap = (image_info->visual->depth == 1); - /* Try to allocate as few possible shared images */ - for (i=0; i < G_N_ELEMENTS (possible_n_images); i++) - { - if (gdk_rgb_allocate_images (image_info, possible_n_images[i], TRUE)) - { - image_info->n_images = possible_n_images[i]; - break; - } - } + image_info->bpp = (_gdk_windowing_get_bits_for_depth (image_info->visual->depth) + 7) / 8; - /* If that fails, just allocate N_REGIONS normal images */ - if (i == G_N_ELEMENTS (possible_n_images)) - { - gdk_rgb_allocate_images (image_info, N_REGIONS, FALSE); - image_info->n_images = N_REGIONS; - } - - image_info->bpp = image_info->static_image[0]->bpp; - - image_info->static_image_idx = 0; - - image_info->horiz_y = REGION_HEIGHT; - image_info->vert_x = REGION_WIDTH; - image_info->tile_x = REGION_WIDTH; - image_info->tile_y1 = image_info->tile_y2 = REGION_HEIGHT; - - gdk_rgb_select_conv (image_info, image_info->static_image[0]); + gdk_rgb_select_conv (image_info); if (!gdk_rgb_quark) gdk_rgb_quark = g_quark_from_static_string (gdk_rgb_key); @@ -1415,7 +1300,7 @@ gdk_rgb_convert_gray8_gray (GdkRgbInfo *image_info, GdkImage *image, #ifdef HAIRY_CONVERT_565 /* Render a 24-bit RGB image in buf into the GdkImage, without dithering. This assumes native byte ordering - what should really be done is to - check whether static_image->byte_order is consistent with the _ENDIAN + check whether the the image byte_order is consistent with the _ENDIAN config flag, and if not, use a different function. This one is even faster than the one below - its inner loop loads 3 @@ -1499,7 +1384,7 @@ gdk_rgb_convert_565 (GdkRgbInfo *image_info, GdkImage *image, #else /* Render a 24-bit RGB image in buf into the GdkImage, without dithering. This assumes native byte ordering - what should really be done is to - check whether static_image->byte_order is consistent with the _ENDIAN + check whether the image byte_order is consistent with the _ENDIAN config flag, and if not, use a different function. This routine is faster than the one included with Gtk 1.0 for a number @@ -2670,7 +2555,7 @@ static guchar * gdk_rgb_ensure_stage (GdkRgbInfo *image_info) { if (image_info->stage_buf == NULL) - image_info->stage_buf = g_malloc (REGION_HEIGHT * STAGE_ROWSTRIDE); + image_info->stage_buf = g_malloc (GDK_SCRATCH_IMAGE_HEIGHT * STAGE_ROWSTRIDE); return image_info->stage_buf; } @@ -2873,7 +2758,7 @@ gdk_rgb_convert_indexed_generic_d (GdkRgbInfo *image_info, GdkImage *image, /* Select a conversion function based on the visual and a representative image. */ static void -gdk_rgb_select_conv (GdkRgbInfo *image_info, GdkImage *image) +gdk_rgb_select_conv (GdkRgbInfo *image_info) { GdkByteOrder byte_order; gint depth, bpp, byterev; @@ -2887,9 +2772,9 @@ gdk_rgb_select_conv (GdkRgbInfo *image_info, GdkImage *image) depth = image_info->visual->depth; - bpp = image->bits_per_pixel; + bpp = _gdk_windowing_get_bits_for_depth (image_info->visual->depth); - byte_order = image->byte_order; + byte_order = image_info->visual->byte_order; if (gdk_rgb_verbose) g_print ("Chose visual type=%s depth=%d, image bpp=%d, %s first\n", visual_names[image_info->visual->type], image_info->visual->depth, @@ -3066,116 +2951,6 @@ gdk_rgb_select_conv (GdkRgbInfo *image_info, GdkImage *image) image_info->conv_indexed_d = conv_indexed_d; } -#ifdef VERBOSE -static gint sincelast; -#endif - -/* Defining NO_FLUSH can cause inconsistent screen updates, but is useful - for performance evaluation. */ - -#undef NO_FLUSH - -static gint -gdk_rgb_alloc_scratch_image (GdkRgbInfo *image_info) -{ - if (image_info->static_image_idx == N_REGIONS) - { -#ifndef NO_FLUSH - gdk_flush (); -#endif -#ifdef VERBOSE - g_print ("flush, %d puts since last flush\n", sincelast); - sincelast = 0; -#endif - image_info->static_image_idx = 0; - - /* Mark all regions that we might be filling in as completely - * full, to force new tiles to be allocated for subsequent - * images - */ - image_info->horiz_y = REGION_HEIGHT; - image_info->vert_x = REGION_WIDTH; - image_info->tile_x = REGION_WIDTH; - image_info->tile_y1 = image_info->tile_y2 = REGION_HEIGHT; - } - return image_info->static_image_idx++; -} - -static GdkImage * -gdk_rgb_alloc_scratch (GdkRgbInfo *image_info, - gint width, gint height, gint *x0, gint *y0) -{ - GdkImage *image; - gint idx; - - if (width >= (REGION_WIDTH >> 1)) - { - if (height >= (REGION_HEIGHT >> 1)) - { - idx = gdk_rgb_alloc_scratch_image (image_info); - *x0 = 0; - *y0 = 0; - } - else - { - if (height + image_info->horiz_y > REGION_HEIGHT) - { - image_info->horiz_idx = gdk_rgb_alloc_scratch_image (image_info); - image_info->horiz_y = 0; - } - idx = image_info->horiz_idx; - *x0 = 0; - *y0 = image_info->horiz_y; - image_info->horiz_y += height; - } - } - else - { - if (height >= (REGION_HEIGHT >> 1)) - { - if (width + image_info->vert_x > REGION_WIDTH) - { - image_info->vert_idx = gdk_rgb_alloc_scratch_image (image_info); - image_info->vert_x = 0; - } - idx = image_info->vert_idx; - *x0 = image_info->vert_x; - *y0 = 0; - /* using 3 and -4 would be slightly more efficient on 32-bit machines - with > 1bpp displays */ - image_info->vert_x += (width + 7) & -8; - } - else - { - if (width + image_info->tile_x > REGION_WIDTH) - { - image_info->tile_y1 = image_info->tile_y2; - image_info->tile_x = 0; - } - if (height + image_info->tile_y1 > REGION_HEIGHT) - { - image_info->tile_idx = gdk_rgb_alloc_scratch_image (image_info); - image_info->tile_x = 0; - image_info->tile_y1 = 0; - image_info->tile_y2 = 0; - } - if (height + image_info->tile_y1 > image_info->tile_y2) - image_info->tile_y2 = height + image_info->tile_y1; - idx = image_info->tile_idx; - *x0 = image_info->tile_x; - *y0 = image_info->tile_y1; - image_info->tile_x += (width + 7) & -8; - } - } - image = image_info->static_image[idx * image_info->n_images / N_REGIONS]; - *x0 += REGION_WIDTH * (idx % (N_REGIONS / image_info->n_images)); -#ifdef VERBOSE - g_print ("index %d, x %d, y %d (%d x %d)\n", idx, *x0, *y0, width, height); - sincelast++; -#endif - return image; -} - static void gdk_draw_rgb_image_core (GdkRgbInfo *image_info, GdkDrawable *drawable, @@ -3212,15 +2987,15 @@ gdk_draw_rgb_image_core (GdkRgbInfo *image_info, } gc = image_info->own_gc; } - for (y0 = 0; y0 < height; y0 += REGION_HEIGHT) + for (y0 = 0; y0 < height; y0 += GDK_SCRATCH_IMAGE_HEIGHT) { - height1 = MIN (height - y0, REGION_HEIGHT); - for (x0 = 0; x0 < width; x0 += REGION_WIDTH) + height1 = MIN (height - y0, GDK_SCRATCH_IMAGE_HEIGHT); + for (x0 = 0; x0 < width; x0 += GDK_SCRATCH_IMAGE_WIDTH) { - width1 = MIN (width - x0, REGION_WIDTH); + width1 = MIN (width - x0, GDK_SCRATCH_IMAGE_WIDTH); buf_ptr = buf + y0 * rowstride + x0 * pixstride; - image = gdk_rgb_alloc_scratch (image_info, width1, height1, &xs0, &ys0); + image = _gdk_image_get_scratch (width1, height1, image_info->visual->depth, &xs0, &ys0); conv (image_info, image, xs0, ys0, width1, height1, buf_ptr, rowstride, x + x0 + xdith, y + y0 + ydith, cmap); diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c index 28c2b26fef..ea9fdc2b23 100644 --- a/gdk/gdkwindow.c +++ b/gdk/gdkwindow.c @@ -126,12 +126,27 @@ static void gdk_window_draw_image (GdkDrawable *drawable, gint width, gint height); -static GdkImage* gdk_window_get_image (GdkDrawable *drawable, - gint x, - gint y, - gint width, - gint height); +static void gdk_window_draw_pixbuf (GdkDrawable *drawable, + GdkGC *gc, + GdkPixbuf *pixbuf, + gint src_x, + gint src_y, + gint dest_x, + gint dest_y, + gint width, + gint height, + GdkRgbDither dither, + gint x_dither, + gint y_dither); +static GdkImage* gdk_window_copy_to_image (GdkDrawable *drawable, + GdkImage *image, + gint src_x, + gint src_y, + gint dest_x, + gint dest_y, + gint width, + gint height); static void gdk_window_real_get_size (GdkDrawable *drawable, gint *width, @@ -223,12 +238,13 @@ gdk_window_class_init (GdkWindowObjectClass *klass) drawable_class->draw_lines = gdk_window_draw_lines; drawable_class->draw_glyphs = gdk_window_draw_glyphs; drawable_class->draw_image = gdk_window_draw_image; + drawable_class->_draw_pixbuf = gdk_window_draw_pixbuf; drawable_class->get_depth = gdk_window_real_get_depth; drawable_class->get_size = gdk_window_real_get_size; drawable_class->set_colormap = gdk_window_real_set_colormap; drawable_class->get_colormap = gdk_window_real_get_colormap; drawable_class->get_visual = gdk_window_real_get_visual; - drawable_class->get_image = gdk_window_get_image; + drawable_class->_copy_to_image = gdk_window_copy_to_image; drawable_class->get_clip_region = gdk_window_get_clip_region; drawable_class->get_visible_region = gdk_window_get_visible_region; drawable_class->get_composite_drawable = gdk_window_get_composite_drawable; @@ -1862,6 +1878,65 @@ gdk_window_draw_image (GdkDrawable *drawable, RESTORE_GC (gc); } +static void +gdk_window_draw_pixbuf (GdkDrawable *drawable, + GdkGC *gc, + GdkPixbuf *pixbuf, + gint src_x, + gint src_y, + gint dest_x, + gint dest_y, + gint width, + gint height, + GdkRgbDither dither, + gint x_dither, + gint y_dither) +{ + GdkWindowObject *private = (GdkWindowObject *)drawable; + + if (GDK_WINDOW_DESTROYED (drawable)) + return; + + if (gc) + { + OFFSET_GC (gc); + + if (private->paint_stack) + { + GdkWindowPaint *paint = private->paint_stack->data; + _gdk_draw_pixbuf (paint->pixmap, gc, pixbuf, src_x, src_y, + dest_x - x_offset, dest_y - y_offset, + width, height, + dither, x_dither - x_offset, y_dither - y_offset); + } + else + _gdk_draw_pixbuf (private->impl, gc, pixbuf, src_x, src_y, + dest_x - x_offset, dest_y - y_offset, + width, height, + dither, x_dither, y_dither); + + RESTORE_GC (gc); + } + else + { + gint x_offset, y_offset; + gdk_window_get_offsets (drawable, &x_offset, &y_offset); + + if (private->paint_stack) + { + GdkWindowPaint *paint = private->paint_stack->data; + _gdk_draw_pixbuf (paint->pixmap, gc, pixbuf, src_x, src_y, + dest_x - x_offset, dest_y - y_offset, + width, height, + dither, x_dither - x_offset, y_dither - y_offset); + } + else + _gdk_draw_pixbuf (private->impl, gc, pixbuf, src_x, src_y, + dest_x - x_offset, dest_y - y_offset, + width, height, + dither, x_dither, y_dither); + } +} static void gdk_window_real_get_size (GdkDrawable *drawable, @@ -1927,11 +2002,14 @@ gdk_window_real_get_colormap (GdkDrawable *drawable) } static GdkImage* -gdk_window_get_image (GdkDrawable *drawable, - gint x, - gint y, - gint width, - gint height) +gdk_window_copy_to_image (GdkDrawable *drawable, + GdkImage *image, + gint src_x, + gint src_y, + gint dest_x, + gint dest_y, + gint width, + gint height) { gint x_offset, y_offset; @@ -1946,10 +2024,12 @@ gdk_window_get_image (GdkDrawable *drawable, _gdk_windowing_window_get_offsets (drawable, &x_offset, &y_offset); - return gdk_drawable_get_image (((GdkWindowObject*)drawable)->impl, - x - x_offset, - y - y_offset, - width, height); + return _gdk_drawable_copy_to_image (((GdkWindowObject*)drawable)->impl, + image, + src_x - x_offset, + src_y - y_offset, + dest_x, dest_y, + width, height); } /* Code for dirty-region queueing diff --git a/gdk/x11/gdkdrawable-x11.c b/gdk/x11/gdkdrawable-x11.c index 0ca8d12201..96f6b05f8a 100644 --- a/gdk/x11/gdkdrawable-x11.c +++ b/gdk/x11/gdkdrawable-x11.c @@ -35,6 +35,7 @@ #endif #include +#include /* for memcpy() */ #if defined (HAVE_IPC_H) && defined (HAVE_SHM_H) && defined (HAVE_XSHM_H) #define USE_SHM @@ -119,6 +120,20 @@ static void gdk_x11_draw_image (GdkDrawable *drawable, gint ydest, gint width, gint height); +#ifdef HAVE_XFT +static void gdk_x11_draw_pixbuf (GdkDrawable *drawable, + GdkGC *gc, + GdkPixbuf *pixbuf, + gint src_x, + gint src_y, + gint dest_x, + gint dest_y, + gint width, + gint height, + GdkRgbDither dither, + gint x_dither, + gint y_dither); +#endif /* HAVE_XFT */ static void gdk_x11_set_colormap (GdkDrawable *drawable, GdkColormap *colormap); @@ -185,6 +200,9 @@ gdk_drawable_impl_x11_class_init (GdkDrawableImplX11Class *klass) drawable_class->draw_lines = gdk_x11_draw_lines; drawable_class->draw_glyphs = gdk_x11_draw_glyphs; drawable_class->draw_image = gdk_x11_draw_image; +#ifdef HAVE_XFT + drawable_class->_draw_pixbuf = gdk_x11_draw_pixbuf; +#endif /* HAVE_XFT */ drawable_class->set_colormap = gdk_x11_set_colormap; drawable_class->get_colormap = gdk_x11_get_colormap; @@ -192,7 +210,7 @@ gdk_drawable_impl_x11_class_init (GdkDrawableImplX11Class *klass) drawable_class->get_depth = gdk_x11_get_depth; drawable_class->get_visual = gdk_x11_get_visual; - drawable_class->get_image = _gdk_x11_get_image; + drawable_class->_copy_to_image = _gdk_x11_copy_to_image; } static void @@ -204,6 +222,17 @@ gdk_drawable_impl_x11_finalize (GObject *object) } #ifdef HAVE_XFT +gboolean +_gdk_x11_have_render (void) +{ + /* This check is cheap, but if we have to do version checks, we will + * need to cache the result since version checks are round-trip + */ + int event_base, error_base; + + return XRenderQueryExtension (gdk_display, &event_base, &error_base); +} + static Picture gdk_x11_drawable_get_picture (GdkDrawable *drawable) { @@ -225,7 +254,8 @@ gdk_x11_drawable_get_picture (GdkDrawable *drawable) } format = XRenderFindVisualFormat (impl->xdisplay, GDK_VISUAL_XVISUAL (visual)); - impl->picture = XRenderCreatePicture (impl->xdisplay, impl->xid, format, 0, NULL); + if (format) + impl->picture = XRenderCreatePicture (impl->xdisplay, impl->xid, format, 0, NULL); } return impl->picture; @@ -752,3 +782,536 @@ gdk_x11_drawable_get_xid (GdkDrawable *drawable) return ((GdkDrawableImplX11 *)impl)->xid; } + +/* Code for accelerated alpha compositing using the RENDER extension. + * It's a bit long because there are lots of possibilities for + * what's the fastest depending on the available picture formats, + * whether we can used shared pixmaps, etc. + */ +#ifdef HAVE_XFT +typedef enum { + FORMAT_NONE, + FORMAT_EXACT_MASK, + FORMAT_ARGB_MASK, + FORMAT_ARGB +} FormatType; + +static FormatType +select_format (Display *xdisplay, + XRenderPictFormat **format, + XRenderPictFormat **mask) +{ + XRenderPictFormat pf; + + +/* Look for a 32-bit xRGB and Axxx formats that exactly match the + * in memory data format. We can use them as pixmap and mask + * to deal with non-premultiplied data. + */ + + pf.type = PictTypeDirect; + pf.depth = 32; + pf.direct.redMask = 0xff; + pf.direct.greenMask = 0xff; + pf.direct.blueMask = 0xff; + + pf.direct.alphaMask = 0; + if (ImageByteOrder (xdisplay) == LSBFirst) + { + /* ABGR */ + pf.direct.red = 0; + pf.direct.green = 8; + pf.direct.blue = 16; + } + else + { + /* RGBA */ + pf.direct.red = 24; + pf.direct.green = 16; + pf.direct.blue = 8; + } + + *format = XRenderFindFormat (xdisplay, + (PictFormatType | PictFormatDepth | + PictFormatRedMask | PictFormatRed | + PictFormatGreenMask | PictFormatGreen | + PictFormatBlueMask | PictFormatBlue | + PictFormatAlphaMask), + &pf, + 0); + + pf.direct.alphaMask = 0xff; + if (ImageByteOrder (xdisplay) == LSBFirst) + { + /* ABGR */ + pf.direct.alpha = 24; + } + else + { + pf.direct.alpha = 0; + } + + *mask = XRenderFindFormat (xdisplay, + (PictFormatType | PictFormatDepth | + PictFormatAlphaMask | PictFormatAlpha), + &pf, + 0); + + if (*format && *mask) + return FORMAT_EXACT_MASK; + + /* OK, that failed, now look for xRGB and Axxx formats in + * RENDER's preferred order + */ + pf.direct.alphaMask = 0; + /* ARGB */ + pf.direct.red = 16; + pf.direct.green = 8; + pf.direct.blue = 0; + + *format = XRenderFindFormat (xdisplay, + (PictFormatType | PictFormatDepth | + PictFormatRedMask | PictFormatRed | + PictFormatGreenMask | PictFormatGreen | + PictFormatBlueMask | PictFormatBlue | + PictFormatAlphaMask), + &pf, + 0); + + pf.direct.alphaMask = 0xff; + pf.direct.alpha = 24; + + *mask = XRenderFindFormat (xdisplay, + (PictFormatType | PictFormatDepth | + PictFormatAlphaMask | PictFormatAlpha), + &pf, + 0); + + if (*format && *mask) + return FORMAT_ARGB_MASK; + + /* Finally, if neither of the above worked, fall back to + * looking for combined ARGB -- we'll premultiply ourselves. + */ + + pf.type = PictTypeDirect; + pf.depth = 32; + pf.direct.red = 16; + pf.direct.green = 8; + pf.direct.blue = 0; + pf.direct.alphaMask = 0xff; + pf.direct.alpha = 24; + + *format = XRenderFindFormat (xdisplay, + (PictFormatType | PictFormatDepth | + PictFormatRedMask | PictFormatRed | + PictFormatGreenMask | PictFormatGreen | + PictFormatBlueMask | PictFormatBlue | + PictFormatAlphaMask | PictFormatAlpha), + &pf, + 0); + *mask = NULL; + + if (*format) + return FORMAT_ARGB; + + return FORMAT_NONE; +} + +#if 0 +static void +list_formats (XRenderPictFormat *pf) +{ + gint i; + + for (i=0 ;; i++) + { + XRenderPictFormat *pf = XRenderFindFormat (impl->xdisplay, 0, NULL, i); + if (pf) + { + g_print ("%2d R-%#06x/%#06x G-%#06x/%#06x B-%#06x/%#06x A-%#06x/%#06x\n", + pf->depth, + pf->direct.red, + pf->direct.redMask, + pf->direct.green, + pf->direct.greenMask, + pf->direct.blue, + pf->direct.blueMask, + pf->direct.alpha, + pf->direct.alphaMask); + } + else + break; + } +} +#endif + +static void +convert_to_format (guchar *src_buf, + gint src_rowstride, + guchar *dest_buf, + gint dest_rowstride, + FormatType dest_format, + GdkByteOrder dest_byteorder, + gint width, + gint height) +{ + gint i; + + if (dest_format == FORMAT_EXACT_MASK && + src_rowstride == dest_rowstride) + { + memcpy (dest_buf, src_buf, height * src_rowstride); + return; + } + + for (i=0; i < height; i++) + { + switch (dest_format) + { + case FORMAT_EXACT_MASK: + { + memcpy (dest_buf + i * dest_rowstride, + src_buf + i * src_rowstride, + width * 4); + break; + } + case FORMAT_ARGB_MASK: + { + guint *p = (guint *)(src_buf + i * src_rowstride); + guint *q = (guint *)(dest_buf + i * dest_rowstride); + guint *end = p + width; + +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + if (dest_byteorder == GDK_LSB_FIRST) + { + /* ABGR => ARGB */ + + while (p < end) + { + *q = ( (*p & 0xff00ff00) | + ((*p & 0x000000ff) << 16) | + ((*p & 0x00ff0000) >> 16)); + q++; + p++; + } + } + else + { + /* ABGR => BGRA */ + + while (p < end) + { + *q = (((*p & 0xff000000) >> 24) | + ((*p & 0x00ffffff) << 8)); + q++; + p++; + } + } +#else /* G_BYTE_ORDER == G_BIG_ENDIAN */ + if (dest_byteorder == GDK_LSB_FIRST) + { + /* RGBA => BGRA */ + + while (p < end) + { + *q = ( (*p & 0x00ff00ff) | + ((*p & 0x0000ff00) << 16) | + ((*p & 0xff000000) >> 16)); + q++; + p++; + } + } + else + { + /* RGBA => ARGB */ + + while (p < end) + { + *q = (((*p & 0xff000000) >> 24) | + ((*p & 0x00ffffff) << 8)); + q++; + p++; + } + } +#endif /* G_BYTE_ORDER*/ + break; + } + case FORMAT_ARGB: + { + guchar *p = (src_buf + i * src_rowstride); + guchar *q = (dest_buf + i * dest_rowstride); + guchar *end = p + 4 * width; + guchar a; + guint t; + +#define MULT(d,c,a) G_STMT_START { t = c * a; d = ((t >> 8) + t) >> 8; } G_STMT_END + + if (dest_byteorder == GDK_LSB_FIRST) + { + while (p < end) + { + a = p[3]; + MULT(q[0], p[2], a); + MULT(q[1], p[1], a); + MULT(q[2], p[0], a); + q[3] = a; + p += 4; + q += 4; + } + } + else + { + while (p < end) + { + a = p[3]; + q[0] = a; + MULT(q[1], p[0], a); + MULT(q[2], p[1], a); + MULT(q[3], p[2], a); + p += 4; + q += 4; + } + } +#undef MULT + break; + } + case FORMAT_NONE: + g_assert_not_reached (); + break; + } + } +} + +static void +draw_with_images (GdkDrawable *drawable, + GdkGC *gc, + FormatType format_type, + XRenderPictFormat *format, + XRenderPictFormat *mask_format, + guchar *src_rgb, + gint src_rowstride, + gint dest_x, + gint dest_y, + gint width, + gint height) +{ + Display *xdisplay = GDK_DRAWABLE_IMPL_X11 (drawable)->xdisplay; + GdkImage *image; + GdkPixmap *pix; + GdkGC *pix_gc; + Picture pict; + Picture dest_pict; + Picture mask = None; + gint x0, y0; + + pix = gdk_pixmap_new (NULL, width, height, 32); + pict = XRenderCreatePicture (xdisplay, + GDK_PIXMAP_XID (pix), + format, 0, NULL); + if (mask_format) + mask = XRenderCreatePicture (xdisplay, + GDK_PIXMAP_XID (pix), + mask_format, 0, NULL); + + dest_pict = gdk_x11_drawable_get_picture (drawable); + + pix_gc = gdk_gc_new (pix); + + for (y0 = 0; y0 < height; y0 += GDK_SCRATCH_IMAGE_HEIGHT) + { + gint height1 = MIN (height - y0, GDK_SCRATCH_IMAGE_HEIGHT); + for (x0 = 0; x0 < width; x0 += GDK_SCRATCH_IMAGE_WIDTH) + { + gint xs0, ys0; + + gint width1 = MIN (width - x0, GDK_SCRATCH_IMAGE_WIDTH); + + image = _gdk_image_get_scratch (width1, height1, 32, &xs0, &ys0); + + convert_to_format (src_rgb + y0 * src_rowstride + 4 * x0, src_rowstride, + image->mem + ys0 * image->bpl + 4 * xs0, image->bpl, + format_type, image->byte_order, + width1, height1); + + gdk_draw_image (pix, pix_gc, + image, xs0, ys0, x0, y0, width1, height1); + } + } + + XRenderComposite (xdisplay, PictOpOver, pict, mask, dest_pict, + 0, 0, 0, 0, dest_x, dest_y, width, height); + + XRenderFreePicture (xdisplay, pict); + if (mask) + XRenderFreePicture (xdisplay, mask); + + g_object_unref (pix); + g_object_unref (pix_gc); +} + +typedef struct _ShmPixmapInfo ShmPixmapInfo; + +struct _ShmPixmapInfo +{ + GdkImage *image; + Pixmap pix; + Picture pict; + Picture mask; +}; + +/* Returns FALSE if we can't get a shm pixmap */ +static gboolean +get_shm_pixmap_for_image (Display *xdisplay, + GdkImage *image, + XRenderPictFormat *format, + XRenderPictFormat *mask_format, + Pixmap *pix, + Picture *pict, + Picture *mask) +{ + ShmPixmapInfo *info; + + if (image->type != GDK_IMAGE_SHARED) + return FALSE; + + info = g_object_get_data (G_OBJECT (image), "gdk-x11-shm-pixmap"); + if (!info) + { + *pix = _gdk_x11_image_get_shm_pixmap (image); + + if (!*pix) + return FALSE; + + info = g_new (ShmPixmapInfo, 1); + info->pix = *pix; + + info->pict = XRenderCreatePicture (xdisplay, info->pix, + format, 0, NULL); + if (mask_format) + info->mask = XRenderCreatePicture (xdisplay, info->pix, + mask_format, 0, NULL); + else + info->mask = None; + + g_object_set_data (G_OBJECT (image), "gdk-x11-shm-pixmap", info); + } + + *pix = info->pix; + *pict = info->pict; + *mask = info->mask; + + return TRUE; +} + +#ifdef USE_SHM +/* Returns FALSE if drawing with ShmPixmaps is not possible */ +static gboolean +draw_with_pixmaps (GdkDrawable *drawable, + GdkGC *gc, + FormatType format_type, + XRenderPictFormat *format, + XRenderPictFormat *mask_format, + guchar *src_rgb, + gint src_rowstride, + gint dest_x, + gint dest_y, + gint width, + gint height) +{ + Display *xdisplay = GDK_DRAWABLE_IMPL_X11 (drawable)->xdisplay; + GdkImage *image; + Pixmap pix; + Picture pict; + Picture dest_pict; + Picture mask = None; + gint x0, y0; + + dest_pict = gdk_x11_drawable_get_picture (drawable); + + for (y0 = 0; y0 < height; y0 += GDK_SCRATCH_IMAGE_HEIGHT) + { + gint height1 = MIN (height - y0, GDK_SCRATCH_IMAGE_HEIGHT); + for (x0 = 0; x0 < width; x0 += GDK_SCRATCH_IMAGE_WIDTH) + { + gint xs0, ys0; + + gint width1 = MIN (width - x0, GDK_SCRATCH_IMAGE_WIDTH); + + image = _gdk_image_get_scratch (width1, height1, 32, &xs0, &ys0); + if (!get_shm_pixmap_for_image (xdisplay, image, format, mask_format, &pix, &pict, &mask)) + return FALSE; + + convert_to_format (src_rgb + y0 * src_rowstride + 4 * x0, src_rowstride, + image->mem + ys0 * image->bpl + 4 * xs0, image->bpl, + format_type, image->byte_order, + width1, height1); + + XRenderComposite (xdisplay, PictOpOver, pict, mask, dest_pict, + xs0, ys0, xs0, ys0, x0 + dest_x, y0 + dest_y, + width1, height1); + } + } + + return TRUE; +} +#endif + +static void +gdk_x11_draw_pixbuf (GdkDrawable *drawable, + GdkGC *gc, + GdkPixbuf *pixbuf, + gint src_x, + gint src_y, + gint dest_x, + gint dest_y, + gint width, + gint height, + GdkRgbDither dither, + gint x_dither, + gint y_dither) +{ + Display *xdisplay = GDK_DRAWABLE_IMPL_X11 (drawable)->xdisplay; + FormatType format_type; + XRenderPictFormat *format, *mask_format; + gint rowstride; +#ifdef USE_SHM + gboolean use_pixmaps = TRUE; +#endif /* USE_SHM */ + + format_type = select_format (xdisplay, &format, &mask_format); + + if (format_type == FORMAT_NONE || + !gdk_pixbuf_get_has_alpha (pixbuf) || + (dither == GDK_RGB_DITHER_MAX && gdk_drawable_get_depth (drawable) != 24)) + { + GdkDrawable *wrapper = GDK_DRAWABLE_IMPL_X11 (drawable)->wrapper; + GDK_DRAWABLE_CLASS (parent_class)->_draw_pixbuf (wrapper, gc, pixbuf, + src_x, src_y, dest_x, dest_y, + width, height, + dither, x_dither, y_dither); + return; + } + + rowstride = gdk_pixbuf_get_rowstride (pixbuf); + +#ifdef USE_SHM + if (use_pixmaps) + { + if (!draw_with_pixmaps (drawable, gc, + format_type, format, mask_format, + gdk_pixbuf_get_pixels (pixbuf) + src_y * rowstride + src_x * 4, + rowstride, + dest_x, dest_y, width, height)) + use_pixmaps = FALSE; + } + + if (!use_pixmaps) +#endif /* USE_SHM */ + draw_with_images (drawable, gc, + format_type, format, mask_format, + gdk_pixbuf_get_pixels (pixbuf) + src_y * rowstride + src_x * 4, + rowstride, + dest_x, dest_y, width, height); +} +#endif /* HAVE_XFT */ diff --git a/gdk/x11/gdkgc-x11.c b/gdk/x11/gdkgc-x11.c index 7412eb726a..b703b7e3b9 100644 --- a/gdk/x11/gdkgc-x11.c +++ b/gdk/x11/gdkgc-x11.c @@ -810,9 +810,13 @@ _gdk_x11_gc_get_fg_picture (GdkGC *gc) { XRenderPictureAttributes pa; XRenderPictFormat *pix_format = foreground_format (gc); + Pixmap pix; - Pixmap pix = XCreatePixmap (x11_gc->xdisplay, _gdk_root_window, - 1, 1, pix_format->depth); + if (!pix_format) + return None; + + pix = XCreatePixmap (x11_gc->xdisplay, _gdk_root_window, + 1, 1, pix_format->depth); pa.repeat = True; x11_gc->fg_picture = XRenderCreatePicture (x11_gc->xdisplay, pix, diff --git a/gdk/x11/gdkimage-x11.c b/gdk/x11/gdkimage-x11.c index 21302d7e6f..4f03ff8de3 100644 --- a/gdk/x11/gdkimage-x11.c +++ b/gdk/x11/gdkimage-x11.c @@ -59,10 +59,12 @@ struct _GdkImagePrivateX11 XImage *ximage; Display *xdisplay; gpointer x_shm_info; + Pixmap shm_pixmap; }; static GList *image_list = NULL; static gpointer parent_class = NULL; +static gboolean have_shm_pixmaps; static void gdk_x11_image_destroy (GdkImage *image); static void gdk_image_init (GdkImage *image); @@ -198,33 +200,42 @@ _gdk_windowing_image_init (void) { if (_gdk_use_xshm) { - if (!gdk_image_check_xshm (gdk_display)) - { - _gdk_use_xshm = False; - } + gint res = gdk_image_check_xshm (gdk_display); + + if (!res) + _gdk_use_xshm = FALSE; + else + have_shm_pixmaps = (res == 2); } } GdkImage* -gdk_image_new (GdkImageType type, - GdkVisual *visual, - gint width, - gint height) +_gdk_image_new_for_depth (GdkImageType type, + GdkVisual *visual, + gint width, + gint height, + gint depth) { GdkImage *image; GdkImagePrivateX11 *private; #ifdef USE_SHM XShmSegmentInfo *x_shm_info; #endif /* USE_SHM */ - Visual *xvisual; + Visual *xvisual = NULL; + g_return_val_if_fail (!visual || GDK_IS_VISUAL (visual), NULL); + g_return_val_if_fail (visual || depth != -1, NULL); + + if (visual) + depth = visual->depth; + switch (type) { case GDK_IMAGE_FASTEST: - image = gdk_image_new (GDK_IMAGE_SHARED, visual, width, height); + image = _gdk_image_new_for_depth (GDK_IMAGE_SHARED, visual, width, height, depth); if (!image) - image = gdk_image_new (GDK_IMAGE_NORMAL, visual, width, height); + image = _gdk_image_new_for_depth (GDK_IMAGE_NORMAL, visual, width, height, depth); break; default: @@ -238,9 +249,10 @@ gdk_image_new (GdkImageType type, image->visual = visual; image->width = width; image->height = height; - image->depth = visual->depth; + image->depth = depth; - xvisual = ((GdkVisualPrivate*) visual)->xvisual; + if (visual) + xvisual = ((GdkVisualPrivate*) visual)->xvisual; switch (type) { @@ -253,7 +265,7 @@ gdk_image_new (GdkImageType type, x_shm_info->shmid = -1; x_shm_info->shmaddr = (char*) -1; - private->ximage = XShmCreateImage (private->xdisplay, xvisual, visual->depth, + private->ximage = XShmCreateImage (private->xdisplay, xvisual, depth, ZPixmap, NULL, x_shm_info, width, height); if (private->ximage == NULL) { @@ -326,7 +338,7 @@ gdk_image_new (GdkImageType type, goto error; break; case GDK_IMAGE_NORMAL: - private->ximage = XCreateImage (private->xdisplay, xvisual, visual->depth, + private->ximage = XCreateImage (private->xdisplay, xvisual, depth, ZPixmap, 0, 0, width, height, 32, 0); /* Use malloc, not g_malloc here, because X will call free() @@ -344,7 +356,7 @@ gdk_image_new (GdkImageType type, if (image) { - image->byte_order = private->ximage->byte_order; + image->byte_order = (private->ximage->byte_order == LSBFirst) ? GDK_LSB_FIRST : GDK_MSB_FIRST; image->mem = private->ximage->data; image->bpl = private->ximage->bytes_per_line; image->bpp = (private->ximage->bits_per_pixel + 7) / 8; @@ -379,39 +391,144 @@ gdk_image_new (GdkImageType type, return NULL; } +Pixmap +_gdk_x11_image_get_shm_pixmap (GdkImage *image) +{ + GdkImagePrivateX11 *private = PRIVATE_DATA (image); + +#ifdef USE_SHM + /* Future: do we need one of these per-screen per-image? ShmPixmaps + * are the same for every screen, but can they be shared? + */ + if (!private->shm_pixmap && image->type == GDK_IMAGE_SHARED && have_shm_pixmaps) + private->shm_pixmap = XShmCreatePixmap (private->xdisplay, _gdk_root_window, + image->mem, private->x_shm_info, + image->width, image->height, image->depth); + + return private->shm_pixmap; +#else + return None; +#endif +} + GdkImage* -_gdk_x11_get_image (GdkDrawable *drawable, - gint x, - gint y, - gint width, - gint height) +gdk_image_new (GdkImageType type, + GdkVisual *visual, + gint width, + gint height) +{ + return _gdk_image_new_for_depth (type, visual, width, height, -1); +} + +GdkImage* +get_full_image (GdkDrawable *drawable, + gint src_x, + gint src_y, + gint width, + gint height) { GdkImage *image; + GdkImagePrivateX11 *private; + GdkDrawableImplX11 *impl; + XImage *ximage; + + impl = GDK_DRAWABLE_IMPL_X11 (drawable); + + ximage = XGetImage (impl->xdisplay, + impl->xid, + src_x, src_y, width, height, + AllPlanes, ZPixmap); + + if (!ximage) + return NULL; + + image = g_object_new (gdk_image_get_type (), NULL); + + private = PRIVATE_DATA (image); + + private->xdisplay = gdk_display; + private->ximage = ximage; + + image->type = GDK_IMAGE_NORMAL; + image->visual = gdk_drawable_get_visual (drawable); /* could be NULL */ + image->width = width; + image->height = height; + image->depth = gdk_drawable_get_depth (drawable); + + image->mem = private->ximage->data; + image->bpl = private->ximage->bytes_per_line; + image->bits_per_pixel = private->ximage->bits_per_pixel; + image->bpp = (private->ximage->bits_per_pixel + 7) / 8; + image->byte_order = (private->ximage->byte_order == LSBFirst) ? GDK_LSB_FIRST : GDK_MSB_FIRST; + + return image; +} + +GdkImage* +_gdk_x11_copy_to_image (GdkDrawable *drawable, + GdkImage *image, + gint src_x, + gint src_y, + gint dest_x, + gint dest_y, + gint width, + gint height) +{ GdkImagePrivateX11 *private; GdkDrawableImplX11 *impl; GdkVisual *visual; gboolean have_grab; GdkRectangle req; GdkRectangle window_rect; - XImage *ximage; + Pixmap shm_pixmap = None; + gboolean success = TRUE; g_return_val_if_fail (GDK_IS_DRAWABLE_IMPL_X11 (drawable), NULL); + g_return_val_if_fail (image != NULL || (dest_x == 0 && dest_y == 0), NULL); visual = gdk_drawable_get_visual (drawable); - - g_assert (visual || !GDK_IS_WINDOW_IMPL_X11 (drawable)); - impl = GDK_DRAWABLE_IMPL_X11 (drawable); have_grab = FALSE; +#define UNGRAB() G_STMT_START { \ + if (have_grab) { \ + gdk_x11_ungrab_server (); \ + XFlush (impl->xdisplay); \ + have_grab = FALSE; } \ + } G_STMT_END + + if (!image && !GDK_IS_WINDOW_IMPL_X11 (drawable)) + return get_full_image (drawable, src_x, src_y, width, height); + + if (image && image->type == GDK_IMAGE_SHARED) + { + shm_pixmap = _gdk_x11_image_get_shm_pixmap (image); + if (shm_pixmap) + { + /* Again easy, we can just XCopyArea, and don't have to worry about clipping + */ + GC xgc = XCreateGC (impl->xdisplay, impl->xid, 0, NULL); + + XCopyArea (impl->xdisplay, impl->xid, shm_pixmap, xgc, + src_x, src_y, width, height, dest_x, dest_y); + XSync (impl->xdisplay, FALSE); + + XFreeGC (impl->xdisplay, xgc); + + return image; + } + } + + /* Now the general case - we may have to worry about clipping to the screen + * bounds, in which case we'll have to grab the server and only get a piece + * of the window. + */ if (GDK_IS_WINDOW_IMPL_X11 (drawable)) { GdkRectangle screen_rect; Window child; - g_assert (visual); - have_grab = TRUE; gdk_x11_grab_server (); @@ -443,13 +560,7 @@ _gdk_x11_get_image (GdkDrawable *drawable, if (gdk_error_trap_pop () || !gdk_rectangle_intersect (&window_rect, &screen_rect, &window_rect)) - { - if (have_grab) - gdk_x11_ungrab_server (); - return image = gdk_image_new (GDK_IMAGE_FASTEST, - visual, - width, height); - } + goto out; } else { @@ -460,8 +571,8 @@ _gdk_x11_get_image (GdkDrawable *drawable, &window_rect.height); } - req.x = x; - req.y = y; + req.x = src_x; + req.y = src_y; req.width = width; req.height = height; @@ -470,97 +581,66 @@ _gdk_x11_get_image (GdkDrawable *drawable, * For pixmaps this is all of the pixmap, for windows it is just * the onscreen part. */ - if (!gdk_rectangle_intersect (&req, &window_rect, &req) && visual) - { - if (have_grab) - gdk_x11_ungrab_server (); - return image = gdk_image_new (GDK_IMAGE_FASTEST, - visual, - width, height); - } + if (!gdk_rectangle_intersect (&req, &window_rect, &req)) + goto out; - if (req.x != x || req.y != y) + private = PRIVATE_DATA (image); + + gdk_error_trap_push (); + + if (!image && + req.x == src_x && req.y == src_y && req.width == width && req.height == height) { - g_assert (GDK_IS_WINDOW (drawable)); - g_assert (visual); - - image = gdk_image_new (GDK_IMAGE_FASTEST, - visual, - width, height); - if (image == NULL) - { - if (have_grab) - gdk_x11_ungrab_server (); - return NULL; - } - - private = PRIVATE_DATA (image); - - gdk_error_trap_push (); - - ximage = XGetSubImage (impl->xdisplay, - impl->xid, - req.x, req.y, req.width, req.height, - AllPlanes, ZPixmap, - private->ximage, - req.x - x, req.y - y); - - if (have_grab) - { - gdk_x11_ungrab_server (); - have_grab = FALSE; - } - - if (gdk_error_trap_pop () || ximage == NULL) - { - g_object_unref (G_OBJECT (image)); - return NULL; - } - - g_assert (ximage == private->ximage); + image = get_full_image (drawable, src_x, src_y, width, height); + if (!image) + success = FALSE; } else { - /* Here we ignore the req.width, req.height - - * XGetImage() will do the right thing without - * them. + gboolean created_image = FALSE; + + if (!image) + { + image = _gdk_image_new_for_depth (GDK_IMAGE_NORMAL, visual, width, height, + gdk_drawable_get_depth (drawable)); + created_image = TRUE; + } + + /* In the ShmImage but no ShmPixmap case, we could use XShmGetImage when + * we are getting the entire image. */ - ximage = XGetImage (impl->xdisplay, - impl->xid, - x, y, width, height, - AllPlanes, ZPixmap); - - if (have_grab) - { - gdk_x11_ungrab_server (); - have_grab = FALSE; - } - - if (!ximage) - return NULL; - - image = g_object_new (gdk_image_get_type (), NULL); - - private = PRIVATE_DATA (image); - - private->xdisplay = gdk_display; - private->ximage = ximage; - - image->type = GDK_IMAGE_NORMAL; - image->visual = visual; /* May be NULL */ - image->width = width; - image->height = height; - image->depth = gdk_drawable_get_depth (drawable); - - image->mem = private->ximage->data; - image->bpl = private->ximage->bytes_per_line; - image->bits_per_pixel = private->ximage->bits_per_pixel; - image->bpp = (private->ximage->bits_per_pixel + 7) / 8; - image->byte_order = private->ximage->byte_order; + if (XGetSubImage (impl->xdisplay, + impl->xid, + req.x, req.y, req.width, req.height, + AllPlanes, ZPixmap, + private->ximage, + dest_x + req.x - src_x, dest_y + req.y - src_y) == None) + { + if (created_image) + g_object_unref (image); + image = NULL; + success = FALSE; + } } - g_assert (!have_grab); + out: + if (have_grab) + { + gdk_x11_ungrab_server (); + XFlush (impl->xdisplay); + have_grab = FALSE; + } + + gdk_error_trap_pop (); + + if (success && !image) + { + /* We "succeeded", but could get no content for the image so return junk */ + image = _gdk_image_new_for_depth (GDK_IMAGE_NORMAL, visual, width, height, + gdk_drawable_get_depth (drawable)); + } + return image; } @@ -625,7 +705,11 @@ gdk_x11_image_destroy (GdkImage *image) case GDK_IMAGE_SHARED: #ifdef USE_SHM gdk_flush(); - + + if (private->shm_pixmap) + XFreePixmap (private->xdisplay, private->shm_pixmap); + + image_list = g_list_remove (image_list, image); XShmDetach (private->xdisplay, private->x_shm_info); XDestroyImage (private->ximage); @@ -634,8 +718,7 @@ gdk_x11_image_destroy (GdkImage *image) g_free (private->x_shm_info); private->x_shm_info = NULL; - - image_list = g_list_remove (image_list, image); + #else /* USE_SHM */ g_error ("trying to destroy shared memory image when gdk was compiled without shared memory support"); #endif /* USE_SHM */ @@ -673,3 +756,23 @@ gdk_x11_image_get_ximage (GdkImage *image) return private->ximage; } + +gint +_gdk_windowing_get_bits_for_depth (gint depth) +{ + XPixmapFormatValues *formats; + gint count, i; + + formats = XListPixmapFormats (gdk_display, &count); + + for (i = 0; i < count; i++) + if (formats[i].depth == depth) + { + gint result = formats[i].bits_per_pixel; + XFree (formats); + return result; + } + + g_assert_not_reached (); + return -1; +} diff --git a/gdk/x11/gdkpango-x11.c b/gdk/x11/gdkpango-x11.c index 411bf01b2c..a823cf96a8 100644 --- a/gdk/x11/gdkpango-x11.c +++ b/gdk/x11/gdkpango-x11.c @@ -49,7 +49,7 @@ gdk_pango_context_get (void) { const char *val = g_getenv ("GDK_USE_XFT"); - use_xft = val && (atoi (val) != 0); + use_xft = val && (atoi (val) != 0) && _gdk_x11_have_render (); } if (use_xft) diff --git a/gdk/x11/gdkprivate-x11.h b/gdk/x11/gdkprivate-x11.h index 6552ff5383..a495c51878 100644 --- a/gdk/x11/gdkprivate-x11.h +++ b/gdk/x11/gdkprivate-x11.h @@ -100,7 +100,8 @@ gint gdk_send_xevent (Window window, GType _gdk_gc_x11_get_type (void); #ifdef HAVE_XFT -Picture _gdk_x11_gc_get_fg_picture (GdkGC *gc); +gboolean _gdk_x11_have_render (void); +Picture _gdk_x11_gc_get_fg_picture (GdkGC *gc); #endif /* HAVE_XFT */ GdkGC *_gdk_x11_gc_new (GdkDrawable *drawable, @@ -112,11 +113,15 @@ GdkVisual * gdk_visual_lookup (Visual *xvisual); void gdk_window_add_colormap_windows (GdkWindow *window); -GdkImage* _gdk_x11_get_image (GdkDrawable *drawable, - gint x, - gint y, - gint width, - gint height); +GdkImage *_gdk_x11_copy_to_image (GdkDrawable *drawable, + GdkImage *image, + gint src_x, + gint src_y, + gint dest_x, + gint dest_y, + gint width, + gint height); +Pixmap _gdk_x11_image_get_shm_pixmap (GdkImage *image); /* Please see gdkwindow.c for comments on how to use */ Window gdk_window_xid_at (Window base, diff --git a/tests/testrgb.c b/tests/testrgb.c index 12f088f605..9a61f92f88 100644 --- a/tests/testrgb.c +++ b/tests/testrgb.c @@ -48,7 +48,7 @@ quit_func (GtkWidget *widget, gpointer dummy) #define WIDTH 640 #define HEIGHT 400 -#define NUM_ITERS 100 +#define NUM_ITERS 50 static void testrgb_rgb_test (GtkWidget *drawing_area) @@ -62,11 +62,13 @@ testrgb_rgb_test (GtkWidget *drawing_area) gboolean dither; int dith_max; GTimer *timer; - - buf = g_malloc (WIDTH * HEIGHT * 6); + GdkPixbuf *pixbuf; + gboolean to_pixmap; + + buf = g_malloc (WIDTH * HEIGHT * 8); val = 0; - for (j = 0; j < WIDTH * HEIGHT * 6; j++) + for (j = 0; j < WIDTH * HEIGHT * 8; j++) { val = (val + ((val + (rand () & 0xff)) >> 1)) >> 1; buf[j] = val; @@ -103,6 +105,7 @@ testrgb_rgb_test (GtkWidget *drawing_area) GDK_RGB_DITHER_NONE, buf + offset, WIDTH * 3); } + gdk_flush (); total_time = g_timer_elapsed (timer, NULL) - start_time; g_print ("Color test%s time elapsed: %.2fs, %.1f fps, %.2f megapixels/s\n", dither ? " (dithered)" : "", @@ -124,6 +127,7 @@ testrgb_rgb_test (GtkWidget *drawing_area) GDK_RGB_DITHER_NONE, buf + offset, WIDTH); } + gdk_flush (); total_time = g_timer_elapsed (timer, NULL) - start_time; g_print ("Grayscale test%s time elapsed: %.2fs, %.1f fps, %.2f megapixels/s\n", dither ? " (dithered)" : "", @@ -132,6 +136,42 @@ testrgb_rgb_test (GtkWidget *drawing_area) NUM_ITERS * (WIDTH * HEIGHT * 1e-6) / total_time); } + for (to_pixmap = FALSE; to_pixmap <= TRUE; to_pixmap++) + { + if (to_pixmap) + { + GdkRectangle rect = { 0, 0, WIDTH, HEIGHT }; + gdk_window_begin_paint_rect (drawing_area->window, &rect); + } + + start_time = g_timer_elapsed (timer, NULL); + for (i = 0; i < NUM_ITERS; i++) + { + offset = (rand () % (WIDTH * HEIGHT * 4)) & -4; + pixbuf = gdk_pixbuf_new_from_data (buf + offset, GDK_COLORSPACE_RGB, TRUE, + 8, WIDTH, HEIGHT, WIDTH * 4, + NULL, NULL); + gdk_pixbuf_render_to_drawable_alpha (pixbuf, drawing_area->window, + 0, 0, 0, 0, WIDTH, HEIGHT, + GDK_PIXBUF_ALPHA_FULL, /* ignored */ + 0x80, /* ignored */ + GDK_RGB_DITHER_NORMAL, + 0, 0); + gdk_pixbuf_unref (pixbuf); + } + gdk_flush (); + total_time = g_timer_elapsed (timer, NULL) - start_time; + + if (to_pixmap) + gdk_window_end_paint (drawing_area->window); + + g_print ("Alpha test%s time elapsed: %.2fs, %.1f fps, %.2f megapixels/s\n", + to_pixmap ? " (to pixmap)" : "", + total_time, + NUM_ITERS / total_time, + NUM_ITERS * (WIDTH * HEIGHT * 1e-6) / total_time); + } + g_print ("Please submit these results to http://www.levien.com/gdkrgb/survey.html\n"); #if 1