Private function to tell if we have RENDER extension.

Thu Jan  3 22:18:15 2002  Owen Taylor  <otaylor@redhat.com>

	* 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.
This commit is contained in:
Owen Taylor 2002-01-04 05:58:01 +00:00 committed by Owen Taylor
parent a755adc58d
commit d12c9702a4
22 changed files with 2446 additions and 630 deletions

View File

@ -1,3 +1,73 @@
Thu Jan 3 22:18:15 2002 Owen Taylor <otaylor@redhat.com>
* 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 <andersca@gnu.org> 2002-01-04 Anders Carlsson <andersca@gnu.org>
* tests/testtreesort.c: Add my cool list of integers. * tests/testtreesort.c: Add my cool list of integers.

View File

@ -1,3 +1,73 @@
Thu Jan 3 22:18:15 2002 Owen Taylor <otaylor@redhat.com>
* 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 <andersca@gnu.org> 2002-01-04 Anders Carlsson <andersca@gnu.org>
* tests/testtreesort.c: Add my cool list of integers. * tests/testtreesort.c: Add my cool list of integers.

View File

@ -1,3 +1,73 @@
Thu Jan 3 22:18:15 2002 Owen Taylor <otaylor@redhat.com>
* 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 <andersca@gnu.org> 2002-01-04 Anders Carlsson <andersca@gnu.org>
* tests/testtreesort.c: Add my cool list of integers. * tests/testtreesort.c: Add my cool list of integers.

View File

@ -1,3 +1,73 @@
Thu Jan 3 22:18:15 2002 Owen Taylor <otaylor@redhat.com>
* 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 <andersca@gnu.org> 2002-01-04 Anders Carlsson <andersca@gnu.org>
* tests/testtreesort.c: Add my cool list of integers. * tests/testtreesort.c: Add my cool list of integers.

View File

@ -1,3 +1,73 @@
Thu Jan 3 22:18:15 2002 Owen Taylor <otaylor@redhat.com>
* 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 <andersca@gnu.org> 2002-01-04 Anders Carlsson <andersca@gnu.org>
* tests/testtreesort.c: Add my cool list of integers. * tests/testtreesort.c: Add my cool list of integers.

View File

@ -1,3 +1,73 @@
Thu Jan 3 22:18:15 2002 Owen Taylor <otaylor@redhat.com>
* 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 <andersca@gnu.org> 2002-01-04 Anders Carlsson <andersca@gnu.org>
* tests/testtreesort.c: Add my cool list of integers. * tests/testtreesort.c: Add my cool list of integers.

View File

@ -1,3 +1,73 @@
Thu Jan 3 22:18:15 2002 Owen Taylor <otaylor@redhat.com>
* 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 <andersca@gnu.org> 2002-01-04 Anders Carlsson <andersca@gnu.org>
* tests/testtreesort.c: Add my cool list of integers. * tests/testtreesort.c: Add my cool list of integers.

View File

@ -27,15 +27,34 @@
#include "gdkdrawable.h" #include "gdkdrawable.h"
#include "gdkinternals.h" #include "gdkinternals.h"
#include "gdkwindow.h" #include "gdkwindow.h"
#include "gdk-pixbuf-private.h"
#include "gdkpixbuf.h"
static GdkDrawable* gdk_drawable_real_get_composite_drawable (GdkDrawable *drawable, static GdkImage* gdk_drawable_real_get_image (GdkDrawable *drawable,
gint x, gint x,
gint y, gint y,
gint width, gint width,
gint height, gint height);
gint *composite_x_offset, static GdkDrawable* gdk_drawable_real_get_composite_drawable (GdkDrawable *drawable,
gint *composite_y_offset); gint x,
static GdkRegion * gdk_drawable_real_get_visible_region (GdkDrawable *drawable); 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); static void gdk_drawable_class_init (GdkDrawableClass *klass);
@ -70,10 +89,12 @@ gdk_drawable_get_type (void)
static void static void
gdk_drawable_class_init (GdkDrawableClass *klass) gdk_drawable_class_init (GdkDrawableClass *klass)
{ {
klass->get_image = gdk_drawable_real_get_image;
klass->get_composite_drawable = gdk_drawable_real_get_composite_drawable; klass->get_composite_drawable = gdk_drawable_real_get_composite_drawable;
/* Default implementation for clip and visible region is the same */ /* Default implementation for clip and visible region is the same */
klass->get_clip_region = gdk_drawable_real_get_visible_region; klass->get_clip_region = gdk_drawable_real_get_visible_region;
klass->get_visible_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 /* Manipulation of drawables
@ -529,6 +550,57 @@ gdk_draw_image (GdkDrawable *drawable,
xdest, ydest, width, height); 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 void
gdk_draw_points (GdkDrawable *drawable, gdk_draw_points (GdkDrawable *drawable,
GdkGC *gc, 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: * gdk_drawable_get_image:
* @drawable: a #GdkDrawable * @drawable: a #GdkDrawable
@ -705,6 +851,16 @@ gdk_drawable_get_image (GdkDrawable *drawable,
return retval; 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* static GdkDrawable*
gdk_drawable_real_get_composite_drawable (GdkDrawable *drawable, gdk_drawable_real_get_composite_drawable (GdkDrawable *drawable,
gint x, gint x,
@ -776,3 +932,386 @@ gdk_drawable_real_get_visible_region (GdkDrawable *drawable)
return gdk_region_rectangle (&rect); 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);
}

View File

@ -3,6 +3,8 @@
#include <gdk/gdktypes.h> #include <gdk/gdktypes.h>
#include <gdk/gdkgc.h> #include <gdk/gdkgc.h>
#include <gdk/gdkrgb.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -130,7 +132,28 @@ struct _GdkDrawableClass
gint height, gint height,
gint *composite_x_offset, gint *composite_x_offset,
gint *composite_y_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_reserved1) (void);
void (*_gdk_reserved2) (void); void (*_gdk_reserved2) (void);
void (*_gdk_reserved3) (void); void (*_gdk_reserved3) (void);

View File

@ -27,8 +27,10 @@
#include <stdlib.h> #include <stdlib.h>
#include <sys/types.h> #include <sys/types.h>
#include "gdk.h" /* For gdk_flush() */
#include "gdkimage.h" #include "gdkimage.h"
#include "gdkprivate.h" #include "gdkprivate.h"
#include "gdkinternals.h" /* For scratch_image code */
/** /**
* gdk_image_ref: * gdk_image_ref:
@ -137,3 +139,264 @@ gdk_image_get_colormap (GdkImage *image)
return image->colormap; 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;
}

View File

@ -158,6 +158,43 @@ void _gdk_event_queue_append (GdkEvent *event);
void _gdk_event_button_generate (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 * * Interfaces used by windowing code *
*************************************/ *************************************/
@ -204,6 +241,11 @@ GdkWindow* _gdk_windowing_window_get_pointer (GdkWindow *window,
gint *y, gint *y,
GdkModifierType *mask); 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) #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 /* Called before processing updates for a window. This gives the windowing

View File

@ -72,7 +72,7 @@ bitmap1 (GdkImage *image,
int bpl; int bpl;
register guint8 data; register guint8 data;
guint8 *o; guint8 *o;
guint8 *srow = image->mem, *orow = pixels; guint8 *srow = image->mem + y1 * image->bpl, *orow = pixels;
d (printf ("bitmap, no alpha\n")); d (printf ("bitmap, no alpha\n"));
@ -128,7 +128,7 @@ bitmap1a (GdkImage *image,
int bpl; int bpl;
register guint8 data; register guint8 data;
guint8 *o; guint8 *o;
guint8 *srow = image->mem, *orow = pixels; guint8 *srow = image->mem + y1 * image->bpl, *orow = pixels;
d (printf ("bitmap, with alpha\n")); d (printf ("bitmap, with alpha\n"));
@ -183,7 +183,7 @@ rgb1 (GdkImage *image,
int bpl; int bpl;
register guint8 data; register guint8 data;
guint8 *o; guint8 *o;
guint8 *srow = image->mem, *orow = pixels; guint8 *srow = image->mem + y1 * image->bpl, *orow = pixels;
d (printf ("1 bits/pixel\n")); d (printf ("1 bits/pixel\n"));
@ -231,7 +231,7 @@ rgb1a (GdkImage *image,
int bpl; int bpl;
register guint8 data; register guint8 data;
guint8 *o; guint8 *o;
guint8 *srow = image->mem, *orow = pixels; guint8 *srow = image->mem + y1 * image->bpl, *orow = pixels;
d (printf ("1 bits/pixel\n")); d (printf ("1 bits/pixel\n"));
@ -279,7 +279,7 @@ rgb8 (GdkImage *image,
int bpl; int bpl;
guint32 mask; guint32 mask;
register guint32 data; 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 *s;
register guint8 *o; register guint8 *o;
@ -326,7 +326,7 @@ rgb8a (GdkImage *image,
guint32 remap[256]; guint32 remap[256];
register guint8 *s; /* read 2 pixels at once */ register guint8 *s; /* read 2 pixels at once */
register guint32 *o; register guint32 *o;
guint8 *srow = image->mem, *orow = pixels; guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
bpl = image->bpl; bpl = image->bpl;
@ -387,7 +387,7 @@ rgb565lsb (GdkImage *image,
register guint8 *s; /* read 2 pixels at once */ register guint8 *s; /* read 2 pixels at once */
#endif #endif
register guint16 *o; register guint16 *o;
guint8 *srow = image->mem, *orow = pixels; guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
bpl = image->bpl; bpl = image->bpl;
@ -490,7 +490,7 @@ rgb565msb (GdkImage *image,
register guint32 *s; /* read 2 pixels at once */ register guint32 *s; /* read 2 pixels at once */
#endif #endif
register guint16 *o; register guint16 *o;
guint8 *srow = image->mem, *orow = pixels; guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
bpl = image->bpl; bpl = image->bpl;
@ -596,7 +596,7 @@ rgb565alsb (GdkImage *image,
#endif #endif
register guint32 *o; register guint32 *o;
guint8 *srow = image->mem, *orow = pixels; guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
bpl = image->bpl; bpl = image->bpl;
@ -659,7 +659,7 @@ rgb565amsb (GdkImage *image,
#endif #endif
register guint32 *o; register guint32 *o;
guint8 *srow = image->mem, *orow = pixels; guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
bpl = image->bpl; bpl = image->bpl;
@ -717,7 +717,7 @@ rgb555lsb (GdkImage *image,
register guint8 *s; /* read 2 pixels at once */ register guint8 *s; /* read 2 pixels at once */
#endif #endif
register guint16 *o; register guint16 *o;
guint8 *srow = image->mem, *orow = pixels; guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
bpl = image->bpl; bpl = image->bpl;
@ -821,7 +821,7 @@ rgb555msb (GdkImage *image,
register guint32 *s; /* read 2 pixels at once */ register guint32 *s; /* read 2 pixels at once */
#endif #endif
register guint16 *o; register guint16 *o;
guint8 *srow = image->mem, *orow = pixels; guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
bpl = image->bpl; bpl = image->bpl;
@ -922,7 +922,7 @@ rgb555alsb (GdkImage *image,
#endif #endif
register guint32 *o; register guint32 *o;
guint8 *srow = image->mem, *orow = pixels; guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
bpl = image->bpl; bpl = image->bpl;
@ -985,7 +985,7 @@ rgb555amsb (GdkImage *image,
#endif #endif
register guint32 *o; register guint32 *o;
guint8 *srow = image->mem, *orow = pixels; guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
bpl = image->bpl; bpl = image->bpl;
@ -1039,7 +1039,7 @@ rgb888alsb (GdkImage *image,
guint8 *s; /* for byte order swapping */ guint8 *s; /* for byte order swapping */
guint8 *o; guint8 *o;
guint8 *srow = image->mem, *orow = pixels; guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
bpl = image->bpl; bpl = image->bpl;
@ -1076,7 +1076,7 @@ rgb888lsb (GdkImage *image,
int xx, yy; int xx, yy;
int bpl; int bpl;
guint8 *srow = image->mem, *orow = pixels; guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
guint8 *o, *s; guint8 *o, *s;
bpl = image->bpl; bpl = image->bpl;
@ -1112,7 +1112,7 @@ rgb888amsb (GdkImage *image,
int xx, yy; int xx, yy;
int bpl; int bpl;
guint8 *srow = image->mem, *orow = pixels; guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
#ifdef LITTLE #ifdef LITTLE
guint32 *o; guint32 *o;
guint32 *s; guint32 *s;
@ -1166,7 +1166,7 @@ rgb888msb (GdkImage *image,
int xx, yy; int xx, yy;
int bpl; int bpl;
guint8 *srow = image->mem, *orow = pixels; guint8 *srow = image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
guint8 *s; guint8 *s;
guint8 *o; guint8 *o;
@ -1207,8 +1207,7 @@ convert_real_slow (GdkImage *image,
{ {
int xx, yy; int xx, yy;
int bpl; int bpl;
guint8 *srow = image->mem, *orow = pixels; guint8 *orow = pixels;
guint8 *s;
guint8 *o; guint8 *o;
guint32 pixel; guint32 pixel;
GdkVisual *v; GdkVisual *v;
@ -1225,7 +1224,6 @@ convert_real_slow (GdkImage *image,
for (yy = y1; yy < y2; yy++) for (yy = y1; yy < y2; yy++)
{ {
s = srow;
o = orow; o = orow;
for (xx = x1; xx < x2; xx++) for (xx = x1; xx < x2; xx++)
{ {
@ -1268,7 +1266,6 @@ convert_real_slow (GdkImage *image,
if (alpha) if (alpha)
*o++ = 0xff; *o++ = 0xff;
} }
srow += bpl;
orow += rowstride; orow += rowstride;
} }
} }
@ -1481,6 +1478,7 @@ gdk_pixbuf_get_from_drawable (GdkPixbuf *dest,
int src_width, src_height; int src_width, src_height;
GdkImage *image; GdkImage *image;
int depth; int depth;
int x0, y0;
/* General sanity checks */ /* 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); 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) if (cmap == NULL)
cmap = gdk_drawable_get_colormap (src); 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_x + width <= dest->width, NULL);
g_return_val_if_fail (dest_y + height <= dest->height, 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; return dest;
} }
@ -1638,8 +1653,8 @@ gdk_pixbuf_get_from_image (GdkPixbuf *dest,
rowstride, rowstride,
alpha, alpha,
src_x, src_y, src_x, src_y,
src_x + width, width,
src_y + height, height,
cmap); cmap);
return dest; return dest;

View File

@ -237,30 +237,19 @@ gdk_pixbuf_render_to_drawable (GdkPixbuf *pixbuf,
* @dest_y: Destination Y coordinate within drawable. * @dest_y: Destination Y coordinate within drawable.
* @width: Width of region to render, in pixels, or -1 to use pixbuf width. * @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. * @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. * @alpha_mode: Ignored. Present for backwards compatibility.
* Otherwise, specifies how to handle transparency when rendering. * @alpha_threshold: Ignored. Present for backwards compatibility
* @alpha_threshold: If the image does have opacity information and @alpha_mode
* is GDK_PIXBUF_ALPHA_BILEVEL, specifies the threshold value for opacity
* values.
* @dither: Dithering mode for GdkRGB. * @dither: Dithering mode for GdkRGB.
* @x_dither: X offset for dither. * @x_dither: X offset for dither.
* @y_dither: Y offset for dither. * @y_dither: Y offset for dither.
* *
* Renders a rectangular portion of a pixbuf to a drawable. This is done using * Renders a rectangular portion of a pixbuf to a drawable. The destination
* GdkRGB, so the specified drawable must have the GdkRGB visual and colormap. * 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 * On older X servers, rendering pixbufs with an alpha channel involves round trips
* out of the thresholded alpha channel of the image and, it has to set this * to the X server, and may be somewhat slow.
* 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).
**/ **/
void void
gdk_pixbuf_render_to_drawable_alpha (GdkPixbuf *pixbuf, gdk_pixbuf_render_to_drawable_alpha (GdkPixbuf *pixbuf,
@ -273,165 +262,9 @@ gdk_pixbuf_render_to_drawable_alpha (GdkPixbuf *pixbuf,
GdkRgbDither dither, GdkRgbDither dither,
int x_dither, int y_dither) int x_dither, int y_dither)
{ {
GdkBitmap *bitmap = NULL; _gdk_draw_pixbuf (drawable, NULL, pixbuf,
GdkGC *gc; src_x, src_y, dest_x, dest_y, width, height,
GdkPixbuf *composited = NULL; dither, x_dither, y_dither);
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);
} }
/** /**
@ -531,5 +364,3 @@ gdk_pixbuf_render_pixmap_and_mask_for_colormap (GdkPixbuf *pixbuf,
*mask_return = NULL; *mask_return = NULL;
} }
} }

View File

@ -102,16 +102,32 @@ static void gdk_pixmap_draw_image (GdkDrawable *drawable,
gint ydest, gint ydest,
gint width, gint width,
gint height); 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, static void gdk_pixmap_real_get_size (GdkDrawable *drawable,
gint *width, gint *width,
gint *height); gint *height);
static GdkImage* gdk_pixmap_get_image (GdkDrawable *drawable, static GdkImage* gdk_pixmap_copy_to_image (GdkDrawable *drawable,
gint x, GdkImage *image,
gint y, gint src_x,
gint width, gint src_y,
gint height); gint dest_x,
gint dest_y,
gint width,
gint height);
static GdkVisual* gdk_pixmap_real_get_visual (GdkDrawable *drawable); static GdkVisual* gdk_pixmap_real_get_visual (GdkDrawable *drawable);
static gint gdk_pixmap_real_get_depth (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_lines = gdk_pixmap_draw_lines;
drawable_class->draw_glyphs = gdk_pixmap_draw_glyphs; drawable_class->draw_glyphs = gdk_pixmap_draw_glyphs;
drawable_class->draw_image = gdk_pixmap_draw_image; 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_depth = gdk_pixmap_real_get_depth;
drawable_class->get_size = gdk_pixmap_real_get_size; drawable_class->get_size = gdk_pixmap_real_get_size;
drawable_class->set_colormap = gdk_pixmap_real_set_colormap; drawable_class->set_colormap = gdk_pixmap_real_set_colormap;
drawable_class->get_colormap = gdk_pixmap_real_get_colormap; drawable_class->get_colormap = gdk_pixmap_real_get_colormap;
drawable_class->get_visual = gdk_pixmap_real_get_visual; 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 static void
@ -366,6 +383,27 @@ gdk_pixmap_draw_image (GdkDrawable *drawable,
width, height); 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 static void
gdk_pixmap_real_get_size (GdkDrawable *drawable, gdk_pixmap_real_get_size (GdkDrawable *drawable,
gint *width, gint *width,
@ -418,16 +456,21 @@ gdk_pixmap_real_get_colormap (GdkDrawable *drawable)
} }
static GdkImage* static GdkImage*
gdk_pixmap_get_image (GdkDrawable *drawable, gdk_pixmap_copy_to_image (GdkDrawable *drawable,
gint x, GdkImage *image,
gint y, gint src_x,
gint width, gint src_y,
gint height) gint dest_x,
gint dest_y,
gint width,
gint height)
{ {
g_return_val_if_fail (GDK_IS_PIXMAP (drawable), NULL); g_return_val_if_fail (GDK_IS_PIXMAP (drawable), NULL);
return gdk_drawable_get_image (((GdkPixmapObject*)drawable)->impl, return _gdk_drawable_copy_to_image (((GdkPixmapObject*)drawable)->impl,
x, y, width, height); image,
src_x, src_y, dest_x, dest_y,
width, height);
} }
static GdkBitmap * static GdkBitmap *

View File

@ -46,22 +46,10 @@
#define ENABLE_GRAYSCALE #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 <gdk/gdkprivate.h>
#else
/* Compiling as a part of Gtk 1.1 or later */
#include "config.h" #include "config.h"
#include "gdkprivate.h" #include "gdkprivate.h"
#include "gdkinternals.h" /* _gdk_windowing_get_bits_for_depth() */
#endif
#include "gdk.h" /* For gdk_flush() */
#include "gdkrgb.h" #include "gdkrgb.h"
typedef struct _GdkRgbInfo GdkRgbInfo; typedef struct _GdkRgbInfo GdkRgbInfo;
@ -84,30 +72,10 @@ static const gchar* visual_names[] =
"direct color", "direct color",
}; };
#define REGION_WIDTH 256 #define STAGE_ROWSTRIDE (GDK_SCRATCH_IMAGE_WIDTH * 3)
#define STAGE_ROWSTRIDE (REGION_WIDTH * 3)
#define REGION_HEIGHT 64
/* We have N_REGION REGION_WIDTH x REGION_HEIGHT regions divided /* Some of these fields should go, as they're not being used at all. (?)
* 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?)
*/ */
#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 struct _GdkRgbInfo
{ {
GdkVisual *visual; GdkVisual *visual;
@ -147,32 +115,6 @@ struct _GdkRgbInfo
GdkRgbConvFunc conv_indexed; GdkRgbConvFunc conv_indexed;
GdkRgbConvFunc conv_indexed_d; 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;
guchar *colorcube_d; guchar *colorcube_d;
@ -562,7 +504,7 @@ gdk_rgb_choose_visual (void)
return best_visual; 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 static void
gdk_rgb_set_gray_cmap (GdkRgbInfo *image_info, 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 static void
gdk_rgb_free_info (GdkRgbInfo *image_info) gdk_rgb_free_info (GdkRgbInfo *image_info)
{ {
gint i;
GSList *tmp_list; GSList *tmp_list;
if (image_info->stage_buf) if (image_info->stage_buf)
g_free (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) if (image_info->own_gc)
gdk_gc_unref (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) if (image_info->colorcube)
g_free (image_info->colorcube); g_free (image_info->colorcube);
@ -679,7 +589,6 @@ static GdkRgbInfo *
gdk_rgb_create_info (GdkVisual *visual, GdkColormap *colormap) gdk_rgb_create_info (GdkVisual *visual, GdkColormap *colormap)
{ {
GdkRgbInfo *image_info; GdkRgbInfo *image_info;
gint i;
image_info = g_new0 (GdkRgbInfo, 1); 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); image_info->bitmap = (image_info->visual->depth == 1);
/* Try to allocate as few possible shared images */ image_info->bpp = (_gdk_windowing_get_bits_for_depth (image_info->visual->depth) + 7) / 8;
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;
}
}
/* If that fails, just allocate N_REGIONS normal images */ gdk_rgb_select_conv (image_info);
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]);
if (!gdk_rgb_quark) if (!gdk_rgb_quark)
gdk_rgb_quark = g_quark_from_static_string (gdk_rgb_key); 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 #ifdef HAIRY_CONVERT_565
/* Render a 24-bit RGB image in buf into the GdkImage, without dithering. /* 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 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. config flag, and if not, use a different function.
This one is even faster than the one below - its inner loop loads 3 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 #else
/* Render a 24-bit RGB image in buf into the GdkImage, without dithering. /* 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 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. config flag, and if not, use a different function.
This routine is faster than the one included with Gtk 1.0 for a number 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) gdk_rgb_ensure_stage (GdkRgbInfo *image_info)
{ {
if (image_info->stage_buf == NULL) 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; 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 /* Select a conversion function based on the visual and a
representative image. */ representative image. */
static void static void
gdk_rgb_select_conv (GdkRgbInfo *image_info, GdkImage *image) gdk_rgb_select_conv (GdkRgbInfo *image_info)
{ {
GdkByteOrder byte_order; GdkByteOrder byte_order;
gint depth, bpp, byterev; gint depth, bpp, byterev;
@ -2887,9 +2772,9 @@ gdk_rgb_select_conv (GdkRgbInfo *image_info, GdkImage *image)
depth = image_info->visual->depth; 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) if (gdk_rgb_verbose)
g_print ("Chose visual type=%s depth=%d, image bpp=%d, %s first\n", g_print ("Chose visual type=%s depth=%d, image bpp=%d, %s first\n",
visual_names[image_info->visual->type], image_info->visual->depth, 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; 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 static void
gdk_draw_rgb_image_core (GdkRgbInfo *image_info, gdk_draw_rgb_image_core (GdkRgbInfo *image_info,
GdkDrawable *drawable, GdkDrawable *drawable,
@ -3212,15 +2987,15 @@ gdk_draw_rgb_image_core (GdkRgbInfo *image_info,
} }
gc = image_info->own_gc; 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); height1 = MIN (height - y0, GDK_SCRATCH_IMAGE_HEIGHT);
for (x0 = 0; x0 < width; x0 += REGION_WIDTH) 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; 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, conv (image_info, image, xs0, ys0, width1, height1, buf_ptr, rowstride,
x + x0 + xdith, y + y0 + ydith, cmap); x + x0 + xdith, y + y0 + ydith, cmap);

View File

@ -126,12 +126,27 @@ static void gdk_window_draw_image (GdkDrawable *drawable,
gint width, gint width,
gint height); gint height);
static GdkImage* gdk_window_get_image (GdkDrawable *drawable, static void gdk_window_draw_pixbuf (GdkDrawable *drawable,
gint x, GdkGC *gc,
gint y, GdkPixbuf *pixbuf,
gint width, gint src_x,
gint height); 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, static void gdk_window_real_get_size (GdkDrawable *drawable,
gint *width, gint *width,
@ -223,12 +238,13 @@ gdk_window_class_init (GdkWindowObjectClass *klass)
drawable_class->draw_lines = gdk_window_draw_lines; drawable_class->draw_lines = gdk_window_draw_lines;
drawable_class->draw_glyphs = gdk_window_draw_glyphs; drawable_class->draw_glyphs = gdk_window_draw_glyphs;
drawable_class->draw_image = gdk_window_draw_image; 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_depth = gdk_window_real_get_depth;
drawable_class->get_size = gdk_window_real_get_size; drawable_class->get_size = gdk_window_real_get_size;
drawable_class->set_colormap = gdk_window_real_set_colormap; drawable_class->set_colormap = gdk_window_real_set_colormap;
drawable_class->get_colormap = gdk_window_real_get_colormap; drawable_class->get_colormap = gdk_window_real_get_colormap;
drawable_class->get_visual = gdk_window_real_get_visual; 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_clip_region = gdk_window_get_clip_region;
drawable_class->get_visible_region = gdk_window_get_visible_region; drawable_class->get_visible_region = gdk_window_get_visible_region;
drawable_class->get_composite_drawable = gdk_window_get_composite_drawable; drawable_class->get_composite_drawable = gdk_window_get_composite_drawable;
@ -1862,6 +1878,65 @@ gdk_window_draw_image (GdkDrawable *drawable,
RESTORE_GC (gc); 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 static void
gdk_window_real_get_size (GdkDrawable *drawable, gdk_window_real_get_size (GdkDrawable *drawable,
@ -1927,11 +2002,14 @@ gdk_window_real_get_colormap (GdkDrawable *drawable)
} }
static GdkImage* static GdkImage*
gdk_window_get_image (GdkDrawable *drawable, gdk_window_copy_to_image (GdkDrawable *drawable,
gint x, GdkImage *image,
gint y, gint src_x,
gint width, gint src_y,
gint height) gint dest_x,
gint dest_y,
gint width,
gint height)
{ {
gint x_offset, y_offset; 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); _gdk_windowing_window_get_offsets (drawable, &x_offset, &y_offset);
return gdk_drawable_get_image (((GdkWindowObject*)drawable)->impl, return _gdk_drawable_copy_to_image (((GdkWindowObject*)drawable)->impl,
x - x_offset, image,
y - y_offset, src_x - x_offset,
width, height); src_y - y_offset,
dest_x, dest_y,
width, height);
} }
/* Code for dirty-region queueing /* Code for dirty-region queueing

View File

@ -35,6 +35,7 @@
#endif #endif
#include <stdlib.h> #include <stdlib.h>
#include <string.h> /* for memcpy() */
#if defined (HAVE_IPC_H) && defined (HAVE_SHM_H) && defined (HAVE_XSHM_H) #if defined (HAVE_IPC_H) && defined (HAVE_SHM_H) && defined (HAVE_XSHM_H)
#define USE_SHM #define USE_SHM
@ -119,6 +120,20 @@ static void gdk_x11_draw_image (GdkDrawable *drawable,
gint ydest, gint ydest,
gint width, gint width,
gint height); 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, static void gdk_x11_set_colormap (GdkDrawable *drawable,
GdkColormap *colormap); 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_lines = gdk_x11_draw_lines;
drawable_class->draw_glyphs = gdk_x11_draw_glyphs; drawable_class->draw_glyphs = gdk_x11_draw_glyphs;
drawable_class->draw_image = gdk_x11_draw_image; 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->set_colormap = gdk_x11_set_colormap;
drawable_class->get_colormap = gdk_x11_get_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_depth = gdk_x11_get_depth;
drawable_class->get_visual = gdk_x11_get_visual; 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 static void
@ -204,6 +222,17 @@ gdk_drawable_impl_x11_finalize (GObject *object)
} }
#ifdef HAVE_XFT #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 static Picture
gdk_x11_drawable_get_picture (GdkDrawable *drawable) 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)); 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; return impl->picture;
@ -752,3 +782,536 @@ gdk_x11_drawable_get_xid (GdkDrawable *drawable)
return ((GdkDrawableImplX11 *)impl)->xid; 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 */

View File

@ -810,9 +810,13 @@ _gdk_x11_gc_get_fg_picture (GdkGC *gc)
{ {
XRenderPictureAttributes pa; XRenderPictureAttributes pa;
XRenderPictFormat *pix_format = foreground_format (gc); XRenderPictFormat *pix_format = foreground_format (gc);
Pixmap pix;
Pixmap pix = XCreatePixmap (x11_gc->xdisplay, _gdk_root_window, if (!pix_format)
1, 1, pix_format->depth); return None;
pix = XCreatePixmap (x11_gc->xdisplay, _gdk_root_window,
1, 1, pix_format->depth);
pa.repeat = True; pa.repeat = True;
x11_gc->fg_picture = XRenderCreatePicture (x11_gc->xdisplay, x11_gc->fg_picture = XRenderCreatePicture (x11_gc->xdisplay,
pix, pix,

View File

@ -59,10 +59,12 @@ struct _GdkImagePrivateX11
XImage *ximage; XImage *ximage;
Display *xdisplay; Display *xdisplay;
gpointer x_shm_info; gpointer x_shm_info;
Pixmap shm_pixmap;
}; };
static GList *image_list = NULL; static GList *image_list = NULL;
static gpointer parent_class = NULL; static gpointer parent_class = NULL;
static gboolean have_shm_pixmaps;
static void gdk_x11_image_destroy (GdkImage *image); static void gdk_x11_image_destroy (GdkImage *image);
static void gdk_image_init (GdkImage *image); static void gdk_image_init (GdkImage *image);
@ -198,33 +200,42 @@ _gdk_windowing_image_init (void)
{ {
if (_gdk_use_xshm) if (_gdk_use_xshm)
{ {
if (!gdk_image_check_xshm (gdk_display)) gint res = gdk_image_check_xshm (gdk_display);
{
_gdk_use_xshm = False; if (!res)
} _gdk_use_xshm = FALSE;
else
have_shm_pixmaps = (res == 2);
} }
} }
GdkImage* GdkImage*
gdk_image_new (GdkImageType type, _gdk_image_new_for_depth (GdkImageType type,
GdkVisual *visual, GdkVisual *visual,
gint width, gint width,
gint height) gint height,
gint depth)
{ {
GdkImage *image; GdkImage *image;
GdkImagePrivateX11 *private; GdkImagePrivateX11 *private;
#ifdef USE_SHM #ifdef USE_SHM
XShmSegmentInfo *x_shm_info; XShmSegmentInfo *x_shm_info;
#endif /* USE_SHM */ #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) switch (type)
{ {
case GDK_IMAGE_FASTEST: 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) 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; break;
default: default:
@ -238,9 +249,10 @@ gdk_image_new (GdkImageType type,
image->visual = visual; image->visual = visual;
image->width = width; image->width = width;
image->height = height; image->height = height;
image->depth = visual->depth; image->depth = depth;
xvisual = ((GdkVisualPrivate*) visual)->xvisual; if (visual)
xvisual = ((GdkVisualPrivate*) visual)->xvisual;
switch (type) switch (type)
{ {
@ -253,7 +265,7 @@ gdk_image_new (GdkImageType type,
x_shm_info->shmid = -1; x_shm_info->shmid = -1;
x_shm_info->shmaddr = (char*) -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); ZPixmap, NULL, x_shm_info, width, height);
if (private->ximage == NULL) if (private->ximage == NULL)
{ {
@ -326,7 +338,7 @@ gdk_image_new (GdkImageType type,
goto error; goto error;
break; break;
case GDK_IMAGE_NORMAL: 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); ZPixmap, 0, 0, width, height, 32, 0);
/* Use malloc, not g_malloc here, because X will call free() /* Use malloc, not g_malloc here, because X will call free()
@ -344,7 +356,7 @@ gdk_image_new (GdkImageType type,
if (image) 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->mem = private->ximage->data;
image->bpl = private->ximage->bytes_per_line; image->bpl = private->ximage->bytes_per_line;
image->bpp = (private->ximage->bits_per_pixel + 7) / 8; image->bpp = (private->ximage->bits_per_pixel + 7) / 8;
@ -379,39 +391,144 @@ gdk_image_new (GdkImageType type,
return NULL; 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* GdkImage*
_gdk_x11_get_image (GdkDrawable *drawable, gdk_image_new (GdkImageType type,
gint x, GdkVisual *visual,
gint y, gint width,
gint width, gint height)
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; 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; GdkImagePrivateX11 *private;
GdkDrawableImplX11 *impl; GdkDrawableImplX11 *impl;
GdkVisual *visual; GdkVisual *visual;
gboolean have_grab; gboolean have_grab;
GdkRectangle req; GdkRectangle req;
GdkRectangle window_rect; 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 (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); visual = gdk_drawable_get_visual (drawable);
g_assert (visual || !GDK_IS_WINDOW_IMPL_X11 (drawable));
impl = GDK_DRAWABLE_IMPL_X11 (drawable); impl = GDK_DRAWABLE_IMPL_X11 (drawable);
have_grab = FALSE; 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)) if (GDK_IS_WINDOW_IMPL_X11 (drawable))
{ {
GdkRectangle screen_rect; GdkRectangle screen_rect;
Window child; Window child;
g_assert (visual);
have_grab = TRUE; have_grab = TRUE;
gdk_x11_grab_server (); gdk_x11_grab_server ();
@ -443,13 +560,7 @@ _gdk_x11_get_image (GdkDrawable *drawable,
if (gdk_error_trap_pop () || if (gdk_error_trap_pop () ||
!gdk_rectangle_intersect (&window_rect, &screen_rect, !gdk_rectangle_intersect (&window_rect, &screen_rect,
&window_rect)) &window_rect))
{ goto out;
if (have_grab)
gdk_x11_ungrab_server ();
return image = gdk_image_new (GDK_IMAGE_FASTEST,
visual,
width, height);
}
} }
else else
{ {
@ -460,8 +571,8 @@ _gdk_x11_get_image (GdkDrawable *drawable,
&window_rect.height); &window_rect.height);
} }
req.x = x; req.x = src_x;
req.y = y; req.y = src_y;
req.width = width; req.width = width;
req.height = height; 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 * For pixmaps this is all of the pixmap, for windows it is just
* the onscreen part. * the onscreen part.
*/ */
if (!gdk_rectangle_intersect (&req, &window_rect, &req) && visual) if (!gdk_rectangle_intersect (&req, &window_rect, &req))
{ goto out;
if (have_grab)
gdk_x11_ungrab_server ();
return image = gdk_image_new (GDK_IMAGE_FASTEST,
visual,
width, height);
}
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)); image = get_full_image (drawable, src_x, src_y, width, height);
g_assert (visual); if (!image)
success = FALSE;
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);
} }
else else
{ {
/* Here we ignore the req.width, req.height - gboolean created_image = FALSE;
* XGetImage() will do the right thing without
* them. 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, if (XGetSubImage (impl->xdisplay,
impl->xid, impl->xid,
x, y, width, height, req.x, req.y, req.width, req.height,
AllPlanes, ZPixmap); AllPlanes, ZPixmap,
private->ximage,
if (have_grab) dest_x + req.x - src_x, dest_y + req.y - src_y) == None)
{ {
gdk_x11_ungrab_server (); if (created_image)
have_grab = FALSE; g_object_unref (image);
} image = NULL;
success = 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;
} }
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; return image;
} }
@ -625,7 +705,11 @@ gdk_x11_image_destroy (GdkImage *image)
case GDK_IMAGE_SHARED: case GDK_IMAGE_SHARED:
#ifdef USE_SHM #ifdef USE_SHM
gdk_flush(); 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); XShmDetach (private->xdisplay, private->x_shm_info);
XDestroyImage (private->ximage); XDestroyImage (private->ximage);
@ -634,8 +718,7 @@ gdk_x11_image_destroy (GdkImage *image)
g_free (private->x_shm_info); g_free (private->x_shm_info);
private->x_shm_info = NULL; private->x_shm_info = NULL;
image_list = g_list_remove (image_list, image);
#else /* USE_SHM */ #else /* USE_SHM */
g_error ("trying to destroy shared memory image when gdk was compiled without shared memory support"); g_error ("trying to destroy shared memory image when gdk was compiled without shared memory support");
#endif /* USE_SHM */ #endif /* USE_SHM */
@ -673,3 +756,23 @@ gdk_x11_image_get_ximage (GdkImage *image)
return private->ximage; 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;
}

View File

@ -49,7 +49,7 @@ gdk_pango_context_get (void)
{ {
const char *val = g_getenv ("GDK_USE_XFT"); 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) if (use_xft)

View File

@ -100,7 +100,8 @@ gint gdk_send_xevent (Window window,
GType _gdk_gc_x11_get_type (void); GType _gdk_gc_x11_get_type (void);
#ifdef HAVE_XFT #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 */ #endif /* HAVE_XFT */
GdkGC *_gdk_x11_gc_new (GdkDrawable *drawable, 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); void gdk_window_add_colormap_windows (GdkWindow *window);
GdkImage* _gdk_x11_get_image (GdkDrawable *drawable, GdkImage *_gdk_x11_copy_to_image (GdkDrawable *drawable,
gint x, GdkImage *image,
gint y, gint src_x,
gint width, gint src_y,
gint height); 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 */ /* Please see gdkwindow.c for comments on how to use */
Window gdk_window_xid_at (Window base, Window gdk_window_xid_at (Window base,

View File

@ -48,7 +48,7 @@ quit_func (GtkWidget *widget, gpointer dummy)
#define WIDTH 640 #define WIDTH 640
#define HEIGHT 400 #define HEIGHT 400
#define NUM_ITERS 100 #define NUM_ITERS 50
static void static void
testrgb_rgb_test (GtkWidget *drawing_area) testrgb_rgb_test (GtkWidget *drawing_area)
@ -62,11 +62,13 @@ testrgb_rgb_test (GtkWidget *drawing_area)
gboolean dither; gboolean dither;
int dith_max; int dith_max;
GTimer *timer; GTimer *timer;
GdkPixbuf *pixbuf;
buf = g_malloc (WIDTH * HEIGHT * 6); gboolean to_pixmap;
buf = g_malloc (WIDTH * HEIGHT * 8);
val = 0; 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; val = (val + ((val + (rand () & 0xff)) >> 1)) >> 1;
buf[j] = val; buf[j] = val;
@ -103,6 +105,7 @@ testrgb_rgb_test (GtkWidget *drawing_area)
GDK_RGB_DITHER_NONE, GDK_RGB_DITHER_NONE,
buf + offset, WIDTH * 3); buf + offset, WIDTH * 3);
} }
gdk_flush ();
total_time = g_timer_elapsed (timer, NULL) - start_time; total_time = g_timer_elapsed (timer, NULL) - start_time;
g_print ("Color test%s time elapsed: %.2fs, %.1f fps, %.2f megapixels/s\n", g_print ("Color test%s time elapsed: %.2fs, %.1f fps, %.2f megapixels/s\n",
dither ? " (dithered)" : "", dither ? " (dithered)" : "",
@ -124,6 +127,7 @@ testrgb_rgb_test (GtkWidget *drawing_area)
GDK_RGB_DITHER_NONE, GDK_RGB_DITHER_NONE,
buf + offset, WIDTH); buf + offset, WIDTH);
} }
gdk_flush ();
total_time = g_timer_elapsed (timer, NULL) - start_time; total_time = g_timer_elapsed (timer, NULL) - start_time;
g_print ("Grayscale test%s time elapsed: %.2fs, %.1f fps, %.2f megapixels/s\n", g_print ("Grayscale test%s time elapsed: %.2fs, %.1f fps, %.2f megapixels/s\n",
dither ? " (dithered)" : "", dither ? " (dithered)" : "",
@ -132,6 +136,42 @@ testrgb_rgb_test (GtkWidget *drawing_area)
NUM_ITERS * (WIDTH * HEIGHT * 1e-6) / total_time); 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"); g_print ("Please submit these results to http://www.levien.com/gdkrgb/survey.html\n");
#if 1 #if 1