diff --git a/include/boost/compute/closure.hpp b/include/boost/compute/closure.hpp index 385ea3c5..f1eafb8c 100644 --- a/include/boost/compute/closure.hpp +++ b/include/boost/compute/closure.hpp @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -27,6 +28,7 @@ #include #include #include +#include namespace boost { namespace compute { @@ -126,12 +128,6 @@ public: return m_source; } - /// \internal_ - void recapture(const CaptureTuple &capture) - { - m_capture = capture; - } - /// \internal_ void define(std::string name, std::string value = std::string()) { @@ -224,21 +220,24 @@ struct closure_signature_argument_inserter } template - void operator()(const T&) + void operator()(const T&) const { BOOST_ASSERT(n < m_capture_names.size()); - // remove leading and trailing whitespace from variable name - boost::trim(m_capture_names[n]); + // get captured variable name + std::string variable_name = m_capture_names[n]; - s << type_name() << " " << m_capture_names[n]; + // remove leading and trailing whitespace from variable name + boost::trim(variable_name); + + s << capture_traits::type_name() << " " << variable_name; if(n+1 < m_last){ s << ", "; } n++; } - size_t n; + mutable size_t n; size_t m_last; std::vector m_capture_names; std::stringstream &s; @@ -248,7 +247,7 @@ template inline std::string make_closure_declaration(const char *name, const char *arguments, - const CaptureTuple&, + const CaptureTuple &capture_tuple, const char *capture_string) { typedef typename @@ -273,7 +272,7 @@ make_closure_declaration(const char *name, closure_signature_argument_inserter j( s, capture_string, boost::tuples::length::value ); - mpl::for_each(j); + fusion::for_each(capture_tuple, j); s << ")"; return s.str(); @@ -336,12 +335,12 @@ make_closure_impl(const char *name, #else #define BOOST_COMPUTE_CLOSURE(return_type, name, arguments, capture, ...) \ ::boost::compute::closure< \ - return_type arguments, BOOST_TYPEOF(boost::make_tuple capture) \ + return_type arguments, BOOST_TYPEOF(boost::tie capture) \ > name = \ ::boost::compute::detail::make_closure_impl< \ return_type arguments \ >( \ - #name, #arguments, boost::make_tuple capture, #capture, #__VA_ARGS__ \ + #name, #arguments, boost::tie capture, #capture, #__VA_ARGS__ \ ) #endif diff --git a/include/boost/compute/container/array.hpp b/include/boost/compute/container/array.hpp index 76b980a7..6ea0cf95 100644 --- a/include/boost/compute/container/array.hpp +++ b/include/boost/compute/container/array.hpp @@ -23,6 +23,7 @@ #include #include #include +#include #include namespace boost { @@ -244,6 +245,23 @@ struct set_kernel_arg > } }; +// for capturing array with BOOST_COMPUTE_CLOSURE() +template +struct capture_traits > +{ + static std::string type_name() + { + return std::string("__global ") + ::boost::compute::type_name() + "*"; + } +}; + +// meta_kernel streaming operator for array +template +meta_kernel& operator<<(meta_kernel &k, const array &array) +{ + return k << k.get_buffer_identifier(array.get_buffer()); +} + } // end detail namespace } // end compute namespace } // end boost namespace diff --git a/include/boost/compute/container/vector.hpp b/include/boost/compute/container/vector.hpp index 33a239d3..cbc3663a 100644 --- a/include/boost/compute/container/vector.hpp +++ b/include/boost/compute/container/vector.hpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -721,6 +722,23 @@ struct set_kernel_arg > } }; +// for capturing vector with BOOST_COMPUTE_CLOSURE() +template +struct capture_traits > +{ + static std::string type_name() + { + return std::string("__global ") + ::boost::compute::type_name() + "*"; + } +}; + +// meta_kernel streaming operator for vector +template +meta_kernel& operator<<(meta_kernel &k, const vector &vector) +{ + return k << k.get_buffer_identifier(vector.get_buffer()); +} + } // end detail namespace } // end compute namespace } // end boost namespace diff --git a/include/boost/compute/type_traits/detail/capture_traits.hpp b/include/boost/compute/type_traits/detail/capture_traits.hpp new file mode 100644 index 00000000..7ad9f90a --- /dev/null +++ b/include/boost/compute/type_traits/detail/capture_traits.hpp @@ -0,0 +1,33 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Kyle Lutz +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://kylelutz.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#ifndef BOOST_COMPUTE_TYPE_TRAITS_DETAIL_CAPTURE_TRAITS_HPP +#define BOOST_COMPUTE_TYPE_TRAITS_DETAIL_CAPTURE_TRAITS_HPP + +#include + +namespace boost { +namespace compute { +namespace detail { + +template +struct capture_traits +{ + static std::string type_name() + { + return ::boost::compute::type_name(); + } +}; + +} // end detail namespace +} // end compute namespace +} // end boost namespace + +#endif // BOOST_COMPUTE_TYPE_TRAITS_DETAIL_CAPTURE_TRAITS_HPP diff --git a/test/test_closure.cpp b/test/test_closure.cpp index 10224607..be4c0679 100644 --- a/test/test_closure.cpp +++ b/test/test_closure.cpp @@ -16,7 +16,10 @@ #include #include #include +#include +#include #include +#include #include "check_macros.hpp" #include "context_setup.hpp" @@ -64,6 +67,34 @@ BOOST_AUTO_TEST_CASE(add_two_and_pi) BOOST_CHECK_CLOSE(results[3], 9.84f, 1e-6); } +BOOST_AUTO_TEST_CASE(add_y) +{ + // setup input and output vectors + int data[] = { 1, 2, 3, 4 }; + compute::vector input(data, data + 4, queue); + compute::vector output(4, context); + + // make closure which adds 'y' to each value + int y = 2; + BOOST_COMPUTE_CLOSURE(int, add_y, (int x), (y), + { + return x + y; + }); + + compute::transform( + input.begin(), input.end(), output.begin(), add_y, queue + ); + CHECK_RANGE_EQUAL(int, 4, output, (3, 4, 5, 6)); + + // change y and run again + y = 4; + + compute::transform( + input.begin(), input.end(), output.begin(), add_y, queue + ); + CHECK_RANGE_EQUAL(int, 4, output, (5, 6, 7, 8)); +} + BOOST_AUTO_TEST_CASE(scale_add_vec) { const int N = 10; @@ -80,4 +111,111 @@ BOOST_AUTO_TEST_CASE(scale_add_vec) compute::transform(b.begin(), b.end(), a.begin(), b.begin(), scaleAddVec, queue); } +BOOST_AUTO_TEST_CASE(capture_vector) +{ + int data[] = { 6, 7, 8, 9 }; + compute::vector vec(data, data + 4, queue); + + BOOST_COMPUTE_CLOSURE(int, get_vec, (int i), (vec), + { + return vec[i]; + }); + + // run using a counting iterator to copy from vec to output + compute::vector output(4, context); + compute::transform( + compute::make_counting_iterator(0), + compute::make_counting_iterator(4), + output.begin(), + get_vec, + queue + ); + CHECK_RANGE_EQUAL(int, 4, output, (6, 7, 8, 9)); + + // fill vec with 4's and run again + compute::fill(vec.begin(), vec.end(), 4, queue); + compute::transform( + compute::make_counting_iterator(0), + compute::make_counting_iterator(4), + output.begin(), + get_vec, + queue + ); + CHECK_RANGE_EQUAL(int, 4, output, (4, 4, 4, 4)); +} + +BOOST_AUTO_TEST_CASE(capture_array) +{ + int data[] = { 1, 2, 3, 4 }; + compute::array array(context); + compute::copy(data, data + 4, array.begin(), queue); + + BOOST_COMPUTE_CLOSURE(int, negative_array_value, (int i), (array), + { + return -array[i]; + }); + + compute::vector output(4, context); + compute::transform( + compute::make_counting_iterator(0), + compute::make_counting_iterator(4), + output.begin(), + negative_array_value, + queue + ); + CHECK_RANGE_EQUAL(int, 4, output, (-1, -2, -3, -4)); +} + +BOOST_AUTO_TEST_CASE(triangle_area) +{ + using compute::uint4_; + using compute::float4_; + + compute::vector triangle_indices(context); + compute::vector triangle_vertices(context); + + triangle_vertices.push_back(float4_(0, 0, 0, 1), queue); + triangle_vertices.push_back(float4_(1, 1, 0, 1), queue); + triangle_vertices.push_back(float4_(1, 0, 0, 1), queue); + triangle_vertices.push_back(float4_(2, 0, 0, 1), queue); + + triangle_indices.push_back(uint4_(0, 1, 2, 0)); + triangle_indices.push_back(uint4_(2, 1, 3, 0)); + + BOOST_COMPUTE_CLOSURE(float, triangle_area, (const uint4_ i), (triangle_vertices), + { + // load triangle vertices + const float4 a = triangle_vertices[i.x]; + const float4 b = triangle_vertices[i.y]; + const float4 c = triangle_vertices[i.z]; + + // return area of triangle + return length(cross(b-a, c-a)) / 2; + }); + + // compute area of each triangle + compute::vector triangle_areas(triangle_indices.size(), context); + + compute::transform( + triangle_indices.begin(), + triangle_indices.end(), + triangle_areas.begin(), + triangle_area, + queue + ); + + // compute total area of all triangles + float total_area = 0; + + compute::transform_reduce( + triangle_indices.begin(), + triangle_indices.end(), + &total_area, + triangle_area, + compute::plus(), + queue + ); + BOOST_CHECK_CLOSE(total_area, 1.f, 1e-6); +} + BOOST_AUTO_TEST_SUITE_END()