Boost logo

Boost-Commit :

From: lbourdev_at_[hidden]
Date: 2007-11-16 22:38:25


Author: lbourdev
Date: 2007-11-16 22:38:25 EST (Fri, 16 Nov 2007)
New Revision: 41165
URL: http://svn.boost.org/trac/boost/changeset/41165

Log:
Updated to version 2.1.2
Added support for more compilers.
Added new flag GIL_NONWORD_POINTER_ALIGNMENT_SUPPORTED to indicate whether dereferencing on non-word
boundary is supported. Enabling this flag improves performance.
Fixed two bugs related to non-byte-aligned images. The image alignment parameter is now specified in
bytes, and has a default of 0, which means "packed" alignment. In particular, for non-byte-aligned
images alignment of 0 means there are no padding bits at the ends of rows.
Added the allocator as an optional parameter to image constructors and image recreate methods.

Text files modified:
   trunk/boost/gil/channel.hpp | 49 ++++++++++++++++++-----
   trunk/boost/gil/color_convert.hpp | 3
   trunk/boost/gil/gil_config.hpp | 7 ++
   trunk/boost/gil/image.hpp | 83 ++++++++++++++++++++-------------------
   trunk/boost/gil/metafunctions.hpp | 2
   trunk/libs/gil/test/image.cpp | 20 ++++++--
   trunk/libs/gil/test/pixel_iterator.cpp | 1
   7 files changed, 104 insertions(+), 61 deletions(-)

Modified: trunk/boost/gil/channel.hpp
==============================================================================
--- trunk/boost/gil/channel.hpp (original)
+++ trunk/boost/gil/channel.hpp 2007-11-16 22:38:25 EST (Fri, 16 Nov 2007)
@@ -253,6 +253,20 @@
 };
 
 namespace detail {
+
+template <std::size_t K>
+struct static_copy_bytes {
+ void operator()(const unsigned char* from, unsigned char* to) const {
+ *to = *from;
+ static_copy_bytes<K-1>()(++from,++to);
+ }
+};
+
+template <>
+struct static_copy_bytes<0> {
+ void operator()(const unsigned char* from, unsigned char* to) const {}
+};
+
 template <typename Derived, typename BitField, int NumBits, bool Mutable>
 class packed_channel_reference_base {
 protected:
@@ -292,8 +306,21 @@
     data_ptr_t operator &() const {return _data_ptr;}
 protected:
     static const integer_t max_val = (1<<NumBits) - 1;
- const bitfield_t& const_data() const { return *static_cast<const bitfield_t*>(_data_ptr); }
- bitfield_t& data() const { return *static_cast< bitfield_t*>(_data_ptr); }
+
+#ifdef GIL_NONWORD_POINTER_ALIGNMENT_SUPPORTED
+ const bitfield_t& get_data() const { return *static_cast<const bitfield_t*>(_data_ptr); }
+ void set_data(const bitfield_t& val) const { *static_cast< bitfield_t*>(_data_ptr) = val; }
+#else
+ bitfield_t get_data() const {
+ bitfield_t ret;
+ static_copy_bytes<sizeof(bitfield_t) >()(gil_reinterpret_cast_c<const unsigned char*>(_data_ptr),gil_reinterpret_cast<unsigned char*>(&ret));
+ return ret;
+ }
+ void set_data(const bitfield_t& val) const {
+ static_copy_bytes<sizeof(bitfield_t) >()(gil_reinterpret_cast_c<const unsigned char*>(&val),gil_reinterpret_cast<unsigned char*>(_data_ptr));
+ }
+#endif
+
 private:
     void set(integer_t value) const { // can this be done faster??
         const integer_t num_values = max_val+1;
@@ -351,7 +378,7 @@
 
     unsigned first_bit() const { return FirstBit; }
 
- integer_t get() const { return integer_t((this->const_data()&channel_mask) >> FirstBit); }
+ integer_t get() const { return integer_t((this->get_data()&channel_mask) >> FirstBit); }
 };
 
 /// \ingroup PackedChannelReferenceModel
@@ -372,18 +399,18 @@
     packed_channel_reference(const packed_channel_reference& ref) : parent_t(ref._data_ptr) {}
 
     const packed_channel_reference& operator=(integer_t value) const { assert(value<=parent_t::max_val); set_unsafe(value); return *this; }
- const packed_channel_reference& operator=(const mutable_reference& ref) const { set_from_reference(ref.data()); return *this; }
- const packed_channel_reference& operator=(const const_reference& ref) const { set_from_reference(ref.const_data()); return *this; }
+ const packed_channel_reference& operator=(const mutable_reference& ref) const { set_from_reference(ref.get_data()); return *this; }
+ const packed_channel_reference& operator=(const const_reference& ref) const { set_from_reference(ref.get_data()); return *this; }
 
     template <bool Mutable1>
     const packed_channel_reference& operator=(const packed_dynamic_channel_reference<BitField,NumBits,Mutable1>& ref) const { set_unsafe(ref.get()); return *this; }
 
     unsigned first_bit() const { return FirstBit; }
 
- integer_t get() const { return integer_t((this->const_data()&channel_mask) >> FirstBit); }
- void set_unsafe(integer_t value) const { this->data() = (this->const_data() & ~channel_mask) | (value<<FirstBit); }
+ integer_t get() const { return integer_t((this->get_data()&channel_mask) >> FirstBit); }
+ void set_unsafe(integer_t value) const { this->set_data((this->get_data() & ~channel_mask) | (value<<FirstBit)); }
 private:
- void set_from_reference(const BitField& other_bits) const { this->data() = (this->const_data() & ~channel_mask) | (other_bits & channel_mask); }
+ void set_from_reference(const BitField& other_bits) const { this->set_data((this->get_data() & ~channel_mask) | (other_bits & channel_mask)); }
 };
 
 } } // namespace boost::gil
@@ -463,7 +490,7 @@
 
     integer_t get() const {
         const BitField channel_mask = parent_t::max_val<<_first_bit;
- return (this->const_data()&channel_mask) >> _first_bit;
+ return (this->get_data()&channel_mask) >> _first_bit;
     }
 };
 
@@ -498,11 +525,11 @@
 
     integer_t get() const {
         const BitField channel_mask = parent_t::max_val<<_first_bit;
- return (this->const_data()&channel_mask) >> _first_bit;
+ return (this->get_data()&channel_mask) >> _first_bit;
     }
     void set_unsafe(integer_t value) const {
         const BitField channel_mask = parent_t::max_val<<_first_bit;
- this->data() = (this->const_data() & ~channel_mask) | value<<_first_bit;
+ this->set_data((this->get_data() & ~channel_mask) | value<<_first_bit);
     }
 };
 } } // namespace boost::gil

Modified: trunk/boost/gil/color_convert.hpp
==============================================================================
--- trunk/boost/gil/color_convert.hpp (original)
+++ trunk/boost/gil/color_convert.hpp 2007-11-16 22:38:25 EST (Fri, 16 Nov 2007)
@@ -32,7 +32,6 @@
 #include "rgb.hpp"
 #include "rgba.hpp"
 #include "cmyk.hpp"
-#include "image_view_factory.hpp"
 #include "metafunctions.hpp"
 #include "utilities.hpp"
 #include "color_base_algorithm.hpp"
@@ -229,7 +228,7 @@
     return get_color(p,alpha_t());
 }
 template <typename Pixel>
-typename channel_type<Pixel>::type alpha_or_max_impl(const Pixel& p, mpl::false_) {
+typename channel_type<Pixel>::type alpha_or_max_impl(const Pixel& , mpl::false_) {
     return channel_traits<typename channel_type<Pixel>::type>::max_value();
 }
 } // namespace detail

Modified: trunk/boost/gil/gil_config.hpp
==============================================================================
--- trunk/boost/gil/gil_config.hpp (original)
+++ trunk/boost/gil/gil_config.hpp 2007-11-16 22:38:25 EST (Fri, 16 Nov 2007)
@@ -23,7 +23,7 @@
 
 #include <boost/config.hpp>
 
-#define GIL_VERSION "2.1.1"
+#define GIL_VERSION "2.1.2"
 
 #ifdef _DEBUG
 # define GIL_FORCEINLINE inline
@@ -41,5 +41,10 @@
 #endif
 #endif
 
+// Enable GIL_NONWORD_POINTER_ALIGNMENT_SUPPORTED if your platform supports dereferencing on non-word memory boundary.
+// Enabling the flag results in performance improvement
+#if !defined(__hpux) && !defined(sun) && !defined(__sun) && !defined(__osf__)
+ #define GIL_NONWORD_POINTER_ALIGNMENT_SUPPORTED
+#endif
 
 #endif

Modified: trunk/boost/gil/image.hpp
==============================================================================
--- trunk/boost/gil/image.hpp (original)
+++ trunk/boost/gil/image.hpp 2007-11-16 22:38:25 EST (Fri, 16 Nov 2007)
@@ -63,42 +63,44 @@
     x_coord_t width() const { return _view.width(); }
     y_coord_t height() const { return _view.height(); }
 
- explicit image(std::size_t alignment=1,
+ explicit image(std::size_t alignment=0,
                    const Alloc alloc_in = Alloc()) :
- _memory(0), _align(alignment), _alloc(alloc_in) {}
+ _memory(0), _align_in_bytes(alignment), _alloc(alloc_in) {}
 
     // Create with dimensions and optional initial value and alignment
     image(const point_t& dimensions,
- std::size_t alignment=1) : _memory(0), _align(alignment) {
+ std::size_t alignment=0,
+ const Alloc alloc_in = Alloc()) : _memory(0), _align_in_bytes(alignment), _alloc(alloc_in) {
         allocate_and_default_construct(dimensions);
     }
     image(x_coord_t width, y_coord_t height,
- std::size_t alignment=1) : _memory(0), _align(alignment) {
+ std::size_t alignment=0,
+ const Alloc alloc_in = Alloc()) : _memory(0), _align_in_bytes(alignment), _alloc(alloc_in) {
         allocate_and_default_construct(point_t(width,height));
     }
     image(const point_t& dimensions,
           const Pixel& p_in,
           std::size_t alignment,
           const Alloc alloc_in = Alloc()) :
- _memory(0), _align(alignment), _alloc(alloc_in) {
+ _memory(0), _align_in_bytes(alignment), _alloc(alloc_in) {
         allocate_and_fill(dimensions, p_in);
     }
     image(x_coord_t width, y_coord_t height,
           const Pixel& p_in,
           std::size_t alignment,
           const Alloc alloc_in = Alloc()) :
- _memory(0), _align(alignment), _alloc(alloc_in) {
+ _memory(0), _align_in_bytes(alignment), _alloc(alloc_in) {
         allocate_and_fill(point_t(width,height),p_in);
     }
 
     image(const image& img) :
- _memory(0), _align(img._align), _alloc(img._alloc) {
+ _memory(0), _align_in_bytes(img._align_in_bytes), _alloc(img._alloc) {
         allocate_and_copy(img.dimensions(),img._view);
     }
 
     template <typename P2, bool IP2, typename Alloc2>
     image(const image<P2,IP2,Alloc2>& img) :
- _memory(0), _align(img._align), _alloc(img._alloc) {
+ _memory(0), _align_in_bytes(img._align_in_bytes), _alloc(img._alloc) {
        allocate_and_copy(img.dimensions(),img._view);
     }
     image& operator=(const image& img) {
@@ -132,37 +134,37 @@
 
     void swap(image& img) { // required by MutableContainerConcept
         using std::swap;
- swap(_align, img._align);
- swap(_memory,img._memory);
- swap(_view, img._view);
- swap(_alloc, img._alloc);
+ swap(_align_in_bytes, img._align_in_bytes);
+ swap(_memory, img._memory);
+ swap(_view, img._view);
+ swap(_alloc, img._alloc);
     }
 
- void recreate(const point_t& dims, std::size_t alignment=1) {
- if (dims!=_view.dimensions() || _align!=alignment) {
- image tmp(dims, alignment);
+ void recreate(const point_t& dims, std::size_t alignment=0, const Alloc alloc_in = Alloc()) {
+ if (dims!=_view.dimensions() || _align_in_bytes!=alignment || alloc_in!=_alloc) {
+ image tmp(dims, alignment, alloc_in);
             swap(tmp);
         }
     }
- void recreate(x_coord_t width, y_coord_t height, std::size_t alignment=1) {
- recreate(point_t(width,height),alignment);
+ void recreate(x_coord_t width, y_coord_t height, std::size_t alignment=0, const Alloc alloc_in = Alloc()) {
+ recreate(point_t(width,height),alignment,alloc_in);
     }
     void recreate(const point_t& dims,
- const Pixel& p_in, std::size_t alignment) {
- if (dims!=_view.dimensions() || _align!=alignment) {
- image tmp(dims, p_in, alignment);
+ const Pixel& p_in, std::size_t alignment, const Alloc alloc_in = Alloc()) {
+ if (dims!=_view.dimensions() || _align_in_bytes!=alignment || alloc_in!=_alloc) {
+ image tmp(dims, p_in, alignment, alloc_in);
             swap(tmp);
         }
     }
     void recreate(x_coord_t width, y_coord_t height,
- const Pixel& p_in, std::size_t alignment) {
- recreate(point_t(width,height),p_in,alignment);
+ const Pixel& p_in, std::size_t alignment, const Alloc alloc_in = Alloc()) {
+ recreate(point_t(width,height),p_in,alignment,alloc_in);
     }
 
     view_t _view; // contains pointer to the pixels, the image size and ways to navigate pixels
 private:
     unsigned char* _memory;
- std::size_t _align;
+ std::size_t _align_in_bytes;
     allocator_type _alloc;
 
     void allocate_and_default_construct(const point_t& dimensions) {
@@ -192,34 +194,35 @@
     }
 
     std::size_t total_allocated_size_in_bytes(const point_t& dimensions) const {
- std::size_t size_in_units = _total_allocated_size(dimensions, mpl::bool_<IsPlanar>());
- // return the size rounded up to the nearest byte
- return (size_in_units + byte_to_memunit<typename view_t::x_iterator>::value - 1) / byte_to_memunit<typename view_t::x_iterator>::value;
- }
+ std::size_t size_in_units = get_row_size_in_memunits(dimensions.x)*dimensions.y;
+ if (IsPlanar)
+ size_in_units = size_in_units*num_channels<view_t>::value;
 
- std::size_t get_row_size(x_coord_t width) const { // number of units per row
- return align(width*memunit_step(typename view_t::x_iterator()),_align);
+ // return the size rounded up to the nearest byte
+ return (size_in_units + byte_to_memunit<typename view_t::x_iterator>::value - 1) / byte_to_memunit<typename view_t::x_iterator>::value
+ + (_align_in_bytes>0 ? _align_in_bytes-1:0); // add extra padding in case we need to align the first image pixel
     }
 
- std::size_t _total_allocated_size(const point_t& dimensions,mpl::false_) const {
- return get_row_size(dimensions.x)*dimensions.y+_align-1;
+ std::size_t get_row_size_in_memunits(x_coord_t width) const { // number of units per row
+ std::size_t size_in_memunits = width*memunit_step(typename view_t::x_iterator());
+ if (_align_in_bytes>0) {
+ std::size_t alignment_in_memunits=_align_in_bytes*byte_to_memunit<typename view_t::x_iterator>::value;
+ return align(size_in_memunits, alignment_in_memunits);
+ }
+ return size_in_memunits;
     }
- std::size_t _total_allocated_size(const point_t& dimensions,mpl::true_) const {
- std::size_t plane_size=get_row_size(dimensions.x)*dimensions.y;
- return plane_size*num_channels<view_t>::value+_align-1;
- }
-
     
     void allocate_(const point_t& dimensions, mpl::false_) { // if it throws and _memory!=0 the client must deallocate _memory
         _memory=_alloc.allocate(total_allocated_size_in_bytes(dimensions));
- unsigned char* tmp=(unsigned char*)align((std::size_t)_memory,_align);
- _view=view_t(dimensions,typename view_t::locator(typename view_t::x_iterator(tmp),get_row_size(dimensions.x)));
+ unsigned char* tmp=(_align_in_bytes>0) ? (unsigned char*)align((std::size_t)_memory,_align_in_bytes) : _memory;
+ _view=view_t(dimensions,typename view_t::locator(typename view_t::x_iterator(tmp),get_row_size_in_memunits(dimensions.x)));
     }
+
     void allocate_(const point_t& dimensions, mpl::true_) { // if it throws and _memory!=0 the client must deallocate _memory
- std::size_t row_size=get_row_size(dimensions.x);
+ std::size_t row_size=get_row_size_in_memunits(dimensions.x);
         std::size_t plane_size=row_size*dimensions.y;
         _memory=_alloc.allocate(total_allocated_size_in_bytes(dimensions));
- unsigned char* tmp=(unsigned char*)align((std::size_t)_memory,_align);
+ unsigned char* tmp=(_align_in_bytes>0) ? (unsigned char*)align((std::size_t)_memory,_align_in_bytes) : _memory;
         typename view_t::x_iterator first;
         for (int i=0; i<num_channels<view_t>::value; ++i) {
             dynamic_at_c(first,i) = (typename channel_type<view_t>::type*)tmp;

Modified: trunk/boost/gil/metafunctions.hpp
==============================================================================
--- trunk/boost/gil/metafunctions.hpp (original)
+++ trunk/boost/gil/metafunctions.hpp 2007-11-16 22:38:25 EST (Fri, 16 Nov 2007)
@@ -338,7 +338,7 @@
 struct bit_aligned_image_type {
 private:
     BOOST_STATIC_CONSTANT(int, bit_size = (mpl::accumulate<ChannelBitSizeVector, mpl::int_<0>, mpl::plus<mpl::_1, mpl::_2> >::type::value));
- typedef typename detail::min_fast_uint<bit_size>::type bitfield_t;
+ typedef typename detail::min_fast_uint<bit_size+7>::type bitfield_t;
     typedef const bit_aligned_pixel_reference<bitfield_t, ChannelBitSizeVector, Layout, true> bit_alignedref_t;
 public:
     typedef image<bit_alignedref_t,false,Alloc> type;

Modified: trunk/libs/gil/test/image.cpp
==============================================================================
--- trunk/libs/gil/test/image.cpp (original)
+++ trunk/libs/gil/test/image.cpp 2007-11-16 22:38:25 EST (Fri, 16 Nov 2007)
@@ -291,14 +291,22 @@
     histogram_test(mandel,"virtual_");
 }
 
+// Test alignment and packed images
 void image_test::packed_image_test() {
- typedef packed_image3_type<boost::uint16_t, 5,6,5, rgb_layout_t>::type rgb565_image_t;
+ typedef bit_aligned_image3_type<1,3,1, bgr_layout_t>::type bgr131_image_t;
+ typedef bgr131_image_t::value_type bgr131_pixel_t;
+ bgr131_pixel_t fill_val(1,3,1);
 
- rgb565_image_t img565(sample_view.dimensions());
- copy_and_convert_pixels(sample_view, view(img565));
+ bgr131_image_t bgr131_img(3,10);
+ fill_pixels(view(bgr131_img), fill_val);
 
-// TODO: Commented out because there is an error with packed images under GCC 4.1.2, but not under VC8
-// check_view(color_converted_view<rgb8_pixel_t>(const_view(img565)),"packed565");
+ bgr131_image_t bgr131a_img(3,10,1);
+ copy_pixels(const_view(bgr131_img), view(bgr131a_img));
+
+ bgr131_image_t bgr131b_img(3,10,4);
+ copy_pixels(const_view(bgr131_img), view(bgr131b_img));
+
+ error_if(bgr131_img!=bgr131a_img || bgr131a_img!=bgr131b_img);
 }
 
 void image_test::dynamic_image_test() {
@@ -339,7 +347,7 @@
     image_all_test<rgb8_planar_image_t>("planarrgb8_");
     image_all_test<gray8_image_t>("gray8_");
 
- typedef const bit_aligned_pixel_reference<boost::uint8_t, mpl::vector3_c<int,1,2,1>, bgr_layout_t, true> bgr121_ref_t;
+ typedef const bit_aligned_pixel_reference<boost::uint8_t, mpl::vector3_c<int,1,2,1>, bgr_layout_t, true> bgr121_ref_t;
     typedef image<bgr121_ref_t,false> bgr121_image_t;
     image_all_test<bgr121_image_t>("bgr121_");
 

Modified: trunk/libs/gil/test/pixel_iterator.cpp
==============================================================================
--- trunk/libs/gil/test/pixel_iterator.cpp (original)
+++ trunk/libs/gil/test/pixel_iterator.cpp 2007-11-16 22:38:25 EST (Fri, 16 Nov 2007)
@@ -22,6 +22,7 @@
 #include <boost/gil/step_iterator.hpp>
 #include <boost/gil/typedefs.hpp>
 #include <boost/gil/color_convert.hpp>
+#include <boost/gil/image_view_factory.hpp>
 #include <boost/mpl/vector.hpp>
 
 using namespace boost::gil;


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk