From 1f51cff6ba002fbebfb1266dd233fc6d05eca03a Mon Sep 17 00:00:00 2001 From: majid geravand Date: Fri, 23 Jul 2021 11:23:31 +0000 Subject: [PATCH 01/12] Initial commit --- .gitignore | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b24d71e --- /dev/null +++ b/.gitignore @@ -0,0 +1,50 @@ +# These are some examples of commonly ignored file patterns. +# You should customize this list as applicable to your project. +# Learn more about .gitignore: +# https://www.atlassian.com/git/tutorials/saving-changes/gitignore + +# Node artifact files +node_modules/ +dist/ + +# Compiled Java class files +*.class + +# Compiled Python bytecode +*.py[cod] + +# Log files +*.log + +# Package files +*.jar + +# Maven +target/ +dist/ + +# JetBrains IDE +.idea/ + +# Unit test reports +TEST*.xml + +# Generated by MacOS +.DS_Store + +# Generated by Windows +Thumbs.db + +# Applications +*.app +*.exe +*.war + +# Large media files +*.mp4 +*.tiff +*.avi +*.flv +*.mov +*.wmv + From 0825f6a3280a804458e11473418436a3d8f295a9 Mon Sep 17 00:00:00 2001 From: gfuse Date: Fri, 23 Jul 2021 16:02:14 +0200 Subject: [PATCH 02/12] add kernel image alingment --- GPU_version/vio/gtsam/imu_integration.cpp | 12 +- GPU_version/vio/gtsam/imu_integration.h | 2 +- GPU_version/vio/gtsam/svoVisionFactor.h | 8 +- .../vio/gtsam/svoVisionFactorLandMark.h | 4 +- GPU_version/vio/gtsam/svoVisionFactorSmall.h | 4 +- GPU_version/vio/include/vio/abstract_camera.h | 78 + GPU_version/vio/include/vio/aligned_mem.h | 127 + GPU_version/vio/include/vio/atan_camera.h | 100 + .../vio/include/vio/bundle_adjustment.h | 109 + GPU_version/vio/include/vio/camera_loader.h | 46 + GPU_version/vio/include/vio/cl.hpp | 12947 ++++++++++++++++ GPU_version/vio/include/vio/cl_class.h | 191 + GPU_version/vio/include/vio/config.h | 182 + GPU_version/vio/include/vio/depth_filter.h | 170 + GPU_version/vio/include/vio/feature.h | 75 + .../vio/include/vio/feature_alignment.h | 63 + .../vio/include/vio/feature_detection.h | 111 + GPU_version/vio/include/vio/for_it.hpp | 87 + GPU_version/vio/include/vio/frame.h | 185 + .../vio/include/vio/frame_handler_base.h | 118 + .../vio/include/vio/frame_handler_mono.h | 112 + GPU_version/vio/include/vio/global.h | 120 + GPU_version/vio/include/vio/homography.h | 85 + GPU_version/vio/include/vio/initialization.h | 87 + GPU_version/vio/include/vio/map.h | 137 + GPU_version/vio/include/vio/matcher.h | 130 + GPU_version/vio/include/vio/math_utils.h | 171 + GPU_version/vio/include/vio/nlls_solver.h | 174 + .../vio/include/vio/nlls_solver_impl.hpp | 316 + GPU_version/vio/include/vio/output_helper.h | 90 + GPU_version/vio/include/vio/params_helper.h | 57 + GPU_version/vio/include/vio/patch_score.h | 225 + GPU_version/vio/include/vio/point.h | 108 + GPU_version/vio/include/vio/pose_optimizer.h | 50 + GPU_version/vio/include/vio/reprojector.h | 101 + GPU_version/vio/include/vio/robust_cost.h | 156 + .../vio/include/vio/sparse_img_align.h | 85 + .../vio/include/vio/sparse_img_align_gpu.h | 82 + GPU_version/vio/include/vio/timer.h | 81 + GPU_version/vio/include/vio/ukf.h | 155 + GPU_version/vio/include/vio/vision.h | 80 + GPU_version/vio/include/vio/visualizer.h | 62 + GPU_version/vio/kernel/compute-residual.cl | 50 + GPU_version/vio/src/atan_camera.cpp | 4 +- GPU_version/vio/src/cl_class.cpp | 4 +- GPU_version/vio/src/config.cpp | 8 +- GPU_version/vio/src/depth_filter.cpp | 26 +- GPU_version/vio/src/feature_alignment.cpp | 6 +- GPU_version/vio/src/feature_detection.cpp | 10 +- GPU_version/vio/src/frame.cpp | 16 +- GPU_version/vio/src/frame_handler_base.cpp | 18 +- GPU_version/vio/src/frame_handler_mono.cpp | 49 +- GPU_version/vio/src/homography.cpp | 2 +- GPU_version/vio/src/initialization.cpp | 20 +- GPU_version/vio/src/map.cpp | 12 +- GPU_version/vio/src/matcher.cpp | 24 +- GPU_version/vio/src/math_utils.cpp | 2 +- GPU_version/vio/src/output_helper.cpp | 2 +- GPU_version/vio/src/point.cpp | 12 +- GPU_version/vio/src/pose_optimizer.cpp | 16 +- GPU_version/vio/src/reprojector.cpp | 22 +- GPU_version/vio/src/robust_cost.cpp | 4 +- GPU_version/vio/src/sparse_img_align.cpp | 30 +- GPU_version/vio/src/sparse_img_align_gpu.cpp | 128 + GPU_version/vio/src/vision.cpp | 2 +- GPU_version/vio/src/visualizer.cpp | 20 +- GPU_version/vio/src/vo_node.cpp | 20 +- GPU_version/vio/test/test_pipeline.cpp | 4 +- GPU_version/vio/test/test_pose_optimizer.cpp | 2 +- .../vio/test/test_sparse_img_align.cpp | 21 +- GPU_version/vio/test/test_utils.h | 4 +- 71 files changed, 17636 insertions(+), 185 deletions(-) create mode 100644 GPU_version/vio/include/vio/abstract_camera.h create mode 100644 GPU_version/vio/include/vio/aligned_mem.h create mode 100644 GPU_version/vio/include/vio/atan_camera.h create mode 100644 GPU_version/vio/include/vio/bundle_adjustment.h create mode 100644 GPU_version/vio/include/vio/camera_loader.h create mode 100644 GPU_version/vio/include/vio/cl.hpp create mode 100644 GPU_version/vio/include/vio/cl_class.h create mode 100644 GPU_version/vio/include/vio/config.h create mode 100644 GPU_version/vio/include/vio/depth_filter.h create mode 100644 GPU_version/vio/include/vio/feature.h create mode 100644 GPU_version/vio/include/vio/feature_alignment.h create mode 100644 GPU_version/vio/include/vio/feature_detection.h create mode 100755 GPU_version/vio/include/vio/for_it.hpp create mode 100644 GPU_version/vio/include/vio/frame.h create mode 100644 GPU_version/vio/include/vio/frame_handler_base.h create mode 100644 GPU_version/vio/include/vio/frame_handler_mono.h create mode 100644 GPU_version/vio/include/vio/global.h create mode 100644 GPU_version/vio/include/vio/homography.h create mode 100644 GPU_version/vio/include/vio/initialization.h create mode 100644 GPU_version/vio/include/vio/map.h create mode 100644 GPU_version/vio/include/vio/matcher.h create mode 100644 GPU_version/vio/include/vio/math_utils.h create mode 100644 GPU_version/vio/include/vio/nlls_solver.h create mode 100644 GPU_version/vio/include/vio/nlls_solver_impl.hpp create mode 100644 GPU_version/vio/include/vio/output_helper.h create mode 100644 GPU_version/vio/include/vio/params_helper.h create mode 100644 GPU_version/vio/include/vio/patch_score.h create mode 100644 GPU_version/vio/include/vio/point.h create mode 100644 GPU_version/vio/include/vio/pose_optimizer.h create mode 100644 GPU_version/vio/include/vio/reprojector.h create mode 100644 GPU_version/vio/include/vio/robust_cost.h create mode 100644 GPU_version/vio/include/vio/sparse_img_align.h create mode 100644 GPU_version/vio/include/vio/sparse_img_align_gpu.h create mode 100644 GPU_version/vio/include/vio/timer.h create mode 100644 GPU_version/vio/include/vio/ukf.h create mode 100644 GPU_version/vio/include/vio/vision.h create mode 100644 GPU_version/vio/include/vio/visualizer.h create mode 100644 GPU_version/vio/kernel/compute-residual.cl create mode 100644 GPU_version/vio/src/sparse_img_align_gpu.cpp diff --git a/GPU_version/vio/gtsam/imu_integration.cpp b/GPU_version/vio/gtsam/imu_integration.cpp index d2e751b..d8e50b0 100755 --- a/GPU_version/vio/gtsam/imu_integration.cpp +++ b/GPU_version/vio/gtsam/imu_integration.cpp @@ -5,14 +5,14 @@ #include "imu_integration.h" #include #include -#include "gpu_svo/feature.h" -#include "gpu_svo/point.h" -#include "gpu_svo/svoVisionFactor.h" +#include "vio/feature.h" +#include "vio/point.h" +#include "vio/svoVisionFactor.h" #include #include -#include -#include -#include +#include +#include +#include #define debug 0 Imu_Integration::Imu_Integration(Sophus::SE3& SE_init){ graphPtr=std::make_shared(); diff --git a/GPU_version/vio/gtsam/imu_integration.h b/GPU_version/vio/gtsam/imu_integration.h index 11eb514..58dfa92 100644 --- a/GPU_version/vio/gtsam/imu_integration.h +++ b/GPU_version/vio/gtsam/imu_integration.h @@ -13,7 +13,7 @@ #include #include #include -#include +#include using gtsam::symbol_shorthand::B; // Bias (ax,ay,az,gx,gy,gz) using gtsam::symbol_shorthand::V; // Vel (xdot,ydot,zdot) diff --git a/GPU_version/vio/gtsam/svoVisionFactor.h b/GPU_version/vio/gtsam/svoVisionFactor.h index 01ad6da..4011177 100644 --- a/GPU_version/vio/gtsam/svoVisionFactor.h +++ b/GPU_version/vio/gtsam/svoVisionFactor.h @@ -10,11 +10,11 @@ #include #include #include -#include -#include -#include +#include +#include +#include -namespace svo { +namespace vio { class VisionFactor: public gtsam::NoiseModelFactor1 { diff --git a/GPU_version/vio/gtsam/svoVisionFactorLandMark.h b/GPU_version/vio/gtsam/svoVisionFactorLandMark.h index 69ed0c8..5f8f636 100644 --- a/GPU_version/vio/gtsam/svoVisionFactorLandMark.h +++ b/GPU_version/vio/gtsam/svoVisionFactorLandMark.h @@ -12,9 +12,9 @@ #include #include #include -#include +#include -namespace svo { +namespace vio { class VisionFactorLandMark: public gtsam::NoiseModelFactor3 { diff --git a/GPU_version/vio/gtsam/svoVisionFactorSmall.h b/GPU_version/vio/gtsam/svoVisionFactorSmall.h index 738bd95..b119e15 100644 --- a/GPU_version/vio/gtsam/svoVisionFactorSmall.h +++ b/GPU_version/vio/gtsam/svoVisionFactorSmall.h @@ -12,9 +12,9 @@ #include #include #include -#include +#include -namespace svo { +namespace vio { class VisionFactor: public gtsam::NoiseModelFactor1 { diff --git a/GPU_version/vio/include/vio/abstract_camera.h b/GPU_version/vio/include/vio/abstract_camera.h new file mode 100644 index 0000000..ccd3c98 --- /dev/null +++ b/GPU_version/vio/include/vio/abstract_camera.h @@ -0,0 +1,78 @@ +/* + * abstract_camera.h + * + * Created on: Jul 23, 2012 + * Author: cforster + */ + +#ifndef ABSTRACT_CAMERA_H_ +#define ABSTRACT_CAMERA_H_ + +#include + +namespace vk +{ + +using namespace std; +using namespace Eigen; + +class AbstractCamera +{ +protected: + + int width_; // TODO cannot be const because of omni-camera model + int height_; + +public: + + AbstractCamera() {}; // need this constructor for omni camera + AbstractCamera(int width, int height) : width_(width), height_(height) {}; + + virtual ~AbstractCamera() {}; + + /// Project from pixels to world coordiantes. Returns a bearing vector of unit length. + virtual Vector3d + cam2world(const double& x, const double& y) const = 0; + virtual double* params() const =0; + + /// Project from pixels to world coordiantes. Returns a bearing vector of unit length. + virtual Vector3d + cam2world(const Vector2d& px) const = 0; + + virtual Vector2d + world2cam(const Vector3d& xyz_c) const = 0; + + /// projects unit plane coordinates to camera coordinates + virtual Vector2d + world2cam(const Vector2d& uv) const = 0; + + virtual double + errorMultiplier2() const = 0; + + virtual double + errorMultiplier() const = 0; + + inline int width() const { return width_; } + + inline int height() const { return height_; } + + inline bool isInFrame(const Vector2i & obs, int boundary=0) const + { + if(obs[0]>=boundary && obs[0]=boundary && obs[1]= boundary && obs[0] < width()/(1<= boundary && obs[1] // memset +#include // memset +#include +#include + +namespace vk { +namespace aligned_mem { + + /// Check if the pointer is aligned to the specified byte granularity + inline bool + is_aligned8(const void* ptr) + { + return ((reinterpret_cast(ptr)) & 0x7) == 0; + } + + inline bool + is_aligned16(const void* ptr) + { + return ((reinterpret_cast(ptr)) & 0xF) == 0; + } + + template struct placement_delete + { + enum { Size = (1<= Size) { + placement_delete::free(buf+Size,M-Size); + placement_delete::destruct(buf); + } else { + placement_delete::free(buf, M); + } + } + }; + + template struct placement_delete + { + static inline void free(T*, size_t ) {} + }; + + inline void * aligned_alloc(size_t count, size_t alignment){ + void * mem = NULL; + assert(posix_memalign(&mem, alignment, count) == 0); + return mem; + } + + inline void aligned_free(void * memory) { + free(memory); + } + + template + inline T * aligned_alloc(size_t count, size_t alignment){ + void * data = aligned_alloc(sizeof(T)* count, alignment); + return new (data) T[count]; + } + + template + inline void aligned_free(T * memory, size_t count){ + placement_delete::free(memory, count); + aligned_free(memory); + } + + template inline void memfill(T* data, int n, const T val) + { + T* de = data + n; + for(;data < de; data++) + *data=val; + } + + template<> inline void memfill(unsigned char* data, int n, const unsigned char val) + { + memset(data, val, n); + } + + template<> inline void memfill(signed char* data, int n, const signed char val) + { + memset(data, val, n); + } + + template<> inline void memfill(char* data, int n, const char val) + { + memset(data, val, n); + } + + template + struct AlignedMem { + T* mem; + size_t count; + AlignedMem(size_t c) : count(c) { + mem = aligned_alloc(count, N); + } + ~AlignedMem() { + aligned_free(mem, count); + } + T* data() { return mem; } + const T* data() const { return mem; } + }; + +} // namespace aligned_mem +} // namespace vikit + + +#endif // VIKIT_ALIGNED_MEM_H_ diff --git a/GPU_version/vio/include/vio/atan_camera.h b/GPU_version/vio/include/vio/atan_camera.h new file mode 100644 index 0000000..97c2f75 --- /dev/null +++ b/GPU_version/vio/include/vio/atan_camera.h @@ -0,0 +1,100 @@ +/* + * atan_camera.h + * + * Created on: Aug 21, 2012 + * Author: cforster + * + * This class implements the FOV distortion model of Deverneay and Faugeras, + * Straight lines have to be straight, 2001. + * + * The code is an implementation of the ATAN class in PTAM by Georg Klein using Eigen. + */ + +#ifndef ATAN_CAMERA_H_ +#define ATAN_CAMERA_H_ + +#include +#include +#include +#include +#include + +namespace vk { + +using namespace std; +using namespace Eigen; + +class ATANCamera : public AbstractCamera { + +private: + double fx_, fy_; //!< focal length + double fx_inv_, fy_inv_; //!< inverse focal length + double cx_, cy_; //!< projection center + double s_, s_inv_; //!< distortion model coeff + double tans_; //!< distortion model coeff + double tans_inv_; //!< distortion model coeff + bool distortion_; //!< use distortion model? + double* param_; + + //! Radial distortion transformation factor: returns ration of distorted / undistorted radius. + inline double rtrans_factor(double r) const + { + if(r < 0.001 || s_ == 0.0) + return 1.0; + else + return (s_inv_* atan(r * tans_) / r); + }; + + //! Inverse radial distortion: returns un-distorted radius from distorted. + inline double invrtrans(double r) const + { + if(s_ == 0.0) + return r; + return (tan(r * s_) * tans_inv_); + }; + +public: + + ATANCamera(double width, double height, double fx, double fy, double dx, double dy, double s); + + ~ATANCamera(); + + virtual Vector3d + cam2world(const double& x, const double& y) const; + + virtual Vector3d + cam2world(const Vector2d& px) const; + + virtual Vector2d + world2cam(const Vector3d& xyz_c) const; + + virtual Vector2d + world2cam(const Vector2d& uv) const; + + const Vector2d focal_length() const + { + return Vector2d(fx_, fy_); + } + + virtual double errorMultiplier2() const + { + return fx_; + } + + virtual double errorMultiplier() const + { + return 4*fx_*fy_; + } + virtual double* params() const{ + param_[0]=fx_; + param_[1]=fy_; + param_[2]=cx_; + param_[3]=cy_; + param_[4]=s_; + return param_; + } +}; + +} // end namespace vk + +#endif /* ATAN_CAMERA_H_ */ diff --git a/GPU_version/vio/include/vio/bundle_adjustment.h b/GPU_version/vio/include/vio/bundle_adjustment.h new file mode 100644 index 0000000..d032cde --- /dev/null +++ b/GPU_version/vio/include/vio/bundle_adjustment.h @@ -0,0 +1,109 @@ +// This file is part of SVO - Semi-direct Visual Odometry. +// +// Copyright (C) 2014 Christian Forster +// (Robotics and Perception Group, University of Zurich, Switzerland). +// +// SVO is free software: you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the Free Software +// Foundation, either version 3 of the License, or any later version. +// +// SVO is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#ifndef SVO_BUNDLE_ADJUSTMENT_H_ +#define SVO_BUNDLE_ADJUSTMENT_H_ + +#include + +namespace g2o { +class EdgeProjectXYZ2UV; +class SparseOptimizer; +class VertexSE3Expmap; +class VertexSBAPointXYZ; +} + +namespace vio { + +typedef g2o::EdgeProjectXYZ2UV g2oEdgeSE3; +typedef g2o::VertexSE3Expmap g2oFrameSE3; +typedef g2o::VertexSBAPointXYZ g2oPoint; + +class Frame; +class Point; +class Feature; +class Map; + +/// Local, global and 2-view bundle adjustment with g2o +namespace ba { + +/// Temporary container to hold the g2o edge with reference to frame and point. +struct EdgeContainerSE3 +{ + g2oEdgeSE3* edge; + Frame* frame; + Feature* feature; + bool is_deleted; + EdgeContainerSE3(g2oEdgeSE3* e, Frame* frame, Feature* feature) : + edge(e), frame(frame), feature(feature), is_deleted(false) + {} +}; + +/// Optimize two camera frames and their observed 3D points. +/// Is used after initialization. +void twoViewBA(Frame* frame1, Frame* frame2, double reproj_thresh, Map* map); + +/// Local bundle adjustment. +/// Optimizes core_kfs and their observed map points while keeping the +/// neighbourhood fixed. +void localBA( + Frame* center_kf, + set* core_kfs, + Map* map, + size_t& n_incorrect_edges_1, + size_t& n_incorrect_edges_2, + double& init_error, + double& final_error); + +/// Global bundle adjustment. +/// Optimizes the whole map. Is currently not used in SVO. +void globalBA(Map* map); + +/// Initialize g2o with solver type, optimization strategy and camera model. +void setupG2o(g2o::SparseOptimizer * optimizer); + +/// Run the optimization on the provided graph. +void runSparseBAOptimizer( + g2o::SparseOptimizer* optimizer, + unsigned int num_iter, + double& init_error, + double& final_error); + +/// Create a g2o vertice from a keyframe object. +g2oFrameSE3* createG2oFrameSE3( + Frame* kf, + size_t id, + bool fixed); + +/// Creates a g2o vertice from a mappoint object. +g2oPoint* createG2oPoint( + Vector3d pos, + size_t id, + bool fixed); + +/// Creates a g2o edge between a g2o keyframe and mappoint vertice with the provided measurement. +g2oEdgeSE3* createG2oEdgeSE3( + g2oFrameSE3* v_kf, + g2oPoint* v_mp, + const Vector2d& f_up, + bool robust_kernel, + double huber_width, + double weight = 1); + +} // namespace ba +} // namespace vio + +#endif // SVO_BUNDLE_ADJUSTMENT_H_ diff --git a/GPU_version/vio/include/vio/camera_loader.h b/GPU_version/vio/include/vio/camera_loader.h new file mode 100644 index 0000000..612ff64 --- /dev/null +++ b/GPU_version/vio/include/vio/camera_loader.h @@ -0,0 +1,46 @@ +/* + * camera_loader.h + * + * Created on: Feb 11, 2014 + * Author: cforster + */ + +#ifndef VIKIT_CAMERA_LOADER_H_ +#define VIKIT_CAMERA_LOADER_H_ + +#include +#include +#include +#include + +namespace vk { +namespace camera_loader { + +/// Load from ROS Namespace +bool loadFromRosNs(const std::string& ns, vk::AbstractCamera*& cam) +{ + bool res = true; + std::string cam_model(getParam(ns+"/cam_model")); + if(cam_model == "ATAN") + { + cam = new vk::ATANCamera( + getParam(ns+"/cam_width"), + getParam(ns+"/cam_height"), + getParam(ns+"/cam_fx"), + getParam(ns+"/cam_fy"), + getParam(ns+"/cam_cx"), + getParam(ns+"/cam_cy"), + getParam(ns+"/cam_d0")); + } + else + { + cam = NULL; + res = false; + } + return res; +} + +} // namespace camera_loader +} // namespace vk + +#endif // VIKIT_CAMERA_LOADER_H_ diff --git a/GPU_version/vio/include/vio/cl.hpp b/GPU_version/vio/include/vio/cl.hpp new file mode 100644 index 0000000..6634f8c --- /dev/null +++ b/GPU_version/vio/include/vio/cl.hpp @@ -0,0 +1,12947 @@ +/******************************************************************************* + * Copyright (c) 2008-2015 The Khronos Group Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and/or associated documentation files (the + * "Materials"), to deal in the Materials without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Materials, and to + * permit persons to whom the Materials are furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Materials. + * + * MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS + * KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS + * SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT + * https://www.khronos.org/registry/ + * + * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. + ******************************************************************************/ + +/*! \file + * + * \brief C++ bindings for OpenCL 1.0 (rev 48), OpenCL 1.1 (rev 33) and + * OpenCL 1.2 (rev 15) + * \author Benedict R. Gaster, Laurent Morichetti and Lee Howes + * + * Additions and fixes from: + * Brian Cole, March 3rd 2010 and April 2012 + * Matt Gruenke, April 2012. + * Bruce Merry, February 2013. + * Tom Deakin and Simon McIntosh-Smith, July 2013 + * + * \version 1.2.9 + * \date December 2015 + * + * Optional extension support + * + * cl + * cl_ext_device_fission + * #define USE_CL_DEVICE_FISSION + */ + +/*! \mainpage + * \section intro Introduction + * For many large applications C++ is the language of choice and so it seems + * reasonable to define C++ bindings for OpenCL. + * + * + * The interface is contained with a single C++ header file \em cl.hpp and all + * definitions are contained within the namespace \em cl. There is no additional + * requirement to include \em cl.h and to use either the C++ or original C + * bindings it is enough to simply include \em cl.hpp. + * + * The bindings themselves are lightweight and correspond closely to the + * underlying C API. Using the C++ bindings introduces no additional execution + * overhead. + * + * For detail documentation on the bindings see: + * + * The OpenCL C++ Wrapper API 1.2 (revision 09) + * http://www.khronos.org/registry/cl/specs/opencl-cplusplus-1.2.pdf + * + * \section example Example + * + * The following example shows a general use case for the C++ + * bindings, including support for the optional exception feature and + * also the supplied vector and string classes, see following sections for + * decriptions of these features. + * + * \code + * #define __CL_ENABLE_EXCEPTIONS + * + * #if defined(__APPLE__) || defined(__MACOSX) + * #include + * #else + * #include + * #endif + * #include + * #include + * #include + * + * const char * helloStr = "__kernel void " + * "hello(void) " + * "{ " + * " " + * "} "; + * + * int + * main(void) + * { + * cl_int err = CL_SUCCESS; + * try { + * + * std::vector platforms; + * cl::Platform::get(&platforms); + * if (platforms.size() == 0) { + * std::cout << "Platform size 0\n"; + * return -1; + * } + * + * cl_context_properties properties[] = + * { CL_CONTEXT_PLATFORM, (cl_context_properties)(platforms[0])(), 0}; + * cl::Context context(CL_DEVICE_TYPE_CPU, properties); + * + * std::vector devices = context.getInfo(); + * + * cl::Program::Sources source(1, + * std::make_pair(helloStr,strlen(helloStr))); + * cl::Program program_ = cl::Program(context, source); + * program_.build(devices); + * + * cl::Kernel kernel(program_, "hello", &err); + * + * cl::Event event; + * cl::CommandQueue queue(context, devices[0], 0, &err); + * queue.enqueueNDRangeKernel( + * kernel, + * cl::NullRange, + * cl::NDRange(4,4), + * cl::NullRange, + * NULL, + * &event); + * + * event.wait(); + * } + * catch (cl::Error err) { + * std::cerr + * << "ERROR: " + * << err.what() + * << "(" + * << err.err() + * << ")" + * << std::endl; + * } + * + * return EXIT_SUCCESS; + * } + * + * \endcode + * + */ +#ifndef CL_HPP_ +#define CL_HPP_ + +#ifdef _WIN32 + +#include + +#if defined(USE_DX_INTEROP) +#include +#include +#endif +#endif // _WIN32 + +#if defined(_MSC_VER) +#include +#endif // _MSC_VER + +// +#if defined(USE_CL_DEVICE_FISSION) +#include +#endif + +#if defined(__APPLE__) || defined(__MACOSX) +#include +#else +#include +#endif // !__APPLE__ + +#if (_MSC_VER >= 1700) || (__cplusplus >= 201103L) +#define CL_HPP_RVALUE_REFERENCES_SUPPORTED +#define CL_HPP_CPP11_ATOMICS_SUPPORTED +#include +#endif + +#if (__cplusplus >= 201103L) +#define CL_HPP_NOEXCEPT noexcept +#else +#define CL_HPP_NOEXCEPT +#endif + + +// To avoid accidentally taking ownership of core OpenCL types +// such as cl_kernel constructors are made explicit +// under OpenCL 1.2 +#if defined(CL_VERSION_1_2) && !defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) +#define __CL_EXPLICIT_CONSTRUCTORS explicit +#else // #if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) +#define __CL_EXPLICIT_CONSTRUCTORS +#endif // #if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) + +// Define deprecated prefixes and suffixes to ensure compilation +// in case they are not pre-defined +#if !defined(CL_EXT_PREFIX__VERSION_1_1_DEPRECATED) +#define CL_EXT_PREFIX__VERSION_1_1_DEPRECATED +#endif // #if !defined(CL_EXT_PREFIX__VERSION_1_1_DEPRECATED) +#if !defined(CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED) +#define CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED +#endif // #if !defined(CL_EXT_PREFIX__VERSION_1_1_DEPRECATED) + +#if !defined(CL_CALLBACK) +#define CL_CALLBACK +#endif //CL_CALLBACK + +#include +#include +#include + +#if defined(__CL_ENABLE_EXCEPTIONS) +#include +#endif // #if defined(__CL_ENABLE_EXCEPTIONS) + +#if !defined(__NO_STD_VECTOR) +#include +#endif + +#if !defined(__NO_STD_STRING) +#include +#endif + +#if defined(__ANDROID__) || defined(linux) || defined(__APPLE__) || defined(__MACOSX) +#include +#endif // linux + +#include + + +/*! \namespace cl + * + * \brief The OpenCL C++ bindings are defined within this namespace. + * + */ +namespace cl { + +class Memory; + +/** + * Deprecated APIs for 1.2 + */ +#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) || (defined(CL_VERSION_1_1) && !defined(CL_VERSION_1_2)) +#define __INIT_CL_EXT_FCN_PTR(name) \ + if(!pfn_##name) { \ + pfn_##name = (PFN_##name) \ + clGetExtensionFunctionAddress(#name); \ + if(!pfn_##name) { \ + } \ + } +#endif // #if defined(CL_VERSION_1_1) + +#if defined(CL_VERSION_1_2) +#define __INIT_CL_EXT_FCN_PTR_PLATFORM(platform, name) \ + if(!pfn_##name) { \ + pfn_##name = (PFN_##name) \ + clGetExtensionFunctionAddressForPlatform(platform, #name); \ + if(!pfn_##name) { \ + } \ + } +#endif // #if defined(CL_VERSION_1_1) + +class Program; +class Device; +class Context; +class CommandQueue; +class Memory; +class Buffer; + +#if defined(__CL_ENABLE_EXCEPTIONS) +/*! \brief Exception class + * + * This may be thrown by API functions when __CL_ENABLE_EXCEPTIONS is defined. + */ +class Error : public std::exception +{ +private: + cl_int err_; + const char * errStr_; +public: + /*! \brief Create a new CL error exception for a given error code + * and corresponding message. + * + * \param err error code value. + * + * \param errStr a descriptive string that must remain in scope until + * handling of the exception has concluded. If set, it + * will be returned by what(). + */ + Error(cl_int err, const char * errStr = NULL) : err_(err), errStr_(errStr) + {} + + ~Error() throw() {} + + /*! \brief Get error string associated with exception + * + * \return A memory pointer to the error message string. + */ + virtual const char * what() const throw () + { + if (errStr_ == NULL) { + return "empty"; + } + else { + return errStr_; + } + } + + /*! \brief Get error code associated with exception + * + * \return The error code. + */ + cl_int err(void) const { return err_; } +}; + +#define __ERR_STR(x) #x +#else +#define __ERR_STR(x) NULL +#endif // __CL_ENABLE_EXCEPTIONS + + +namespace detail +{ +#if defined(__CL_ENABLE_EXCEPTIONS) +static inline cl_int errHandler ( + cl_int err, + const char * errStr = NULL) +{ + if (err != CL_SUCCESS) { + throw Error(err, errStr); + } + return err; +} +#else +static inline cl_int errHandler (cl_int err, const char * errStr = NULL) +{ + (void) errStr; // suppress unused variable warning + return err; +} +#endif // __CL_ENABLE_EXCEPTIONS +} + + + +//! \cond DOXYGEN_DETAIL +#if !defined(__CL_USER_OVERRIDE_ERROR_STRINGS) +#define __GET_DEVICE_INFO_ERR __ERR_STR(clGetDeviceInfo) +#define __GET_PLATFORM_INFO_ERR __ERR_STR(clGetPlatformInfo) +#define __GET_DEVICE_IDS_ERR __ERR_STR(clGetDeviceIDs) +#define __GET_PLATFORM_IDS_ERR __ERR_STR(clGetPlatformIDs) +#define __GET_CONTEXT_INFO_ERR __ERR_STR(clGetContextInfo) +#define __GET_EVENT_INFO_ERR __ERR_STR(clGetEventInfo) +#define __GET_EVENT_PROFILE_INFO_ERR __ERR_STR(clGetEventProfileInfo) +#define __GET_MEM_OBJECT_INFO_ERR __ERR_STR(clGetMemObjectInfo) +#define __GET_IMAGE_INFO_ERR __ERR_STR(clGetImageInfo) +#define __GET_SAMPLER_INFO_ERR __ERR_STR(clGetSamplerInfo) +#define __GET_KERNEL_INFO_ERR __ERR_STR(clGetKernelInfo) +#if defined(CL_VERSION_1_2) +#define __GET_KERNEL_ARG_INFO_ERR __ERR_STR(clGetKernelArgInfo) +#endif // #if defined(CL_VERSION_1_2) +#define __GET_KERNEL_WORK_GROUP_INFO_ERR __ERR_STR(clGetKernelWorkGroupInfo) +#define __GET_PROGRAM_INFO_ERR __ERR_STR(clGetProgramInfo) +#define __GET_PROGRAM_BUILD_INFO_ERR __ERR_STR(clGetProgramBuildInfo) +#define __GET_COMMAND_QUEUE_INFO_ERR __ERR_STR(clGetCommandQueueInfo) + +#define __CREATE_CONTEXT_ERR __ERR_STR(clCreateContext) +#define __CREATE_CONTEXT_FROM_TYPE_ERR __ERR_STR(clCreateContextFromType) +#define __GET_SUPPORTED_IMAGE_FORMATS_ERR __ERR_STR(clGetSupportedImageFormats) + +#define __CREATE_BUFFER_ERR __ERR_STR(clCreateBuffer) +#define __COPY_ERR __ERR_STR(cl::copy) +#define __CREATE_SUBBUFFER_ERR __ERR_STR(clCreateSubBuffer) +#define __CREATE_GL_BUFFER_ERR __ERR_STR(clCreateFromGLBuffer) +#define __CREATE_GL_RENDER_BUFFER_ERR __ERR_STR(clCreateFromGLBuffer) +#define __GET_GL_OBJECT_INFO_ERR __ERR_STR(clGetGLObjectInfo) +#if defined(CL_VERSION_1_2) +#define __CREATE_IMAGE_ERR __ERR_STR(clCreateImage) +#define __CREATE_GL_TEXTURE_ERR __ERR_STR(clCreateFromGLTexture) +#define __IMAGE_DIMENSION_ERR __ERR_STR(Incorrect image dimensions) +#endif // #if defined(CL_VERSION_1_2) +#define __CREATE_SAMPLER_ERR __ERR_STR(clCreateSampler) +#define __SET_MEM_OBJECT_DESTRUCTOR_CALLBACK_ERR __ERR_STR(clSetMemObjectDestructorCallback) + +#define __CREATE_USER_EVENT_ERR __ERR_STR(clCreateUserEvent) +#define __SET_USER_EVENT_STATUS_ERR __ERR_STR(clSetUserEventStatus) +#define __SET_EVENT_CALLBACK_ERR __ERR_STR(clSetEventCallback) +#define __WAIT_FOR_EVENTS_ERR __ERR_STR(clWaitForEvents) + +#define __CREATE_KERNEL_ERR __ERR_STR(clCreateKernel) +#define __SET_KERNEL_ARGS_ERR __ERR_STR(clSetKernelArg) +#define __CREATE_PROGRAM_WITH_SOURCE_ERR __ERR_STR(clCreateProgramWithSource) +#define __CREATE_PROGRAM_WITH_BINARY_ERR __ERR_STR(clCreateProgramWithBinary) +#if defined(CL_VERSION_1_2) +#define __CREATE_PROGRAM_WITH_BUILT_IN_KERNELS_ERR __ERR_STR(clCreateProgramWithBuiltInKernels) +#endif // #if defined(CL_VERSION_1_2) +#define __BUILD_PROGRAM_ERR __ERR_STR(clBuildProgram) +#if defined(CL_VERSION_1_2) +#define __COMPILE_PROGRAM_ERR __ERR_STR(clCompileProgram) +#define __LINK_PROGRAM_ERR __ERR_STR(clLinkProgram) +#endif // #if defined(CL_VERSION_1_2) +#define __CREATE_KERNELS_IN_PROGRAM_ERR __ERR_STR(clCreateKernelsInProgram) + +#define __CREATE_COMMAND_QUEUE_ERR __ERR_STR(clCreateCommandQueue) +#define __SET_COMMAND_QUEUE_PROPERTY_ERR __ERR_STR(clSetCommandQueueProperty) +#define __ENQUEUE_READ_BUFFER_ERR __ERR_STR(clEnqueueReadBuffer) +#define __ENQUEUE_READ_BUFFER_RECT_ERR __ERR_STR(clEnqueueReadBufferRect) +#define __ENQUEUE_WRITE_BUFFER_ERR __ERR_STR(clEnqueueWriteBuffer) +#define __ENQUEUE_WRITE_BUFFER_RECT_ERR __ERR_STR(clEnqueueWriteBufferRect) +#define __ENQEUE_COPY_BUFFER_ERR __ERR_STR(clEnqueueCopyBuffer) +#define __ENQEUE_COPY_BUFFER_RECT_ERR __ERR_STR(clEnqueueCopyBufferRect) +#define __ENQUEUE_FILL_BUFFER_ERR __ERR_STR(clEnqueueFillBuffer) +#define __ENQUEUE_READ_IMAGE_ERR __ERR_STR(clEnqueueReadImage) +#define __ENQUEUE_WRITE_IMAGE_ERR __ERR_STR(clEnqueueWriteImage) +#define __ENQUEUE_COPY_IMAGE_ERR __ERR_STR(clEnqueueCopyImage) +#define __ENQUEUE_FILL_IMAGE_ERR __ERR_STR(clEnqueueFillImage) +#define __ENQUEUE_COPY_IMAGE_TO_BUFFER_ERR __ERR_STR(clEnqueueCopyImageToBuffer) +#define __ENQUEUE_COPY_BUFFER_TO_IMAGE_ERR __ERR_STR(clEnqueueCopyBufferToImage) +#define __ENQUEUE_MAP_BUFFER_ERR __ERR_STR(clEnqueueMapBuffer) +#define __ENQUEUE_MAP_IMAGE_ERR __ERR_STR(clEnqueueMapImage) +#define __ENQUEUE_UNMAP_MEM_OBJECT_ERR __ERR_STR(clEnqueueUnMapMemObject) +#define __ENQUEUE_NDRANGE_KERNEL_ERR __ERR_STR(clEnqueueNDRangeKernel) +#define __ENQUEUE_TASK_ERR __ERR_STR(clEnqueueTask) +#define __ENQUEUE_NATIVE_KERNEL __ERR_STR(clEnqueueNativeKernel) +#if defined(CL_VERSION_1_2) +#define __ENQUEUE_MIGRATE_MEM_OBJECTS_ERR __ERR_STR(clEnqueueMigrateMemObjects) +#endif // #if defined(CL_VERSION_1_2) + +#define __ENQUEUE_ACQUIRE_GL_ERR __ERR_STR(clEnqueueAcquireGLObjects) +#define __ENQUEUE_RELEASE_GL_ERR __ERR_STR(clEnqueueReleaseGLObjects) + + +#define __RETAIN_ERR __ERR_STR(Retain Object) +#define __RELEASE_ERR __ERR_STR(Release Object) +#define __FLUSH_ERR __ERR_STR(clFlush) +#define __FINISH_ERR __ERR_STR(clFinish) +#define __VECTOR_CAPACITY_ERR __ERR_STR(Vector capacity error) + +/** + * CL 1.2 version that uses device fission. + */ +#if defined(CL_VERSION_1_2) +#define __CREATE_SUB_DEVICES __ERR_STR(clCreateSubDevices) +#else +#define __CREATE_SUB_DEVICES __ERR_STR(clCreateSubDevicesEXT) +#endif // #if defined(CL_VERSION_1_2) + +/** + * Deprecated APIs for 1.2 + */ +#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) || (defined(CL_VERSION_1_1) && !defined(CL_VERSION_1_2)) +#define __ENQUEUE_MARKER_ERR __ERR_STR(clEnqueueMarker) +#define __ENQUEUE_WAIT_FOR_EVENTS_ERR __ERR_STR(clEnqueueWaitForEvents) +#define __ENQUEUE_BARRIER_ERR __ERR_STR(clEnqueueBarrier) +#define __UNLOAD_COMPILER_ERR __ERR_STR(clUnloadCompiler) +#define __CREATE_GL_TEXTURE_2D_ERR __ERR_STR(clCreateFromGLTexture2D) +#define __CREATE_GL_TEXTURE_3D_ERR __ERR_STR(clCreateFromGLTexture3D) +#define __CREATE_IMAGE2D_ERR __ERR_STR(clCreateImage2D) +#define __CREATE_IMAGE3D_ERR __ERR_STR(clCreateImage3D) +#endif // #if defined(CL_VERSION_1_1) + +#endif // __CL_USER_OVERRIDE_ERROR_STRINGS +//! \endcond + +/** + * CL 1.2 marker and barrier commands + */ +#if defined(CL_VERSION_1_2) +#define __ENQUEUE_MARKER_WAIT_LIST_ERR __ERR_STR(clEnqueueMarkerWithWaitList) +#define __ENQUEUE_BARRIER_WAIT_LIST_ERR __ERR_STR(clEnqueueBarrierWithWaitList) +#endif // #if defined(CL_VERSION_1_2) + +#if !defined(__USE_DEV_STRING) && !defined(__NO_STD_STRING) +typedef std::string STRING_CLASS; +#elif !defined(__USE_DEV_STRING) + +/*! \class string + * \brief Simple string class, that provides a limited subset of std::string + * functionality but avoids many of the issues that come with that class. + + * \note Deprecated. Please use std::string as default or + * re-define the string class to match the std::string + * interface by defining STRING_CLASS + */ +class CL_EXT_PREFIX__VERSION_1_1_DEPRECATED string +{ +private: + ::size_t size_; + char * str_; +public: + //! \brief Constructs an empty string, allocating no memory. + string(void) : size_(0), str_(NULL) + { + } + + /*! \brief Constructs a string populated from an arbitrary value of + * specified size. + * + * An extra '\0' is added, in case none was contained in str. + * + * \param str the initial value of the string instance. Note that '\0' + * characters receive no special treatment. If NULL, + * the string is left empty, with a size of 0. + * + * \param size the number of characters to copy from str. + */ + string(const char * str, ::size_t size) : + size_(size), + str_(NULL) + { + if( size > 0 ) { + str_ = new char[size_+1]; + if (str_ != NULL) { + memcpy(str_, str, size_ * sizeof(char)); + str_[size_] = '\0'; + } + else { + size_ = 0; + } + } + } + + /*! \brief Constructs a string populated from a null-terminated value. + * + * \param str the null-terminated initial value of the string instance. + * If NULL, the string is left empty, with a size of 0. + */ + string(const char * str) : + size_(0), + str_(NULL) + { + if( str ) { + size_= ::strlen(str); + } + if( size_ > 0 ) { + str_ = new char[size_ + 1]; + if (str_ != NULL) { + memcpy(str_, str, (size_ + 1) * sizeof(char)); + } + } + } + + void resize( ::size_t n ) + { + if( size_ == n ) { + return; + } + if (n == 0) { + if( str_ ) { + delete [] str_; + } + str_ = NULL; + size_ = 0; + } + else { + char *newString = new char[n + 1]; + ::size_t copySize = n; + if( size_ < n ) { + copySize = size_; + } + size_ = n; + + if(str_) { + memcpy(newString, str_, (copySize + 1) * sizeof(char)); + } + if( copySize < size_ ) { + memset(newString + copySize, 0, size_ - copySize); + } + newString[size_] = '\0'; + + delete [] str_; + str_ = newString; + } + } + + const char& operator[] ( ::size_t pos ) const + { + return str_[pos]; + } + + char& operator[] ( ::size_t pos ) + { + return str_[pos]; + } + + /*! \brief Copies the value of another string to this one. + * + * \param rhs the string to copy. + * + * \returns a reference to the modified instance. + */ + string& operator=(const string& rhs) + { + if (this == &rhs) { + return *this; + } + + if( str_ != NULL ) { + delete [] str_; + str_ = NULL; + size_ = 0; + } + + if (rhs.size_ == 0 || rhs.str_ == NULL) { + str_ = NULL; + size_ = 0; + } + else { + str_ = new char[rhs.size_ + 1]; + size_ = rhs.size_; + + if (str_ != NULL) { + memcpy(str_, rhs.str_, (size_ + 1) * sizeof(char)); + } + else { + size_ = 0; + } + } + + return *this; + } + + /*! \brief Constructs a string by copying the value of another instance. + * + * \param rhs the string to copy. + */ + string(const string& rhs) : + size_(0), + str_(NULL) + { + *this = rhs; + } + + //! \brief Destructor - frees memory used to hold the current value. + ~string() + { + delete[] str_; + str_ = NULL; + } + + //! \brief Queries the length of the string, excluding any added '\0's. + ::size_t size(void) const { return size_; } + + //! \brief Queries the length of the string, excluding any added '\0's. + ::size_t length(void) const { return size(); } + + /*! \brief Returns a pointer to the private copy held by this instance, + * or "" if empty/unset. + */ + const char * c_str(void) const { return (str_) ? str_ : "";} +} CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; +typedef cl::string STRING_CLASS; +#endif // #elif !defined(__USE_DEV_STRING) + +#if !defined(__USE_DEV_VECTOR) && !defined(__NO_STD_VECTOR) +#define VECTOR_CLASS std::vector +#elif !defined(__USE_DEV_VECTOR) +#define VECTOR_CLASS cl::vector + +#if !defined(__MAX_DEFAULT_VECTOR_SIZE) +#define __MAX_DEFAULT_VECTOR_SIZE 10 +#endif + +/*! \class vector + * \brief Fixed sized vector implementation that mirroring + * + * \note Deprecated. Please use std::vector as default or + * re-define the vector class to match the std::vector + * interface by defining VECTOR_CLASS + + * \note Not recommended for use with custom objects as + * current implementation will construct N elements + * + * std::vector functionality. + * \brief Fixed sized vector compatible with std::vector. + * + * \note + * This differs from std::vector<> not just in memory allocation, + * but also in terms of when members are constructed, destroyed, + * and assigned instead of being copy constructed. + * + * \param T type of element contained in the vector. + * + * \param N maximum size of the vector. + */ +template +class CL_EXT_PREFIX__VERSION_1_1_DEPRECATED vector +{ +private: + T data_[N]; + unsigned int size_; + +public: + //! \brief Constructs an empty vector with no memory allocated. + vector() : + size_(static_cast(0)) + {} + + //! \brief Deallocates the vector's memory and destroys all of its elements. + ~vector() + { + clear(); + } + + //! \brief Returns the number of elements currently contained. + unsigned int size(void) const + { + return size_; + } + + /*! \brief Empties the vector of all elements. + * \note + * This does not deallocate memory but will invoke destructors + * on contained elements. + */ + void clear() + { + while(!empty()) { + pop_back(); + } + } + + /*! \brief Appends an element after the last valid element. + * Calling this on a vector that has reached capacity will throw an + * exception if exceptions are enabled. + */ + void push_back (const T& x) + { + if (size() < N) { + new (&data_[size_]) T(x); + size_++; + } else { + detail::errHandler(CL_MEM_OBJECT_ALLOCATION_FAILURE, __VECTOR_CAPACITY_ERR); + } + } + + /*! \brief Removes the last valid element from the vector. + * Calling this on an empty vector will throw an exception + * if exceptions are enabled. + */ + void pop_back(void) + { + if (size_ != 0) { + --size_; + data_[size_].~T(); + } else { + detail::errHandler(CL_MEM_OBJECT_ALLOCATION_FAILURE, __VECTOR_CAPACITY_ERR); + } + } + + /*! \brief Constructs with a value copied from another. + * + * \param vec the vector to copy. + */ + vector(const vector& vec) : + size_(vec.size_) + { + if (size_ != 0) { + assign(vec.begin(), vec.end()); + } + } + + /*! \brief Constructs with a specified number of initial elements. + * + * \param size number of initial elements. + * + * \param val value of initial elements. + */ + vector(unsigned int size, const T& val = T()) : + size_(0) + { + for (unsigned int i = 0; i < size; i++) { + push_back(val); + } + } + + /*! \brief Overwrites the current content with that copied from another + * instance. + * + * \param rhs vector to copy. + * + * \returns a reference to this. + */ + vector& operator=(const vector& rhs) + { + if (this == &rhs) { + return *this; + } + + if (rhs.size_ != 0) { + assign(rhs.begin(), rhs.end()); + } else { + clear(); + } + + return *this; + } + + /*! \brief Tests equality against another instance. + * + * \param vec the vector against which to compare. + */ + bool operator==(vector &vec) + { + if (size() != vec.size()) { + return false; + } + + for( unsigned int i = 0; i < size(); ++i ) { + if( operator[](i) != vec[i] ) { + return false; + } + } + return true; + } + + //! \brief Conversion operator to T*. + operator T* () { return data_; } + + //! \brief Conversion operator to const T*. + operator const T* () const { return data_; } + + //! \brief Tests whether this instance has any elements. + bool empty (void) const + { + return size_==0; + } + + //! \brief Returns the maximum number of elements this instance can hold. + unsigned int max_size (void) const + { + return N; + } + + //! \brief Returns the maximum number of elements this instance can hold. + unsigned int capacity () const + { + return N; + } + + //! \brief Resizes the vector to the given size + void resize(unsigned int newSize, T fill = T()) + { + if (newSize > N) + { + detail::errHandler(CL_MEM_OBJECT_ALLOCATION_FAILURE, __VECTOR_CAPACITY_ERR); + } + else + { + while (size_ < newSize) + { + new (&data_[size_]) T(fill); + size_++; + } + while (size_ > newSize) + { + --size_; + data_[size_].~T(); + } + } + } + + /*! \brief Returns a reference to a given element. + * + * \param index which element to access. * + * \note + * The caller is responsible for ensuring index is >= 0 and < size(). + */ + T& operator[](int index) + { + return data_[index]; + } + + /*! \brief Returns a const reference to a given element. + * + * \param index which element to access. + * + * \note + * The caller is responsible for ensuring index is >= 0 and < size(). + */ + const T& operator[](int index) const + { + return data_[index]; + } + + /*! \brief Assigns elements of the vector based on a source iterator range. + * + * \param start Beginning iterator of source range + * \param end Enditerator of source range + * + * \note + * Will throw an exception if exceptions are enabled and size exceeded. + */ + template + void assign(I start, I end) + { + clear(); + while(start != end) { + push_back(*start); + start++; + } + } + + /*! \class iterator + * \brief Const iterator class for vectors + */ + class iterator + { + private: + const vector *vec_; + int index_; + + /** + * Internal iterator constructor to capture reference + * to the vector it iterates over rather than taking + * the vector by copy. + */ + iterator (const vector &vec, int index) : + vec_(&vec) + { + if( !vec.empty() ) { + index_ = index; + } else { + index_ = -1; + } + } + + public: + iterator(void) : + index_(-1), + vec_(NULL) + { + } + + iterator(const iterator& rhs) : + vec_(rhs.vec_), + index_(rhs.index_) + { + } + + ~iterator(void) {} + + static iterator begin(const cl::vector &vec) + { + iterator i(vec, 0); + + return i; + } + + static iterator end(const cl::vector &vec) + { + iterator i(vec, vec.size()); + + return i; + } + + bool operator==(iterator i) + { + return ((vec_ == i.vec_) && + (index_ == i.index_)); + } + + bool operator!=(iterator i) + { + return (!(*this==i)); + } + + iterator& operator++() + { + ++index_; + return *this; + } + + iterator operator++(int) + { + iterator retVal(*this); + ++index_; + return retVal; + } + + iterator& operator--() + { + --index_; + return *this; + } + + iterator operator--(int) + { + iterator retVal(*this); + --index_; + return retVal; + } + + const T& operator *() const + { + return (*vec_)[index_]; + } + }; + + iterator begin(void) + { + return iterator::begin(*this); + } + + iterator begin(void) const + { + return iterator::begin(*this); + } + + iterator end(void) + { + return iterator::end(*this); + } + + iterator end(void) const + { + return iterator::end(*this); + } + + T& front(void) + { + return data_[0]; + } + + T& back(void) + { + return data_[size_]; + } + + const T& front(void) const + { + return data_[0]; + } + + const T& back(void) const + { + return data_[size_-1]; + } +} CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; +#endif // #if !defined(__USE_DEV_VECTOR) && !defined(__NO_STD_VECTOR) + + + + + +namespace detail { +#define __DEFAULT_NOT_INITIALIZED 1 +#define __DEFAULT_BEING_INITIALIZED 2 +#define __DEFAULT_INITIALIZED 4 + + /* + * Compare and exchange primitives are needed for handling of defaults + */ + +#ifdef CL_HPP_CPP11_ATOMICS_SUPPORTED + inline int compare_exchange(std::atomic * dest, int exchange, int comparand) +#else // !CL_HPP_CPP11_ATOMICS_SUPPORTED + inline int compare_exchange(volatile int * dest, int exchange, int comparand) +#endif // !CL_HPP_CPP11_ATOMICS_SUPPORTED + { +#ifdef CL_HPP_CPP11_ATOMICS_SUPPORTED + std::atomic_compare_exchange_strong(dest, &comparand, exchange); + return comparand; +#elif _MSC_VER + return (int)(_InterlockedCompareExchange( + (volatile long*)dest, + (long)exchange, + (long)comparand)); +#else // !_MSC_VER && !CL_HPP_CPP11_ATOMICS_SUPPORTED + return (__sync_val_compare_and_swap( + dest, + comparand, + exchange)); +#endif // !CL_HPP_CPP11_ATOMICS_SUPPORTED + } + + inline void fence() { +#ifdef CL_HPP_CPP11_ATOMICS_SUPPORTED + std::atomic_thread_fence(std::memory_order_seq_cst); +#elif _MSC_VER // !CL_HPP_CPP11_ATOMICS_SUPPORTED + _ReadWriteBarrier(); +#else // !_MSC_VER && !CL_HPP_CPP11_ATOMICS_SUPPORTED + __sync_synchronize(); +#endif // !CL_HPP_CPP11_ATOMICS_SUPPORTED + } +} // namespace detail + + +/*! \brief class used to interface between C++ and + * OpenCL C calls that require arrays of size_t values, whose + * size is known statically. + */ +template +class size_t +{ +private: + ::size_t data_[N]; + +public: + //! \brief Initialize size_t to all 0s + size_t() + { + for( int i = 0; i < N; ++i ) { + data_[i] = 0; + } + } + + ::size_t& operator[](int index) + { + return data_[index]; + } + + const ::size_t& operator[](int index) const + { + return data_[index]; + } + + //! \brief Conversion operator to T*. + operator ::size_t* () { return data_; } + + //! \brief Conversion operator to const T*. + operator const ::size_t* () const { return data_; } +}; + +namespace detail { + +// Generic getInfoHelper. The final parameter is used to guide overload +// resolution: the actual parameter passed is an int, which makes this +// a worse conversion sequence than a specialization that declares the +// parameter as an int. +template +inline cl_int getInfoHelper(Functor f, cl_uint name, T* param, long) +{ + return f(name, sizeof(T), param, NULL); +} + +// Specialized getInfoHelper for VECTOR_CLASS params +template +inline cl_int getInfoHelper(Func f, cl_uint name, VECTOR_CLASS* param, long) +{ + ::size_t required; + cl_int err = f(name, 0, NULL, &required); + if (err != CL_SUCCESS) { + return err; + } + + T* value = (T*) alloca(required); + err = f(name, required, value, NULL); + if (err != CL_SUCCESS) { + return err; + } + + param->assign(&value[0], &value[required/sizeof(T)]); + return CL_SUCCESS; +} + +/* Specialization for reference-counted types. This depends on the + * existence of Wrapper::cl_type, and none of the other types having the + * cl_type member. Note that simplify specifying the parameter as Wrapper + * does not work, because when using a derived type (e.g. Context) the generic + * template will provide a better match. + */ +template +inline cl_int getInfoHelper(Func f, cl_uint name, VECTOR_CLASS* param, int, typename T::cl_type = 0) +{ + ::size_t required; + cl_int err = f(name, 0, NULL, &required); + if (err != CL_SUCCESS) { + return err; + } + + typename T::cl_type * value = (typename T::cl_type *) alloca(required); + err = f(name, required, value, NULL); + if (err != CL_SUCCESS) { + return err; + } + + ::size_t elements = required / sizeof(typename T::cl_type); + param->assign(&value[0], &value[elements]); + for (::size_t i = 0; i < elements; i++) + { + if (value[i] != NULL) + { + err = (*param)[i].retain(); + if (err != CL_SUCCESS) { + return err; + } + } + } + return CL_SUCCESS; +} + +// Specialized for getInfo +template +inline cl_int getInfoHelper(Func f, cl_uint name, VECTOR_CLASS* param, int) +{ + cl_int err = f(name, param->size() * sizeof(char *), &(*param)[0], NULL); + + if (err != CL_SUCCESS) { + return err; + } + + return CL_SUCCESS; +} + +// Specialized GetInfoHelper for STRING_CLASS params +template +inline cl_int getInfoHelper(Func f, cl_uint name, STRING_CLASS* param, long) +{ +#if defined(__NO_STD_VECTOR) || defined(__NO_STD_STRING) + ::size_t required; + cl_int err = f(name, 0, NULL, &required); + if (err != CL_SUCCESS) { + return err; + } + + char* value = (char*)alloca(required); + err = f(name, required, value, NULL); + if (err != CL_SUCCESS) { + return err; + } + + *param = value; + return CL_SUCCESS; +#else + ::size_t required; + cl_int err = f(name, 0, NULL, &required); + if (err != CL_SUCCESS) { + return err; + } + + // std::string has a constant data member + // a char vector does not + VECTOR_CLASS value(required); + err = f(name, required, value.data(), NULL); + if (err != CL_SUCCESS) { + return err; + } + if (param) { + param->assign(value.begin(), value.end()); + } +#endif + return CL_SUCCESS; +} + +// Specialized GetInfoHelper for cl::size_t params +template +inline cl_int getInfoHelper(Func f, cl_uint name, size_t* param, long) +{ + ::size_t required; + cl_int err = f(name, 0, NULL, &required); + if (err != CL_SUCCESS) { + return err; + } + + ::size_t* value = (::size_t*) alloca(required); + err = f(name, required, value, NULL); + if (err != CL_SUCCESS) { + return err; + } + + for(int i = 0; i < N; ++i) { + (*param)[i] = value[i]; + } + + return CL_SUCCESS; +} + +template struct ReferenceHandler; + +/* Specialization for reference-counted types. This depends on the + * existence of Wrapper::cl_type, and none of the other types having the + * cl_type member. Note that simplify specifying the parameter as Wrapper + * does not work, because when using a derived type (e.g. Context) the generic + * template will provide a better match. + */ +template +inline cl_int getInfoHelper(Func f, cl_uint name, T* param, int, typename T::cl_type = 0) +{ + typename T::cl_type value; + cl_int err = f(name, sizeof(value), &value, NULL); + if (err != CL_SUCCESS) { + return err; + } + *param = value; + if (value != NULL) + { + err = param->retain(); + if (err != CL_SUCCESS) { + return err; + } + } + return CL_SUCCESS; +} + +#define __PARAM_NAME_INFO_1_0(F) \ + F(cl_platform_info, CL_PLATFORM_PROFILE, STRING_CLASS) \ + F(cl_platform_info, CL_PLATFORM_VERSION, STRING_CLASS) \ + F(cl_platform_info, CL_PLATFORM_NAME, STRING_CLASS) \ + F(cl_platform_info, CL_PLATFORM_VENDOR, STRING_CLASS) \ + F(cl_platform_info, CL_PLATFORM_EXTENSIONS, STRING_CLASS) \ + \ + F(cl_device_info, CL_DEVICE_TYPE, cl_device_type) \ + F(cl_device_info, CL_DEVICE_VENDOR_ID, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_COMPUTE_UNITS, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_WORK_GROUP_SIZE, ::size_t) \ + F(cl_device_info, CL_DEVICE_MAX_WORK_ITEM_SIZES, VECTOR_CLASS< ::size_t>) \ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR, cl_uint) \ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT, cl_uint) \ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT, cl_uint) \ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG, cl_uint) \ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT, cl_uint) \ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_CLOCK_FREQUENCY, cl_uint) \ + F(cl_device_info, CL_DEVICE_ADDRESS_BITS, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_READ_IMAGE_ARGS, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_WRITE_IMAGE_ARGS, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_MEM_ALLOC_SIZE, cl_ulong) \ + F(cl_device_info, CL_DEVICE_IMAGE2D_MAX_WIDTH, ::size_t) \ + F(cl_device_info, CL_DEVICE_IMAGE2D_MAX_HEIGHT, ::size_t) \ + F(cl_device_info, CL_DEVICE_IMAGE3D_MAX_WIDTH, ::size_t) \ + F(cl_device_info, CL_DEVICE_IMAGE3D_MAX_HEIGHT, ::size_t) \ + F(cl_device_info, CL_DEVICE_IMAGE3D_MAX_DEPTH, ::size_t) \ + F(cl_device_info, CL_DEVICE_IMAGE_SUPPORT, cl_bool) \ + F(cl_device_info, CL_DEVICE_MAX_PARAMETER_SIZE, ::size_t) \ + F(cl_device_info, CL_DEVICE_MAX_SAMPLERS, cl_uint) \ + F(cl_device_info, CL_DEVICE_MEM_BASE_ADDR_ALIGN, cl_uint) \ + F(cl_device_info, CL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE, cl_uint) \ + F(cl_device_info, CL_DEVICE_SINGLE_FP_CONFIG, cl_device_fp_config) \ + F(cl_device_info, CL_DEVICE_GLOBAL_MEM_CACHE_TYPE, cl_device_mem_cache_type) \ + F(cl_device_info, CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE, cl_uint)\ + F(cl_device_info, CL_DEVICE_GLOBAL_MEM_CACHE_SIZE, cl_ulong) \ + F(cl_device_info, CL_DEVICE_GLOBAL_MEM_SIZE, cl_ulong) \ + F(cl_device_info, CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE, cl_ulong) \ + F(cl_device_info, CL_DEVICE_MAX_CONSTANT_ARGS, cl_uint) \ + F(cl_device_info, CL_DEVICE_LOCAL_MEM_TYPE, cl_device_local_mem_type) \ + F(cl_device_info, CL_DEVICE_LOCAL_MEM_SIZE, cl_ulong) \ + F(cl_device_info, CL_DEVICE_ERROR_CORRECTION_SUPPORT, cl_bool) \ + F(cl_device_info, CL_DEVICE_PROFILING_TIMER_RESOLUTION, ::size_t) \ + F(cl_device_info, CL_DEVICE_ENDIAN_LITTLE, cl_bool) \ + F(cl_device_info, CL_DEVICE_AVAILABLE, cl_bool) \ + F(cl_device_info, CL_DEVICE_COMPILER_AVAILABLE, cl_bool) \ + F(cl_device_info, CL_DEVICE_EXECUTION_CAPABILITIES, cl_device_exec_capabilities) \ + F(cl_device_info, CL_DEVICE_QUEUE_PROPERTIES, cl_command_queue_properties) \ + F(cl_device_info, CL_DEVICE_PLATFORM, cl_platform_id) \ + F(cl_device_info, CL_DEVICE_NAME, STRING_CLASS) \ + F(cl_device_info, CL_DEVICE_VENDOR, STRING_CLASS) \ + F(cl_device_info, CL_DRIVER_VERSION, STRING_CLASS) \ + F(cl_device_info, CL_DEVICE_PROFILE, STRING_CLASS) \ + F(cl_device_info, CL_DEVICE_VERSION, STRING_CLASS) \ + F(cl_device_info, CL_DEVICE_EXTENSIONS, STRING_CLASS) \ + \ + F(cl_context_info, CL_CONTEXT_REFERENCE_COUNT, cl_uint) \ + F(cl_context_info, CL_CONTEXT_DEVICES, VECTOR_CLASS) \ + F(cl_context_info, CL_CONTEXT_PROPERTIES, VECTOR_CLASS) \ + \ + F(cl_event_info, CL_EVENT_COMMAND_QUEUE, cl::CommandQueue) \ + F(cl_event_info, CL_EVENT_COMMAND_TYPE, cl_command_type) \ + F(cl_event_info, CL_EVENT_REFERENCE_COUNT, cl_uint) \ + F(cl_event_info, CL_EVENT_COMMAND_EXECUTION_STATUS, cl_int) \ + \ + F(cl_profiling_info, CL_PROFILING_COMMAND_QUEUED, cl_ulong) \ + F(cl_profiling_info, CL_PROFILING_COMMAND_SUBMIT, cl_ulong) \ + F(cl_profiling_info, CL_PROFILING_COMMAND_START, cl_ulong) \ + F(cl_profiling_info, CL_PROFILING_COMMAND_END, cl_ulong) \ + \ + F(cl_mem_info, CL_MEM_TYPE, cl_mem_object_type) \ + F(cl_mem_info, CL_MEM_FLAGS, cl_mem_flags) \ + F(cl_mem_info, CL_MEM_SIZE, ::size_t) \ + F(cl_mem_info, CL_MEM_HOST_PTR, void*) \ + F(cl_mem_info, CL_MEM_MAP_COUNT, cl_uint) \ + F(cl_mem_info, CL_MEM_REFERENCE_COUNT, cl_uint) \ + F(cl_mem_info, CL_MEM_CONTEXT, cl::Context) \ + \ + F(cl_image_info, CL_IMAGE_FORMAT, cl_image_format) \ + F(cl_image_info, CL_IMAGE_ELEMENT_SIZE, ::size_t) \ + F(cl_image_info, CL_IMAGE_ROW_PITCH, ::size_t) \ + F(cl_image_info, CL_IMAGE_SLICE_PITCH, ::size_t) \ + F(cl_image_info, CL_IMAGE_WIDTH, ::size_t) \ + F(cl_image_info, CL_IMAGE_HEIGHT, ::size_t) \ + F(cl_image_info, CL_IMAGE_DEPTH, ::size_t) \ + \ + F(cl_sampler_info, CL_SAMPLER_REFERENCE_COUNT, cl_uint) \ + F(cl_sampler_info, CL_SAMPLER_CONTEXT, cl::Context) \ + F(cl_sampler_info, CL_SAMPLER_NORMALIZED_COORDS, cl_bool) \ + F(cl_sampler_info, CL_SAMPLER_ADDRESSING_MODE, cl_addressing_mode) \ + F(cl_sampler_info, CL_SAMPLER_FILTER_MODE, cl_filter_mode) \ + \ + F(cl_program_info, CL_PROGRAM_REFERENCE_COUNT, cl_uint) \ + F(cl_program_info, CL_PROGRAM_CONTEXT, cl::Context) \ + F(cl_program_info, CL_PROGRAM_NUM_DEVICES, cl_uint) \ + F(cl_program_info, CL_PROGRAM_DEVICES, VECTOR_CLASS) \ + F(cl_program_info, CL_PROGRAM_SOURCE, STRING_CLASS) \ + F(cl_program_info, CL_PROGRAM_BINARY_SIZES, VECTOR_CLASS< ::size_t>) \ + F(cl_program_info, CL_PROGRAM_BINARIES, VECTOR_CLASS) \ + \ + F(cl_program_build_info, CL_PROGRAM_BUILD_STATUS, cl_build_status) \ + F(cl_program_build_info, CL_PROGRAM_BUILD_OPTIONS, STRING_CLASS) \ + F(cl_program_build_info, CL_PROGRAM_BUILD_LOG, STRING_CLASS) \ + \ + F(cl_kernel_info, CL_KERNEL_FUNCTION_NAME, STRING_CLASS) \ + F(cl_kernel_info, CL_KERNEL_NUM_ARGS, cl_uint) \ + F(cl_kernel_info, CL_KERNEL_REFERENCE_COUNT, cl_uint) \ + F(cl_kernel_info, CL_KERNEL_CONTEXT, cl::Context) \ + F(cl_kernel_info, CL_KERNEL_PROGRAM, cl::Program) \ + \ + F(cl_kernel_work_group_info, CL_KERNEL_WORK_GROUP_SIZE, ::size_t) \ + F(cl_kernel_work_group_info, CL_KERNEL_COMPILE_WORK_GROUP_SIZE, cl::size_t<3>) \ + F(cl_kernel_work_group_info, CL_KERNEL_LOCAL_MEM_SIZE, cl_ulong) \ + \ + F(cl_command_queue_info, CL_QUEUE_CONTEXT, cl::Context) \ + F(cl_command_queue_info, CL_QUEUE_DEVICE, cl::Device) \ + F(cl_command_queue_info, CL_QUEUE_REFERENCE_COUNT, cl_uint) \ + F(cl_command_queue_info, CL_QUEUE_PROPERTIES, cl_command_queue_properties) + +#if defined(CL_VERSION_1_1) +#define __PARAM_NAME_INFO_1_1(F) \ + F(cl_context_info, CL_CONTEXT_NUM_DEVICES, cl_uint)\ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_HALF, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_CHAR, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_SHORT, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_INT, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_LONG, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_FLOAT, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_DOUBLE, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_HALF, cl_uint) \ + F(cl_device_info, CL_DEVICE_DOUBLE_FP_CONFIG, cl_device_fp_config) \ + F(cl_device_info, CL_DEVICE_HALF_FP_CONFIG, cl_device_fp_config) \ + F(cl_device_info, CL_DEVICE_HOST_UNIFIED_MEMORY, cl_bool) \ + F(cl_device_info, CL_DEVICE_OPENCL_C_VERSION, STRING_CLASS) \ + \ + F(cl_mem_info, CL_MEM_ASSOCIATED_MEMOBJECT, cl::Memory) \ + F(cl_mem_info, CL_MEM_OFFSET, ::size_t) \ + \ + F(cl_kernel_work_group_info, CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE, ::size_t) \ + F(cl_kernel_work_group_info, CL_KERNEL_PRIVATE_MEM_SIZE, cl_ulong) \ + \ + F(cl_event_info, CL_EVENT_CONTEXT, cl::Context) +#endif // CL_VERSION_1_1 + + +#if defined(CL_VERSION_1_2) +#define __PARAM_NAME_INFO_1_2(F) \ + F(cl_image_info, CL_IMAGE_BUFFER, cl::Buffer) \ + \ + F(cl_program_info, CL_PROGRAM_NUM_KERNELS, ::size_t) \ + F(cl_program_info, CL_PROGRAM_KERNEL_NAMES, STRING_CLASS) \ + \ + F(cl_program_build_info, CL_PROGRAM_BINARY_TYPE, cl_program_binary_type) \ + \ + F(cl_kernel_info, CL_KERNEL_ATTRIBUTES, STRING_CLASS) \ + \ + F(cl_kernel_arg_info, CL_KERNEL_ARG_ADDRESS_QUALIFIER, cl_kernel_arg_address_qualifier) \ + F(cl_kernel_arg_info, CL_KERNEL_ARG_ACCESS_QUALIFIER, cl_kernel_arg_access_qualifier) \ + F(cl_kernel_arg_info, CL_KERNEL_ARG_TYPE_NAME, STRING_CLASS) \ + F(cl_kernel_arg_info, CL_KERNEL_ARG_NAME, STRING_CLASS) \ + F(cl_kernel_arg_info, CL_KERNEL_ARG_TYPE_QUALIFIER, cl_kernel_arg_type_qualifier) \ + \ + F(cl_device_info, CL_DEVICE_PARENT_DEVICE, cl_device_id) \ + F(cl_device_info, CL_DEVICE_PARTITION_PROPERTIES, VECTOR_CLASS) \ + F(cl_device_info, CL_DEVICE_PARTITION_TYPE, VECTOR_CLASS) \ + F(cl_device_info, CL_DEVICE_REFERENCE_COUNT, cl_uint) \ + F(cl_device_info, CL_DEVICE_PREFERRED_INTEROP_USER_SYNC, ::size_t) \ + F(cl_device_info, CL_DEVICE_PARTITION_AFFINITY_DOMAIN, cl_device_affinity_domain) \ + F(cl_device_info, CL_DEVICE_BUILT_IN_KERNELS, STRING_CLASS) +#endif // #if defined(CL_VERSION_1_2) + +#if defined(USE_CL_DEVICE_FISSION) +#define __PARAM_NAME_DEVICE_FISSION(F) \ + F(cl_device_info, CL_DEVICE_PARENT_DEVICE_EXT, cl_device_id) \ + F(cl_device_info, CL_DEVICE_PARTITION_TYPES_EXT, VECTOR_CLASS) \ + F(cl_device_info, CL_DEVICE_AFFINITY_DOMAINS_EXT, VECTOR_CLASS) \ + F(cl_device_info, CL_DEVICE_REFERENCE_COUNT_EXT , cl_uint) \ + F(cl_device_info, CL_DEVICE_PARTITION_STYLE_EXT, VECTOR_CLASS) +#endif // USE_CL_DEVICE_FISSION + +template +struct param_traits {}; + +#define __CL_DECLARE_PARAM_TRAITS(token, param_name, T) \ +struct token; \ +template<> \ +struct param_traits \ +{ \ + enum { value = param_name }; \ + typedef T param_type; \ +}; + +__PARAM_NAME_INFO_1_0(__CL_DECLARE_PARAM_TRAITS) +#if defined(CL_VERSION_1_1) +__PARAM_NAME_INFO_1_1(__CL_DECLARE_PARAM_TRAITS) +#endif // CL_VERSION_1_1 +#if defined(CL_VERSION_1_2) +__PARAM_NAME_INFO_1_2(__CL_DECLARE_PARAM_TRAITS) +#endif // CL_VERSION_1_1 + +#if defined(USE_CL_DEVICE_FISSION) +__PARAM_NAME_DEVICE_FISSION(__CL_DECLARE_PARAM_TRAITS); +#endif // USE_CL_DEVICE_FISSION + +#ifdef CL_PLATFORM_ICD_SUFFIX_KHR +__CL_DECLARE_PARAM_TRAITS(cl_platform_info, CL_PLATFORM_ICD_SUFFIX_KHR, STRING_CLASS) +#endif + +#ifdef CL_DEVICE_PROFILING_TIMER_OFFSET_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_PROFILING_TIMER_OFFSET_AMD, cl_ulong) +#endif + +#ifdef CL_DEVICE_GLOBAL_FREE_MEMORY_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_GLOBAL_FREE_MEMORY_AMD, VECTOR_CLASS< ::size_t>) +#endif +#ifdef CL_DEVICE_SIMD_PER_COMPUTE_UNIT_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_SIMD_PER_COMPUTE_UNIT_AMD, cl_uint) +#endif +#ifdef CL_DEVICE_SIMD_WIDTH_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_SIMD_WIDTH_AMD, cl_uint) +#endif +#ifdef CL_DEVICE_SIMD_INSTRUCTION_WIDTH_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_SIMD_INSTRUCTION_WIDTH_AMD, cl_uint) +#endif +#ifdef CL_DEVICE_WAVEFRONT_WIDTH_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_WAVEFRONT_WIDTH_AMD, cl_uint) +#endif +#ifdef CL_DEVICE_GLOBAL_MEM_CHANNELS_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_GLOBAL_MEM_CHANNELS_AMD, cl_uint) +#endif +#ifdef CL_DEVICE_GLOBAL_MEM_CHANNEL_BANKS_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_GLOBAL_MEM_CHANNEL_BANKS_AMD, cl_uint) +#endif +#ifdef CL_DEVICE_GLOBAL_MEM_CHANNEL_BANK_WIDTH_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_GLOBAL_MEM_CHANNEL_BANK_WIDTH_AMD, cl_uint) +#endif +#ifdef CL_DEVICE_LOCAL_MEM_SIZE_PER_COMPUTE_UNIT_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_LOCAL_MEM_SIZE_PER_COMPUTE_UNIT_AMD, cl_uint) +#endif +#ifdef CL_DEVICE_LOCAL_MEM_BANKS_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_LOCAL_MEM_BANKS_AMD, cl_uint) +#endif + +#ifdef CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV, cl_uint) +#endif +#ifdef CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV, cl_uint) +#endif +#ifdef CL_DEVICE_REGISTERS_PER_BLOCK_NV +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_REGISTERS_PER_BLOCK_NV, cl_uint) +#endif +#ifdef CL_DEVICE_WARP_SIZE_NV +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_WARP_SIZE_NV, cl_uint) +#endif +#ifdef CL_DEVICE_GPU_OVERLAP_NV +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_GPU_OVERLAP_NV, cl_bool) +#endif +#ifdef CL_DEVICE_KERNEL_EXEC_TIMEOUT_NV +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_KERNEL_EXEC_TIMEOUT_NV, cl_bool) +#endif +#ifdef CL_DEVICE_INTEGRATED_MEMORY_NV +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_INTEGRATED_MEMORY_NV, cl_bool) +#endif + +// Convenience functions + +template +inline cl_int +getInfo(Func f, cl_uint name, T* param) +{ + return getInfoHelper(f, name, param, 0); +} + +template +struct GetInfoFunctor0 +{ + Func f_; const Arg0& arg0_; + cl_int operator ()( + cl_uint param, ::size_t size, void* value, ::size_t* size_ret) + { return f_(arg0_, param, size, value, size_ret); } +}; + +template +struct GetInfoFunctor1 +{ + Func f_; const Arg0& arg0_; const Arg1& arg1_; + cl_int operator ()( + cl_uint param, ::size_t size, void* value, ::size_t* size_ret) + { return f_(arg0_, arg1_, param, size, value, size_ret); } +}; + +template +inline cl_int +getInfo(Func f, const Arg0& arg0, cl_uint name, T* param) +{ + GetInfoFunctor0 f0 = { f, arg0 }; + return getInfoHelper(f0, name, param, 0); +} + +template +inline cl_int +getInfo(Func f, const Arg0& arg0, const Arg1& arg1, cl_uint name, T* param) +{ + GetInfoFunctor1 f0 = { f, arg0, arg1 }; + return getInfoHelper(f0, name, param, 0); +} + +template +struct ReferenceHandler +{ }; + +#if defined(CL_VERSION_1_2) +/** + * OpenCL 1.2 devices do have retain/release. + */ +template <> +struct ReferenceHandler +{ + /** + * Retain the device. + * \param device A valid device created using createSubDevices + * \return + * CL_SUCCESS if the function executed successfully. + * CL_INVALID_DEVICE if device was not a valid subdevice + * CL_OUT_OF_RESOURCES + * CL_OUT_OF_HOST_MEMORY + */ + static cl_int retain(cl_device_id device) + { return ::clRetainDevice(device); } + /** + * Retain the device. + * \param device A valid device created using createSubDevices + * \return + * CL_SUCCESS if the function executed successfully. + * CL_INVALID_DEVICE if device was not a valid subdevice + * CL_OUT_OF_RESOURCES + * CL_OUT_OF_HOST_MEMORY + */ + static cl_int release(cl_device_id device) + { return ::clReleaseDevice(device); } +}; +#else // #if defined(CL_VERSION_1_2) +/** + * OpenCL 1.1 devices do not have retain/release. + */ +template <> +struct ReferenceHandler +{ + // cl_device_id does not have retain(). + static cl_int retain(cl_device_id) + { return CL_SUCCESS; } + // cl_device_id does not have release(). + static cl_int release(cl_device_id) + { return CL_SUCCESS; } +}; +#endif // #if defined(CL_VERSION_1_2) + +template <> +struct ReferenceHandler +{ + // cl_platform_id does not have retain(). + static cl_int retain(cl_platform_id) + { return CL_SUCCESS; } + // cl_platform_id does not have release(). + static cl_int release(cl_platform_id) + { return CL_SUCCESS; } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_context context) + { return ::clRetainContext(context); } + static cl_int release(cl_context context) + { return ::clReleaseContext(context); } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_command_queue queue) + { return ::clRetainCommandQueue(queue); } + static cl_int release(cl_command_queue queue) + { return ::clReleaseCommandQueue(queue); } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_mem memory) + { return ::clRetainMemObject(memory); } + static cl_int release(cl_mem memory) + { return ::clReleaseMemObject(memory); } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_sampler sampler) + { return ::clRetainSampler(sampler); } + static cl_int release(cl_sampler sampler) + { return ::clReleaseSampler(sampler); } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_program program) + { return ::clRetainProgram(program); } + static cl_int release(cl_program program) + { return ::clReleaseProgram(program); } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_kernel kernel) + { return ::clRetainKernel(kernel); } + static cl_int release(cl_kernel kernel) + { return ::clReleaseKernel(kernel); } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_event event) + { return ::clRetainEvent(event); } + static cl_int release(cl_event event) + { return ::clReleaseEvent(event); } +}; + + +// Extracts version number with major in the upper 16 bits, minor in the lower 16 +static cl_uint getVersion(const char *versionInfo) +{ + int highVersion = 0; + int lowVersion = 0; + int index = 7; + while(versionInfo[index] != '.' ) { + highVersion *= 10; + highVersion += versionInfo[index]-'0'; + ++index; + } + ++index; + while(versionInfo[index] != ' ' && versionInfo[index] != '\0') { + lowVersion *= 10; + lowVersion += versionInfo[index]-'0'; + ++index; + } + return (highVersion << 16) | lowVersion; +} + +static cl_uint getPlatformVersion(cl_platform_id platform) +{ + ::size_t size = 0; + clGetPlatformInfo(platform, CL_PLATFORM_VERSION, 0, NULL, &size); + char *versionInfo = (char *) alloca(size); + clGetPlatformInfo(platform, CL_PLATFORM_VERSION, size, &versionInfo[0], &size); + return getVersion(versionInfo); +} + +static cl_uint getDevicePlatformVersion(cl_device_id device) +{ + cl_platform_id platform; + clGetDeviceInfo(device, CL_DEVICE_PLATFORM, sizeof(platform), &platform, NULL); + return getPlatformVersion(platform); +} + +#if defined(CL_VERSION_1_2) && defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) +static cl_uint getContextPlatformVersion(cl_context context) +{ + // The platform cannot be queried directly, so we first have to grab a + // device and obtain its context + ::size_t size = 0; + clGetContextInfo(context, CL_CONTEXT_DEVICES, 0, NULL, &size); + if (size == 0) + return 0; + cl_device_id *devices = (cl_device_id *) alloca(size); + clGetContextInfo(context, CL_CONTEXT_DEVICES, size, devices, NULL); + return getDevicePlatformVersion(devices[0]); +} +#endif // #if defined(CL_VERSION_1_2) && defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) + +template +class Wrapper +{ +public: + typedef T cl_type; + +protected: + cl_type object_; + +public: + Wrapper() : object_(NULL) { } + + Wrapper(const cl_type &obj) : object_(obj) { } + + ~Wrapper() + { + if (object_ != NULL) { release(); } + } + + Wrapper(const Wrapper& rhs) + { + object_ = rhs.object_; + if (object_ != NULL) { detail::errHandler(retain(), __RETAIN_ERR); } + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + Wrapper(Wrapper&& rhs) CL_HPP_NOEXCEPT + { + object_ = rhs.object_; + rhs.object_ = NULL; + } +#endif + + Wrapper& operator = (const Wrapper& rhs) + { + if (this != &rhs) { + if (object_ != NULL) { detail::errHandler(release(), __RELEASE_ERR); } + object_ = rhs.object_; + if (object_ != NULL) { detail::errHandler(retain(), __RETAIN_ERR); } + } + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + Wrapper& operator = (Wrapper&& rhs) + { + if (this != &rhs) { + if (object_ != NULL) { detail::errHandler(release(), __RELEASE_ERR); } + object_ = rhs.object_; + rhs.object_ = NULL; + } + return *this; + } +#endif + + Wrapper& operator = (const cl_type &rhs) + { + if (object_ != NULL) { detail::errHandler(release(), __RELEASE_ERR); } + object_ = rhs; + return *this; + } + + cl_type operator ()() const { return object_; } + + cl_type& operator ()() { return object_; } + +protected: + template + friend inline cl_int getInfoHelper(Func, cl_uint, U*, int, typename U::cl_type); + + cl_int retain() const + { + return ReferenceHandler::retain(object_); + } + + cl_int release() const + { + return ReferenceHandler::release(object_); + } +}; + +template <> +class Wrapper +{ +public: + typedef cl_device_id cl_type; + +protected: + cl_type object_; + bool referenceCountable_; + + static bool isReferenceCountable(cl_device_id device) + { + bool retVal = false; + if (device != NULL) { + int version = getDevicePlatformVersion(device); + if(version > ((1 << 16) + 1)) { + retVal = true; + } + } + return retVal; + } + +public: + Wrapper() : object_(NULL), referenceCountable_(false) + { + } + + Wrapper(const cl_type &obj) : object_(obj), referenceCountable_(false) + { + referenceCountable_ = isReferenceCountable(obj); + } + + ~Wrapper() + { + if (object_ != NULL) { release(); } + } + + Wrapper(const Wrapper& rhs) + { + object_ = rhs.object_; + referenceCountable_ = isReferenceCountable(object_); + if (object_ != NULL) { detail::errHandler(retain(), __RETAIN_ERR); } + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + Wrapper(Wrapper&& rhs) CL_HPP_NOEXCEPT + { + object_ = rhs.object_; + referenceCountable_ = rhs.referenceCountable_; + rhs.object_ = NULL; + rhs.referenceCountable_ = false; + } +#endif + + Wrapper& operator = (const Wrapper& rhs) + { + if (this != &rhs) { + if (object_ != NULL) { detail::errHandler(release(), __RELEASE_ERR); } + object_ = rhs.object_; + referenceCountable_ = rhs.referenceCountable_; + if (object_ != NULL) { detail::errHandler(retain(), __RETAIN_ERR); } + } + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + Wrapper& operator = (Wrapper&& rhs) + { + if (this != &rhs) { + if (object_ != NULL) { detail::errHandler(release(), __RELEASE_ERR); } + object_ = rhs.object_; + referenceCountable_ = rhs.referenceCountable_; + rhs.object_ = NULL; + rhs.referenceCountable_ = false; + } + return *this; + } +#endif + + Wrapper& operator = (const cl_type &rhs) + { + if (object_ != NULL) { detail::errHandler(release(), __RELEASE_ERR); } + object_ = rhs; + referenceCountable_ = isReferenceCountable(object_); + return *this; + } + + cl_type operator ()() const { return object_; } + + cl_type& operator ()() { return object_; } + +protected: + template + friend inline cl_int getInfoHelper(Func, cl_uint, U*, int, typename U::cl_type); + + template + friend inline cl_int getInfoHelper(Func, cl_uint, VECTOR_CLASS*, int, typename U::cl_type); + + cl_int retain() const + { + if( referenceCountable_ ) { + return ReferenceHandler::retain(object_); + } + else { + return CL_SUCCESS; + } + } + + cl_int release() const + { + if( referenceCountable_ ) { + return ReferenceHandler::release(object_); + } + else { + return CL_SUCCESS; + } + } +}; + +} // namespace detail +//! \endcond + +/*! \stuct ImageFormat + * \brief Adds constructors and member functions for cl_image_format. + * + * \see cl_image_format + */ +struct ImageFormat : public cl_image_format +{ + //! \brief Default constructor - performs no initialization. + ImageFormat(){} + + //! \brief Initializing constructor. + ImageFormat(cl_channel_order order, cl_channel_type type) + { + image_channel_order = order; + image_channel_data_type = type; + } + + //! \brief Assignment operator. + ImageFormat& operator = (const ImageFormat& rhs) + { + if (this != &rhs) { + this->image_channel_data_type = rhs.image_channel_data_type; + this->image_channel_order = rhs.image_channel_order; + } + return *this; + } +}; + +/*! \brief Class interface for cl_device_id. + * + * \note Copies of these objects are inexpensive, since they don't 'own' + * any underlying resources or data structures. + * + * \see cl_device_id + */ +class Device : public detail::Wrapper +{ +public: + //! \brief Default constructor - initializes to NULL. + Device() : detail::Wrapper() { } + + /*! \brief Constructor from cl_device_id. + * + * This simply copies the device ID value, which is an inexpensive operation. + */ + __CL_EXPLICIT_CONSTRUCTORS Device(const cl_device_id &device) : detail::Wrapper(device) { } + + /*! \brief Returns the first device on the default context. + * + * \see Context::getDefault() + */ + static Device getDefault(cl_int * err = NULL); + + /*! \brief Assignment operator from cl_device_id. + * + * This simply copies the device ID value, which is an inexpensive operation. + */ + Device& operator = (const cl_device_id& rhs) + { + detail::Wrapper::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Device(const Device& dev) : detail::Wrapper(dev) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Device& operator = (const Device &dev) + { + detail::Wrapper::operator=(dev); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Device(Device&& dev) CL_HPP_NOEXCEPT : detail::Wrapper(std::move(dev)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Device& operator = (Device &&dev) + { + detail::Wrapper::operator=(std::move(dev)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + + //! \brief Wrapper for clGetDeviceInfo(). + template + cl_int getInfo(cl_device_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetDeviceInfo, object_, name, param), + __GET_DEVICE_INFO_ERR); + } + + //! \brief Wrapper for clGetDeviceInfo() that returns by value. + template typename + detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_device_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + + /** + * CL 1.2 version + */ +#if defined(CL_VERSION_1_2) + //! \brief Wrapper for clCreateSubDevicesEXT(). + cl_int createSubDevices( + const cl_device_partition_property * properties, + VECTOR_CLASS* devices) + { + cl_uint n = 0; + cl_int err = clCreateSubDevices(object_, properties, 0, NULL, &n); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __CREATE_SUB_DEVICES); + } + + cl_device_id* ids = (cl_device_id*) alloca(n * sizeof(cl_device_id)); + err = clCreateSubDevices(object_, properties, n, ids, NULL); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __CREATE_SUB_DEVICES); + } + + devices->assign(&ids[0], &ids[n]); + return CL_SUCCESS; + } +#endif // #if defined(CL_VERSION_1_2) + +/** + * CL 1.1 version that uses device fission. + */ +#if defined(CL_VERSION_1_1) +#if defined(USE_CL_DEVICE_FISSION) + cl_int createSubDevices( + const cl_device_partition_property_ext * properties, + VECTOR_CLASS* devices) + { + typedef CL_API_ENTRY cl_int + ( CL_API_CALL * PFN_clCreateSubDevicesEXT)( + cl_device_id /*in_device*/, + const cl_device_partition_property_ext * /* properties */, + cl_uint /*num_entries*/, + cl_device_id * /*out_devices*/, + cl_uint * /*num_devices*/ ) CL_EXT_SUFFIX__VERSION_1_1; + + static PFN_clCreateSubDevicesEXT pfn_clCreateSubDevicesEXT = NULL; + __INIT_CL_EXT_FCN_PTR(clCreateSubDevicesEXT); + + cl_uint n = 0; + cl_int err = pfn_clCreateSubDevicesEXT(object_, properties, 0, NULL, &n); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __CREATE_SUB_DEVICES); + } + + cl_device_id* ids = (cl_device_id*) alloca(n * sizeof(cl_device_id)); + err = pfn_clCreateSubDevicesEXT(object_, properties, n, ids, NULL); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __CREATE_SUB_DEVICES); + } + + devices->assign(&ids[0], &ids[n]); + return CL_SUCCESS; + } +#endif // #if defined(USE_CL_DEVICE_FISSION) +#endif // #if defined(CL_VERSION_1_1) +}; + +/*! \brief Class interface for cl_platform_id. + * + * \note Copies of these objects are inexpensive, since they don't 'own' + * any underlying resources or data structures. + * + * \see cl_platform_id + */ +class Platform : public detail::Wrapper +{ +public: + //! \brief Default constructor - initializes to NULL. + Platform() : detail::Wrapper() { } + + /*! \brief Constructor from cl_platform_id. + * + * This simply copies the platform ID value, which is an inexpensive operation. + */ + __CL_EXPLICIT_CONSTRUCTORS Platform(const cl_platform_id &platform) : detail::Wrapper(platform) { } + + /*! \brief Assignment operator from cl_platform_id. + * + * This simply copies the platform ID value, which is an inexpensive operation. + */ + Platform& operator = (const cl_platform_id& rhs) + { + detail::Wrapper::operator=(rhs); + return *this; + } + + //! \brief Wrapper for clGetPlatformInfo(). + cl_int getInfo(cl_platform_info name, STRING_CLASS* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetPlatformInfo, object_, name, param), + __GET_PLATFORM_INFO_ERR); + } + + //! \brief Wrapper for clGetPlatformInfo() that returns by value. + template typename + detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_platform_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + + /*! \brief Gets a list of devices for this platform. + * + * Wraps clGetDeviceIDs(). + */ + cl_int getDevices( + cl_device_type type, + VECTOR_CLASS* devices) const + { + cl_uint n = 0; + if( devices == NULL ) { + return detail::errHandler(CL_INVALID_ARG_VALUE, __GET_DEVICE_IDS_ERR); + } + cl_int err = ::clGetDeviceIDs(object_, type, 0, NULL, &n); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __GET_DEVICE_IDS_ERR); + } + + cl_device_id* ids = (cl_device_id*) alloca(n * sizeof(cl_device_id)); + err = ::clGetDeviceIDs(object_, type, n, ids, NULL); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __GET_DEVICE_IDS_ERR); + } + + devices->assign(&ids[0], &ids[n]); + return CL_SUCCESS; + } + +#if defined(USE_DX_INTEROP) + /*! \brief Get the list of available D3D10 devices. + * + * \param d3d_device_source. + * + * \param d3d_object. + * + * \param d3d_device_set. + * + * \param devices returns a vector of OpenCL D3D10 devices found. The cl::Device + * values returned in devices can be used to identify a specific OpenCL + * device. If \a devices argument is NULL, this argument is ignored. + * + * \return One of the following values: + * - CL_SUCCESS if the function is executed successfully. + * + * The application can query specific capabilities of the OpenCL device(s) + * returned by cl::getDevices. This can be used by the application to + * determine which device(s) to use. + * + * \note In the case that exceptions are enabled and a return value + * other than CL_SUCCESS is generated, then cl::Error exception is + * generated. + */ + cl_int getDevices( + cl_d3d10_device_source_khr d3d_device_source, + void * d3d_object, + cl_d3d10_device_set_khr d3d_device_set, + VECTOR_CLASS* devices) const + { + typedef CL_API_ENTRY cl_int (CL_API_CALL *PFN_clGetDeviceIDsFromD3D10KHR)( + cl_platform_id platform, + cl_d3d10_device_source_khr d3d_device_source, + void * d3d_object, + cl_d3d10_device_set_khr d3d_device_set, + cl_uint num_entries, + cl_device_id * devices, + cl_uint* num_devices); + + if( devices == NULL ) { + return detail::errHandler(CL_INVALID_ARG_VALUE, __GET_DEVICE_IDS_ERR); + } + + static PFN_clGetDeviceIDsFromD3D10KHR pfn_clGetDeviceIDsFromD3D10KHR = NULL; + __INIT_CL_EXT_FCN_PTR_PLATFORM(object_, clGetDeviceIDsFromD3D10KHR); + + cl_uint n = 0; + cl_int err = pfn_clGetDeviceIDsFromD3D10KHR( + object_, + d3d_device_source, + d3d_object, + d3d_device_set, + 0, + NULL, + &n); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __GET_DEVICE_IDS_ERR); + } + + cl_device_id* ids = (cl_device_id*) alloca(n * sizeof(cl_device_id)); + err = pfn_clGetDeviceIDsFromD3D10KHR( + object_, + d3d_device_source, + d3d_object, + d3d_device_set, + n, + ids, + NULL); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __GET_DEVICE_IDS_ERR); + } + + devices->assign(&ids[0], &ids[n]); + return CL_SUCCESS; + } +#endif + + /*! \brief Gets a list of available platforms. + * + * Wraps clGetPlatformIDs(). + */ + static cl_int get( + VECTOR_CLASS* platforms) + { + cl_uint n = 0; + + if( platforms == NULL ) { + return detail::errHandler(CL_INVALID_ARG_VALUE, __GET_PLATFORM_IDS_ERR); + } + + cl_int err = ::clGetPlatformIDs(0, NULL, &n); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __GET_PLATFORM_IDS_ERR); + } + + cl_platform_id* ids = (cl_platform_id*) alloca( + n * sizeof(cl_platform_id)); + err = ::clGetPlatformIDs(n, ids, NULL); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __GET_PLATFORM_IDS_ERR); + } + + platforms->assign(&ids[0], &ids[n]); + return CL_SUCCESS; + } + + /*! \brief Gets the first available platform. + * + * Wraps clGetPlatformIDs(), returning the first result. + */ + static cl_int get( + Platform * platform) + { + cl_uint n = 0; + + if( platform == NULL ) { + return detail::errHandler(CL_INVALID_ARG_VALUE, __GET_PLATFORM_IDS_ERR); + } + + cl_int err = ::clGetPlatformIDs(0, NULL, &n); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __GET_PLATFORM_IDS_ERR); + } + + cl_platform_id* ids = (cl_platform_id*) alloca( + n * sizeof(cl_platform_id)); + err = ::clGetPlatformIDs(n, ids, NULL); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __GET_PLATFORM_IDS_ERR); + } + + *platform = ids[0]; + return CL_SUCCESS; + } + + /*! \brief Gets the first available platform, returning it by value. + * + * Wraps clGetPlatformIDs(), returning the first result. + */ + static Platform get( + cl_int * errResult = NULL) + { + Platform platform; + cl_uint n = 0; + cl_int err = ::clGetPlatformIDs(0, NULL, &n); + if (err != CL_SUCCESS) { + detail::errHandler(err, __GET_PLATFORM_IDS_ERR); + if (errResult != NULL) { + *errResult = err; + } + return Platform(); + } + + cl_platform_id* ids = (cl_platform_id*) alloca( + n * sizeof(cl_platform_id)); + err = ::clGetPlatformIDs(n, ids, NULL); + + if (err != CL_SUCCESS) { + detail::errHandler(err, __GET_PLATFORM_IDS_ERR); + if (errResult != NULL) { + *errResult = err; + } + return Platform(); + } + + + return Platform(ids[0]); + } + + static Platform getDefault( + cl_int *errResult = NULL ) + { + return get(errResult); + } + + +#if defined(CL_VERSION_1_2) + //! \brief Wrapper for clUnloadCompiler(). + cl_int + unloadCompiler() + { + return ::clUnloadPlatformCompiler(object_); + } +#endif // #if defined(CL_VERSION_1_2) +}; // class Platform + +/** + * Deprecated APIs for 1.2 + */ +#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) || (defined(CL_VERSION_1_1) && !defined(CL_VERSION_1_2)) +/** + * Unload the OpenCL compiler. + * \note Deprecated for OpenCL 1.2. Use Platform::unloadCompiler instead. + */ +inline CL_EXT_PREFIX__VERSION_1_1_DEPRECATED cl_int +UnloadCompiler() CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; +inline cl_int +UnloadCompiler() +{ + return ::clUnloadCompiler(); +} +#endif // #if defined(CL_VERSION_1_1) + +/*! \brief Class interface for cl_context. + * + * \note Copies of these objects are shallow, meaning that the copy will refer + * to the same underlying cl_context as the original. For details, see + * clRetainContext() and clReleaseContext(). + * + * \see cl_context + */ +class Context + : public detail::Wrapper +{ +private: + +#ifdef CL_HPP_CPP11_ATOMICS_SUPPORTED + static std::atomic default_initialized_; +#else // !CL_HPP_CPP11_ATOMICS_SUPPORTED + static volatile int default_initialized_; +#endif // !CL_HPP_CPP11_ATOMICS_SUPPORTED + static Context default_; + static volatile cl_int default_error_; +public: + /*! \brief Constructs a context including a list of specified devices. + * + * Wraps clCreateContext(). + */ + Context( + const VECTOR_CLASS& devices, + cl_context_properties* properties = NULL, + void (CL_CALLBACK * notifyFptr)( + const char *, + const void *, + ::size_t, + void *) = NULL, + void* data = NULL, + cl_int* err = NULL) + { + cl_int error; + + ::size_t numDevices = devices.size(); + cl_device_id* deviceIDs = (cl_device_id*) alloca(numDevices * sizeof(cl_device_id)); + for( ::size_t deviceIndex = 0; deviceIndex < numDevices; ++deviceIndex ) { + deviceIDs[deviceIndex] = (devices[deviceIndex])(); + } + + object_ = ::clCreateContext( + properties, (cl_uint) numDevices, + deviceIDs, + notifyFptr, data, &error); + + detail::errHandler(error, __CREATE_CONTEXT_ERR); + if (err != NULL) { + *err = error; + } + } + + Context( + const Device& device, + cl_context_properties* properties = NULL, + void (CL_CALLBACK * notifyFptr)( + const char *, + const void *, + ::size_t, + void *) = NULL, + void* data = NULL, + cl_int* err = NULL) + { + cl_int error; + + cl_device_id deviceID = device(); + + object_ = ::clCreateContext( + properties, 1, + &deviceID, + notifyFptr, data, &error); + + detail::errHandler(error, __CREATE_CONTEXT_ERR); + if (err != NULL) { + *err = error; + } + } + + /*! \brief Constructs a context including all or a subset of devices of a specified type. + * + * Wraps clCreateContextFromType(). + */ + Context( + cl_device_type type, + cl_context_properties* properties = NULL, + void (CL_CALLBACK * notifyFptr)( + const char *, + const void *, + ::size_t, + void *) = NULL, + void* data = NULL, + cl_int* err = NULL) + { + cl_int error; + +#if !defined(__APPLE__) && !defined(__MACOS) + cl_context_properties prop[4] = {CL_CONTEXT_PLATFORM, 0, 0, 0 }; + + if (properties == NULL) { + // Get a valid platform ID as we cannot send in a blank one + VECTOR_CLASS platforms; + error = Platform::get(&platforms); + if (error != CL_SUCCESS) { + detail::errHandler(error, __CREATE_CONTEXT_FROM_TYPE_ERR); + if (err != NULL) { + *err = error; + } + return; + } + + // Check the platforms we found for a device of our specified type + cl_context_properties platform_id = 0; + for (unsigned int i = 0; i < platforms.size(); i++) { + + VECTOR_CLASS devices; + +#if defined(__CL_ENABLE_EXCEPTIONS) + try { +#endif + + error = platforms[i].getDevices(type, &devices); + +#if defined(__CL_ENABLE_EXCEPTIONS) + } catch (Error) {} + // Catch if exceptions are enabled as we don't want to exit if first platform has no devices of type + // We do error checking next anyway, and can throw there if needed +#endif + + // Only squash CL_SUCCESS and CL_DEVICE_NOT_FOUND + if (error != CL_SUCCESS && error != CL_DEVICE_NOT_FOUND) { + detail::errHandler(error, __CREATE_CONTEXT_FROM_TYPE_ERR); + if (err != NULL) { + *err = error; + } + } + + if (devices.size() > 0) { + platform_id = (cl_context_properties)platforms[i](); + break; + } + } + + if (platform_id == 0) { + detail::errHandler(CL_DEVICE_NOT_FOUND, __CREATE_CONTEXT_FROM_TYPE_ERR); + if (err != NULL) { + *err = CL_DEVICE_NOT_FOUND; + } + return; + } + + prop[1] = platform_id; + properties = &prop[0]; + } +#endif + object_ = ::clCreateContextFromType( + properties, type, notifyFptr, data, &error); + + detail::errHandler(error, __CREATE_CONTEXT_FROM_TYPE_ERR); + if (err != NULL) { + *err = error; + } + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Context(const Context& ctx) : detail::Wrapper(ctx) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Context& operator = (const Context &ctx) + { + detail::Wrapper::operator=(ctx); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Context(Context&& ctx) CL_HPP_NOEXCEPT : detail::Wrapper(std::move(ctx)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Context& operator = (Context &&ctx) + { + detail::Wrapper::operator=(std::move(ctx)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + + /*! \brief Returns a singleton context including all devices of CL_DEVICE_TYPE_DEFAULT. + * + * \note All calls to this function return the same cl_context as the first. + */ + static Context getDefault(cl_int * err = NULL) + { + int state = detail::compare_exchange( + &default_initialized_, + __DEFAULT_BEING_INITIALIZED, __DEFAULT_NOT_INITIALIZED); + + if (state & __DEFAULT_INITIALIZED) { + if (err != NULL) { + *err = default_error_; + } + return default_; + } + + if (state & __DEFAULT_BEING_INITIALIZED) { + // Assume writes will propagate eventually... + while(default_initialized_ != __DEFAULT_INITIALIZED) { + detail::fence(); + } + + if (err != NULL) { + *err = default_error_; + } + return default_; + } + + cl_int error; + default_ = Context( + CL_DEVICE_TYPE_DEFAULT, + NULL, + NULL, + NULL, + &error); + + detail::fence(); + + default_error_ = error; + // Assume writes will propagate eventually... + default_initialized_ = __DEFAULT_INITIALIZED; + + detail::fence(); + + if (err != NULL) { + *err = default_error_; + } + return default_; + + } + + //! \brief Default constructor - initializes to NULL. + Context() : detail::Wrapper() { } + + /*! \brief Constructor from cl_context - takes ownership. + * + * This effectively transfers ownership of a refcount on the cl_context + * into the new Context object. + */ + __CL_EXPLICIT_CONSTRUCTORS Context(const cl_context& context) : detail::Wrapper(context) { } + + /*! \brief Assignment operator from cl_context - takes ownership. + * + * This effectively transfers ownership of a refcount on the rhs and calls + * clReleaseContext() on the value previously held by this instance. + */ + Context& operator = (const cl_context& rhs) + { + detail::Wrapper::operator=(rhs); + return *this; + } + + //! \brief Wrapper for clGetContextInfo(). + template + cl_int getInfo(cl_context_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetContextInfo, object_, name, param), + __GET_CONTEXT_INFO_ERR); + } + + //! \brief Wrapper for clGetContextInfo() that returns by value. + template typename + detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_context_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + + /*! \brief Gets a list of supported image formats. + * + * Wraps clGetSupportedImageFormats(). + */ + cl_int getSupportedImageFormats( + cl_mem_flags flags, + cl_mem_object_type type, + VECTOR_CLASS* formats) const + { + cl_uint numEntries; + + if (!formats) { + return CL_SUCCESS; + } + + cl_int err = ::clGetSupportedImageFormats( + object_, + flags, + type, + 0, + NULL, + &numEntries); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __GET_SUPPORTED_IMAGE_FORMATS_ERR); + } + + if (numEntries > 0) { + ImageFormat* value = (ImageFormat*) + alloca(numEntries * sizeof(ImageFormat)); + err = ::clGetSupportedImageFormats( + object_, + flags, + type, + numEntries, + (cl_image_format*)value, + NULL); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __GET_SUPPORTED_IMAGE_FORMATS_ERR); + } + + formats->assign(&value[0], &value[numEntries]); + } + else { + formats->clear(); + } + return CL_SUCCESS; + } +}; + +inline Device Device::getDefault(cl_int * err) +{ + cl_int error; + Device device; + + Context context = Context::getDefault(&error); + detail::errHandler(error, __CREATE_CONTEXT_ERR); + + if (error != CL_SUCCESS) { + if (err != NULL) { + *err = error; + } + } + else { + device = context.getInfo()[0]; + if (err != NULL) { + *err = CL_SUCCESS; + } + } + + return device; +} + + +#ifdef _WIN32 +#ifdef CL_HPP_CPP11_ATOMICS_SUPPORTED +__declspec(selectany) std::atomic Context::default_initialized_; +#else // !CL_HPP_CPP11_ATOMICS_SUPPORTED +__declspec(selectany) volatile int Context::default_initialized_ = __DEFAULT_NOT_INITIALIZED; +#endif // !CL_HPP_CPP11_ATOMICS_SUPPORTED +__declspec(selectany) Context Context::default_; +__declspec(selectany) volatile cl_int Context::default_error_ = CL_SUCCESS; +#else // !_WIN32 +#ifdef CL_HPP_CPP11_ATOMICS_SUPPORTED +__attribute__((weak)) std::atomic Context::default_initialized_; +#else // !CL_HPP_CPP11_ATOMICS_SUPPORTED +__attribute__((weak)) volatile int Context::default_initialized_ = __DEFAULT_NOT_INITIALIZED; +#endif // !CL_HPP_CPP11_ATOMICS_SUPPORTED +__attribute__((weak)) Context Context::default_; +__attribute__((weak)) volatile cl_int Context::default_error_ = CL_SUCCESS; +#endif // !_WIN32 + +/*! \brief Class interface for cl_event. + * + * \note Copies of these objects are shallow, meaning that the copy will refer + * to the same underlying cl_event as the original. For details, see + * clRetainEvent() and clReleaseEvent(). + * + * \see cl_event + */ +class Event : public detail::Wrapper +{ +public: + //! \brief Default constructor - initializes to NULL. + Event() : detail::Wrapper() { } + + /*! \brief Constructor from cl_event - takes ownership. + * + * This effectively transfers ownership of a refcount on the cl_event + * into the new Event object. + */ + __CL_EXPLICIT_CONSTRUCTORS Event(const cl_event& event) : detail::Wrapper(event) { } + + /*! \brief Assignment operator from cl_event - takes ownership. + * + * This effectively transfers ownership of a refcount on the rhs and calls + * clReleaseEvent() on the value previously held by this instance. + */ + Event& operator = (const cl_event& rhs) + { + detail::Wrapper::operator=(rhs); + return *this; + } + + //! \brief Wrapper for clGetEventInfo(). + template + cl_int getInfo(cl_event_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetEventInfo, object_, name, param), + __GET_EVENT_INFO_ERR); + } + + //! \brief Wrapper for clGetEventInfo() that returns by value. + template typename + detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_event_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + + //! \brief Wrapper for clGetEventProfilingInfo(). + template + cl_int getProfilingInfo(cl_profiling_info name, T* param) const + { + return detail::errHandler(detail::getInfo( + &::clGetEventProfilingInfo, object_, name, param), + __GET_EVENT_PROFILE_INFO_ERR); + } + + //! \brief Wrapper for clGetEventProfilingInfo() that returns by value. + template typename + detail::param_traits::param_type + getProfilingInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_profiling_info, name>::param_type param; + cl_int result = getProfilingInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + + /*! \brief Blocks the calling thread until this event completes. + * + * Wraps clWaitForEvents(). + */ + cl_int wait() const + { + return detail::errHandler( + ::clWaitForEvents(1, &object_), + __WAIT_FOR_EVENTS_ERR); + } + +#if defined(CL_VERSION_1_1) + /*! \brief Registers a user callback function for a specific command execution status. + * + * Wraps clSetEventCallback(). + */ + cl_int setCallback( + cl_int type, + void (CL_CALLBACK * pfn_notify)(cl_event, cl_int, void *), + void * user_data = NULL) + { + return detail::errHandler( + ::clSetEventCallback( + object_, + type, + pfn_notify, + user_data), + __SET_EVENT_CALLBACK_ERR); + } +#endif + + /*! \brief Blocks the calling thread until every event specified is complete. + * + * Wraps clWaitForEvents(). + */ + static cl_int + waitForEvents(const VECTOR_CLASS& events) + { + return detail::errHandler( + ::clWaitForEvents( + (cl_uint) events.size(), (events.size() > 0) ? (cl_event*)&events.front() : NULL), + __WAIT_FOR_EVENTS_ERR); + } +}; + +#if defined(CL_VERSION_1_1) +/*! \brief Class interface for user events (a subset of cl_event's). + * + * See Event for details about copy semantics, etc. + */ +class UserEvent : public Event +{ +public: + /*! \brief Constructs a user event on a given context. + * + * Wraps clCreateUserEvent(). + */ + UserEvent( + const Context& context, + cl_int * err = NULL) + { + cl_int error; + object_ = ::clCreateUserEvent( + context(), + &error); + + detail::errHandler(error, __CREATE_USER_EVENT_ERR); + if (err != NULL) { + *err = error; + } + } + + //! \brief Default constructor - initializes to NULL. + UserEvent() : Event() { } + + /*! \brief Sets the execution status of a user event object. + * + * Wraps clSetUserEventStatus(). + */ + cl_int setStatus(cl_int status) + { + return detail::errHandler( + ::clSetUserEventStatus(object_,status), + __SET_USER_EVENT_STATUS_ERR); + } +}; +#endif + +/*! \brief Blocks the calling thread until every event specified is complete. + * + * Wraps clWaitForEvents(). + */ +inline static cl_int +WaitForEvents(const VECTOR_CLASS& events) +{ + return detail::errHandler( + ::clWaitForEvents( + (cl_uint) events.size(), (events.size() > 0) ? (cl_event*)&events.front() : NULL), + __WAIT_FOR_EVENTS_ERR); +} + +/*! \brief Class interface for cl_mem. + * + * \note Copies of these objects are shallow, meaning that the copy will refer + * to the same underlying cl_mem as the original. For details, see + * clRetainMemObject() and clReleaseMemObject(). + * + * \see cl_mem + */ +class Memory : public detail::Wrapper +{ +public: + //! \brief Default constructor - initializes to NULL. + Memory() : detail::Wrapper() { } + + /*! \brief Constructor from cl_mem - takes ownership. + * + * This effectively transfers ownership of a refcount on the cl_mem + * into the new Memory object. + */ + __CL_EXPLICIT_CONSTRUCTORS Memory(const cl_mem& memory) : detail::Wrapper(memory) { } + + /*! \brief Assignment operator from cl_mem - takes ownership. + * + * This effectively transfers ownership of a refcount on the rhs and calls + * clReleaseMemObject() on the value previously held by this instance. + */ + Memory& operator = (const cl_mem& rhs) + { + detail::Wrapper::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Memory(const Memory& mem) : detail::Wrapper(mem) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Memory& operator = (const Memory &mem) + { + detail::Wrapper::operator=(mem); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Memory(Memory&& mem) CL_HPP_NOEXCEPT : detail::Wrapper(std::move(mem)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Memory& operator = (Memory &&mem) + { + detail::Wrapper::operator=(std::move(mem)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + + //! \brief Wrapper for clGetMemObjectInfo(). + template + cl_int getInfo(cl_mem_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetMemObjectInfo, object_, name, param), + __GET_MEM_OBJECT_INFO_ERR); + } + + //! \brief Wrapper for clGetMemObjectInfo() that returns by value. + template typename + detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_mem_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + +#if defined(CL_VERSION_1_1) + /*! \brief Registers a callback function to be called when the memory object + * is no longer needed. + * + * Wraps clSetMemObjectDestructorCallback(). + * + * Repeated calls to this function, for a given cl_mem value, will append + * to the list of functions called (in reverse order) when memory object's + * resources are freed and the memory object is deleted. + * + * \note + * The registered callbacks are associated with the underlying cl_mem + * value - not the Memory class instance. + */ + cl_int setDestructorCallback( + void (CL_CALLBACK * pfn_notify)(cl_mem, void *), + void * user_data = NULL) + { + return detail::errHandler( + ::clSetMemObjectDestructorCallback( + object_, + pfn_notify, + user_data), + __SET_MEM_OBJECT_DESTRUCTOR_CALLBACK_ERR); + } +#endif + +}; + +// Pre-declare copy functions +class Buffer; +template< typename IteratorType > +cl_int copy( IteratorType startIterator, IteratorType endIterator, cl::Buffer &buffer ); +template< typename IteratorType > +cl_int copy( const cl::Buffer &buffer, IteratorType startIterator, IteratorType endIterator ); +template< typename IteratorType > +cl_int copy( const CommandQueue &queue, IteratorType startIterator, IteratorType endIterator, cl::Buffer &buffer ); +template< typename IteratorType > +cl_int copy( const CommandQueue &queue, const cl::Buffer &buffer, IteratorType startIterator, IteratorType endIterator ); + + +/*! \brief Class interface for Buffer Memory Objects. + * + * See Memory for details about copy semantics, etc. + * + * \see Memory + */ +class Buffer : public Memory +{ +public: + + /*! \brief Constructs a Buffer in a specified context. + * + * Wraps clCreateBuffer(). + * + * \param host_ptr Storage to be used if the CL_MEM_USE_HOST_PTR flag was + * specified. Note alignment & exclusivity requirements. + */ + Buffer( + const Context& context, + cl_mem_flags flags, + ::size_t size, + void* host_ptr = NULL, + cl_int* err = NULL) + { + cl_int error; + object_ = ::clCreateBuffer(context(), flags, size, host_ptr, &error); + + detail::errHandler(error, __CREATE_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + } + + /*! \brief Constructs a Buffer in the default context. + * + * Wraps clCreateBuffer(). + * + * \param host_ptr Storage to be used if the CL_MEM_USE_HOST_PTR flag was + * specified. Note alignment & exclusivity requirements. + * + * \see Context::getDefault() + */ + Buffer( + cl_mem_flags flags, + ::size_t size, + void* host_ptr = NULL, + cl_int* err = NULL) + { + cl_int error; + + Context context = Context::getDefault(err); + + object_ = ::clCreateBuffer(context(), flags, size, host_ptr, &error); + + detail::errHandler(error, __CREATE_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + } + + /*! + * \brief Construct a Buffer from a host container via iterators. + * IteratorType must be random access. + * If useHostPtr is specified iterators must represent contiguous data. + */ + template< typename IteratorType > + Buffer( + IteratorType startIterator, + IteratorType endIterator, + bool readOnly, + bool useHostPtr = false, + cl_int* err = NULL) + { + typedef typename std::iterator_traits::value_type DataType; + cl_int error; + + cl_mem_flags flags = 0; + if( readOnly ) { + flags |= CL_MEM_READ_ONLY; + } + else { + flags |= CL_MEM_READ_WRITE; + } + if( useHostPtr ) { + flags |= CL_MEM_USE_HOST_PTR; + } + + ::size_t size = sizeof(DataType)*(endIterator - startIterator); + + Context context = Context::getDefault(err); + + if( useHostPtr ) { + object_ = ::clCreateBuffer(context(), flags, size, static_cast(&*startIterator), &error); + } else { + object_ = ::clCreateBuffer(context(), flags, size, 0, &error); + } + + detail::errHandler(error, __CREATE_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + + if( !useHostPtr ) { + error = cl::copy(startIterator, endIterator, *this); + detail::errHandler(error, __CREATE_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + } + } + + /*! + * \brief Construct a Buffer from a host container via iterators using a specified context. + * IteratorType must be random access. + * If useHostPtr is specified iterators must represent contiguous data. + */ + template< typename IteratorType > + Buffer(const Context &context, IteratorType startIterator, IteratorType endIterator, + bool readOnly, bool useHostPtr = false, cl_int* err = NULL); + + /*! + * \brief Construct a Buffer from a host container via iterators using a specified queue. + * If useHostPtr is specified iterators must represent contiguous data. + */ + template< typename IteratorType > + Buffer(const CommandQueue &queue, IteratorType startIterator, IteratorType endIterator, + bool readOnly, bool useHostPtr = false, cl_int* err = NULL); + + //! \brief Default constructor - initializes to NULL. + Buffer() : Memory() { } + + /*! \brief Constructor from cl_mem - takes ownership. + * + * See Memory for further details. + */ + __CL_EXPLICIT_CONSTRUCTORS Buffer(const cl_mem& buffer) : Memory(buffer) { } + + /*! \brief Assignment from cl_mem - performs shallow copy. + * + * See Memory for further details. + */ + Buffer& operator = (const cl_mem& rhs) + { + Memory::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Buffer(const Buffer& buf) : Memory(buf) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Buffer& operator = (const Buffer &buf) + { + Memory::operator=(buf); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Buffer(Buffer&& buf) CL_HPP_NOEXCEPT : Memory(std::move(buf)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Buffer& operator = (Buffer &&buf) + { + Memory::operator=(std::move(buf)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + +#if defined(CL_VERSION_1_1) + /*! \brief Creates a new buffer object from this. + * + * Wraps clCreateSubBuffer(). + */ + Buffer createSubBuffer( + cl_mem_flags flags, + cl_buffer_create_type buffer_create_type, + const void * buffer_create_info, + cl_int * err = NULL) + { + Buffer result; + cl_int error; + result.object_ = ::clCreateSubBuffer( + object_, + flags, + buffer_create_type, + buffer_create_info, + &error); + + detail::errHandler(error, __CREATE_SUBBUFFER_ERR); + if (err != NULL) { + *err = error; + } + + return result; + } +#endif +}; + +#if defined (USE_DX_INTEROP) +/*! \brief Class interface for creating OpenCL buffers from ID3D10Buffer's. + * + * This is provided to facilitate interoperability with Direct3D. + * + * See Memory for details about copy semantics, etc. + * + * \see Memory + */ +class BufferD3D10 : public Buffer +{ +public: + typedef CL_API_ENTRY cl_mem (CL_API_CALL *PFN_clCreateFromD3D10BufferKHR)( + cl_context context, cl_mem_flags flags, ID3D10Buffer* buffer, + cl_int* errcode_ret); + + /*! \brief Constructs a BufferD3D10, in a specified context, from a + * given ID3D10Buffer. + * + * Wraps clCreateFromD3D10BufferKHR(). + */ + BufferD3D10( + const Context& context, + cl_mem_flags flags, + ID3D10Buffer* bufobj, + cl_int * err = NULL) + { + static PFN_clCreateFromD3D10BufferKHR pfn_clCreateFromD3D10BufferKHR = NULL; + +#if defined(CL_VERSION_1_2) + vector props = context.getInfo(); + cl_platform platform = -1; + for( int i = 0; i < props.size(); ++i ) { + if( props[i] == CL_CONTEXT_PLATFORM ) { + platform = props[i+1]; + } + } + __INIT_CL_EXT_FCN_PTR_PLATFORM(platform, clCreateFromD3D10BufferKHR); +#endif +#if defined(CL_VERSION_1_1) + __INIT_CL_EXT_FCN_PTR(clCreateFromD3D10BufferKHR); +#endif + + cl_int error; + object_ = pfn_clCreateFromD3D10BufferKHR( + context(), + flags, + bufobj, + &error); + + detail::errHandler(error, __CREATE_GL_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + } + + //! \brief Default constructor - initializes to NULL. + BufferD3D10() : Buffer() { } + + /*! \brief Constructor from cl_mem - takes ownership. + * + * See Memory for further details. + */ + __CL_EXPLICIT_CONSTRUCTORS BufferD3D10(const cl_mem& buffer) : Buffer(buffer) { } + + /*! \brief Assignment from cl_mem - performs shallow copy. + * + * See Memory for further details. + */ + BufferD3D10& operator = (const cl_mem& rhs) + { + Buffer::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + BufferD3D10(const BufferD3D10& buf) : Buffer(buf) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + BufferD3D10& operator = (const BufferD3D10 &buf) + { + Buffer::operator=(buf); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + BufferD3D10(BufferD3D10&& buf) CL_HPP_NOEXCEPT : Buffer(std::move(buf)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + BufferD3D10& operator = (BufferD3D10 &&buf) + { + Buffer::operator=(std::move(buf)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) +}; +#endif + +/*! \brief Class interface for GL Buffer Memory Objects. + * + * This is provided to facilitate interoperability with OpenGL. + * + * See Memory for details about copy semantics, etc. + * + * \see Memory + */ +class BufferGL : public Buffer +{ +public: + /*! \brief Constructs a BufferGL in a specified context, from a given + * GL buffer. + * + * Wraps clCreateFromGLBuffer(). + */ + BufferGL( + const Context& context, + cl_mem_flags flags, + cl_GLuint bufobj, + cl_int * err = NULL) + { + cl_int error; + object_ = ::clCreateFromGLBuffer( + context(), + flags, + bufobj, + &error); + + detail::errHandler(error, __CREATE_GL_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + } + + //! \brief Default constructor - initializes to NULL. + BufferGL() : Buffer() { } + + /*! \brief Constructor from cl_mem - takes ownership. + * + * See Memory for further details. + */ + __CL_EXPLICIT_CONSTRUCTORS BufferGL(const cl_mem& buffer) : Buffer(buffer) { } + + /*! \brief Assignment from cl_mem - performs shallow copy. + * + * See Memory for further details. + */ + BufferGL& operator = (const cl_mem& rhs) + { + Buffer::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + BufferGL(const BufferGL& buf) : Buffer(buf) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + BufferGL& operator = (const BufferGL &buf) + { + Buffer::operator=(buf); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + BufferGL(BufferGL&& buf) CL_HPP_NOEXCEPT : Buffer(std::move(buf)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + BufferGL& operator = (BufferGL &&buf) + { + Buffer::operator=(std::move(buf)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + + //! \brief Wrapper for clGetGLObjectInfo(). + cl_int getObjectInfo( + cl_gl_object_type *type, + cl_GLuint * gl_object_name) + { + return detail::errHandler( + ::clGetGLObjectInfo(object_,type,gl_object_name), + __GET_GL_OBJECT_INFO_ERR); + } +}; + +/*! \brief C++ base class for Image Memory objects. + * + * See Memory for details about copy semantics, etc. + * + * \see Memory + */ +class Image : public Memory +{ +protected: + //! \brief Default constructor - initializes to NULL. + Image() : Memory() { } + + /*! \brief Constructor from cl_mem - takes ownership. + * + * See Memory for further details. + */ + __CL_EXPLICIT_CONSTRUCTORS Image(const cl_mem& image) : Memory(image) { } + + /*! \brief Assignment from cl_mem - performs shallow copy. + * + * See Memory for further details. + */ + Image& operator = (const cl_mem& rhs) + { + Memory::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image(const Image& img) : Memory(img) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image& operator = (const Image &img) + { + Memory::operator=(img); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Image(Image&& img) CL_HPP_NOEXCEPT : Memory(std::move(img)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Image& operator = (Image &&img) + { + Memory::operator=(std::move(img)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + +public: + //! \brief Wrapper for clGetImageInfo(). + template + cl_int getImageInfo(cl_image_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetImageInfo, object_, name, param), + __GET_IMAGE_INFO_ERR); + } + + //! \brief Wrapper for clGetImageInfo() that returns by value. + template typename + detail::param_traits::param_type + getImageInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_image_info, name>::param_type param; + cl_int result = getImageInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } +}; + +#if defined(CL_VERSION_1_2) +/*! \brief Class interface for 1D Image Memory objects. + * + * See Memory for details about copy semantics, etc. + * + * \see Memory + */ +class Image1D : public Image +{ +public: + /*! \brief Constructs a 1D Image in a specified context. + * + * Wraps clCreateImage(). + */ + Image1D( + const Context& context, + cl_mem_flags flags, + ImageFormat format, + ::size_t width, + void* host_ptr = NULL, + cl_int* err = NULL) + { + cl_int error; + cl_image_desc desc = + { + CL_MEM_OBJECT_IMAGE1D, + width, + 0, 0, 0, 0, 0, 0, 0, 0 + }; + object_ = ::clCreateImage( + context(), + flags, + &format, + &desc, + host_ptr, + &error); + + detail::errHandler(error, __CREATE_IMAGE_ERR); + if (err != NULL) { + *err = error; + } + } + + //! \brief Default constructor - initializes to NULL. + Image1D() { } + + /*! \brief Constructor from cl_mem - takes ownership. + * + * See Memory for further details. + */ + __CL_EXPLICIT_CONSTRUCTORS Image1D(const cl_mem& image1D) : Image(image1D) { } + + /*! \brief Assignment from cl_mem - performs shallow copy. + * + * See Memory for further details. + */ + Image1D& operator = (const cl_mem& rhs) + { + Image::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image1D(const Image1D& img) : Image(img) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image1D& operator = (const Image1D &img) + { + Image::operator=(img); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Image1D(Image1D&& img) CL_HPP_NOEXCEPT : Image(std::move(img)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Image1D& operator = (Image1D &&img) + { + Image::operator=(std::move(img)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) +}; + +/*! \class Image1DBuffer + * \brief Image interface for 1D buffer images. + */ +class Image1DBuffer : public Image +{ +public: + Image1DBuffer( + const Context& context, + cl_mem_flags flags, + ImageFormat format, + ::size_t width, + const Buffer &buffer, + cl_int* err = NULL) + { + cl_int error; + cl_image_desc desc = + { + CL_MEM_OBJECT_IMAGE1D_BUFFER, + width, + 0, 0, 0, 0, 0, 0, 0, + buffer() + }; + object_ = ::clCreateImage( + context(), + flags, + &format, + &desc, + NULL, + &error); + + detail::errHandler(error, __CREATE_IMAGE_ERR); + if (err != NULL) { + *err = error; + } + } + + Image1DBuffer() { } + + __CL_EXPLICIT_CONSTRUCTORS Image1DBuffer(const cl_mem& image1D) : Image(image1D) { } + + Image1DBuffer& operator = (const cl_mem& rhs) + { + Image::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image1DBuffer(const Image1DBuffer& img) : Image(img) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image1DBuffer& operator = (const Image1DBuffer &img) + { + Image::operator=(img); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Image1DBuffer(Image1DBuffer&& img) CL_HPP_NOEXCEPT : Image(std::move(img)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Image1DBuffer& operator = (Image1DBuffer &&img) + { + Image::operator=(std::move(img)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) +}; + +/*! \class Image1DArray + * \brief Image interface for arrays of 1D images. + */ +class Image1DArray : public Image +{ +public: + Image1DArray( + const Context& context, + cl_mem_flags flags, + ImageFormat format, + ::size_t arraySize, + ::size_t width, + ::size_t rowPitch, + void* host_ptr = NULL, + cl_int* err = NULL) + { + cl_int error; + cl_image_desc desc = + { + CL_MEM_OBJECT_IMAGE1D_ARRAY, + width, + 0, 0, // height, depth (unused) + arraySize, + rowPitch, + 0, 0, 0, 0 + }; + object_ = ::clCreateImage( + context(), + flags, + &format, + &desc, + host_ptr, + &error); + + detail::errHandler(error, __CREATE_IMAGE_ERR); + if (err != NULL) { + *err = error; + } + } + + Image1DArray() { } + + __CL_EXPLICIT_CONSTRUCTORS Image1DArray(const cl_mem& imageArray) : Image(imageArray) { } + + Image1DArray& operator = (const cl_mem& rhs) + { + Image::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image1DArray(const Image1DArray& img) : Image(img) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image1DArray& operator = (const Image1DArray &img) + { + Image::operator=(img); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Image1DArray(Image1DArray&& img) CL_HPP_NOEXCEPT : Image(std::move(img)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Image1DArray& operator = (Image1DArray &&img) + { + Image::operator=(std::move(img)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) +}; +#endif // #if defined(CL_VERSION_1_2) + + +/*! \brief Class interface for 2D Image Memory objects. + * + * See Memory for details about copy semantics, etc. + * + * \see Memory + */ +class Image2D : public Image +{ +public: + /*! \brief Constructs a 1D Image in a specified context. + * + * Wraps clCreateImage(). + */ + Image2D( + const Context& context, + cl_mem_flags flags, + ImageFormat format, + ::size_t width, + ::size_t height, + ::size_t row_pitch = 0, + void* host_ptr = NULL, + cl_int* err = NULL) + { + cl_int error; + bool useCreateImage; + +#if defined(CL_VERSION_1_2) && defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) + // Run-time decision based on the actual platform + { + cl_uint version = detail::getContextPlatformVersion(context()); + useCreateImage = (version >= 0x10002); // OpenCL 1.2 or above + } +#elif defined(CL_VERSION_1_2) + useCreateImage = true; +#else + useCreateImage = false; +#endif + +#if defined(CL_VERSION_1_2) + if (useCreateImage) + { + cl_image_desc desc = + { + CL_MEM_OBJECT_IMAGE2D, + width, + height, + 0, 0, // depth, array size (unused) + row_pitch, + 0, 0, 0, 0 + }; + object_ = ::clCreateImage( + context(), + flags, + &format, + &desc, + host_ptr, + &error); + + detail::errHandler(error, __CREATE_IMAGE_ERR); + if (err != NULL) { + *err = error; + } + } +#endif // #if defined(CL_VERSION_1_2) +#if !defined(CL_VERSION_1_2) || defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) + if (!useCreateImage) + { + object_ = ::clCreateImage2D( + context(), flags,&format, width, height, row_pitch, host_ptr, &error); + + detail::errHandler(error, __CREATE_IMAGE2D_ERR); + if (err != NULL) { + *err = error; + } + } +#endif // #if !defined(CL_VERSION_1_2) || defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) + } + + //! \brief Default constructor - initializes to NULL. + Image2D() { } + + /*! \brief Constructor from cl_mem - takes ownership. + * + * See Memory for further details. + */ + __CL_EXPLICIT_CONSTRUCTORS Image2D(const cl_mem& image2D) : Image(image2D) { } + + /*! \brief Assignment from cl_mem - performs shallow copy. + * + * See Memory for further details. + */ + Image2D& operator = (const cl_mem& rhs) + { + Image::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image2D(const Image2D& img) : Image(img) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image2D& operator = (const Image2D &img) + { + Image::operator=(img); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Image2D(Image2D&& img) CL_HPP_NOEXCEPT : Image(std::move(img)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Image2D& operator = (Image2D &&img) + { + Image::operator=(std::move(img)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) +}; + + +#if !defined(CL_VERSION_1_2) +/*! \brief Class interface for GL 2D Image Memory objects. + * + * This is provided to facilitate interoperability with OpenGL. + * + * See Memory for details about copy semantics, etc. + * + * \see Memory + * \note Deprecated for OpenCL 1.2. Please use ImageGL instead. + */ +class CL_EXT_PREFIX__VERSION_1_1_DEPRECATED Image2DGL CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED : public Image2D +{ +public: + /*! \brief Constructs an Image2DGL in a specified context, from a given + * GL Texture. + * + * Wraps clCreateFromGLTexture2D(). + */ + Image2DGL( + const Context& context, + cl_mem_flags flags, + cl_GLenum target, + cl_GLint miplevel, + cl_GLuint texobj, + cl_int * err = NULL) + { + cl_int error; + object_ = ::clCreateFromGLTexture2D( + context(), + flags, + target, + miplevel, + texobj, + &error); + + detail::errHandler(error, __CREATE_GL_TEXTURE_2D_ERR); + if (err != NULL) { + *err = error; + } + + } + + //! \brief Default constructor - initializes to NULL. + Image2DGL() : Image2D() { } + + /*! \brief Constructor from cl_mem - takes ownership. + * + * See Memory for further details. + */ + __CL_EXPLICIT_CONSTRUCTORS Image2DGL(const cl_mem& image) : Image2D(image) { } + + /*! \brief Assignment from cl_mem - performs shallow copy. + * + * See Memory for further details. + */ + Image2DGL& operator = (const cl_mem& rhs) + { + Image2D::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image2DGL(const Image2DGL& img) : Image2D(img) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image2DGL& operator = (const Image2DGL &img) + { + Image2D::operator=(img); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Image2DGL(Image2DGL&& img) CL_HPP_NOEXCEPT : Image2D(std::move(img)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Image2DGL& operator = (Image2DGL &&img) + { + Image2D::operator=(std::move(img)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) +}; +#endif // #if !defined(CL_VERSION_1_2) + +#if defined(CL_VERSION_1_2) +/*! \class Image2DArray + * \brief Image interface for arrays of 2D images. + */ +class Image2DArray : public Image +{ +public: + Image2DArray( + const Context& context, + cl_mem_flags flags, + ImageFormat format, + ::size_t arraySize, + ::size_t width, + ::size_t height, + ::size_t rowPitch, + ::size_t slicePitch, + void* host_ptr = NULL, + cl_int* err = NULL) + { + cl_int error; + cl_image_desc desc = + { + CL_MEM_OBJECT_IMAGE2D_ARRAY, + width, + height, + 0, // depth (unused) + arraySize, + rowPitch, + slicePitch, + 0, 0, 0 + }; + object_ = ::clCreateImage( + context(), + flags, + &format, + &desc, + host_ptr, + &error); + + detail::errHandler(error, __CREATE_IMAGE_ERR); + if (err != NULL) { + *err = error; + } + } + + Image2DArray() { } + + __CL_EXPLICIT_CONSTRUCTORS Image2DArray(const cl_mem& imageArray) : Image(imageArray) { } + + Image2DArray& operator = (const cl_mem& rhs) + { + Image::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image2DArray(const Image2DArray& img) : Image(img) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image2DArray& operator = (const Image2DArray &img) + { + Image::operator=(img); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Image2DArray(Image2DArray&& img) CL_HPP_NOEXCEPT : Image(std::move(img)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Image2DArray& operator = (Image2DArray &&img) + { + Image::operator=(std::move(img)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) +}; +#endif // #if defined(CL_VERSION_1_2) + +/*! \brief Class interface for 3D Image Memory objects. + * + * See Memory for details about copy semantics, etc. + * + * \see Memory + */ +class Image3D : public Image +{ +public: + /*! \brief Constructs a 3D Image in a specified context. + * + * Wraps clCreateImage(). + */ + Image3D( + const Context& context, + cl_mem_flags flags, + ImageFormat format, + ::size_t width, + ::size_t height, + ::size_t depth, + ::size_t row_pitch = 0, + ::size_t slice_pitch = 0, + void* host_ptr = NULL, + cl_int* err = NULL) + { + cl_int error; + bool useCreateImage; + +#if defined(CL_VERSION_1_2) && defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) + // Run-time decision based on the actual platform + { + cl_uint version = detail::getContextPlatformVersion(context()); + useCreateImage = (version >= 0x10002); // OpenCL 1.2 or above + } +#elif defined(CL_VERSION_1_2) + useCreateImage = true; +#else + useCreateImage = false; +#endif + +#if defined(CL_VERSION_1_2) + if (useCreateImage) + { + cl_image_desc desc = + { + CL_MEM_OBJECT_IMAGE3D, + width, + height, + depth, + 0, // array size (unused) + row_pitch, + slice_pitch, + 0, 0, 0 + }; + object_ = ::clCreateImage( + context(), + flags, + &format, + &desc, + host_ptr, + &error); + + detail::errHandler(error, __CREATE_IMAGE_ERR); + if (err != NULL) { + *err = error; + } + } +#endif // #if defined(CL_VERSION_1_2) +#if !defined(CL_VERSION_1_2) || defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) + if (!useCreateImage) + { + object_ = ::clCreateImage3D( + context(), flags, &format, width, height, depth, row_pitch, + slice_pitch, host_ptr, &error); + + detail::errHandler(error, __CREATE_IMAGE3D_ERR); + if (err != NULL) { + *err = error; + } + } +#endif // #if !defined(CL_VERSION_1_2) || defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) + } + + //! \brief Default constructor - initializes to NULL. + Image3D() : Image() { } + + /*! \brief Constructor from cl_mem - takes ownership. + * + * See Memory for further details. + */ + __CL_EXPLICIT_CONSTRUCTORS Image3D(const cl_mem& image3D) : Image(image3D) { } + + /*! \brief Assignment from cl_mem - performs shallow copy. + * + * See Memory for further details. + */ + Image3D& operator = (const cl_mem& rhs) + { + Image::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image3D(const Image3D& img) : Image(img) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image3D& operator = (const Image3D &img) + { + Image::operator=(img); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Image3D(Image3D&& img) CL_HPP_NOEXCEPT : Image(std::move(img)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Image3D& operator = (Image3D &&img) + { + Image::operator=(std::move(img)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) +}; + +#if !defined(CL_VERSION_1_2) +/*! \brief Class interface for GL 3D Image Memory objects. + * + * This is provided to facilitate interoperability with OpenGL. + * + * See Memory for details about copy semantics, etc. + * + * \see Memory + */ +class Image3DGL : public Image3D +{ +public: + /*! \brief Constructs an Image3DGL in a specified context, from a given + * GL Texture. + * + * Wraps clCreateFromGLTexture3D(). + */ + Image3DGL( + const Context& context, + cl_mem_flags flags, + cl_GLenum target, + cl_GLint miplevel, + cl_GLuint texobj, + cl_int * err = NULL) + { + cl_int error; + object_ = ::clCreateFromGLTexture3D( + context(), + flags, + target, + miplevel, + texobj, + &error); + + detail::errHandler(error, __CREATE_GL_TEXTURE_3D_ERR); + if (err != NULL) { + *err = error; + } + } + + //! \brief Default constructor - initializes to NULL. + Image3DGL() : Image3D() { } + + /*! \brief Constructor from cl_mem - takes ownership. + * + * See Memory for further details. + */ + __CL_EXPLICIT_CONSTRUCTORS Image3DGL(const cl_mem& image) : Image3D(image) { } + + /*! \brief Assignment from cl_mem - performs shallow copy. + * + * See Memory for further details. + */ + Image3DGL& operator = (const cl_mem& rhs) + { + Image3D::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image3DGL(const Image3DGL& img) : Image3D(img) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image3DGL& operator = (const Image3DGL &img) + { + Image3D::operator=(img); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Image3DGL(Image3DGL&& img) CL_HPP_NOEXCEPT : Image3D(std::move(img)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Image3DGL& operator = (Image3DGL &&img) + { + Image3D::operator=(std::move(img)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) +}; +#endif // #if !defined(CL_VERSION_1_2) + +#if defined(CL_VERSION_1_2) +/*! \class ImageGL + * \brief general image interface for GL interop. + * We abstract the 2D and 3D GL images into a single instance here + * that wraps all GL sourced images on the grounds that setup information + * was performed by OpenCL anyway. + */ +class ImageGL : public Image +{ +public: + ImageGL( + const Context& context, + cl_mem_flags flags, + cl_GLenum target, + cl_GLint miplevel, + cl_GLuint texobj, + cl_int * err = NULL) + { + cl_int error; + object_ = ::clCreateFromGLTexture( + context(), + flags, + target, + miplevel, + texobj, + &error); + + detail::errHandler(error, __CREATE_GL_TEXTURE_ERR); + if (err != NULL) { + *err = error; + } + } + + ImageGL() : Image() { } + + __CL_EXPLICIT_CONSTRUCTORS ImageGL(const cl_mem& image) : Image(image) { } + + ImageGL& operator = (const cl_mem& rhs) + { + Image::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + ImageGL(const ImageGL& img) : Image(img) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + ImageGL& operator = (const ImageGL &img) + { + Image::operator=(img); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + ImageGL(ImageGL&& img) CL_HPP_NOEXCEPT : Image(std::move(img)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + ImageGL& operator = (ImageGL &&img) + { + Image::operator=(std::move(img)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) +}; +#endif // #if defined(CL_VERSION_1_2) + +/*! \brief Class interface for GL Render Buffer Memory Objects. +* +* This is provided to facilitate interoperability with OpenGL. +* +* See Memory for details about copy semantics, etc. +* +* \see Memory +*/ +class BufferRenderGL : +#if defined(CL_VERSION_1_2) + public ImageGL +#else // #if defined(CL_VERSION_1_2) + public Image2DGL +#endif //#if defined(CL_VERSION_1_2) +{ +public: + /*! \brief Constructs a BufferRenderGL in a specified context, from a given + * GL Renderbuffer. + * + * Wraps clCreateFromGLRenderbuffer(). + */ + BufferRenderGL( + const Context& context, + cl_mem_flags flags, + cl_GLuint bufobj, + cl_int * err = NULL) + { + cl_int error; + object_ = ::clCreateFromGLRenderbuffer( + context(), + flags, + bufobj, + &error); + + detail::errHandler(error, __CREATE_GL_RENDER_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + } + + //! \brief Default constructor - initializes to NULL. +#if defined(CL_VERSION_1_2) + BufferRenderGL() : ImageGL() {}; +#else // #if defined(CL_VERSION_1_2) + BufferRenderGL() : Image2DGL() {}; +#endif //#if defined(CL_VERSION_1_2) + + /*! \brief Constructor from cl_mem - takes ownership. + * + * See Memory for further details. + */ +#if defined(CL_VERSION_1_2) + __CL_EXPLICIT_CONSTRUCTORS BufferRenderGL(const cl_mem& buffer) : ImageGL(buffer) { } +#else // #if defined(CL_VERSION_1_2) + __CL_EXPLICIT_CONSTRUCTORS BufferRenderGL(const cl_mem& buffer) : Image2DGL(buffer) { } +#endif //#if defined(CL_VERSION_1_2) + + + /*! \brief Assignment from cl_mem - performs shallow copy. + * + * See Memory for further details. + */ + BufferRenderGL& operator = (const cl_mem& rhs) + { +#if defined(CL_VERSION_1_2) + ImageGL::operator=(rhs); +#else // #if defined(CL_VERSION_1_2) + Image2DGL::operator=(rhs); +#endif //#if defined(CL_VERSION_1_2) + + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ +#if defined(CL_VERSION_1_2) + BufferRenderGL(const BufferRenderGL& buf) : ImageGL(buf) {} +#else // #if defined(CL_VERSION_1_2) + BufferRenderGL(const BufferRenderGL& buf) : Image2DGL(buf) {} +#endif //#if defined(CL_VERSION_1_2) + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + BufferRenderGL& operator = (const BufferRenderGL &rhs) + { +#if defined(CL_VERSION_1_2) + ImageGL::operator=(rhs); +#else // #if defined(CL_VERSION_1_2) + Image2DGL::operator=(rhs); +#endif //#if defined(CL_VERSION_1_2) + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ +#if defined(CL_VERSION_1_2) + BufferRenderGL(BufferRenderGL&& buf) CL_HPP_NOEXCEPT : ImageGL(std::move(buf)) {} +#else // #if defined(CL_VERSION_1_2) + BufferRenderGL(BufferRenderGL&& buf) CL_HPP_NOEXCEPT : Image2DGL(std::move(buf)) {} +#endif //#if defined(CL_VERSION_1_2) + + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + BufferRenderGL& operator = (BufferRenderGL &&buf) + { +#if defined(CL_VERSION_1_2) + ImageGL::operator=(std::move(buf)); +#else // #if defined(CL_VERSION_1_2) + Image2DGL::operator=(std::move(buf)); +#endif //#if defined(CL_VERSION_1_2) + + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + + //! \brief Wrapper for clGetGLObjectInfo(). + cl_int getObjectInfo( + cl_gl_object_type *type, + cl_GLuint * gl_object_name) + { + return detail::errHandler( + ::clGetGLObjectInfo(object_, type, gl_object_name), + __GET_GL_OBJECT_INFO_ERR); + } +}; + +/*! \brief Class interface for cl_sampler. + * + * \note Copies of these objects are shallow, meaning that the copy will refer + * to the same underlying cl_sampler as the original. For details, see + * clRetainSampler() and clReleaseSampler(). + * + * \see cl_sampler + */ +class Sampler : public detail::Wrapper +{ +public: + //! \brief Default constructor - initializes to NULL. + Sampler() { } + + /*! \brief Constructs a Sampler in a specified context. + * + * Wraps clCreateSampler(). + */ + Sampler( + const Context& context, + cl_bool normalized_coords, + cl_addressing_mode addressing_mode, + cl_filter_mode filter_mode, + cl_int* err = NULL) + { + cl_int error; + object_ = ::clCreateSampler( + context(), + normalized_coords, + addressing_mode, + filter_mode, + &error); + + detail::errHandler(error, __CREATE_SAMPLER_ERR); + if (err != NULL) { + *err = error; + } + } + + /*! \brief Constructor from cl_sampler - takes ownership. + * + * This effectively transfers ownership of a refcount on the cl_sampler + * into the new Sampler object. + */ + __CL_EXPLICIT_CONSTRUCTORS Sampler(const cl_sampler& sampler) : detail::Wrapper(sampler) { } + + /*! \brief Assignment operator from cl_sampler - takes ownership. + * + * This effectively transfers ownership of a refcount on the rhs and calls + * clReleaseSampler() on the value previously held by this instance. + */ + Sampler& operator = (const cl_sampler& rhs) + { + detail::Wrapper::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Sampler(const Sampler& sam) : detail::Wrapper(sam) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Sampler& operator = (const Sampler &sam) + { + detail::Wrapper::operator=(sam); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Sampler(Sampler&& sam) CL_HPP_NOEXCEPT : detail::Wrapper(std::move(sam)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Sampler& operator = (Sampler &&sam) + { + detail::Wrapper::operator=(std::move(sam)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + + //! \brief Wrapper for clGetSamplerInfo(). + template + cl_int getInfo(cl_sampler_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetSamplerInfo, object_, name, param), + __GET_SAMPLER_INFO_ERR); + } + + //! \brief Wrapper for clGetSamplerInfo() that returns by value. + template typename + detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_sampler_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } +}; + +class Program; +class CommandQueue; +class Kernel; + +//! \brief Class interface for specifying NDRange values. +class NDRange +{ +private: + size_t<3> sizes_; + cl_uint dimensions_; + +public: + //! \brief Default constructor - resulting range has zero dimensions. + NDRange() + : dimensions_(0) + { } + + //! \brief Constructs one-dimensional range. + NDRange(::size_t size0) + : dimensions_(1) + { + sizes_[0] = size0; + } + + //! \brief Constructs two-dimensional range. + NDRange(::size_t size0, ::size_t size1) + : dimensions_(2) + { + sizes_[0] = size0; + sizes_[1] = size1; + } + + //! \brief Constructs three-dimensional range. + NDRange(::size_t size0, ::size_t size1, ::size_t size2) + : dimensions_(3) + { + sizes_[0] = size0; + sizes_[1] = size1; + sizes_[2] = size2; + } + + /*! \brief Conversion operator to const ::size_t *. + * + * \returns a pointer to the size of the first dimension. + */ + operator const ::size_t*() const { + return (const ::size_t*) sizes_; + } + + //! \brief Queries the number of dimensions in the range. + ::size_t dimensions() const { return dimensions_; } +}; + +//! \brief A zero-dimensional range. +static const NDRange NullRange; + +//! \brief Local address wrapper for use with Kernel::setArg +struct LocalSpaceArg +{ + ::size_t size_; +}; + +namespace detail { + +template +struct KernelArgumentHandler +{ + static ::size_t size(const T&) { return sizeof(T); } + static const T* ptr(const T& value) { return &value; } +}; + +template <> +struct KernelArgumentHandler +{ + static ::size_t size(const LocalSpaceArg& value) { return value.size_; } + static const void* ptr(const LocalSpaceArg&) { return NULL; } +}; + +} +//! \endcond + +/*! __local + * \brief Helper function for generating LocalSpaceArg objects. + * Deprecated. Replaced with Local. + */ +inline CL_EXT_PREFIX__VERSION_1_1_DEPRECATED LocalSpaceArg +__local(::size_t size) CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; +inline LocalSpaceArg +__local(::size_t size) +{ + LocalSpaceArg ret = { size }; + return ret; +} + +/*! Local + * \brief Helper function for generating LocalSpaceArg objects. + */ +inline LocalSpaceArg +Local(::size_t size) +{ + LocalSpaceArg ret = { size }; + return ret; +} + +//class KernelFunctor; + +/*! \brief Class interface for cl_kernel. + * + * \note Copies of these objects are shallow, meaning that the copy will refer + * to the same underlying cl_kernel as the original. For details, see + * clRetainKernel() and clReleaseKernel(). + * + * \see cl_kernel + */ +class Kernel : public detail::Wrapper +{ +public: + inline Kernel(const Program& program, const char* name, cl_int* err = NULL); + + //! \brief Default constructor - initializes to NULL. + Kernel() { } + + /*! \brief Constructor from cl_kernel - takes ownership. + * + * This effectively transfers ownership of a refcount on the cl_kernel + * into the new Kernel object. + */ + __CL_EXPLICIT_CONSTRUCTORS Kernel(const cl_kernel& kernel) : detail::Wrapper(kernel) { } + + /*! \brief Assignment operator from cl_kernel - takes ownership. + * + * This effectively transfers ownership of a refcount on the rhs and calls + * clReleaseKernel() on the value previously held by this instance. + */ + Kernel& operator = (const cl_kernel& rhs) + { + detail::Wrapper::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Kernel(const Kernel& kernel) : detail::Wrapper(kernel) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Kernel& operator = (const Kernel &kernel) + { + detail::Wrapper::operator=(kernel); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Kernel(Kernel&& kernel) CL_HPP_NOEXCEPT : detail::Wrapper(std::move(kernel)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Kernel& operator = (Kernel &&kernel) + { + detail::Wrapper::operator=(std::move(kernel)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + + template + cl_int getInfo(cl_kernel_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetKernelInfo, object_, name, param), + __GET_KERNEL_INFO_ERR); + } + + template typename + detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_kernel_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + +#if defined(CL_VERSION_1_2) + template + cl_int getArgInfo(cl_uint argIndex, cl_kernel_arg_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetKernelArgInfo, object_, argIndex, name, param), + __GET_KERNEL_ARG_INFO_ERR); + } + + template typename + detail::param_traits::param_type + getArgInfo(cl_uint argIndex, cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_kernel_arg_info, name>::param_type param; + cl_int result = getArgInfo(argIndex, name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } +#endif // #if defined(CL_VERSION_1_2) + + template + cl_int getWorkGroupInfo( + const Device& device, cl_kernel_work_group_info name, T* param) const + { + return detail::errHandler( + detail::getInfo( + &::clGetKernelWorkGroupInfo, object_, device(), name, param), + __GET_KERNEL_WORK_GROUP_INFO_ERR); + } + + template typename + detail::param_traits::param_type + getWorkGroupInfo(const Device& device, cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_kernel_work_group_info, name>::param_type param; + cl_int result = getWorkGroupInfo(device, name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + + template + cl_int setArg(cl_uint index, const T &value) + { + return detail::errHandler( + ::clSetKernelArg( + object_, + index, + detail::KernelArgumentHandler::size(value), + detail::KernelArgumentHandler::ptr(value)), + __SET_KERNEL_ARGS_ERR); + } + + cl_int setArg(cl_uint index, ::size_t size, const void* argPtr) + { + return detail::errHandler( + ::clSetKernelArg(object_, index, size, argPtr), + __SET_KERNEL_ARGS_ERR); + } +}; + +/*! \class Program + * \brief Program interface that implements cl_program. + */ +class Program : public detail::Wrapper +{ +public: + typedef VECTOR_CLASS > Binaries; + typedef VECTOR_CLASS > Sources; + + Program( + const STRING_CLASS& source, + bool build = false, + cl_int* err = NULL) + { + cl_int error; + + const char * strings = source.c_str(); + const ::size_t length = source.size(); + + Context context = Context::getDefault(err); + + object_ = ::clCreateProgramWithSource( + context(), (cl_uint)1, &strings, &length, &error); + + detail::errHandler(error, __CREATE_PROGRAM_WITH_SOURCE_ERR); + + if (error == CL_SUCCESS && build) { + + error = ::clBuildProgram( + object_, + 0, + NULL, + "", + NULL, + NULL); + + detail::errHandler(error, __BUILD_PROGRAM_ERR); + } + + if (err != NULL) { + *err = error; + } + } + + Program( + const Context& context, + const STRING_CLASS& source, + bool build = false, + cl_int* err = NULL) + { + cl_int error; + + const char * strings = source.c_str(); + const ::size_t length = source.size(); + + object_ = ::clCreateProgramWithSource( + context(), (cl_uint)1, &strings, &length, &error); + + detail::errHandler(error, __CREATE_PROGRAM_WITH_SOURCE_ERR); + + if (error == CL_SUCCESS && build) { + + error = ::clBuildProgram( + object_, + 0, + NULL, + "", + NULL, + NULL); + + detail::errHandler(error, __BUILD_PROGRAM_ERR); + } + + if (err != NULL) { + *err = error; + } + } + + Program( + const Context& context, + const Sources& sources, + cl_int* err = NULL) + { + cl_int error; + + const ::size_t n = (::size_t)sources.size(); + ::size_t* lengths = (::size_t*) alloca(n * sizeof(::size_t)); + const char** strings = (const char**) alloca(n * sizeof(const char*)); + + for (::size_t i = 0; i < n; ++i) { + strings[i] = sources[(int)i].first; + lengths[i] = sources[(int)i].second; + } + + object_ = ::clCreateProgramWithSource( + context(), (cl_uint)n, strings, lengths, &error); + + detail::errHandler(error, __CREATE_PROGRAM_WITH_SOURCE_ERR); + if (err != NULL) { + *err = error; + } + } + + /** + * Construct a program object from a list of devices and a per-device list of binaries. + * \param context A valid OpenCL context in which to construct the program. + * \param devices A vector of OpenCL device objects for which the program will be created. + * \param binaries A vector of pairs of a pointer to a binary object and its length. + * \param binaryStatus An optional vector that on completion will be resized to + * match the size of binaries and filled with values to specify if each binary + * was successfully loaded. + * Set to CL_SUCCESS if the binary was successfully loaded. + * Set to CL_INVALID_VALUE if the length is 0 or the binary pointer is NULL. + * Set to CL_INVALID_BINARY if the binary provided is not valid for the matching device. + * \param err if non-NULL will be set to CL_SUCCESS on successful operation or one of the following errors: + * CL_INVALID_CONTEXT if context is not a valid context. + * CL_INVALID_VALUE if the length of devices is zero; or if the length of binaries does not match the length of devices; + * or if any entry in binaries is NULL or has length 0. + * CL_INVALID_DEVICE if OpenCL devices listed in devices are not in the list of devices associated with context. + * CL_INVALID_BINARY if an invalid program binary was encountered for any device. binaryStatus will return specific status for each device. + * CL_OUT_OF_HOST_MEMORY if there is a failure to allocate resources required by the OpenCL implementation on the host. + */ + Program( + const Context& context, + const VECTOR_CLASS& devices, + const Binaries& binaries, + VECTOR_CLASS* binaryStatus = NULL, + cl_int* err = NULL) + { + cl_int error; + + const ::size_t numDevices = devices.size(); + + // Catch size mismatch early and return + if(binaries.size() != numDevices) { + error = CL_INVALID_VALUE; + detail::errHandler(error, __CREATE_PROGRAM_WITH_BINARY_ERR); + if (err != NULL) { + *err = error; + } + return; + } + + ::size_t* lengths = (::size_t*) alloca(numDevices * sizeof(::size_t)); + const unsigned char** images = (const unsigned char**) alloca(numDevices * sizeof(const unsigned char**)); + + for (::size_t i = 0; i < numDevices; ++i) { + images[i] = (const unsigned char*)binaries[i].first; + lengths[i] = binaries[(int)i].second; + } + + cl_device_id* deviceIDs = (cl_device_id*) alloca(numDevices * sizeof(cl_device_id)); + for( ::size_t deviceIndex = 0; deviceIndex < numDevices; ++deviceIndex ) { + deviceIDs[deviceIndex] = (devices[deviceIndex])(); + } + + if(binaryStatus) { + binaryStatus->resize(numDevices); + } + + object_ = ::clCreateProgramWithBinary( + context(), (cl_uint) devices.size(), + deviceIDs, + lengths, images, (binaryStatus != NULL && numDevices > 0) + ? &binaryStatus->front() + : NULL, &error); + + detail::errHandler(error, __CREATE_PROGRAM_WITH_BINARY_ERR); + if (err != NULL) { + *err = error; + } + } + + +#if defined(CL_VERSION_1_2) + /** + * Create program using builtin kernels. + * \param kernelNames Semi-colon separated list of builtin kernel names + */ + Program( + const Context& context, + const VECTOR_CLASS& devices, + const STRING_CLASS& kernelNames, + cl_int* err = NULL) + { + cl_int error; + + + ::size_t numDevices = devices.size(); + cl_device_id* deviceIDs = (cl_device_id*) alloca(numDevices * sizeof(cl_device_id)); + for( ::size_t deviceIndex = 0; deviceIndex < numDevices; ++deviceIndex ) { + deviceIDs[deviceIndex] = (devices[deviceIndex])(); + } + + object_ = ::clCreateProgramWithBuiltInKernels( + context(), + (cl_uint) devices.size(), + deviceIDs, + kernelNames.c_str(), + &error); + + detail::errHandler(error, __CREATE_PROGRAM_WITH_BUILT_IN_KERNELS_ERR); + if (err != NULL) { + *err = error; + } + } +#endif // #if defined(CL_VERSION_1_2) + + Program() { } + + __CL_EXPLICIT_CONSTRUCTORS Program(const cl_program& program) : detail::Wrapper(program) { } + + Program& operator = (const cl_program& rhs) + { + detail::Wrapper::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Program(const Program& program) : detail::Wrapper(program) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Program& operator = (const Program &program) + { + detail::Wrapper::operator=(program); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Program(Program&& program) CL_HPP_NOEXCEPT : detail::Wrapper(std::move(program)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Program& operator = (Program &&program) + { + detail::Wrapper::operator=(std::move(program)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + + cl_int build( + const VECTOR_CLASS& devices, + const char* options = NULL, + void (CL_CALLBACK * notifyFptr)(cl_program, void *) = NULL, + void* data = NULL) const + { + ::size_t numDevices = devices.size(); + cl_device_id* deviceIDs = (cl_device_id*) alloca(numDevices * sizeof(cl_device_id)); + for( ::size_t deviceIndex = 0; deviceIndex < numDevices; ++deviceIndex ) { + deviceIDs[deviceIndex] = (devices[deviceIndex])(); + } + + return detail::errHandler( + ::clBuildProgram( + object_, + (cl_uint) + devices.size(), + deviceIDs, + options, + notifyFptr, + data), + __BUILD_PROGRAM_ERR); + } + + cl_int build( + const char* options = NULL, + void (CL_CALLBACK * notifyFptr)(cl_program, void *) = NULL, + void* data = NULL) const + { + return detail::errHandler( + ::clBuildProgram( + object_, + 0, + NULL, + options, + notifyFptr, + data), + __BUILD_PROGRAM_ERR); + } + +#if defined(CL_VERSION_1_2) + cl_int compile( + const char* options = NULL, + void (CL_CALLBACK * notifyFptr)(cl_program, void *) = NULL, + void* data = NULL) const + { + return detail::errHandler( + ::clCompileProgram( + object_, + 0, + NULL, + options, + 0, + NULL, + NULL, + notifyFptr, + data), + __COMPILE_PROGRAM_ERR); + } +#endif + + template + cl_int getInfo(cl_program_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetProgramInfo, object_, name, param), + __GET_PROGRAM_INFO_ERR); + } + + template typename + detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_program_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + + template + cl_int getBuildInfo( + const Device& device, cl_program_build_info name, T* param) const + { + return detail::errHandler( + detail::getInfo( + &::clGetProgramBuildInfo, object_, device(), name, param), + __GET_PROGRAM_BUILD_INFO_ERR); + } + + template typename + detail::param_traits::param_type + getBuildInfo(const Device& device, cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_program_build_info, name>::param_type param; + cl_int result = getBuildInfo(device, name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + + cl_int createKernels(VECTOR_CLASS* kernels) + { + cl_uint numKernels; + cl_int err = ::clCreateKernelsInProgram(object_, 0, NULL, &numKernels); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __CREATE_KERNELS_IN_PROGRAM_ERR); + } + + Kernel* value = (Kernel*) alloca(numKernels * sizeof(Kernel)); + err = ::clCreateKernelsInProgram( + object_, numKernels, (cl_kernel*) value, NULL); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __CREATE_KERNELS_IN_PROGRAM_ERR); + } + + kernels->assign(&value[0], &value[numKernels]); + return CL_SUCCESS; + } +}; + +#if defined(CL_VERSION_1_2) +inline Program linkProgram( + Program input1, + Program input2, + const char* options = NULL, + void (CL_CALLBACK * notifyFptr)(cl_program, void *) = NULL, + void* data = NULL, + cl_int* err = NULL) +{ + cl_int error_local = CL_SUCCESS; + + cl_program programs[2] = { input1(), input2() }; + + Context ctx = input1.getInfo(&error_local); + if(error_local!=CL_SUCCESS) { + detail::errHandler(error_local, __LINK_PROGRAM_ERR); + } + + cl_program prog = ::clLinkProgram( + ctx(), + 0, + NULL, + options, + 2, + programs, + notifyFptr, + data, + &error_local); + + detail::errHandler(error_local,__COMPILE_PROGRAM_ERR); + if (err != NULL) { + *err = error_local; + } + + return Program(prog); +} + +inline Program linkProgram( + VECTOR_CLASS inputPrograms, + const char* options = NULL, + void (CL_CALLBACK * notifyFptr)(cl_program, void *) = NULL, + void* data = NULL, + cl_int* err = NULL) +{ + cl_int error_local = CL_SUCCESS; + + cl_program * programs = (cl_program*) alloca(inputPrograms.size() * sizeof(cl_program)); + + if (programs != NULL) { + for (unsigned int i = 0; i < inputPrograms.size(); i++) { + programs[i] = inputPrograms[i](); + } + } + + Context ctx; + if(inputPrograms.size() > 0) { + ctx = inputPrograms[0].getInfo(&error_local); + if(error_local!=CL_SUCCESS) { + detail::errHandler(error_local, __LINK_PROGRAM_ERR); + } + } + cl_program prog = ::clLinkProgram( + ctx(), + 0, + NULL, + options, + (cl_uint)inputPrograms.size(), + programs, + notifyFptr, + data, + &error_local); + + detail::errHandler(error_local,__COMPILE_PROGRAM_ERR); + if (err != NULL) { + *err = error_local; + } + + return Program(prog); +} +#endif + +template<> +inline VECTOR_CLASS cl::Program::getInfo(cl_int* err) const +{ + VECTOR_CLASS< ::size_t> sizes = getInfo(); + VECTOR_CLASS binaries; + for (VECTOR_CLASS< ::size_t>::iterator s = sizes.begin(); s != sizes.end(); ++s) + { + char *ptr = NULL; + if (*s != 0) + ptr = new char[*s]; + binaries.push_back(ptr); + } + + cl_int result = getInfo(CL_PROGRAM_BINARIES, &binaries); + if (err != NULL) { + *err = result; + } + return binaries; +} + +inline Kernel::Kernel(const Program& program, const char* name, cl_int* err) +{ + cl_int error; + + object_ = ::clCreateKernel(program(), name, &error); + detail::errHandler(error, __CREATE_KERNEL_ERR); + + if (err != NULL) { + *err = error; + } + +} + +/*! \class CommandQueue + * \brief CommandQueue interface for cl_command_queue. + */ +class CommandQueue : public detail::Wrapper +{ +private: +#ifdef CL_HPP_CPP11_ATOMICS_SUPPORTED + static std::atomic default_initialized_; +#else // !CL_HPP_CPP11_ATOMICS_SUPPORTED + static volatile int default_initialized_; +#endif // !CL_HPP_CPP11_ATOMICS_SUPPORTED + static CommandQueue default_; + static volatile cl_int default_error_; +public: + CommandQueue( + cl_command_queue_properties properties, + cl_int* err = NULL) + { + cl_int error; + + Context context = Context::getDefault(&error); + detail::errHandler(error, __CREATE_CONTEXT_ERR); + + if (error != CL_SUCCESS) { + if (err != NULL) { + *err = error; + } + } + else { + Device device = context.getInfo()[0]; + + object_ = ::clCreateCommandQueue( + context(), device(), properties, &error); + + detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR); + if (err != NULL) { + *err = error; + } + } + } + /*! + * \brief Constructs a CommandQueue for an implementation defined device in the given context + */ + explicit CommandQueue( + const Context& context, + cl_command_queue_properties properties = 0, + cl_int* err = NULL) + { + cl_int error; + VECTOR_CLASS devices; + error = context.getInfo(CL_CONTEXT_DEVICES, &devices); + + detail::errHandler(error, __CREATE_CONTEXT_ERR); + + if (error != CL_SUCCESS) + { + if (err != NULL) { + *err = error; + } + return; + } + + object_ = ::clCreateCommandQueue(context(), devices[0](), properties, &error); + + detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR); + + if (err != NULL) { + *err = error; + } + + } + + CommandQueue( + const Context& context, + const Device& device, + cl_command_queue_properties properties = 0, + cl_int* err = NULL) + { + cl_int error; + object_ = ::clCreateCommandQueue( + context(), device(), properties, &error); + + detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR); + if (err != NULL) { + *err = error; + } + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + CommandQueue(const CommandQueue& queue) : detail::Wrapper(queue) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + CommandQueue& operator = (const CommandQueue &queue) + { + detail::Wrapper::operator=(queue); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + CommandQueue(CommandQueue&& queue) CL_HPP_NOEXCEPT : detail::Wrapper(std::move(queue)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + CommandQueue& operator = (CommandQueue &&queue) + { + detail::Wrapper::operator=(std::move(queue)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + + static CommandQueue getDefault(cl_int * err = NULL) + { + int state = detail::compare_exchange( + &default_initialized_, + __DEFAULT_BEING_INITIALIZED, __DEFAULT_NOT_INITIALIZED); + + if (state & __DEFAULT_INITIALIZED) { + if (err != NULL) { + *err = default_error_; + } + return default_; + } + + if (state & __DEFAULT_BEING_INITIALIZED) { + // Assume writes will propagate eventually... + while(default_initialized_ != __DEFAULT_INITIALIZED) { + detail::fence(); + } + + if (err != NULL) { + *err = default_error_; + } + return default_; + } + + cl_int error; + + Context context = Context::getDefault(&error); + detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR); + + if (error != CL_SUCCESS) { + if (err != NULL) { + *err = error; + } + } + else { + Device device = context.getInfo()[0]; + + default_ = CommandQueue(context, device, 0, &error); + + detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR); + if (err != NULL) { + *err = error; + } + } + + detail::fence(); + + default_error_ = error; + // Assume writes will propagate eventually... + default_initialized_ = __DEFAULT_INITIALIZED; + + detail::fence(); + + if (err != NULL) { + *err = default_error_; + } + return default_; + + } + + CommandQueue() { } + + __CL_EXPLICIT_CONSTRUCTORS CommandQueue(const cl_command_queue& commandQueue) : detail::Wrapper(commandQueue) { } + + CommandQueue& operator = (const cl_command_queue& rhs) + { + detail::Wrapper::operator=(rhs); + return *this; + } + + template + cl_int getInfo(cl_command_queue_info name, T* param) const + { + return detail::errHandler( + detail::getInfo( + &::clGetCommandQueueInfo, object_, name, param), + __GET_COMMAND_QUEUE_INFO_ERR); + } + + template typename + detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_command_queue_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + + cl_int enqueueReadBuffer( + const Buffer& buffer, + cl_bool blocking, + ::size_t offset, + ::size_t size, + void* ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueReadBuffer( + object_, buffer(), blocking, offset, size, + ptr, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_READ_BUFFER_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueWriteBuffer( + const Buffer& buffer, + cl_bool blocking, + ::size_t offset, + ::size_t size, + const void* ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueWriteBuffer( + object_, buffer(), blocking, offset, size, + ptr, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_WRITE_BUFFER_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueCopyBuffer( + const Buffer& src, + const Buffer& dst, + ::size_t src_offset, + ::size_t dst_offset, + ::size_t size, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueCopyBuffer( + object_, src(), dst(), src_offset, dst_offset, size, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQEUE_COPY_BUFFER_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueReadBufferRect( + const Buffer& buffer, + cl_bool blocking, + const size_t<3>& buffer_offset, + const size_t<3>& host_offset, + const size_t<3>& region, + ::size_t buffer_row_pitch, + ::size_t buffer_slice_pitch, + ::size_t host_row_pitch, + ::size_t host_slice_pitch, + void *ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueReadBufferRect( + object_, + buffer(), + blocking, + (const ::size_t *)buffer_offset, + (const ::size_t *)host_offset, + (const ::size_t *)region, + buffer_row_pitch, + buffer_slice_pitch, + host_row_pitch, + host_slice_pitch, + ptr, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_READ_BUFFER_RECT_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueWriteBufferRect( + const Buffer& buffer, + cl_bool blocking, + const size_t<3>& buffer_offset, + const size_t<3>& host_offset, + const size_t<3>& region, + ::size_t buffer_row_pitch, + ::size_t buffer_slice_pitch, + ::size_t host_row_pitch, + ::size_t host_slice_pitch, + const void *ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueWriteBufferRect( + object_, + buffer(), + blocking, + (const ::size_t *)buffer_offset, + (const ::size_t *)host_offset, + (const ::size_t *)region, + buffer_row_pitch, + buffer_slice_pitch, + host_row_pitch, + host_slice_pitch, + ptr, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_WRITE_BUFFER_RECT_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueCopyBufferRect( + const Buffer& src, + const Buffer& dst, + const size_t<3>& src_origin, + const size_t<3>& dst_origin, + const size_t<3>& region, + ::size_t src_row_pitch, + ::size_t src_slice_pitch, + ::size_t dst_row_pitch, + ::size_t dst_slice_pitch, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueCopyBufferRect( + object_, + src(), + dst(), + (const ::size_t *)src_origin, + (const ::size_t *)dst_origin, + (const ::size_t *)region, + src_row_pitch, + src_slice_pitch, + dst_row_pitch, + dst_slice_pitch, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQEUE_COPY_BUFFER_RECT_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + +#if defined(CL_VERSION_1_2) + /** + * Enqueue a command to fill a buffer object with a pattern + * of a given size. The pattern is specified a as vector. + * \tparam PatternType The datatype of the pattern field. + * The pattern type must be an accepted OpenCL data type. + */ + template + cl_int enqueueFillBuffer( + const Buffer& buffer, + PatternType pattern, + ::size_t offset, + ::size_t size, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueFillBuffer( + object_, + buffer(), + static_cast(&pattern), + sizeof(PatternType), + offset, + size, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_FILL_BUFFER_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } +#endif // #if defined(CL_VERSION_1_2) + + cl_int enqueueReadImage( + const Image& image, + cl_bool blocking, + const size_t<3>& origin, + const size_t<3>& region, + ::size_t row_pitch, + ::size_t slice_pitch, + void* ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueReadImage( + object_, image(), blocking, (const ::size_t *) origin, + (const ::size_t *) region, row_pitch, slice_pitch, ptr, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_READ_IMAGE_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueWriteImage( + const Image& image, + cl_bool blocking, + const size_t<3>& origin, + const size_t<3>& region, + ::size_t row_pitch, + ::size_t slice_pitch, + const void* ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueWriteImage( + object_, image(), blocking, (const ::size_t *) origin, + (const ::size_t *) region, row_pitch, slice_pitch, ptr, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_WRITE_IMAGE_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueCopyImage( + const Image& src, + const Image& dst, + const size_t<3>& src_origin, + const size_t<3>& dst_origin, + const size_t<3>& region, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueCopyImage( + object_, src(), dst(), (const ::size_t *) src_origin, + (const ::size_t *)dst_origin, (const ::size_t *) region, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_COPY_IMAGE_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + +#if defined(CL_VERSION_1_2) + /** + * Enqueue a command to fill an image object with a specified color. + * \param fillColor is the color to use to fill the image. + * This is a four component RGBA floating-point color value if + * the image channel data type is not an unnormalized signed or + * unsigned data type. + */ + cl_int enqueueFillImage( + const Image& image, + cl_float4 fillColor, + const size_t<3>& origin, + const size_t<3>& region, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueFillImage( + object_, + image(), + static_cast(&fillColor), + (const ::size_t *) origin, + (const ::size_t *) region, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_FILL_IMAGE_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + /** + * Enqueue a command to fill an image object with a specified color. + * \param fillColor is the color to use to fill the image. + * This is a four component RGBA signed integer color value if + * the image channel data type is an unnormalized signed integer + * type. + */ + cl_int enqueueFillImage( + const Image& image, + cl_int4 fillColor, + const size_t<3>& origin, + const size_t<3>& region, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueFillImage( + object_, + image(), + static_cast(&fillColor), + (const ::size_t *) origin, + (const ::size_t *) region, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_FILL_IMAGE_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + /** + * Enqueue a command to fill an image object with a specified color. + * \param fillColor is the color to use to fill the image. + * This is a four component RGBA unsigned integer color value if + * the image channel data type is an unnormalized unsigned integer + * type. + */ + cl_int enqueueFillImage( + const Image& image, + cl_uint4 fillColor, + const size_t<3>& origin, + const size_t<3>& region, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueFillImage( + object_, + image(), + static_cast(&fillColor), + (const ::size_t *) origin, + (const ::size_t *) region, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_FILL_IMAGE_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } +#endif // #if defined(CL_VERSION_1_2) + + cl_int enqueueCopyImageToBuffer( + const Image& src, + const Buffer& dst, + const size_t<3>& src_origin, + const size_t<3>& region, + ::size_t dst_offset, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueCopyImageToBuffer( + object_, src(), dst(), (const ::size_t *) src_origin, + (const ::size_t *) region, dst_offset, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_COPY_IMAGE_TO_BUFFER_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueCopyBufferToImage( + const Buffer& src, + const Image& dst, + ::size_t src_offset, + const size_t<3>& dst_origin, + const size_t<3>& region, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueCopyBufferToImage( + object_, src(), dst(), src_offset, + (const ::size_t *) dst_origin, (const ::size_t *) region, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_COPY_BUFFER_TO_IMAGE_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + void* enqueueMapBuffer( + const Buffer& buffer, + cl_bool blocking, + cl_map_flags flags, + ::size_t offset, + ::size_t size, + const VECTOR_CLASS* events = NULL, + Event* event = NULL, + cl_int* err = NULL) const + { + cl_event tmp; + cl_int error; + void * result = ::clEnqueueMapBuffer( + object_, buffer(), blocking, flags, offset, size, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL, + &error); + + detail::errHandler(error, __ENQUEUE_MAP_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + if (event != NULL && error == CL_SUCCESS) + *event = tmp; + + return result; + } + + void* enqueueMapImage( + const Image& buffer, + cl_bool blocking, + cl_map_flags flags, + const size_t<3>& origin, + const size_t<3>& region, + ::size_t * row_pitch, + ::size_t * slice_pitch, + const VECTOR_CLASS* events = NULL, + Event* event = NULL, + cl_int* err = NULL) const + { + cl_event tmp; + cl_int error; + void * result = ::clEnqueueMapImage( + object_, buffer(), blocking, flags, + (const ::size_t *) origin, (const ::size_t *) region, + row_pitch, slice_pitch, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL, + &error); + + detail::errHandler(error, __ENQUEUE_MAP_IMAGE_ERR); + if (err != NULL) { + *err = error; + } + if (event != NULL && error == CL_SUCCESS) + *event = tmp; + return result; + } + + cl_int enqueueUnmapMemObject( + const Memory& memory, + void* mapped_ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueUnmapMemObject( + object_, memory(), mapped_ptr, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_UNMAP_MEM_OBJECT_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + +#if defined(CL_VERSION_1_2) + /** + * Enqueues a marker command which waits for either a list of events to complete, + * or all previously enqueued commands to complete. + * + * Enqueues a marker command which waits for either a list of events to complete, + * or if the list is empty it waits for all commands previously enqueued in command_queue + * to complete before it completes. This command returns an event which can be waited on, + * i.e. this event can be waited on to insure that all events either in the event_wait_list + * or all previously enqueued commands, queued before this command to command_queue, + * have completed. + */ + cl_int enqueueMarkerWithWaitList( + const VECTOR_CLASS *events = 0, + Event *event = 0) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueMarkerWithWaitList( + object_, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_MARKER_WAIT_LIST_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + /** + * A synchronization point that enqueues a barrier operation. + * + * Enqueues a barrier command which waits for either a list of events to complete, + * or if the list is empty it waits for all commands previously enqueued in command_queue + * to complete before it completes. This command blocks command execution, that is, any + * following commands enqueued after it do not execute until it completes. This command + * returns an event which can be waited on, i.e. this event can be waited on to insure that + * all events either in the event_wait_list or all previously enqueued commands, queued + * before this command to command_queue, have completed. + */ + cl_int enqueueBarrierWithWaitList( + const VECTOR_CLASS *events = 0, + Event *event = 0) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueBarrierWithWaitList( + object_, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_BARRIER_WAIT_LIST_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + /** + * Enqueues a command to indicate with which device a set of memory objects + * should be associated. + */ + cl_int enqueueMigrateMemObjects( + const VECTOR_CLASS &memObjects, + cl_mem_migration_flags flags, + const VECTOR_CLASS* events = NULL, + Event* event = NULL + ) const + { + cl_event tmp; + + cl_mem* localMemObjects = static_cast(alloca(memObjects.size() * sizeof(cl_mem))); + for( int i = 0; i < (int)memObjects.size(); ++i ) { + localMemObjects[i] = memObjects[i](); + } + + + cl_int err = detail::errHandler( + ::clEnqueueMigrateMemObjects( + object_, + (cl_uint)memObjects.size(), + static_cast(localMemObjects), + flags, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_UNMAP_MEM_OBJECT_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } +#endif // #if defined(CL_VERSION_1_2) + + cl_int enqueueNDRangeKernel( + const Kernel& kernel, + const NDRange& offset, + const NDRange& global, + const NDRange& local = NullRange, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueNDRangeKernel( + object_, kernel(), (cl_uint) global.dimensions(), + offset.dimensions() != 0 ? (const ::size_t*) offset : NULL, + (const ::size_t*) global, + local.dimensions() != 0 ? (const ::size_t*) local : NULL, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_NDRANGE_KERNEL_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueTask( + const Kernel& kernel, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueTask( + object_, kernel(), + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_TASK_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueNativeKernel( + void (CL_CALLBACK *userFptr)(void *), + std::pair args, + const VECTOR_CLASS* mem_objects = NULL, + const VECTOR_CLASS* mem_locs = NULL, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_mem * mems = (mem_objects != NULL && mem_objects->size() > 0) + ? (cl_mem*) alloca(mem_objects->size() * sizeof(cl_mem)) + : NULL; + + if (mems != NULL) { + for (unsigned int i = 0; i < mem_objects->size(); i++) { + mems[i] = ((*mem_objects)[i])(); + } + } + + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueNativeKernel( + object_, userFptr, args.first, args.second, + (mem_objects != NULL) ? (cl_uint) mem_objects->size() : 0, + mems, + (mem_locs != NULL && mem_locs->size() > 0) ? (const void **) &mem_locs->front() : NULL, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_NATIVE_KERNEL); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + +/** + * Deprecated APIs for 1.2 + */ +#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) || (defined(CL_VERSION_1_1) && !defined(CL_VERSION_1_2)) + CL_EXT_PREFIX__VERSION_1_1_DEPRECATED + cl_int enqueueMarker(Event* event = NULL) const CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueMarker( + object_, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_MARKER_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + CL_EXT_PREFIX__VERSION_1_1_DEPRECATED + cl_int enqueueWaitForEvents(const VECTOR_CLASS& events) const CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED + { + return detail::errHandler( + ::clEnqueueWaitForEvents( + object_, + (cl_uint) events.size(), + events.size() > 0 ? (const cl_event*) &events.front() : NULL), + __ENQUEUE_WAIT_FOR_EVENTS_ERR); + } +#endif // #if defined(CL_VERSION_1_1) + + cl_int enqueueAcquireGLObjects( + const VECTOR_CLASS* mem_objects = NULL, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueAcquireGLObjects( + object_, + (mem_objects != NULL) ? (cl_uint) mem_objects->size() : 0, + (mem_objects != NULL && mem_objects->size() > 0) ? (const cl_mem *) &mem_objects->front(): NULL, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_ACQUIRE_GL_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueReleaseGLObjects( + const VECTOR_CLASS* mem_objects = NULL, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueReleaseGLObjects( + object_, + (mem_objects != NULL) ? (cl_uint) mem_objects->size() : 0, + (mem_objects != NULL && mem_objects->size() > 0) ? (const cl_mem *) &mem_objects->front(): NULL, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_RELEASE_GL_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + +#if defined (USE_DX_INTEROP) +typedef CL_API_ENTRY cl_int (CL_API_CALL *PFN_clEnqueueAcquireD3D10ObjectsKHR)( + cl_command_queue command_queue, cl_uint num_objects, + const cl_mem* mem_objects, cl_uint num_events_in_wait_list, + const cl_event* event_wait_list, cl_event* event); +typedef CL_API_ENTRY cl_int (CL_API_CALL *PFN_clEnqueueReleaseD3D10ObjectsKHR)( + cl_command_queue command_queue, cl_uint num_objects, + const cl_mem* mem_objects, cl_uint num_events_in_wait_list, + const cl_event* event_wait_list, cl_event* event); + + cl_int enqueueAcquireD3D10Objects( + const VECTOR_CLASS* mem_objects = NULL, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + static PFN_clEnqueueAcquireD3D10ObjectsKHR pfn_clEnqueueAcquireD3D10ObjectsKHR = NULL; +#if defined(CL_VERSION_1_2) + cl_context context = getInfo(); + cl::Device device(getInfo()); + cl_platform_id platform = device.getInfo(); + __INIT_CL_EXT_FCN_PTR_PLATFORM(platform, clEnqueueAcquireD3D10ObjectsKHR); +#endif +#if defined(CL_VERSION_1_1) + __INIT_CL_EXT_FCN_PTR(clEnqueueAcquireD3D10ObjectsKHR); +#endif + + cl_event tmp; + cl_int err = detail::errHandler( + pfn_clEnqueueAcquireD3D10ObjectsKHR( + object_, + (mem_objects != NULL) ? (cl_uint) mem_objects->size() : 0, + (mem_objects != NULL && mem_objects->size() > 0) ? (const cl_mem *) &mem_objects->front(): NULL, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_ACQUIRE_GL_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueReleaseD3D10Objects( + const VECTOR_CLASS* mem_objects = NULL, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + static PFN_clEnqueueReleaseD3D10ObjectsKHR pfn_clEnqueueReleaseD3D10ObjectsKHR = NULL; +#if defined(CL_VERSION_1_2) + cl_context context = getInfo(); + cl::Device device(getInfo()); + cl_platform_id platform = device.getInfo(); + __INIT_CL_EXT_FCN_PTR_PLATFORM(platform, clEnqueueReleaseD3D10ObjectsKHR); +#endif // #if defined(CL_VERSION_1_2) +#if defined(CL_VERSION_1_1) + __INIT_CL_EXT_FCN_PTR(clEnqueueReleaseD3D10ObjectsKHR); +#endif // #if defined(CL_VERSION_1_1) + + cl_event tmp; + cl_int err = detail::errHandler( + pfn_clEnqueueReleaseD3D10ObjectsKHR( + object_, + (mem_objects != NULL) ? (cl_uint) mem_objects->size() : 0, + (mem_objects != NULL && mem_objects->size() > 0) ? (const cl_mem *) &mem_objects->front(): NULL, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_RELEASE_GL_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } +#endif + +/** + * Deprecated APIs for 1.2 + */ +#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) || (defined(CL_VERSION_1_1) && !defined(CL_VERSION_1_2)) + CL_EXT_PREFIX__VERSION_1_1_DEPRECATED + cl_int enqueueBarrier() const CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED + { + return detail::errHandler( + ::clEnqueueBarrier(object_), + __ENQUEUE_BARRIER_ERR); + } +#endif // #if defined(CL_VERSION_1_1) + + cl_int flush() const + { + return detail::errHandler(::clFlush(object_), __FLUSH_ERR); + } + + cl_int finish() const + { + return detail::errHandler(::clFinish(object_), __FINISH_ERR); + } +}; + +#ifdef _WIN32 +#ifdef CL_HPP_CPP11_ATOMICS_SUPPORTED +__declspec(selectany) std::atomic CommandQueue::default_initialized_; +#else // !CL_HPP_CPP11_ATOMICS_SUPPORTED +__declspec(selectany) volatile int CommandQueue::default_initialized_ = __DEFAULT_NOT_INITIALIZED; +#endif // !CL_HPP_CPP11_ATOMICS_SUPPORTED +__declspec(selectany) CommandQueue CommandQueue::default_; +__declspec(selectany) volatile cl_int CommandQueue::default_error_ = CL_SUCCESS; +#else // !_WIN32 +#ifdef CL_HPP_CPP11_ATOMICS_SUPPORTED +__attribute__((weak)) std::atomic CommandQueue::default_initialized_; +#else // !CL_HPP_CPP11_ATOMICS_SUPPORTED +__attribute__((weak)) volatile int CommandQueue::default_initialized_ = __DEFAULT_NOT_INITIALIZED; +#endif // !CL_HPP_CPP11_ATOMICS_SUPPORTED +__attribute__((weak)) CommandQueue CommandQueue::default_; +__attribute__((weak)) volatile cl_int CommandQueue::default_error_ = CL_SUCCESS; +#endif // !_WIN32 + +template< typename IteratorType > +Buffer::Buffer( + const Context &context, + IteratorType startIterator, + IteratorType endIterator, + bool readOnly, + bool useHostPtr, + cl_int* err) +{ + typedef typename std::iterator_traits::value_type DataType; + cl_int error; + + cl_mem_flags flags = 0; + if( readOnly ) { + flags |= CL_MEM_READ_ONLY; + } + else { + flags |= CL_MEM_READ_WRITE; + } + if( useHostPtr ) { + flags |= CL_MEM_USE_HOST_PTR; + } + + ::size_t size = sizeof(DataType)*(endIterator - startIterator); + + if( useHostPtr ) { + object_ = ::clCreateBuffer(context(), flags, size, static_cast(&*startIterator), &error); + } else { + object_ = ::clCreateBuffer(context(), flags, size, 0, &error); + } + + detail::errHandler(error, __CREATE_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + + if( !useHostPtr ) { + CommandQueue queue(context, 0, &error); + detail::errHandler(error, __CREATE_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + + error = cl::copy(queue, startIterator, endIterator, *this); + detail::errHandler(error, __CREATE_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + } +} + +template< typename IteratorType > +Buffer::Buffer( + const CommandQueue &queue, + IteratorType startIterator, + IteratorType endIterator, + bool readOnly, + bool useHostPtr, + cl_int* err) +{ + typedef typename std::iterator_traits::value_type DataType; + cl_int error; + + cl_mem_flags flags = 0; + if (readOnly) { + flags |= CL_MEM_READ_ONLY; + } + else { + flags |= CL_MEM_READ_WRITE; + } + if (useHostPtr) { + flags |= CL_MEM_USE_HOST_PTR; + } + + ::size_t size = sizeof(DataType)*(endIterator - startIterator); + + Context context = queue.getInfo(); + + if (useHostPtr) { + object_ = ::clCreateBuffer(context(), flags, size, static_cast(&*startIterator), &error); + } + else { + object_ = ::clCreateBuffer(context(), flags, size, 0, &error); + } + + detail::errHandler(error, __CREATE_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + + if (!useHostPtr) { + error = cl::copy(queue, startIterator, endIterator, *this); + detail::errHandler(error, __CREATE_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + } +} + +inline cl_int enqueueReadBuffer( + const Buffer& buffer, + cl_bool blocking, + ::size_t offset, + ::size_t size, + void* ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) { + return error; + } + + return queue.enqueueReadBuffer(buffer, blocking, offset, size, ptr, events, event); +} + +inline cl_int enqueueWriteBuffer( + const Buffer& buffer, + cl_bool blocking, + ::size_t offset, + ::size_t size, + const void* ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) { + return error; + } + + return queue.enqueueWriteBuffer(buffer, blocking, offset, size, ptr, events, event); +} + +inline void* enqueueMapBuffer( + const Buffer& buffer, + cl_bool blocking, + cl_map_flags flags, + ::size_t offset, + ::size_t size, + const VECTOR_CLASS* events = NULL, + Event* event = NULL, + cl_int* err = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + detail::errHandler(error, __ENQUEUE_MAP_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + + void * result = ::clEnqueueMapBuffer( + queue(), buffer(), blocking, flags, offset, size, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (cl_event*) event, + &error); + + detail::errHandler(error, __ENQUEUE_MAP_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + return result; +} + +inline cl_int enqueueUnmapMemObject( + const Memory& memory, + void* mapped_ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + detail::errHandler(error, __ENQUEUE_MAP_BUFFER_ERR); + if (error != CL_SUCCESS) { + return error; + } + + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueUnmapMemObject( + queue(), memory(), mapped_ptr, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_UNMAP_MEM_OBJECT_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; +} + +inline cl_int enqueueCopyBuffer( + const Buffer& src, + const Buffer& dst, + ::size_t src_offset, + ::size_t dst_offset, + ::size_t size, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) { + return error; + } + + return queue.enqueueCopyBuffer(src, dst, src_offset, dst_offset, size, events, event); +} + +/** + * Blocking copy operation between iterators and a buffer. + * Host to Device. + * Uses default command queue. + */ +template< typename IteratorType > +inline cl_int copy( IteratorType startIterator, IteratorType endIterator, cl::Buffer &buffer ) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + if (error != CL_SUCCESS) + return error; + + return cl::copy(queue, startIterator, endIterator, buffer); +} + +/** + * Blocking copy operation between iterators and a buffer. + * Device to Host. + * Uses default command queue. + */ +template< typename IteratorType > +inline cl_int copy( const cl::Buffer &buffer, IteratorType startIterator, IteratorType endIterator ) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + if (error != CL_SUCCESS) + return error; + + return cl::copy(queue, buffer, startIterator, endIterator); +} + +/** + * Blocking copy operation between iterators and a buffer. + * Host to Device. + * Uses specified queue. + */ +template< typename IteratorType > +inline cl_int copy( const CommandQueue &queue, IteratorType startIterator, IteratorType endIterator, cl::Buffer &buffer ) +{ + typedef typename std::iterator_traits::value_type DataType; + cl_int error; + + ::size_t length = endIterator-startIterator; + ::size_t byteLength = length*sizeof(DataType); + + DataType *pointer = + static_cast(queue.enqueueMapBuffer(buffer, CL_TRUE, CL_MAP_WRITE, 0, byteLength, 0, 0, &error)); + // if exceptions enabled, enqueueMapBuffer will throw + if( error != CL_SUCCESS ) { + return error; + } +#if defined(_MSC_VER) + std::copy( + startIterator, + endIterator, + stdext::checked_array_iterator( + pointer, length)); +#else + std::copy(startIterator, endIterator, pointer); +#endif + Event endEvent; + error = queue.enqueueUnmapMemObject(buffer, pointer, 0, &endEvent); + // if exceptions enabled, enqueueUnmapMemObject will throw + if( error != CL_SUCCESS ) { + return error; + } + endEvent.wait(); + return CL_SUCCESS; +} + +/** + * Blocking copy operation between iterators and a buffer. + * Device to Host. + * Uses specified queue. + */ +template< typename IteratorType > +inline cl_int copy( const CommandQueue &queue, const cl::Buffer &buffer, IteratorType startIterator, IteratorType endIterator ) +{ + typedef typename std::iterator_traits::value_type DataType; + cl_int error; + + ::size_t length = endIterator-startIterator; + ::size_t byteLength = length*sizeof(DataType); + + DataType *pointer = + static_cast(queue.enqueueMapBuffer(buffer, CL_TRUE, CL_MAP_READ, 0, byteLength, 0, 0, &error)); + // if exceptions enabled, enqueueMapBuffer will throw + if( error != CL_SUCCESS ) { + return error; + } + std::copy(pointer, pointer + length, startIterator); + Event endEvent; + error = queue.enqueueUnmapMemObject(buffer, pointer, 0, &endEvent); + // if exceptions enabled, enqueueUnmapMemObject will throw + if( error != CL_SUCCESS ) { + return error; + } + endEvent.wait(); + return CL_SUCCESS; +} + +#if defined(CL_VERSION_1_1) +inline cl_int enqueueReadBufferRect( + const Buffer& buffer, + cl_bool blocking, + const size_t<3>& buffer_offset, + const size_t<3>& host_offset, + const size_t<3>& region, + ::size_t buffer_row_pitch, + ::size_t buffer_slice_pitch, + ::size_t host_row_pitch, + ::size_t host_slice_pitch, + void *ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) { + return error; + } + + return queue.enqueueReadBufferRect( + buffer, + blocking, + buffer_offset, + host_offset, + region, + buffer_row_pitch, + buffer_slice_pitch, + host_row_pitch, + host_slice_pitch, + ptr, + events, + event); +} + +inline cl_int enqueueWriteBufferRect( + const Buffer& buffer, + cl_bool blocking, + const size_t<3>& buffer_offset, + const size_t<3>& host_offset, + const size_t<3>& region, + ::size_t buffer_row_pitch, + ::size_t buffer_slice_pitch, + ::size_t host_row_pitch, + ::size_t host_slice_pitch, + const void *ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) { + return error; + } + + return queue.enqueueWriteBufferRect( + buffer, + blocking, + buffer_offset, + host_offset, + region, + buffer_row_pitch, + buffer_slice_pitch, + host_row_pitch, + host_slice_pitch, + ptr, + events, + event); +} + +inline cl_int enqueueCopyBufferRect( + const Buffer& src, + const Buffer& dst, + const size_t<3>& src_origin, + const size_t<3>& dst_origin, + const size_t<3>& region, + ::size_t src_row_pitch, + ::size_t src_slice_pitch, + ::size_t dst_row_pitch, + ::size_t dst_slice_pitch, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) { + return error; + } + + return queue.enqueueCopyBufferRect( + src, + dst, + src_origin, + dst_origin, + region, + src_row_pitch, + src_slice_pitch, + dst_row_pitch, + dst_slice_pitch, + events, + event); +} +#endif + +inline cl_int enqueueReadImage( + const Image& image, + cl_bool blocking, + const size_t<3>& origin, + const size_t<3>& region, + ::size_t row_pitch, + ::size_t slice_pitch, + void* ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) { + return error; + } + + return queue.enqueueReadImage( + image, + blocking, + origin, + region, + row_pitch, + slice_pitch, + ptr, + events, + event); +} + +inline cl_int enqueueWriteImage( + const Image& image, + cl_bool blocking, + const size_t<3>& origin, + const size_t<3>& region, + ::size_t row_pitch, + ::size_t slice_pitch, + const void* ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) { + return error; + } + + return queue.enqueueWriteImage( + image, + blocking, + origin, + region, + row_pitch, + slice_pitch, + ptr, + events, + event); +} + +inline cl_int enqueueCopyImage( + const Image& src, + const Image& dst, + const size_t<3>& src_origin, + const size_t<3>& dst_origin, + const size_t<3>& region, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) { + return error; + } + + return queue.enqueueCopyImage( + src, + dst, + src_origin, + dst_origin, + region, + events, + event); +} + +inline cl_int enqueueCopyImageToBuffer( + const Image& src, + const Buffer& dst, + const size_t<3>& src_origin, + const size_t<3>& region, + ::size_t dst_offset, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) { + return error; + } + + return queue.enqueueCopyImageToBuffer( + src, + dst, + src_origin, + region, + dst_offset, + events, + event); +} + +inline cl_int enqueueCopyBufferToImage( + const Buffer& src, + const Image& dst, + ::size_t src_offset, + const size_t<3>& dst_origin, + const size_t<3>& region, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) { + return error; + } + + return queue.enqueueCopyBufferToImage( + src, + dst, + src_offset, + dst_origin, + region, + events, + event); +} + + +inline cl_int flush(void) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) { + return error; + } + + return queue.flush(); +} + +inline cl_int finish(void) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) { + return error; + } + + + return queue.finish(); +} + +// Kernel Functor support +// New interface as of September 2011 +// Requires the C++11 std::tr1::function (note do not support TR1) +// Visual Studio 2010 and GCC 4.2 + +struct EnqueueArgs +{ + CommandQueue queue_; + const NDRange offset_; + const NDRange global_; + const NDRange local_; + VECTOR_CLASS events_; + + EnqueueArgs(NDRange global) : + queue_(CommandQueue::getDefault()), + offset_(NullRange), + global_(global), + local_(NullRange) + { + + } + + EnqueueArgs(NDRange global, NDRange local) : + queue_(CommandQueue::getDefault()), + offset_(NullRange), + global_(global), + local_(local) + { + + } + + EnqueueArgs(NDRange offset, NDRange global, NDRange local) : + queue_(CommandQueue::getDefault()), + offset_(offset), + global_(global), + local_(local) + { + + } + + EnqueueArgs(Event e, NDRange global) : + queue_(CommandQueue::getDefault()), + offset_(NullRange), + global_(global), + local_(NullRange) + { + events_.push_back(e); + } + + EnqueueArgs(Event e, NDRange global, NDRange local) : + queue_(CommandQueue::getDefault()), + offset_(NullRange), + global_(global), + local_(local) + { + events_.push_back(e); + } + + EnqueueArgs(Event e, NDRange offset, NDRange global, NDRange local) : + queue_(CommandQueue::getDefault()), + offset_(offset), + global_(global), + local_(local) + { + events_.push_back(e); + } + + EnqueueArgs(const VECTOR_CLASS &events, NDRange global) : + queue_(CommandQueue::getDefault()), + offset_(NullRange), + global_(global), + local_(NullRange), + events_(events) + { + + } + + EnqueueArgs(const VECTOR_CLASS &events, NDRange global, NDRange local) : + queue_(CommandQueue::getDefault()), + offset_(NullRange), + global_(global), + local_(local), + events_(events) + { + + } + + EnqueueArgs(const VECTOR_CLASS &events, NDRange offset, NDRange global, NDRange local) : + queue_(CommandQueue::getDefault()), + offset_(offset), + global_(global), + local_(local), + events_(events) + { + + } + + EnqueueArgs(CommandQueue &queue, NDRange global) : + queue_(queue), + offset_(NullRange), + global_(global), + local_(NullRange) + { + + } + + EnqueueArgs(CommandQueue &queue, NDRange global, NDRange local) : + queue_(queue), + offset_(NullRange), + global_(global), + local_(local) + { + + } + + EnqueueArgs(CommandQueue &queue, NDRange offset, NDRange global, NDRange local) : + queue_(queue), + offset_(offset), + global_(global), + local_(local) + { + + } + + EnqueueArgs(CommandQueue &queue, Event e, NDRange global) : + queue_(queue), + offset_(NullRange), + global_(global), + local_(NullRange) + { + events_.push_back(e); + } + + EnqueueArgs(CommandQueue &queue, Event e, NDRange global, NDRange local) : + queue_(queue), + offset_(NullRange), + global_(global), + local_(local) + { + events_.push_back(e); + } + + EnqueueArgs(CommandQueue &queue, Event e, NDRange offset, NDRange global, NDRange local) : + queue_(queue), + offset_(offset), + global_(global), + local_(local) + { + events_.push_back(e); + } + + EnqueueArgs(CommandQueue &queue, const VECTOR_CLASS &events, NDRange global) : + queue_(queue), + offset_(NullRange), + global_(global), + local_(NullRange), + events_(events) + { + + } + + EnqueueArgs(CommandQueue &queue, const VECTOR_CLASS &events, NDRange global, NDRange local) : + queue_(queue), + offset_(NullRange), + global_(global), + local_(local), + events_(events) + { + + } + + EnqueueArgs(CommandQueue &queue, const VECTOR_CLASS &events, NDRange offset, NDRange global, NDRange local) : + queue_(queue), + offset_(offset), + global_(global), + local_(local), + events_(events) + { + + } +}; + +namespace detail { + +class NullType {}; + +template +struct SetArg +{ + static void set (Kernel kernel, T0 arg) + { + kernel.setArg(index, arg); + } +}; + +template +struct SetArg +{ + static void set (Kernel, NullType) + { + } +}; + +template < + typename T0, typename T1, typename T2, typename T3, + typename T4, typename T5, typename T6, typename T7, + typename T8, typename T9, typename T10, typename T11, + typename T12, typename T13, typename T14, typename T15, + typename T16, typename T17, typename T18, typename T19, + typename T20, typename T21, typename T22, typename T23, + typename T24, typename T25, typename T26, typename T27, + typename T28, typename T29, typename T30, typename T31 + +> +class KernelFunctorGlobal +{ +private: + Kernel kernel_; + +public: + KernelFunctorGlobal( + Kernel kernel) : + kernel_(kernel) + {} + + KernelFunctorGlobal( + const Program& program, + const STRING_CLASS name, + cl_int * err = NULL) : + kernel_(program, name.c_str(), err) + {} + + Event operator() ( + const EnqueueArgs& args, + T0 t0, + T1 t1 = NullType(), + T2 t2 = NullType(), + T3 t3 = NullType(), + T4 t4 = NullType(), + T5 t5 = NullType(), + T6 t6 = NullType(), + T7 t7 = NullType(), + T8 t8 = NullType(), + T9 t9 = NullType(), + T10 t10 = NullType(), + T11 t11 = NullType(), + T12 t12 = NullType(), + T13 t13 = NullType(), + T14 t14 = NullType(), + T15 t15 = NullType(), + T16 t16 = NullType(), + T17 t17 = NullType(), + T18 t18 = NullType(), + T19 t19 = NullType(), + T20 t20 = NullType(), + T21 t21 = NullType(), + T22 t22 = NullType(), + T23 t23 = NullType(), + T24 t24 = NullType(), + T25 t25 = NullType(), + T26 t26 = NullType(), + T27 t27 = NullType(), + T28 t28 = NullType(), + T29 t29 = NullType(), + T30 t30 = NullType(), + T31 t31 = NullType() + + ) + { + Event event; + SetArg<0, T0>::set(kernel_, t0); + SetArg<1, T1>::set(kernel_, t1); + SetArg<2, T2>::set(kernel_, t2); + SetArg<3, T3>::set(kernel_, t3); + SetArg<4, T4>::set(kernel_, t4); + SetArg<5, T5>::set(kernel_, t5); + SetArg<6, T6>::set(kernel_, t6); + SetArg<7, T7>::set(kernel_, t7); + SetArg<8, T8>::set(kernel_, t8); + SetArg<9, T9>::set(kernel_, t9); + SetArg<10, T10>::set(kernel_, t10); + SetArg<11, T11>::set(kernel_, t11); + SetArg<12, T12>::set(kernel_, t12); + SetArg<13, T13>::set(kernel_, t13); + SetArg<14, T14>::set(kernel_, t14); + SetArg<15, T15>::set(kernel_, t15); + SetArg<16, T16>::set(kernel_, t16); + SetArg<17, T17>::set(kernel_, t17); + SetArg<18, T18>::set(kernel_, t18); + SetArg<19, T19>::set(kernel_, t19); + SetArg<20, T20>::set(kernel_, t20); + SetArg<21, T21>::set(kernel_, t21); + SetArg<22, T22>::set(kernel_, t22); + SetArg<23, T23>::set(kernel_, t23); + SetArg<24, T24>::set(kernel_, t24); + SetArg<25, T25>::set(kernel_, t25); + SetArg<26, T26>::set(kernel_, t26); + SetArg<27, T27>::set(kernel_, t27); + SetArg<28, T28>::set(kernel_, t28); + SetArg<29, T29>::set(kernel_, t29); + SetArg<30, T30>::set(kernel_, t30); + SetArg<31, T31>::set(kernel_, t31); + + + args.queue_.enqueueNDRangeKernel( + kernel_, + args.offset_, + args.global_, + args.local_, + &args.events_, + &event); + + return event; + } + +}; + +//------------------------------------------------------------------------------------------------------ + + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21, + typename T22, + typename T23, + typename T24, + typename T25, + typename T26, + typename T27, + typename T28, + typename T29, + typename T30, + typename T31> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + T28, + T29, + T30, + T31> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 32)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + T28, + T29, + T30, + T31); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21, + T22 arg22, + T23 arg23, + T24 arg24, + T25 arg25, + T26 arg26, + T27 arg27, + T28 arg28, + T29 arg29, + T30 arg30, + T31 arg31) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21, + arg22, + arg23, + arg24, + arg25, + arg26, + arg27, + arg28, + arg29, + arg30, + arg31); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21, + typename T22, + typename T23, + typename T24, + typename T25, + typename T26, + typename T27, + typename T28, + typename T29, + typename T30> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + T28, + T29, + T30, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + T28, + T29, + T30, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 31)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + T28, + T29, + T30); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21, + T22 arg22, + T23 arg23, + T24 arg24, + T25 arg25, + T26 arg26, + T27 arg27, + T28 arg28, + T29 arg29, + T30 arg30) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21, + arg22, + arg23, + arg24, + arg25, + arg26, + arg27, + arg28, + arg29, + arg30); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21, + typename T22, + typename T23, + typename T24, + typename T25, + typename T26, + typename T27, + typename T28, + typename T29> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + T28, + T29, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + T28, + T29, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 30)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + T28, + T29); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21, + T22 arg22, + T23 arg23, + T24 arg24, + T25 arg25, + T26 arg26, + T27 arg27, + T28 arg28, + T29 arg29) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21, + arg22, + arg23, + arg24, + arg25, + arg26, + arg27, + arg28, + arg29); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21, + typename T22, + typename T23, + typename T24, + typename T25, + typename T26, + typename T27, + typename T28> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + T28, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + T28, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 29)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + T28); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21, + T22 arg22, + T23 arg23, + T24 arg24, + T25 arg25, + T26 arg26, + T27 arg27, + T28 arg28) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21, + arg22, + arg23, + arg24, + arg25, + arg26, + arg27, + arg28); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21, + typename T22, + typename T23, + typename T24, + typename T25, + typename T26, + typename T27> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 28)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21, + T22 arg22, + T23 arg23, + T24 arg24, + T25 arg25, + T26 arg26, + T27 arg27) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21, + arg22, + arg23, + arg24, + arg25, + arg26, + arg27); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21, + typename T22, + typename T23, + typename T24, + typename T25, + typename T26> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 27)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21, + T22 arg22, + T23 arg23, + T24 arg24, + T25 arg25, + T26 arg26) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21, + arg22, + arg23, + arg24, + arg25, + arg26); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21, + typename T22, + typename T23, + typename T24, + typename T25> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 26)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21, + T22 arg22, + T23 arg23, + T24 arg24, + T25 arg25) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21, + arg22, + arg23, + arg24, + arg25); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21, + typename T22, + typename T23, + typename T24> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 25)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21, + T22 arg22, + T23 arg23, + T24 arg24) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21, + arg22, + arg23, + arg24); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21, + typename T22, + typename T23> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 24)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21, + T22 arg22, + T23 arg23) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21, + arg22, + arg23); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21, + typename T22> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 23)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21, + T22 arg22) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21, + arg22); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 22)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 21)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 20)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 19)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 18)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 17)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 16)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 15)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 14)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 13)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 12)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 11)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 10)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 9)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 8)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 7)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 6)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 5)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 4)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3); + } + + +}; + +template< + typename T0, + typename T1, + typename T2> +struct functionImplementation_ +< T0, + T1, + T2, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 3)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2); + } + + +}; + +template< + typename T0, + typename T1> +struct functionImplementation_ +< T0, + T1, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 2)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1) + { + return functor_( + enqueueArgs, + arg0, + arg1); + } + + +}; + +template< + typename T0> +struct functionImplementation_ +< T0, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 1)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0) + { + return functor_( + enqueueArgs, + arg0); + } + + +}; + + + + + +} // namespace detail + +//---------------------------------------------------------------------------------------------- + +template < + typename T0, typename T1 = detail::NullType, typename T2 = detail::NullType, + typename T3 = detail::NullType, typename T4 = detail::NullType, + typename T5 = detail::NullType, typename T6 = detail::NullType, + typename T7 = detail::NullType, typename T8 = detail::NullType, + typename T9 = detail::NullType, typename T10 = detail::NullType, + typename T11 = detail::NullType, typename T12 = detail::NullType, + typename T13 = detail::NullType, typename T14 = detail::NullType, + typename T15 = detail::NullType, typename T16 = detail::NullType, + typename T17 = detail::NullType, typename T18 = detail::NullType, + typename T19 = detail::NullType, typename T20 = detail::NullType, + typename T21 = detail::NullType, typename T22 = detail::NullType, + typename T23 = detail::NullType, typename T24 = detail::NullType, + typename T25 = detail::NullType, typename T26 = detail::NullType, + typename T27 = detail::NullType, typename T28 = detail::NullType, + typename T29 = detail::NullType, typename T30 = detail::NullType, + typename T31 = detail::NullType + +> +struct make_kernel : + public detail::functionImplementation_< + T0, T1, T2, T3, + T4, T5, T6, T7, + T8, T9, T10, T11, + T12, T13, T14, T15, + T16, T17, T18, T19, + T20, T21, T22, T23, + T24, T25, T26, T27, + T28, T29, T30, T31 + + > +{ +public: + typedef detail::KernelFunctorGlobal< + T0, T1, T2, T3, + T4, T5, T6, T7, + T8, T9, T10, T11, + T12, T13, T14, T15, + T16, T17, T18, T19, + T20, T21, T22, T23, + T24, T25, T26, T27, + T28, T29, T30, T31 + + > FunctorType; + + make_kernel( + const Program& program, + const STRING_CLASS name, + cl_int * err = NULL) : + detail::functionImplementation_< + T0, T1, T2, T3, + T4, T5, T6, T7, + T8, T9, T10, T11, + T12, T13, T14, T15, + T16, T17, T18, T19, + T20, T21, T22, T23, + T24, T25, T26, T27, + T28, T29, T30, T31 + + >( + FunctorType(program, name, err)) + {} + + make_kernel( + const Kernel kernel) : + detail::functionImplementation_< + T0, T1, T2, T3, + T4, T5, T6, T7, + T8, T9, T10, T11, + T12, T13, T14, T15, + T16, T17, T18, T19, + T20, T21, T22, T23, + T24, T25, T26, T27, + T28, T29, T30, T31 + + >( + FunctorType(kernel)) + {} +}; + + +//---------------------------------------------------------------------------------------------------------------------- + +#undef __ERR_STR +#if !defined(__CL_USER_OVERRIDE_ERROR_STRINGS) +#undef __GET_DEVICE_INFO_ERR +#undef __GET_PLATFORM_INFO_ERR +#undef __GET_DEVICE_IDS_ERR +#undef __GET_CONTEXT_INFO_ERR +#undef __GET_EVENT_INFO_ERR +#undef __GET_EVENT_PROFILE_INFO_ERR +#undef __GET_MEM_OBJECT_INFO_ERR +#undef __GET_IMAGE_INFO_ERR +#undef __GET_SAMPLER_INFO_ERR +#undef __GET_KERNEL_INFO_ERR +#undef __GET_KERNEL_ARG_INFO_ERR +#undef __GET_KERNEL_WORK_GROUP_INFO_ERR +#undef __GET_PROGRAM_INFO_ERR +#undef __GET_PROGRAM_BUILD_INFO_ERR +#undef __GET_COMMAND_QUEUE_INFO_ERR + +#undef __CREATE_CONTEXT_ERR +#undef __CREATE_CONTEXT_FROM_TYPE_ERR +#undef __GET_SUPPORTED_IMAGE_FORMATS_ERR + +#undef __CREATE_BUFFER_ERR +#undef __CREATE_SUBBUFFER_ERR +#undef __CREATE_IMAGE2D_ERR +#undef __CREATE_IMAGE3D_ERR +#undef __CREATE_SAMPLER_ERR +#undef __SET_MEM_OBJECT_DESTRUCTOR_CALLBACK_ERR + +#undef __CREATE_USER_EVENT_ERR +#undef __SET_USER_EVENT_STATUS_ERR +#undef __SET_EVENT_CALLBACK_ERR +#undef __SET_PRINTF_CALLBACK_ERR + +#undef __WAIT_FOR_EVENTS_ERR + +#undef __CREATE_KERNEL_ERR +#undef __SET_KERNEL_ARGS_ERR +#undef __CREATE_PROGRAM_WITH_SOURCE_ERR +#undef __CREATE_PROGRAM_WITH_BINARY_ERR +#undef __CREATE_PROGRAM_WITH_BUILT_IN_KERNELS_ERR +#undef __BUILD_PROGRAM_ERR +#undef __CREATE_KERNELS_IN_PROGRAM_ERR + +#undef __CREATE_COMMAND_QUEUE_ERR +#undef __SET_COMMAND_QUEUE_PROPERTY_ERR +#undef __ENQUEUE_READ_BUFFER_ERR +#undef __ENQUEUE_WRITE_BUFFER_ERR +#undef __ENQUEUE_READ_BUFFER_RECT_ERR +#undef __ENQUEUE_WRITE_BUFFER_RECT_ERR +#undef __ENQEUE_COPY_BUFFER_ERR +#undef __ENQEUE_COPY_BUFFER_RECT_ERR +#undef __ENQUEUE_READ_IMAGE_ERR +#undef __ENQUEUE_WRITE_IMAGE_ERR +#undef __ENQUEUE_COPY_IMAGE_ERR +#undef __ENQUEUE_COPY_IMAGE_TO_BUFFER_ERR +#undef __ENQUEUE_COPY_BUFFER_TO_IMAGE_ERR +#undef __ENQUEUE_MAP_BUFFER_ERR +#undef __ENQUEUE_MAP_IMAGE_ERR +#undef __ENQUEUE_UNMAP_MEM_OBJECT_ERR +#undef __ENQUEUE_NDRANGE_KERNEL_ERR +#undef __ENQUEUE_TASK_ERR +#undef __ENQUEUE_NATIVE_KERNEL + +#undef __CL_EXPLICIT_CONSTRUCTORS + +#undef __UNLOAD_COMPILER_ERR +#endif //__CL_USER_OVERRIDE_ERROR_STRINGS + +#undef __CL_FUNCTION_TYPE + +// Extensions +/** + * Deprecated APIs for 1.2 + */ +#if defined(CL_VERSION_1_1) +#undef __INIT_CL_EXT_FCN_PTR +#endif // #if defined(CL_VERSION_1_1) +#undef __CREATE_SUB_DEVICES + +#if defined(USE_CL_DEVICE_FISSION) +#undef __PARAM_NAME_DEVICE_FISSION +#endif // USE_CL_DEVICE_FISSION + +#undef __DEFAULT_NOT_INITIALIZED +#undef __DEFAULT_BEING_INITIALIZED +#undef __DEFAULT_INITIALIZED + +#undef CL_HPP_RVALUE_REFERENCES_SUPPORTED +#undef CL_HPP_NOEXCEPT + +} // namespace cl + +#endif // CL_HPP_ diff --git a/GPU_version/vio/include/vio/cl_class.h b/GPU_version/vio/include/vio/cl_class.h new file mode 100644 index 0000000..7088a56 --- /dev/null +++ b/GPU_version/vio/include/vio/cl_class.h @@ -0,0 +1,191 @@ +// +// Created by root on 4/27/21. +// + +#ifndef VIO_OPENCL_CL_CLASS_H +#define VIO_OPENCL_CL_CLASS_H +#include +#include +#include +#include +#include +#include +#include +#include + +class kernel{ +public: + kernel(cl::Program* program,std::string name){_kernel = new cl::Kernel(*program,name.c_str());}; + ~kernel(){ + _buffers.clear(); + _images.clear(); + }; + template + int32_t write(size_t id/*buffer ID*/,T* buf,cl::CommandQueue* queue,cl::Context* context,size_t buf_size){ + _buffers.push_back(std::pair,size_t>(std::pair(cl::Buffer(*context, CL_MEM_READ_WRITE, sizeof(T) * buf_size), + buf_size),id)); + cl_int err=queue->enqueueWriteBuffer(_buffers.back().first.first,CL_TRUE, 0, sizeof(T) * buf_size, buf); + if(err!=0){ + std::cerr<<"Error C:Kernel, F:write, L:enqueueWriteBuffer\n"<setArg(id,_buffers.back().first.first); + if(err!=0){ + std::cerr<<"Error C:Kernel, F:write, L3:setArg\n"<(cl::Image2D(*context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, + cl::ImageFormat(CL_R, CL_UNSIGNED_INT8), + buf.size().width, + buf.size().height, + 0, + reinterpret_cast(buf.data)),id)); + + cl_int err=_kernel->setArg(id,_images.back().first); + if(err!=0){ + std::cerr<<"Error C:Kernel, F:write image, L:setArg\n"< + int32_t reload(size_t id,T* buf,cl::CommandQueue* queue){ + try{ + if(id>_buffers.size())return CL_MAP_FAILURE; + for(auto i:_buffers)if(i.second==id) + queue->enqueueWriteBuffer(i.first.first,CL_TRUE, 0, sizeof(T) * i.first.second, buf); + return CL_SUCCESS; + }catch (std::exception& err){ + std::cerr<<"Reload buffer on GPU failed\n"<(buf.data)); + } + + return CL_SUCCESS; + }catch (std::exception& err){ + std::cerr<<"Reload buffer on GPU failed\n"< read(size_t id){ + for(auto i:_buffers)if(i.second==id)return i.first; + } + cl::Image2D read_img(size_t id){ + for(auto i:_images)if(i.second==id)return i.first; + } +private: + std::vector,size_t>> _buffers; + std::vector> _images; + +}; +class read_cl{ +public: + read_cl(std::string path){ + src_str=(char *)malloc(0x100000); + FILE *fp; + fp = fopen(path.c_str(), "r"); + size = fread(src_str, 1, 0x100000, fp); + fclose(fp); + } + void print(){ + std::cerr< + int32_t write_buf(size_t id1/*kernal ID*/,size_t id2/*buffer ID*/, int size,T* buf) { + try{ + _kernels.at(id1).write(id2,buf,queue,context,size); + return CL_SUCCESS; + }catch (std::exception& err){ + std::cerr<<"Write buffer on GPU failed\n"< + int32_t write_buf(size_t id1/*kernal ID*/,size_t id2/*buffer ID*/,T&& value){ + _kernels.at(id1)._kernel->setArg(id2,value); + }; + template + int32_t reload_buf(size_t id1/*kernal ID*/,size_t id2/*buffer ID*/,T* buf) { + try{ + _kernels.at(id1).reload(id2,buf,queue); + return CL_SUCCESS; + }catch (std::exception& err){ + std::cerr<<"Reload buffer on GPU failed\n"<1 && y>1){ + err=queue->enqueueNDRangeKernel(*_kernels.at(id1)._kernel, cl::NullRange/*offset*/, cl::NDRange(x,y,z)/*Global*/, cl::NullRange/*local*/); + }else if(z<2 && y>1){ + err=queue->enqueueNDRangeKernel(*_kernels.at(id1)._kernel, cl::NullRange/*offset*/, cl::NDRange(x,y)/*Global*/, cl::NullRange/*local*/); + }else{ + err=queue->enqueueNDRangeKernel(*_kernels.at(id1)._kernel, cl::NullRange/*offset*/, cl::NDRange(x)/*Global*/, cl::NullRange/*local*/); + }; + queue->finish(); + if(err!=0){ + std::cerr<<"kernel: "<<_kernels.at(id1)._kernel->getInfo(); + std::cerr<<" ,Args: "<<_kernels.at(id1)._kernel->getInfo()<<" ,Run out: "<getInfo();++i) + std::cerr<<"argument type "<getArgInfo(i)<<'\n'; + } + return err; + + } + template + void read(size_t id1/*kernal ID*/,size_t id2/*buffer ID*/, T* out){ + queue->enqueueReadBuffer(_kernels.at(id1).read(id2).first, CL_TRUE, 0, sizeof(T) * _kernels.at(id1).read(id2).second, out); + } + void clear_buf(); +private: + std::vector _kernels; + cl::Context* context = NULL; + cl::Device device; + cl::Program* program = NULL; + cl::CommandQueue* queue=NULL; +}; + +#endif //VIO_OPENCL_CL_CLASS_H diff --git a/GPU_version/vio/include/vio/config.h b/GPU_version/vio/include/vio/config.h new file mode 100644 index 0000000..8ecb89f --- /dev/null +++ b/GPU_version/vio/include/vio/config.h @@ -0,0 +1,182 @@ +// This file is part of SVO - Semi-direct Visual Odometry. +// +// Copyright (C) 2014 Christian Forster +// (Robotics and Perception Group, University of Zurich, Switzerland). +// +// SVO is free software: you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the Free Software +// Foundation, either version 3 of the License, or any later version. +// +// SVO is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#ifndef SVO_CONFIG_H_ +#define SVO_CONFIG_H_ + +#include +#include +#include + +namespace vio { + +using std::string; + +/// Global configuration file of SVO. +/// Implements the Singleton design pattern to allow global access and to ensure +/// that only one instance exists. +class Config +{ +public: + static Config& getInstance(); + + /// Base-name of the tracefiles. + static string& traceName() { return getInstance().trace_name; } + + /// Directory where the tracefiles are saved. + static string& traceDir() { return getInstance().trace_dir; } + + /// Number of pyramid levels used for features. + static size_t& nPyrLevels() { return getInstance().n_pyr_levels; } + + /// Use the IMU to get relative rotations. + static bool& useImu() { return getInstance().use_imu; } + + /// Number of keyframes in the core. The core-kfs are optimized through bundle adjustment. + static size_t& coreNKfs() { return getInstance().core_n_kfs; } + + /// Initial scale of the map. Depends on the distance the camera is moved for the initialization. + static double& mapScale() { return getInstance().map_scale; } + + /// Feature grid size of a cell in [px]. + static size_t& gridSize() { return getInstance().grid_size; } + + /// Initialization: Minimum required disparity between the first two frames. + static double& initMinDisparity() { return getInstance().init_min_disparity; } + + /// Initialization: Minimum number of tracked features. + static size_t& initMinTracked() { return getInstance().init_min_tracked; } + + /// Initialization: Minimum number of inliers after RANSAC. + static size_t& initMinInliers() { return getInstance().init_min_inliers; } + + /// Maximum level of the Lucas Kanade tracker. + static size_t& kltMaxLevel() { return getInstance().klt_max_level; } + + /// Minimum level of the Lucas Kanade tracker. + static size_t& kltMinLevel() { return getInstance().klt_min_level; } + + /// Reprojection threshold [px]. + static double& reprojThresh() { return getInstance().reproj_thresh; } + + /// Reprojection threshold after pose optimization. + static double& poseOptimThresh() { return getInstance().poseoptim_thresh; } + + /// Number of iterations in local bundle adjustment. + static size_t& poseOptimNumIter() { return getInstance().poseoptim_num_iter; } + + /// Maximum number of points to optimize at every iteration. + static size_t& structureOptimMaxPts() { return getInstance().structureoptim_max_pts; } + + /// Number of iterations in structure optimization. + static size_t& structureOptimNumIter() { return getInstance().structureoptim_num_iter; } + + /// Reprojection threshold after bundle adjustment. + static double& lobaThresh() { return getInstance().loba_thresh; } + + /// Threshold for the robust Huber kernel of the local bundle adjustment. + static double& lobaRobustHuberWidth() { return getInstance().loba_robust_huber_width; } + + /// Number of iterations in the local bundle adjustment. + static size_t& lobaNumIter() { return getInstance().loba_num_iter; } + + /// Minimum distance between two keyframes. Relative to the average height in the map. + static double& kfSelectMinDist() { return getInstance().kfselect_mindist; } + + /// Select only features with a minimum Harris corner score for triangulation. + static double& triangMinCornerScore() { return getInstance().triang_min_corner_score; } + + /// Subpixel refinement of reprojection and triangulation. Set to 0 if no subpix refinement required! + static size_t& subpixNIter() { return getInstance().subpix_n_iter; } + + /// Limit the number of keyframes in the map. This makes nslam essentially. + /// a Visual Odometry. Set to 0 if unlimited number of keyframes are allowed. + /// Minimum number of keyframes is 3. + static size_t& maxNKfs() { return getInstance().max_n_kfs; } + + /// How much (in milliseconds) is the camera delayed with respect to the imu. + static double& imgImuDelay() { return getInstance().img_imu_delay; } + + /// Maximum number of features that should be tracked. + static size_t& maxFts() { return getInstance().max_fts; } + + /// If the number of tracked features drops below this threshold. Tracking quality is bad. + static size_t& qualityMinFts() { return getInstance().quality_min_fts; } + + /// If within one frame, this amount of features are dropped. Tracking quality is bad. + static int& qualityMaxFtsDrop() { return getInstance().quality_max_drop_fts; } + + /// acc white noise in continuous. + static double& ACC_Noise() { return getInstance().ACC_noise; } + + /// Gro white noise in continuous. + static double& GYO_Noise() { return getInstance().GYO_noise; } + /// integration uncertainty continuous + static double& IUC() { return getInstance().iuc; } + /// acc bias in continuous + static double& ABC() { return getInstance().abc; } + /// gyro bias in continuous + static double& GBC() { return getInstance().gbc; } + /// error in the bias used for preintegration + static double& EBP() { return getInstance().ebp; } + /// the noise used for projection + static double& NRP() { return getInstance().nrp; } + static double& Svo_Ekf() { return getInstance().svo_ekf; } + static double& X_off() { return getInstance().acc_x_off; } + static double& Y_off() { return getInstance().acc_y_off; } + static double& Teta_off() { return getInstance().gyr_z_off; } + static double& Cmd_Cov() { return getInstance().cmd_cov; } + + +private: + Config(); + Config(Config const&); + void operator=(Config const&); + string trace_name; + string trace_dir; + size_t n_pyr_levels; + bool use_imu; + size_t core_n_kfs; + double map_scale; + size_t grid_size; + double init_min_disparity; + size_t init_min_tracked; + size_t init_min_inliers; + size_t klt_max_level; + size_t klt_min_level; + double reproj_thresh; + double poseoptim_thresh; + size_t poseoptim_num_iter; + size_t structureoptim_max_pts; + size_t structureoptim_num_iter; + double loba_thresh; + double loba_robust_huber_width; + size_t loba_num_iter; + double kfselect_mindist; + double triang_min_corner_score; + size_t triang_half_patch_size; + size_t subpix_n_iter; + size_t max_n_kfs; + double img_imu_delay; + size_t max_fts; + size_t quality_min_fts; + int quality_max_drop_fts; + double nrp,ebp,gbc,abc,iuc,ACC_noise,GYO_noise,svo_ekf,acc_x_off,acc_y_off,gyr_z_off,cmd_cov; +}; + +} // namespace vio + +#endif // SVO_CONFIG_H_ diff --git a/GPU_version/vio/include/vio/depth_filter.h b/GPU_version/vio/include/vio/depth_filter.h new file mode 100644 index 0000000..04190a9 --- /dev/null +++ b/GPU_version/vio/include/vio/depth_filter.h @@ -0,0 +1,170 @@ +// This file is part of SVO - Semi-direct Visual Odometry. +// +// Copyright (C) 2014 Christian Forster +// (Robotics and Perception Group, University of Zurich, Switzerland). +// +// SVO is free software: you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the Free Software +// Foundation, either version 3 of the License, or any later version. +// +// SVO is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#ifndef SVO_DEPTH_FILTER_H_ +#define SVO_DEPTH_FILTER_H_ + +#include +#include +#include +//#include +#include +#include +#include + +namespace vio { + +class Frame; +class Feature; +class Point; + +/// A seed is a probabilistic depth estimate for a single pixel. +struct Seed +{ + EIGEN_MAKE_ALIGNED_OPERATOR_NEW + + static int batch_counter; + static int seed_counter; + int batch_id; //!< Batch id is the id of the keyframe for which the seed was created. + int id; //!< Seed ID, only used for visualization. + Feature* ftr; //!< Feature in the keyframe for which the depth should be computed. + float a; //!< a of Beta distribution: When high, probability of inlier is large. + float b; //!< b of Beta distribution: When high, probability of outlier is large. + float mu; //!< Mean of normal distribution. + float z_range; //!< Max range of the possible depth. + float sigma2; //!< Variance of normal distribution. + Matrix2d patch_cov; //!< Patch covariance in reference image. + Seed(Feature* ftr, float depth_mean, float depth_min); +}; + +/// Depth filter implements the Bayesian Update proposed in: +/// "Video-based, Real-Time Multi View Stereo" by G. Vogiatzis and C. Hernández. +/// In Image and Vision Computing, 29(7):434-441, 2011. +/// +/// The class uses a callback mechanism such that it can be used also by other +/// algorithms than nslam and for simplified testing. +class DepthFilter +{ +public: + EIGEN_MAKE_ALIGNED_OPERATOR_NEW + + typedef boost::unique_lock lock_t; + typedef boost::function callback_t; + + /// Depth-filter config parameters + struct Options + { + bool check_ftr_angle; //!< gradient features are only updated if the epipolar line is orthogonal to the gradient. + bool epi_search_1d; //!< restrict Gauss Newton in the epipolar search to the epipolar line. + bool verbose; //!< display output. + bool use_photometric_disparity_error; //!< use photometric disparity error instead of 1px error in tau computation. + int max_n_kfs; //!< maximum number of keyframes for which we maintain seeds. + double sigma_i_sq; //!< image noise. + double seed_convergence_sigma2_thresh; //!< threshold on depth uncertainty for convergence. + Options() + : check_ftr_angle(false), + epi_search_1d(false), + verbose(false), + use_photometric_disparity_error(false), + max_n_kfs(10), + sigma_i_sq(5e-4), + seed_convergence_sigma2_thresh(200.0) + {} + } options_; + + DepthFilter( + feature_detection::DetectorPtr feature_detector, + callback_t seed_converged_cb); + + virtual ~DepthFilter(); + + /// Start this thread when seed updating should be in a parallel thread. + void startThread(); + + /// Stop the parallel thread that is running. + void stopThread(); + + /// Add frame to the queue to be processed. + void addFrame(FramePtr frame); + + /// Add new keyframe to the queue + void addKeyframe(FramePtr frame, double depth_mean, double depth_min); + + /// Remove all seeds which are initialized from the specified keyframe. This + /// function is used to make sure that no seeds points to a non-existent frame + /// when a frame is removed from the map. + void removeKeyframe(FramePtr frame); + + /// If the map is reset, call this function such that we don't have pointers + /// to old frames. + void reset(); + + /// Returns a copy of the seeds belonging to frame. Thread-safe. + /// Can be used to compute the Next-Best-View in parallel. + /// IMPORTANT! Make sure you hold a valid reference counting pointer to frame + /// so it is not being deleted while you use it. + void getSeedsCopy(const FramePtr& frame, std::list& seeds); + + /// Return a reference to the seeds. This is NOT THREAD SAFE! + //std::list& getSeeds() { return seeds_; } Bug 238 + std::list>& getSeeds() { return seeds_; } + + /// Bayes update of the seed, x is the measurement, tau2 the measurement uncertainty + static void updateSeed( + const float x, + const float tau2, + Seed* seed); + + /// Compute the uncertainty of the measurement. + static double computeTau( + const SE3& T_ref_cur, + const Vector3d& f, + const double z, + const double px_error_angle); + +protected: + feature_detection::DetectorPtr feature_detector_; + callback_t seed_converged_cb_; + std::list> seeds_; + boost::mutex seeds_mut_; + bool seeds_updating_halt_; //!< Set this value to true when seeds updating should be interrupted. + boost::thread* thread_; + std::queue frame_queue_; + boost::mutex frame_queue_mut_; + boost::condition_variable frame_queue_cond_; + FramePtr new_keyframe_; //!< Next keyframe to extract new seeds. + bool new_keyframe_set_; //!< Do we have a new keyframe to process?. + double new_keyframe_min_depth_; //!< Minimum depth in the new keyframe. Used for range in new seeds. + double new_keyframe_mean_depth_; //!< Maximum depth in the new keyframe. Used for range in new seeds. + Matcher matcher_; + uint seeds_cont_=0; + + /// Initialize new seeds from a frame. + void initializeSeeds(FramePtr frame); + + /// Update all seeds with a new measurement frame. + virtual void updateSeeds(FramePtr frame); + + /// When a new keyframe arrives, the frame queue should be cleared. + void clearFrameQueue(); + + /// A thread that is continuously updating the seeds. + void updateSeedsLoop(); +}; + +} // namespace vio + +#endif // SVO_DEPTH_FILTER_H_ diff --git a/GPU_version/vio/include/vio/feature.h b/GPU_version/vio/include/vio/feature.h new file mode 100644 index 0000000..54b9149 --- /dev/null +++ b/GPU_version/vio/include/vio/feature.h @@ -0,0 +1,75 @@ +// This file is part of SVO - Semi-direct Visual Odometry. +// +// Copyright (C) 2014 Christian Forster +// (Robotics and Perception Group, University of Zurich, Switzerland). +// +// SVO is free software: you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the Free Software +// Foundation, either version 3 of the License, or any later version. +// +// SVO is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#ifndef SVO_FEATURE_H_ +#define SVO_FEATURE_H_ + +#include + +namespace vio { + +/// A salient image region that is tracked across frames. +struct Feature +{ + EIGEN_MAKE_ALIGNED_OPERATOR_NEW + + enum FeatureType { + CORNER, + EDGELET + }; + + FeatureType type; //!< Type can be corner or edgelet. + Frame* frame; //!< Pointer to frame in which the feature was detected. + Vector2d px; //!< Coordinates in pixels on pyramid level 0. + Vector3d f; //!< Unit-bearing vector of the feature. + int level; //!< Image pyramid level where feature was extracted. + Point* point; //!< Pointer to 3D point which corresponds to the feature. + Vector2d grad; //!< Dominant gradient direction for edglets, normalized. + + Feature(Frame* _frame, const Vector2d& _px, int _level) : + type(CORNER), + frame(_frame), + px(_px), + f(frame->cam_->cam2world(px)), + level(_level), + point(NULL), + grad(1.0,0.0) + {} + + Feature(Frame* _frame, const Vector2d& _px, const Vector3d& _f, int _level) : + type(CORNER), + frame(_frame), + px(_px), + f(_f), + level(_level), + point(NULL), + grad(1.0,0.0) + {} + + Feature(Frame* _frame, Point* _point, const Vector2d& _px, const Vector3d& _f, int _level) : + type(CORNER), + frame(_frame), + px(_px), + f(_f), + level(_level), + point(_point), + grad(1.0,0.0) + {} +}; + +} // namespace vio + +#endif // SVO_FEATURE_H_ diff --git a/GPU_version/vio/include/vio/feature_alignment.h b/GPU_version/vio/include/vio/feature_alignment.h new file mode 100644 index 0000000..5befb9e --- /dev/null +++ b/GPU_version/vio/include/vio/feature_alignment.h @@ -0,0 +1,63 @@ +// This file is part of SVO - Semi-direct Visual Odometry. +// +// Copyright (C) 2014 Christian Forster +// (Robotics and Perception Group, University of Zurich, Switzerland). +// +// SVO is free software: you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the Free Software +// Foundation, either version 3 of the License, or any later version. +// +// SVO is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#ifndef SVO_FEATURE_ALIGNMENT_H_ +#define SVO_FEATURE_ALIGNMENT_H_ + +#include + +namespace vio { + +/// Subpixel refinement of a reference feature patch with the current image. +/// Implements the inverse-compositional approach (see "Lucas-Kanade 20 Years on" +/// paper by Baker. +namespace feature_alignment { + +bool align1D( + const cv::Mat& cur_img, + const Vector2f& dir, // direction in which the patch is allowed to move + uint8_t* ref_patch_with_border, + uint8_t* ref_patch, + const int n_iter, + Vector2d& cur_px_estimate, + double& h_inv); + +bool align2D( + const cv::Mat& cur_img, + uint8_t* ref_patch_with_border, + uint8_t* ref_patch, + const int n_iter, + Vector2d& cur_px_estimate, + bool no_simd = false); + +bool align2D_SSE2( + const cv::Mat& cur_img, + uint8_t* ref_patch_with_border, + uint8_t* ref_patch, + const int n_iter, + Vector2d& cur_px_estimate); + +bool align2D_NEON( + const cv::Mat& cur_img, + uint8_t* ref_patch_with_border, + uint8_t* ref_patch, + const int n_iter, + Vector2d& cur_px_estimate); + +} // namespace feature_alignment +} // namespace vio + +#endif // SVO_FEATURE_ALIGNMENT_H_ diff --git a/GPU_version/vio/include/vio/feature_detection.h b/GPU_version/vio/include/vio/feature_detection.h new file mode 100644 index 0000000..7cdf4da --- /dev/null +++ b/GPU_version/vio/include/vio/feature_detection.h @@ -0,0 +1,111 @@ +// This file is part of SVO - Semi-direct Visual Odometry. +// +// Copyright (C) 2014 Christian Forster +// (Robotics and Perception Group, University of Zurich, Switzerland). +// +// SVO is free software: you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the Free Software +// Foundation, either version 3 of the License, or any later version. +// +// SVO is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#ifndef SVO_FEATURE_DETECTION_H_ +#define SVO_FEATURE_DETECTION_H_ + +#include +#include +#include + +namespace vio { + +/// Implementation of various feature detectors. +namespace feature_detection { + +/// Temporary container used for corner detection. Features are initialized from these. +struct Corner +{ + int x; //!< x-coordinate of corner in the image. + int y; //!< y-coordinate of corner in the image. + int level; //!< pyramid level of the corner. + float score; //!< shi-tomasi score of the corner. + float angle; //!< for gradient-features: dominant gradient angle. + Corner(int x, int y, float score, int level, float angle) : + x(x), y(y), level(level), score(score), angle(angle) + {} +}; +typedef vector Corners; + +/// All detectors should derive from this abstract class. +class AbstractDetector +{ +public: + AbstractDetector( + const int img_width, + const int img_height, + const int cell_size, + const int n_pyr_levels); + + virtual ~AbstractDetector() { + }; + + virtual void detect( + Frame* frame, + const ImgPyr& img_pyr, + const double detection_threshold, + Features& fts) = 0; + + /// Flag the grid cell as occupied + void setGridOccpuancy(const Vector2d& px); + + /// Set grid cells of existing features as occupied + void setExistingFeatures(const Features& fts); + +protected: + + static const int border_ = 8; //!< no feature should be within 8px of border. + const int cell_size_; + const int n_pyr_levels_; + const int grid_n_cols_; + const int grid_n_rows_; + vector grid_occupancy_; + + void resetGrid(); + + inline int getCellIndex(int x, int y, int level) + { + const int scale = (1< DetectorPtr; + +/// FAST detector by Edward Rosten. +class FastDetector : public AbstractDetector +{ +public: + FastDetector( + const int img_width, + const int img_height, + const int cell_size, + opencl* gpu_fast_, + const int n_pyr_levels); + + virtual ~FastDetector() {} + + virtual void detect( + Frame* frame, + const ImgPyr& img_pyr, + const double detection_threshold, + Features& fts); + opencl* gpu_fast_; +}; + +} // namespace feature_detection +} // namespace vio + +#endif // SVO_FEATURE_DETECTION_H_ diff --git a/GPU_version/vio/include/vio/for_it.hpp b/GPU_version/vio/include/vio/for_it.hpp new file mode 100755 index 0000000..f5fce79 --- /dev/null +++ b/GPU_version/vio/include/vio/for_it.hpp @@ -0,0 +1,87 @@ +// +// Created by root on 5/12/21. +// + +#ifndef VIO_FOR_IT_H +#define VIO_FOR_IT_H +#include +#include +#include + +//https://stackoverflow.com/questions/24881799/get-index-in-c11-foreach-loop +// Wrapper class +template +class for_impl +{ +public: + // The return value of the operator* of the iterator, this + // is what you will get inside of the for loop + struct item + { + size_t index; + typename T::value_type & item; + }; + typedef item value_type; + + // Custom iterator with minimal interface + struct iterator + { + iterator(typename T::iterator _it, size_t counter=0) : + it(_it), counter(counter) + {} + + iterator operator++() + { + return iterator(++it, ++counter); + } + + bool operator!=(iterator other) + { + return it != other.it; + } + + typename T::iterator::value_type item() + { + return *it; + } + + value_type operator*() + { + return value_type{counter, *it}; + } + + size_t index() + { + return counter; + } + + private: + typename T::iterator it; + size_t counter; + }; + + for_impl(T & t) : container(t) {} + + iterator begin() + { + return iterator(container.begin()); + } + + iterator end() + { + return iterator(container.end()); + } + +private: + T & container; +}; + + +// A templated free function allows you to create the wrapper class +// conveniently +template +for_impl _for(T & t) +{ + return for_impl(t); +} +#endif //VIO_FOR_IT_H diff --git a/GPU_version/vio/include/vio/frame.h b/GPU_version/vio/include/vio/frame.h new file mode 100644 index 0000000..7408805 --- /dev/null +++ b/GPU_version/vio/include/vio/frame.h @@ -0,0 +1,185 @@ +// This file is part of SVO - Semi-direct Visual Odometry. +// +// Copyright (C) 2014 Christian Forster +// (Robotics and Perception Group, University of Zurich, Switzerland). +// +// SVO is free software: you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the Free Software +// Foundation, either version 3 of the License, or any later version. +// +// SVO is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#ifndef SVO_FRAME_H_ +#define SVO_FRAME_H_ + +#include +#include +#include +#include +#include + +namespace g2o { +class VertexSE3Expmap; +} +typedef g2o::VertexSE3Expmap g2oFrameSE3; + +namespace vio { + +class Point; +struct Feature; + +typedef list Features; +typedef vector ImgPyr; + + +/// A frame saves the image, the associated features and the estimated pose. +class Frame : boost::noncopyable +{ +public: + EIGEN_MAKE_ALIGNED_OPERATOR_NEW + + static int frame_counter_; //!< Counts the number of created frames. Used to set the unique id. + int id_; //!< Unique id of the frame. + double timestamp_; //!< Timestamp of when the image was recorded. + vk::AbstractCamera* cam_; //!< Camera model. + SE2_5 T_f_w_; //!< Transform (f)rame from (w)orld. + Matrix Cov_; //!< Covariance. + ImgPyr img_pyr_; //!< Image Pyramid. + Features fts_; //!< List of features in the image. + vector key_pts_; //!< Five features and associated 3D points which are used to detect if two frames have overlapping field of view. + bool is_keyframe_; //!< Was this frames selected as keyframe? + g2oFrameSE3* v_kf_; //!< Temporary pointer to the g2o node object of the keyframe. + int last_published_ts_; //!< Timestamp of last publishing. + + Frame(vk::AbstractCamera* cam, const cv::Mat& img, double timestamp); + ~Frame(); + + /// Initialize new frame and create image pyramid. + void initFrame(const cv::Mat& img); + + /// Select this frame as keyframe. + void setKeyframe(); + + /// Add a feature to the image + void addFeature(Feature* ftr); + + /// The KeyPoints are those five features which are closest to the 4 image corners + /// and to the center and which have a 3D point assigned. These points are used + /// to quickly check whether two frames have overlapping field of view. + void setKeyPoints(); + + /// Check if we can select five better key-points. + void checkKeyPoints(Feature* ftr); + + /// If a point is deleted, we must remove the corresponding key-point. + void removeKeyPoint(Feature* ftr); + + /// Return number of point observations. + inline size_t nObs() const { return fts_.size(); } + + /// Check if a point in (w)orld coordinate frame is visible in the image. + bool isVisible(const Vector3d& xyz_w) const; + + /// Full resolution image stored in the frame. + inline const cv::Mat& img() const { return img_pyr_[0]; } + + /// Was this frame selected as keyframe? + inline bool isKeyframe() const { return is_keyframe_; } + + /// Transforms point coordinates in world-frame (w) to camera pixel coordinates (c). + inline Vector2d w2c(const Vector3d& xyz_w) const { + return cam_->world2cam( T_f_w_.se3()*xyz_w); + } + /// Transforms point coordinates in world-frame (w) to camera pixel coordinates (c). + inline Vector2d w2px(const Vector3d& xyz_w) const { return cam_->world2cam( xyz_w ); } + + /// Transforms pixel coordinates (c) to frame unit sphere coordinates (f). + inline Vector3d c2f(const Vector2d& px) const { return cam_->cam2world(px[0], px[1]); } + + /// Transforms pixel coordinates (c) to frame unit sphere coordinates (f). + inline Vector3d c2f(const double x, const double y) const { return cam_->cam2world(x, y); } + + /// Transforms point coordinates in world-frame (w) to camera-frams (f). + inline Vector3d w2f(const Vector3d& xyz_w) const { + return Vector3d(T_f_w_.se3()*xyz_w); + } + + /// Transforms point from frame unit sphere (f) frame to world coordinate frame (w). + inline Vector3d f2w(const Vector3d& f) const { + return getSE3Inv() * f; + } + + /// Projects Point from unit sphere (f) in camera pixels (c). + inline Vector2d f2c(const Vector3d& f) const { return cam_->world2cam( f ); } + + /// Return the pose of the frame in the (w)orld coordinate frame. + inline Vector2d pos() const { return T_f_w_.se2().translation(); } + + inline SE3 se3() const{ + return T_f_w_.se3(); + } + + inline SE3 getSE3Inv() const{ + Eigen::Matrix R; + R<& J) + { + const double x = xyz_in_f[0]; + const double y = xyz_in_f[1]; + const double z_inv = 1./xyz_in_f[2]; + const double z_inv_2 = z_inv*z_inv; + + J(0,0) = -z_inv; // -1/z + J(0,1) = x*z_inv_2; // x/z^2 + J(0,2) = -(1.0 + pow(x,2)/z_inv_2); // -(1.0 + x^2/z^2) + + J(1,0) = 1e-19; // 0 + J(1,1) = y*z_inv_2; // y/z^2 + J(1,2) = -x*y/z_inv_2; // -x*y/z^2 + } + inline static void jacobian_l2uv( + const Matrix& p, + Matrix& J){ + double A = -1.0*sqrt(p.z()); + double z_inv = -1/p.z(); + J(0,0) = z_inv; + J(0,1) = 1e-19; + J(0,2) = p.x()*A; + + J(1,0) = 1e-19; + J(1,1) = z_inv; + J(1,2) =A*p.y(); + } +}; + + +/// Some helper functions for the frame object. +namespace frame_utils { + +/// Creates an image pyramid of half-sampled images. +void createImgPyramid(const cv::Mat& img_level_0, int n_levels, ImgPyr& pyr); + +/// Get the average depth of the features in the image. +bool getSceneDepth(const Frame& frame, double& depth_mean, double& depth_min); + +} // namespace frame_utils +} // namespace vio + +#endif // SVO_FRAME_H_ diff --git a/GPU_version/vio/include/vio/frame_handler_base.h b/GPU_version/vio/include/vio/frame_handler_base.h new file mode 100644 index 0000000..994f048 --- /dev/null +++ b/GPU_version/vio/include/vio/frame_handler_base.h @@ -0,0 +1,118 @@ +// This file is part of SVO - Semi-direct Visual Odometry. +// +// Copyright (C) 2014 Christian Forster +// (Robotics and Perception Group, University of Zurich, Switzerland). +// +// SVO is free software: you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the Free Software +// Foundation, either version 3 of the License, or any later version. +// +// SVO is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#ifndef SVO_FRAME_HANDLER_BASE_H_ +#define SVO_FRAME_HANDLER_BASE_H_ + +#include +#include +#include +#include +#include +#include + +namespace vk +{ +class AbstractCamera; +//class PerformanceMonitor; +} + +namespace vio +{ +class Point; +class Matcher; +class DepthFilter; + +/// Base class for various VO pipelines. Manages the map and the state machine. +class FrameHandlerBase : boost::noncopyable +{ +public: + enum Stage { + STAGE_PAUSED, + STAGE_FIRST_FRAME, + STAGE_SECOND_FRAME, + STAGE_DEFAULT_FRAME, + STAGE_RELOCALIZING + }; + enum TrackingQuality { + TRACKING_INSUFFICIENT, + TRACKING_BAD, + TRACKING_GOOD + }; + enum UpdateResult { + RESULT_NO_KEYFRAME, + RESULT_IS_KEYFRAME, + RESULT_FAILURE + }; + + FrameHandlerBase(); + + virtual ~FrameHandlerBase(); + + /// Get the current map. + const Map& map() const { return map_; } + + /// Will reset the map as soon as the current frame is finished processing. + void reset() { set_reset_ = true; } + + /// Start processing. + void start() { set_start_ = true; } + + /// Get the current stage of the algorithm. + Stage stage() const { return stage_; } + + /// Get tracking quality. + TrackingQuality trackingQuality() const { return tracking_quality_; } + + /// Get the processing time of the previous iteration. + //double lastProcessingTime() const { return timer_.getTime(); } + + /// Get the number of feature observations of the last frame. + // size_t lastNumObservations() const { return num_obs_last_; } + +protected: + Stage stage_; //!< Current stage of the algorithm. + bool set_reset_; //!< Flag that the user can set. Will reset the system before the next iteration. + bool set_start_; //!< Flag the user can set to start the system when the next image is received. + Map map_; //!< Map of keyframes created by the slam system. + size_t num_obs_last_; //!< Number of observations in the previous frame. + TrackingQuality tracking_quality_; //!< An estimate of the tracking quality based on the number of tracked features. + + /// Before a frame is processed, this function is called. + bool startFrameProcessingCommon(const double timestamp); + + /// When a frame is finished processing, this function is called. + int finishFrameProcessingCommon( + const size_t update_id, + const UpdateResult dropout, + const size_t num_observations); + + /// Reset the map and frame handler to start from scratch. + void resetCommon(); + + /// Reset the frame handler. Implement in derived class. + virtual void resetAll() { resetCommon(); } + + /// Set the tracking quality based on the number of tracked features. + virtual void setTrackingQuality(const size_t num_observations); + + /// Optimize some of the observed 3D points. + virtual void optimizeStructure(FramePtr frame, size_t max_n_pts, int max_iter); +}; + +} // namespace nslam + +#endif // SVO_FRAME_HANDLER_BASE_H_ diff --git a/GPU_version/vio/include/vio/frame_handler_mono.h b/GPU_version/vio/include/vio/frame_handler_mono.h new file mode 100644 index 0000000..aa5a148 --- /dev/null +++ b/GPU_version/vio/include/vio/frame_handler_mono.h @@ -0,0 +1,112 @@ +// This file is part of SVO - Semi-direct Visual Odometry. +// +// Copyright (C) 2014 Christian Forster +// (Robotics and Perception Group, University of Zurich, Switzerland). +// +// SVO is free software: you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the Free Software +// Foundation, either version 3 of the License, or any later version. +// +// SVO is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#ifndef SVO_FRAME_HANDLER_H_ +#define SVO_FRAME_HANDLER_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace vio { + +/// Monocular Visual Odometry Pipeline as described in the SVO paper. +class FrameHandlerMono : public FrameHandlerBase +{ +public: + EIGEN_MAKE_ALIGNED_OPERATOR_NEW + + FrameHandlerMono(vk::AbstractCamera* cam,Eigen::Matrix& init); + virtual ~FrameHandlerMono(); + + /// Provide an image. + void addImage(const cv::Mat& img, double timestamp,const ros::Time& time); + + /// Set the first frame (used for synthetic datasets in benchmark node) + void setFirstFrame(const FramePtr& first_frame); + + /// Get the last frame that has been processed. + FramePtr lastFrame() { return last_frame_; } + + /// Get the set of spatially closest keyframes of the last frame. + const set& coreKeyframes() { return core_kfs_; } + + /// Return the feature track to visualize the KLT tracking during initialization. + const vector& initFeatureTrackRefPx() const { return klt_homography_init_->px_ref_; } + const vector& initFeatureTrackCurPx() const { return klt_homography_init_->px_cur_; } + + /// Access the depth filter. + DepthFilter* depthFilter() const{ return depth_filter_; } + + /// An external place recognition module may know where to relocalize. + bool relocalizeFrameAtPose( + const int keyframe_id, + const SE3& T_kf_f, + const cv::Mat& img, + const double timestamp); + //std::shared_ptr imu_integPtr_; //Integration of IMU + void UpdateIMU(double* value,const ros::Time& time); + void UpdateCmd(double* value,const ros::Time& time); + UKF ukfPtr_; + +protected: + vk::AbstractCamera* cam_; //!< Camera model, can be ATAN, Pinhole or Ocam (see vikit). + Reprojector reprojector_; //!< Projects points from other keyframes into the current frame + FramePtr new_frame_; //!< Current frame. + FramePtr last_frame_; //!< Last frame, not necessarily a keyframe. + set core_kfs_; //!< Keyframes in the closer neighbourhood. + vector< pair > overlap_kfs_; //!< All keyframes with overlapping field of view. the paired number specifies how many common mappoints are observed TODO: why vector!? + initialization::KltHomographyInit* klt_homography_init_; //!< Used to estimate pose of the first two keyframes by estimating a homography. + DepthFilter* depth_filter_; //!< Depth estimation algorithm runs in a parallel thread and is used to initialize new 3D points. + opencl* gpu_fast_; + ros::Time time_; + SparseImgAlignGpu* imageAlign_; + + + /// Initialize the visual odometry algorithm. + virtual void initialize(); + + /// Processes the first frame and sets it as a keyframe. + virtual UpdateResult processFirstFrame(); + + /// Processes all frames after the first frame until a keyframe is selected. + virtual UpdateResult processSecondFrame(); + + /// Processes all frames after the first two keyframes. + virtual UpdateResult processFrame(); + + /// Try relocalizing the frame at relative position to provided keyframe. + virtual UpdateResult relocalizeFrame( + const SE3& T_cur_ref, + FramePtr ref_keyframe); + + /// Reset the frame handler. Implement in derived class. + virtual void resetAll(); + + /// Keyframe selection criterion. + virtual bool needNewKf(double scene_depth_mean); + + void setCoreKfs(size_t n_closest); +}; + +} // namespace vio + +#endif // SVO_FRAME_HANDLER_H_ diff --git a/GPU_version/vio/include/vio/global.h b/GPU_version/vio/include/vio/global.h new file mode 100644 index 0000000..69fae99 --- /dev/null +++ b/GPU_version/vio/include/vio/global.h @@ -0,0 +1,120 @@ +// This file is part of SVO - Semi-direct Visual Odometry. +// +// Copyright (C) 2014 Christian Forster +// (Robotics and Perception Group, University of Zurich, Switzerland). +// +// SVO is free software: you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the Free Software +// Foundation, either version 3 of the License, or any later version. +// +// SVO is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#ifndef SVO_GLOBAL_H_ +#define SVO_GLOBAL_H_ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#ifndef RPG_SVO_VIKIT_IS_VECTOR_SPECIALIZED //Guard for rpg_vikit +#define RPG_SVO_VIKIT_IS_VECTOR_SPECIALIZED +EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Eigen::Vector3d) +EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Eigen::Vector2d) +#endif +#include +#define SVO_DEBUG_STREAM(x) ROS_DEBUG_STREAM(x) +#define SVO_INFO_STREAM(x) ROS_INFO_STREAM(x) +#define SVO_WARN_STREAM(x) ROS_WARN_STREAM(x) +#define SVO_WARN_STREAM_THROTTLE(rate, x) ROS_WARN_STREAM_THROTTLE(rate, x) +#define SVO_ERROR_STREAM(x) ROS_ERROR_STREAM(x) + + +namespace vio +{ + using namespace Eigen; + using namespace Sophus; + + const double EPS = 0.0000000001; + const double PI = 3.14159265; + class SE2_5: public SE2{ + public: + SE2_5(SE2&& se2):T2_(se2){ + } + SE2_5(SE2& se2):T2_(se2){ + } + SE2_5(SE3&& se3){ + Quaterniond q=se3.unit_quaternion().normalized(); + double pitch=asin(2.0*(q.w()*q.y()-q.z()*q.x())); + if (std::abs(pitch) >= 1) + pitch = std::copysign(M_PI / 2.0, pitch); // use 90 degrees if out of range + else + pitch = std::asin(pitch); + Eigen::Matrix R; + R<= 1) + pitch = std::copysign(M_PI / 2.0, pitch); // use 90 degrees if out of range + else + pitch = std::asin(pitch); + Eigen::Matrix R; + R< R; + R< R; + R< FramePtr; +} // namespace vio + +#endif // SVO_GLOBAL_H_ diff --git a/GPU_version/vio/include/vio/homography.h b/GPU_version/vio/include/vio/homography.h new file mode 100644 index 0000000..527c974 --- /dev/null +++ b/GPU_version/vio/include/vio/homography.h @@ -0,0 +1,85 @@ +/* + * homography.cpp + * Adaptation of PTAM-GPL HomographyInit class. + * https://github.com/Oxford-PTAM/PTAM-GPL + * Licence: GPLv3 + * Copyright 2008 Isis Innovation Limited + * + * Created on: Sep 2, 2012 + * by: cforster + * + * This class implements the homography decomposition of Faugeras and Lustman's + * 1988 tech report. Code converted to Eigen from PTAM. + * + */ + +#ifndef HOMOGRAPHY_H_ +#define HOMOGRAPHY_H_ + +#include +#include +#include +#include + +namespace vk { + +using namespace Eigen; +using namespace std; + +struct HomographyDecomposition +{ + Vector3d t; + Matrix3d R; + double d; + Vector3d n; + + // Resolved Composition + Sophus::SE3 T; //!< second from first + int score; +}; + +class Homography +{ +public: + EIGEN_MAKE_ALIGNED_OPERATOR_NEW + + Homography (const vector >& _fts1, + const vector >& _fts2, + double _error_multiplier2, + double _thresh_in_px); + + void + calcFromPlaneParams (const Vector3d & normal, + const Vector3d & point_on_plane); + + void + calcFromMatches (); + + size_t + computeMatchesInliers (); + + bool + computeSE3fromMatches (); + + bool + decompose (); + + void + findBestDecomposition (); + + double thresh; + double error_multiplier2; + const vector >& fts_c1; //!< Features on first image on unit plane + const vector >& fts_c2; //!< Features on second image on unit plane + vector inliers; + SE3 T_c2_from_c1; //!< Relative translation and rotation of two images + Matrix3d H_c2_from_c1; //!< Homography + vector decompositions; +}; + + + + +} /* end namespace vk */ + +#endif /* HOMOGRAPHY_H_ */ diff --git a/GPU_version/vio/include/vio/initialization.h b/GPU_version/vio/include/vio/initialization.h new file mode 100644 index 0000000..f9e551b --- /dev/null +++ b/GPU_version/vio/include/vio/initialization.h @@ -0,0 +1,87 @@ +// This file is part of SVO - Semi-direct Visual Odometry. +// +// Copyright (C) 2014 Christian Forster +// (Robotics and Perception Group, University of Zurich, Switzerland). +// +// SVO is free software: you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the Free Software +// Foundation, either version 3 of the License, or any later version. +// +// SVO is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#ifndef SVO_INITIALIZATION_H +#define SVO_INITIALIZATION_H + +#include +#include +//#include "../../gtsam/imu_integration.h" + +namespace vio { + +class FrameHandlerMono; + +/// Bootstrapping the map from the first two views. +namespace initialization { + +enum InitResult { FAILURE, NO_KEYFRAME, SUCCESS }; + +/// Tracks features using Lucas-Kanade tracker and then estimates a homography. +class KltHomographyInit { + friend class vio::FrameHandlerMono; +public: + EIGEN_MAKE_ALIGNED_OPERATOR_NEW + + FramePtr frame_ref_; + KltHomographyInit(opencl* gpu_fast_):gpu_fast_(gpu_fast_),T_cur_from_ref_(0.0,0.0,0.0) {}; + ~KltHomographyInit() {}; + InitResult addFirstFrame(FramePtr frame_ref); + InitResult addSecondFrame(FramePtr frame_ref); + void reset(); + +protected: + vector px_ref_; //!< keypoints to be tracked in reference frame. + vector px_cur_; //!< tracked keypoints in current frame. + vector f_ref_; //!< bearing vectors corresponding to the keypoints in the reference image. + vector f_cur_; //!< bearing vectors corresponding to the keypoints in the current image. + vector disparities_; //!< disparity between first and second frame. + vector inliers_; //!< inliers after the geometric check (e.g., Homography). + vector xyz_in_cur_; //!< 3D points computed during the geometric check. + SE2_5 T_cur_from_ref_; //!< computed transformation between the first two frames. + opencl* gpu_fast_; +}; + +/// Detect Fast corners in the image. +void detectFeatures( + FramePtr frame, + vector& px_vec, + vector& f_vec, + opencl* gpu_fast); + +/// Compute optical flow (Lucas Kanade) for selected keypoints. +void trackKlt( + FramePtr frame_ref, + FramePtr frame_cur, + vector& px_ref, + vector& px_cur, + vector& f_ref, + vector& f_cur, + vector& disparities); + +void computeHomography( + const vector& f_ref, + const vector& f_cur, + double focal_length, + double reprojection_threshold, + vector& inliers, + vector& xyz_in_cur, + SE2_5& T_cur_from_ref); + +} // namespace initialization +} // namespace vio + +#endif // SVO_INITIALIZATION_H diff --git a/GPU_version/vio/include/vio/map.h b/GPU_version/vio/include/vio/map.h new file mode 100644 index 0000000..9f218cb --- /dev/null +++ b/GPU_version/vio/include/vio/map.h @@ -0,0 +1,137 @@ +// This file is part of SVO - Semi-direct Visual Odometry. +// +// Copyright (C) 2014 Christian Forster +// (Robotics and Perception Group, University of Zurich, Switzerland). +// +// SVO is free software: you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the Free Software +// Foundation, either version 3 of the License, or any later version. +// +// SVO is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#ifndef SVO_MAP_H_ +#define SVO_MAP_H_ + +#include +#include +#include +#include + +namespace vio { + +class Point; +class Feature; +class Seed; + +/// Container for converged 3D points that are not already assigned to two keyframes. +class MapPointCandidates +{ +public: + typedef pair PointCandidate; + typedef list PointCandidateList; + + /// The depth-filter is running in a parallel thread and fills the canidate list. + /// This mutex controls concurrent access to point_candidates. + boost::mutex mut_; + + /// Candidate points are created from converged seeds. + /// Until the next keyframe, these points can be used for reprojection and pose optimization. + PointCandidateList candidates_; + list< Point* > trash_points_; + + MapPointCandidates(); + ~MapPointCandidates(); + + /// Add a candidate point. + void newCandidatePoint(Point* point, double depth_sigma2); + + /// Adds the feature to the frame and deletes candidate from list. + void addCandidatePointToFrame(FramePtr frame); + + /// Remove a candidate point from the list of candidates. + bool deleteCandidatePoint(Point* point); + + /// Remove all candidates that belong to a frame. + void removeFrameCandidates(FramePtr frame); + + /// Reset the candidate list, remove and delete all points. + void reset(); + + void deleteCandidate(PointCandidate& c); + + void emptyTrash(); +}; +static bool syn_=false; +/// Map object which saves all keyframes which are in a map. +class Map : boost::noncopyable +{ +public: + list< FramePtr > keyframes_; //!< List of keyframes in the map. + list< Point* > trash_points_; //!< A deleted point is moved to the trash bin. Now and then this is cleaned. One reason is that the visualizer must remove the points also. + MapPointCandidates point_candidates_; + + + Map(); + ~Map(); + + /// Reset the map. Delete all keyframes and reset the frame and point counters. + void reset(); + + /// Delete a point in the map and remove all references in keyframes to it. + void safeDeletePoint(Point* pt); + + /// Moves the point to the trash queue which is cleaned now and then. + void deletePoint(Point* pt); + + /// Moves the frame to the trash queue which is cleaned now and then. + bool safeDeleteFrame(FramePtr frame); + + /// Remove the references between a point and a frame. + void removePtFrameRef(Frame* frame, Feature* ftr); + + /// Add a new keyframe to the map. + void addKeyframe(FramePtr new_keyframe); + + /// Given a frame, return all keyframes which have an overlapping field of view. + void getCloseKeyframes(const FramePtr& frame, list< pair >& close_kfs) const; + + /// Return the keyframe which is spatially closest and has overlapping field of view. + FramePtr getClosestKeyframe(const FramePtr& frame) const; + + /// Return the keyframe which is furthest apart from pos. + FramePtr getFurthestKeyframe(const Vector2d& pos) const; + + bool getKeyframeById(const int id, FramePtr& frame) const; + + /// Transform the whole map with rotation R, translation t and scale s. + void transform(const Matrix2d& R, const Vector2d& t, const double& s); + + /// Empty trash bin of deleted keyframes and map points. We don't delete the + /// points immediately to ensure proper cleanup and to provide the visualizer + /// a list of objects which must be removed. + void emptyTrash(); + + /// Return the keyframe which was last inserted in the map. + inline FramePtr lastKeyframe() { return keyframes_.back(); } + + /// Return the number of keyframes in the map + inline size_t size() const { return keyframes_.size(); } +}; + +/// A collection of debug functions to check the data consistency. +namespace map_debug { + +void mapStatistics(Map* map); +void mapValidation(Map* map, int id); +void frameValidation(Frame* frame, int id); +void pointValidation(Point* point, int id); + +} // namespace map_debug +} // namespace vio + +#endif // SVO_MAP_H_ diff --git a/GPU_version/vio/include/vio/matcher.h b/GPU_version/vio/include/vio/matcher.h new file mode 100644 index 0000000..c7c1c6e --- /dev/null +++ b/GPU_version/vio/include/vio/matcher.h @@ -0,0 +1,130 @@ +// This file is part of SVO - Semi-direct Visual Odometry. +// +// Copyright (C) 2014 Christian Forster +// (Robotics and Perception Group, University of Zurich, Switzerland). +// +// SVO is free software: you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the Free Software +// Foundation, either version 3 of the License, or any later version. +// +// SVO is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#ifndef SVO_MATCHER_H_ +#define SVO_MATCHER_H_ + +#include + +namespace vk { + class AbstractCamera; + namespace patch_score { + template class ZMSSD; + } +} + +namespace vio { + +class Point; +class Frame; +class Feature; + +/// Warp a patch from the reference view to the current view. +namespace warp { + +void getWarpMatrixAffine( + const vk::AbstractCamera& cam_ref, + const vk::AbstractCamera& cam_cur, + const Vector2d& px_ref, + const Vector3d& f_ref, + const double depth_ref, + const SE3& T_cur_ref, + const int level_ref, + Matrix2d& A_cur_ref); + +int getBestSearchLevel( + const Matrix2d& A_cur_ref, + const int max_level); + +bool warpAffine( + const Matrix2d& A_cur_ref, + const cv::Mat& img_ref, + const Vector2d& px_ref, + const int level_ref, + const int level_cur, + const int halfpatch_size, + uint8_t* patch); + +} // namespace warp + +/// Patch-matcher for reprojection-matching and epipolar search in triangulation. +class Matcher +{ +public: + EIGEN_MAKE_ALIGNED_OPERATOR_NEW + + static const int halfpatch_size_ = 4; + static const int patch_size_ = 8; + + typedef vk::patch_score::ZMSSD PatchScore; + + struct Options + { + bool align_1d; //!< in epipolar search: align patch 1D along epipolar line + int align_max_iter; //!< number of iterations for aligning the feature patches in gauss newton + double max_epi_length_optim;//!< max length of epipolar line to skip epipolar search and directly go to img align + size_t max_epi_search_steps;//!< max number of evaluations along epipolar line + bool subpix_refinement; //!< do gauss newton feature patch alignment after epipolar search + bool epi_search_edgelet_filtering; + double epi_search_edgelet_max_angle; + Options() : + align_1d(false), + align_max_iter(10), + max_epi_length_optim(2.0), + max_epi_search_steps(1000), + subpix_refinement(true), + epi_search_edgelet_filtering(true), + epi_search_edgelet_max_angle(0.7) + {} + } options_; + + uint8_t patch_[patch_size_*patch_size_] __attribute__ ((aligned (16))); + uint8_t patch_with_border_[(patch_size_+2)*(patch_size_+2)] __attribute__ ((aligned (16))); + Matrix2d A_cur_ref_; //!< affine warp matrix + Vector2d epi_dir_; + double epi_length_; //!< length of epipolar line segment in pixels (only used for epipolar search) + double h_inv_; //!< hessian of 1d image alignment along epipolar line + int search_level_; + bool reject_; + Feature* ref_ftr_; + Vector2d px_cur_; + + Matcher() = default; + ~Matcher() = default; + + /// Find a match by directly applying subpix refinement. + /// IMPORTANT! This function assumes that px_cur is already set to an estimate that is within ~2-3 pixel of the final result! + bool findMatchDirect( + const Point& pt, + const Frame& frame, + Vector2d& px_cur); + + /// Find a match by searching along the epipolar line without using any features. + bool findEpipolarMatchDirect( + const Frame& ref_frame, + const Frame& cur_frame, + const Feature& ref_ftr, + const double d_estimate, + const double d_min, + const double d_max, + double& depth); + + void createPatchFromPatchWithBorder(); +}; + +} // namespace vio + +#endif // SVO_MATCHER_H_ diff --git a/GPU_version/vio/include/vio/math_utils.h b/GPU_version/vio/include/vio/math_utils.h new file mode 100644 index 0000000..6fffc38 --- /dev/null +++ b/GPU_version/vio/include/vio/math_utils.h @@ -0,0 +1,171 @@ +/* + * math_utils.h + * + * Created on: Jul 20, 2012 + * Author: cforster + */ + +#ifndef MATH_UTILS_H_ +#define MATH_UTILS_H_ + + +#include +#include +#include + +namespace vk +{ + +using namespace Eigen; +using namespace std; +using namespace Sophus; + +Vector3d triangulateFeatureNonLin( + const Matrix3d& R, + const Vector3d& t, + const Vector3d& feature1, + const Vector3d& feature2); + +/// Assumes the bearing vectors f_c and f_r are on the epipolar plane, i.e. +/// perfect triangulation without noise! +bool depthFromTriangulationExact( + const Matrix3d& R_r_c, + const Vector3d& t_r_c, + const Vector3d& f_r, + const Vector3d& f_c, + double& depth_in_r, + double& depth_in_c); + +double reprojError( + const Vector3d& f1, + const Vector3d& f2, + double error_multiplier2); + +double computeInliers( + const vector& features1, + const vector& features2, + const Matrix3d& R, + const Vector3d& t, + const double reproj_thresh, + double error_multiplier2, + vector& xyz_vec, + vector& inliers, + vector& outliers); + +void computeInliersOneView( + const vector & feature_sphere_vec, + const vector & xyz_vec, + const Matrix3d &R, + const Vector3d &t, + const double reproj_thresh, + const double error_multiplier2, + vector& inliers, + vector& outliers); + +//! Direct Cosine Matrix to Roll Pitch Yaw +Vector3d dcm2rpy(const Matrix3d &R); + +//! Roll Pitch Yaw to Direct Cosine Matrix +Matrix3d rpy2dcm(const Vector3d &rpy); + +//! Angle Axis parametrization to Quaternion +Quaterniond angax2quat(const Vector3d& n, const double& angle); + +//! Angle Axis parametrization to Matrix representation +Matrix3d angax2dcm(const Vector3d& n, const double& angle); + +double sampsonusError( + const Vector2d &v2Dash, + const Matrix3d& m3Essential, + const Vector2d& v2); + +inline Matrix3d sqew(const Vector3d& v) +{ + Matrix3d v_sqew; + v_sqew << 0, -v[2], v[1], + v[2], 0, -v[0], + -v[1], v[0], 0; + return v_sqew; +} + +inline double norm_max(const Eigen::VectorXd & v) +{ + double max = -1; + for (int i=0; imax){ + max = abs; + } + } + return max; +} + +inline Vector2d project2d(const Vector3d& v) +{ + return v.head<2>()/v[2]; +} + +inline Vector3d unproject2d(const Vector2d& v) +{ + return Vector3d(v[0], v[1], 1.0); +} + +inline Vector3d project3d(const Vector4d& v) +{ + return v.head<3>()/v[3]; +} + +inline Vector4d unproject3d(const Vector3d& v) +{ + return Vector4d(v[0], v[1], v[2], 1.0); +} + +template +T getMedian(vector& data_vec) +{ + assert(!data_vec.empty()); + typename vector::iterator it = data_vec.begin()+floor(data_vec.size()/2); + nth_element(data_vec.begin(), it, data_vec.end()); + return *it; +} + +inline double pyrFromZero_d(double x_0, int level) +{ + return x_0/(1< & frame_jac) +{ + const double x = xyz[0]; + const double y = xyz[1]; + const double z = xyz[2]; + const double z_2 = z*z; + + frame_jac(0,0) = -1./z *focal_length; + frame_jac(0,1) = 0; + frame_jac(0,2) = x/z_2 *focal_length; + frame_jac(0,3) = x*y/z_2 * focal_length; + frame_jac(0,4) = -(1+(x*x/z_2)) *focal_length; + frame_jac(0,5) = y/z *focal_length; + + frame_jac(1,0) = 0; + frame_jac(1,1) = -1./z *focal_length; + frame_jac(1,2) = y/z_2 *focal_length; + frame_jac(1,3) = (1+y*y/z_2) *focal_length; + frame_jac(1,4) = -x*y/z_2 *focal_length; + frame_jac(1,5) = -x/z *focal_length; +} + +} // end namespace vk + +#endif /* MATH_UTILS_H_ */ diff --git a/GPU_version/vio/include/vio/nlls_solver.h b/GPU_version/vio/include/vio/nlls_solver.h new file mode 100644 index 0000000..886556d --- /dev/null +++ b/GPU_version/vio/include/vio/nlls_solver.h @@ -0,0 +1,174 @@ +/* + * Abstract Nonlinear Least-Squares Solver Class + * + * nlls_solver.h + * + * Created on: Nov 5, 2012 + * Author: cforster + */ + +#ifndef LM_SOLVER_H_ +#define LM_SOLVER_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace vk { + +using namespace std; +using namespace Eigen; + +/** + * \brief Abstract Class for solving nonlinear least-squares (NLLS) problems. + * + * The function implements two algorithms: Levenberg Marquardt and Gauss Newton + * + * Example implementations of this function can be found in the rpl_examples + * package: img_align_2d.cpp, img_align_3d.cpp + * + * Template Parameters: + * D : dimension of the residual + * T : type of the model, e.g. SE2, SE3 + */ + +template +class NLLSSolver { + +public: + typedef T ModelType; + enum Method{GaussNewton, LevenbergMarquardt}; + enum ScaleEstimatorType{UnitScale, TDistScale, MADScale, NormalScale}; + enum WeightFunctionType{UnitWeight, TDistWeight, TukeyWeight, HuberWeight}; + +protected: + Matrix H_; //!< Hessian approximation + Matrix Jres_; //!< Jacobian x Residual + Matrix x_; //!< update step + bool have_prior_; + ModelType prior_; + Matrix I_prior_; //!< Prior information matrix (inverse covariance) + double chi2_; + double rho_; + Method method_; + + /// If the flag linearize_system is set, the function must also compute the + /// Jacobian and set the member variables H_, Jres_ + virtual double + computeResiduals (const ModelType& model, + bool linearize_system, + bool compute_weight_scale) = 0; + virtual double + computeResiduals (bool linearize_system, + bool compute_weight_scale) = 0; + + /// Solve the linear system H*x = Jres. This function must set the update + /// step in the member variable x_. Must return true if the system could be + /// solved and false if it was singular. + virtual int + solve () = 0; + + virtual void + update (const ModelType& old_model, ModelType& new_model) = 0; + virtual void + update () = 0; + + virtual void + applyPrior (const ModelType& current_model) { } + + virtual void + startIteration () { } + + virtual void + finishIteration () { } + + virtual void + finishTrial () { } + +public: + + /// Damping parameter. If mu > 0, coefficient matrix is positive definite, this + /// ensures that x is a descent direction. If mu is large, x is a short step in + /// the steepest direction. This is good if the current iterate is far from the + /// solution. If mu is small, LM approximates gauss newton iteration and we + /// have (almost) quadratic convergence in the final stages. + double mu_init_, mu_; + double nu_init_, nu_; //!< Increase factor of mu after fail + size_t n_iter_init_, n_iter_; //!< Number of Iterations + size_t n_trials_; //!< Number of trials + size_t n_trials_max_; //!< Max number of trials + size_t n_meas_; //!< Number of measurements + bool stop_; //!< Stop flag + bool verbose_; //!< Output Statistics + double eps_; //!< Stop if update norm is smaller than eps + size_t iter_; //!< Current Iteration + + // robust least squares + bool use_weights_; + float scale_; + robust_cost::ScaleEstimatorPtr scale_estimator_; + robust_cost::WeightFunctionPtr weight_function_; + + NLLSSolver() : + have_prior_(false), + method_(LevenbergMarquardt), + mu_init_(0.01f), + mu_(mu_init_), + nu_init_(2.0), + nu_(nu_init_), + n_iter_init_(15), + n_iter_(n_iter_init_), + n_trials_(0), + n_trials_max_(5), + n_meas_(0), + stop_(false), + verbose_(true), + eps_(0.0000000001), + iter_(0), + use_weights_(false), + scale_(0.0), + scale_estimator_(NULL), + weight_function_(NULL) + { } + + virtual ~NLLSSolver() {} + + /// Calls the GaussNewton or LevenbergMarquardt optimization strategy + void optimize(ModelType& model); + + /// Gauss Newton optimization strategy + void optimizeGaussNewton(); + + /// Levenberg Marquardt optimization strategy + void optimizeLevenbergMarquardt(ModelType& model); + + /// Specify the robust cost that should be used and the appropriate scale estimator + void setRobustCostFunction( + ScaleEstimatorType scale_estimator, + WeightFunctionType weight_function); + + /// Add prior to optimization. + void setPrior( + const ModelType& prior, + const Matrix& Information); + + /// Reset all parameters to restart the optimization + void reset(); + + /// Get the squared error + const double& getChi2() const; + + /// The Information matrix is equal to the inverse covariance matrix. + const Matrix& getInformationMatrix() const; +}; + +} // end namespace vk + +#include "vio/nlls_solver_impl.hpp" + +#endif /* LM_SOLVER_H_ */ diff --git a/GPU_version/vio/include/vio/nlls_solver_impl.hpp b/GPU_version/vio/include/vio/nlls_solver_impl.hpp new file mode 100644 index 0000000..cbd7b6f --- /dev/null +++ b/GPU_version/vio/include/vio/nlls_solver_impl.hpp @@ -0,0 +1,316 @@ +/* + * Abstract Nonlinear Least-Squares Solver Class + * + * nlls_solver.h + * + * Created on: Nov 5, 2012 + * Author: cforster + */ + +#ifndef LM_SOLVER_IMPL_HPP_ +#define LM_SOLVER_IMPL_HPP_ + +#include + +template +void vk::NLLSSolver::optimize(ModelType& model) +{ + if(method_ == GaussNewton) + optimizeGaussNewton(); + else if(method_ == LevenbergMarquardt) + optimizeLevenbergMarquardt(model); +} + +template +void vk::NLLSSolver::optimizeGaussNewton() +{ + // Compute weight scale + if(use_weights_) + computeResiduals(false, true); + // perform iterative estimation + for (iter_ = 0; iter_ 0 && new_chi2 > chi2_) || stop_) + { + if(verbose_) + { + std::cout << "It. " << iter_ + << "\t Failure" + << "\t new_chi2 = " << new_chi2 + << "\t Error increased. Stop optimizing.\n"; + } + break; + } + // update the model + update(); + chi2_ = new_chi2; + if(verbose_) + { + std::cout << "It. " << iter_ + << "\t Success" + << "\t new_chi2 = " << new_chi2 + << "\t n_meas = " << n_meas_ + << "\t x_norm = " << vk::norm_max(x_)<<'\n'; + } + // stop when converged, i.e. update step too small + if(vk::norm_max(x_)<=eps_) + break; + } +} + +template +void vk::NLLSSolver::optimizeLevenbergMarquardt(ModelType& model) +{ + // Compute weight scale + if(use_weights_) + computeResiduals(model, false, true); + + // compute the initial error + chi2_ = computeResiduals(model, true, false); + + if(verbose_) + cout << "init chi2 = " << chi2_ + << "\t n_meas = " << n_meas_ + << endl; + + // TODO: compute initial lambda + // Hartley and Zisserman: "A typical init value of lambda is 10^-3 times the + // average of the diagonal elements of J'J" + + // Compute Initial Lambda + if(mu_ < 0) + { + double H_max_diag = 0; + double tau = 1e-4; + for(size_t j=0; j::Identity(D,D); + Jres_.setZero(); + + // compute initial error + n_meas_ = 0; + computeResiduals(model, true, false); + + // add damping term: + H_ += (H_.diagonal()*mu_).asDiagonal(); + + // add prior + if(have_prior_) + applyPrior(model); + + // solve the linear system + if(solve()) + { + // update the model + update(model, new_model); + + // compute error with new model and compare to old error + n_meas_ = 0; + new_chi2 = computeResiduals(new_model, true, false); + rho_ = chi2_-new_chi2; + } + else + { + // matrix was singular and could not be computed + cout << "Matrix is close to singular!" << endl; + cout << "H = " << H_ << endl; + cout << "Jres = " << Jres_ << endl; + rho_ = -1; + } + + if(rho_>0) + { + // update decrased the error -> success + model = new_model; + chi2_ = new_chi2; + stop_ = vk::norm_max(x_)<=eps_ ? true : false; + mu_ *= max(1./3., min(1.-pow(2*rho_-1,3), 2./3.)); + nu_ = 2.; + if(verbose_) + { + cout << "It. " << iter_ + << "\t Trial " << n_trials_ + << "\t Success" + << "\t n_meas = " << n_meas_ + << "\t new_chi2 = " << new_chi2 + << "\t mu = " << mu_ + << "\t nu = " << nu_ + << "\t x_norm = " << vk::norm_max(x_) + << endl; + } + } + else + { + if(sign){ + if(verbose_) + { + cout << "It. " << iter_ + << "\t Trial " << n_trials_ + << "\t Failure" + << "\t n_meas = " << n_meas_ + << "\t new_chi2 = " << new_chi2 + << "\t mu = " << mu_ + << "\t nu = " << nu_ + << "\t x_norm = " << vk::norm_max(x_) + << endl; + } + mu_ /= nu_; + nu_ /= 2.; + ++n_trials_; + if (n_trials_ >= n_trials_max_) + stop_ = true; + sign=false; + }else{ + if(verbose_) + { + cout << "It. " << iter_ + << "\t Trial " << n_trials_ + << "\t Failure" + << "\t n_meas = " << n_meas_ + << "\t new_chi2 = " << new_chi2 + << "\t mu = " << mu_ + << "\t nu = " << nu_ + << "\t x_norm = " << vk::norm_max(x_) + << endl; + } + mu_ *= nu_; + nu_ *= 2.; + ++n_trials_; + if (n_trials_ >= n_trials_max_) + stop_ = true; + sign=true; + } + + } + + finishTrial(); + + } while(!(rho_>0 || stop_)); + if (stop_) + break; + + finishIteration(); + } +} + + +template +void vk::NLLSSolver::setRobustCostFunction( + ScaleEstimatorType scale_estimator, + WeightFunctionType weight_function) +{ + switch(scale_estimator) + { + case TDistScale: + if(verbose_) + printf("Using TDistribution Scale Estimator\n"); + scale_estimator_.reset(new robust_cost::TDistributionScaleEstimator()); + use_weights_=true; + break; + case MADScale: + if(verbose_) + printf("Using MAD Scale Estimator\n"); + scale_estimator_.reset(new robust_cost::MADScaleEstimator()); + use_weights_=true; + break; + case NormalScale: + if(verbose_) + printf("Using Normal Scale Estimator\n"); + scale_estimator_.reset(new robust_cost::NormalDistributionScaleEstimator()); + use_weights_=true; + break; + default: + if(verbose_) + printf("Using Unit Scale Estimator\n"); + scale_estimator_.reset(new robust_cost::UnitScaleEstimator()); + use_weights_=false; + } + + switch(weight_function) + { + case TDistWeight: + if(verbose_) + printf("Using TDistribution Weight Function\n"); + weight_function_.reset(new robust_cost::TDistributionWeightFunction()); + break; + case TukeyWeight: + if(verbose_) + printf("Using Tukey Weight Function\n"); + weight_function_.reset(new robust_cost::TukeyWeightFunction()); + break; + case HuberWeight: + if(verbose_) + printf("Using Huber Weight Function\n"); + weight_function_.reset(new robust_cost::HuberWeightFunction()); + break; + default: + if(verbose_) + printf("Using Unit Weight Function\n"); + weight_function_.reset(new robust_cost::UnitWeightFunction()); + } +} + +template +void vk::NLLSSolver::setPrior( + const T& prior, + const Matrix& Information) +{ + have_prior_ = true; + prior_ = prior; + I_prior_ = Information; +} + +template +void vk::NLLSSolver::reset() +{ + have_prior_ = false; + chi2_ = 1e10; + mu_ = mu_init_; + nu_ = nu_init_; + n_meas_ = 0; + n_iter_ = n_iter_init_; + iter_ = 0; + stop_ = false; +} + +template +inline const double& vk::NLLSSolver::getChi2() const +{ + return chi2_; +} + +template +inline const vk::Matrix& vk::NLLSSolver::getInformationMatrix() const +{ + return H_; +} + +#endif /* LM_SOLVER_IMPL_HPP_ */ diff --git a/GPU_version/vio/include/vio/output_helper.h b/GPU_version/vio/include/vio/output_helper.h new file mode 100644 index 0000000..b1572a8 --- /dev/null +++ b/GPU_version/vio/include/vio/output_helper.h @@ -0,0 +1,90 @@ +/* + * output_helper.h + * + * Created on: Jan 20, 2013 + * Author: cforster + */ + +#ifndef VIKIT_OUTPUT_HELPER_H_ +#define VIKIT_OUTPUT_HELPER_H_ + +#include +#include +#include +#include +#include + +using namespace std; +using namespace Eigen; + +void +publishTfTransform (const Sophus::SE3& T, const ros::Time& stamp, + const string& frame_id, const string& child_frame_id, + tf::TransformBroadcaster& br); + +void +publishPointMarker (ros::Publisher pub, + const Vector3d& pos, + const string& ns, + const ros::Time& timestamp, + int id, + int action, + double marker_scale, + const Vector3d& color, + ros::Duration lifetime = ros::Duration(0.0)); + +void +publishLineMarker (ros::Publisher pub, + const Vector3d& start, + const Vector3d& end, + const string& ns, + const ros::Time& timestamp, + int id, + int action, + double marker_scale, + const Vector3d& color, + ros::Duration lifetime = ros::Duration(0.0)); + +void +publishArrowMarker (ros::Publisher pub, + const Vector3d& pos, + const Vector3d& dir, + double scale, + const string& ns, + const ros::Time& timestamp, + int id, + int action, + double marker_scale, + const Vector3d& color); + +void +publishHexacopterMarker (ros::Publisher pub, + const string& frame_id, + const string& ns, + const ros::Time& timestamp, + int id, + int action, + double marker_scale, + const Vector3d& color); + +void +publishCameraMarker(ros::Publisher pub, + const string& frame_id, + const string& ns, + const ros::Time& timestamp, + int id, + double marker_scale, + const Vector3d& color); +void +publishFrameMarker (ros::Publisher pub, + const Matrix3d& rot, + const Vector3d& pos, + const string& ns, + const ros::Time& timestamp, + int id, + int action, + double marker_scale, + ros::Duration lifetime = ros::Duration(0.0)); + + +#endif /* VIKIT_OUTPUT_HELPER_H_ */ diff --git a/GPU_version/vio/include/vio/params_helper.h b/GPU_version/vio/include/vio/params_helper.h new file mode 100644 index 0000000..e593c3e --- /dev/null +++ b/GPU_version/vio/include/vio/params_helper.h @@ -0,0 +1,57 @@ +// +// Created by root on 5/24/21. +// + +#ifndef VIO_PARAMS_HELPER_H +#define VIO_PARAMS_HELPER_H +/* + * ros_params_helper.h + * + * Created on: Feb 22, 2013 + * Author: cforster + * + * from libpointmatcher_ros + */ + +#include +#include + +namespace vk { + + inline + bool hasParam(const std::string& name) + { + return ros::param::has(name); + } + + template + T getParam(const std::string& name, const T& defaultValue) + { + T v; + if(ros::param::get(name, v)) + { + ROS_INFO_STREAM("Found parameter: " << name << ", value: " << v); + return v; + } + else + ROS_WARN_STREAM("Cannot find value for parameter: " << name << ", assigning default: " << defaultValue); + return defaultValue; + } + + template + T getParam(const std::string& name) + { + T v; + if(ros::param::get(name, v)) + { + ROS_INFO_STREAM("Found parameter: " << name << ", value: " << v); + return v; + } + else + ROS_ERROR_STREAM("Cannot find value for parameter: " << name); + return T(); + } + +} // namespace vk + +#endif //VIO_PARAMS_HELPER_H diff --git a/GPU_version/vio/include/vio/patch_score.h b/GPU_version/vio/include/vio/patch_score.h new file mode 100644 index 0000000..8f0516c --- /dev/null +++ b/GPU_version/vio/include/vio/patch_score.h @@ -0,0 +1,225 @@ +/* + * patch_score.h + * + * Created on: Dec 5, 2013 + * Author: cforster + */ + +#ifndef VIKIT_PATCH_SCORE_H_ +#define VIKIT_PATCH_SCORE_H_ + +#include + +#if __SSE2__ +#include +#endif + +namespace vk { +namespace patch_score { + + +#if __SSE2__ +// Horizontal sum of uint16s stored in an XMM register +inline int SumXMM_16(__m128i &target) +{ + unsigned short int sums_store[8]; + _mm_storeu_si128((__m128i*)sums_store, target); + return sums_store[0] + sums_store[1] + sums_store[2] + sums_store[3] + + sums_store[4] + sums_store[5] + sums_store[6] + sums_store[7]; +} +// Horizontal sum of uint32s stored in an XMM register +inline int SumXMM_32(__m128i &target) +{ + unsigned int sums_store[4]; + _mm_storeu_si128((__m128i*)sums_store, target); + return sums_store[0] + sums_store[1] + sums_store[2] + sums_store[3]; +} +#endif + +/// Zero Mean Sum of Squared Differences Cost +template +class ZMSSD { +public: + + static const int patch_size_ = 2*HALF_PATCH_SIZE; + static const int patch_area_ = patch_size_*patch_size_; + static const int threshold_ = 2000*patch_area_; + uint8_t* ref_patch_; + int sumA_, sumAA_; + + ZMSSD(uint8_t* ref_patch) : + ref_patch_(ref_patch) + { + uint32_t sumA_uint=0, sumAA_uint=0; + for(int r = 0; r < patch_area_; r++) + { + uint8_t n = ref_patch_[r]; + sumA_uint += n; + sumAA_uint += n*n; + } + sumA_ = sumA_uint; + sumAA_ = sumAA_uint; + } + + static int threshold() { return threshold_; } + + int computeScore(uint8_t* cur_patch) const + { + uint32_t sumB_uint = 0; + uint32_t sumBB_uint = 0; + uint32_t sumAB_uint = 0; + for(int r = 0; r < patch_area_; r++) + { + const uint8_t cur_pixel = cur_patch[r]; + sumB_uint += cur_pixel; + sumBB_uint += cur_pixel*cur_pixel; + sumAB_uint += cur_pixel * ref_patch_[r]; + } + const int sumB = sumB_uint; + const int sumBB = sumBB_uint; + const int sumAB = sumAB_uint; + return sumAA_ - 2*sumAB + sumBB - (sumA_*sumA_ - 2*sumA_*sumB + sumB*sumB)/patch_area_; + } + + int computeScore(uint8_t* cur_patch, int stride) const + { + int sumB, sumBB, sumAB; +#if __SSE2__ + if(patch_size_ == 8) + { + // From PTAM-GPL, Copyright 2008 Isis Innovation Limited + __m128i xImageAsEightBytes; + __m128i xImageAsWords; + __m128i xTemplateAsEightBytes; + __m128i xTemplateAsWords; + __m128i xZero; + __m128i xImageSums; // These sums are 8xuint16 + __m128i xImageSqSums; // These sums are 4xint32 + __m128i xCrossSums; // These sums are 4xint32 + __m128i xProduct; + + xImageSums = _mm_setzero_si128(); + xImageSqSums = _mm_setzero_si128(); + xCrossSums = _mm_setzero_si128(); + xZero = _mm_setzero_si128(); + + uint8_t* imagepointer = cur_patch; + uint8_t* templatepointer = ref_patch_; + long unsigned int cur_stride = stride; + + xImageAsEightBytes=_mm_loadl_epi64((__m128i*) imagepointer); + imagepointer += cur_stride; + xImageAsWords = _mm_unpacklo_epi8(xImageAsEightBytes,xZero); + xImageSums = _mm_adds_epu16(xImageAsWords,xImageSums); + xProduct = _mm_madd_epi16(xImageAsWords, xImageAsWords); + xImageSqSums = _mm_add_epi32(xProduct, xImageSqSums); + xTemplateAsEightBytes=_mm_load_si128((__m128i*) templatepointer); + templatepointer += 16; + xTemplateAsWords = _mm_unpacklo_epi8(xTemplateAsEightBytes,xZero); + xProduct = _mm_madd_epi16(xImageAsWords, xTemplateAsWords); + xCrossSums = _mm_add_epi32(xProduct, xCrossSums); + xImageAsEightBytes=_mm_loadl_epi64((__m128i*) imagepointer); + imagepointer += cur_stride; + xImageAsWords = _mm_unpacklo_epi8(xImageAsEightBytes,xZero); + xImageSums = _mm_adds_epu16(xImageAsWords,xImageSums); + xProduct = _mm_madd_epi16(xImageAsWords, xImageAsWords); + xImageSqSums = _mm_add_epi32(xProduct, xImageSqSums); + xTemplateAsWords = _mm_unpackhi_epi8(xTemplateAsEightBytes,xZero); + xProduct = _mm_madd_epi16(xImageAsWords, xTemplateAsWords); + xCrossSums = _mm_add_epi32(xProduct, xCrossSums); + + xImageAsEightBytes=_mm_loadl_epi64((__m128i*) imagepointer); + imagepointer += cur_stride; + xImageAsWords = _mm_unpacklo_epi8(xImageAsEightBytes,xZero); + xImageSums = _mm_adds_epu16(xImageAsWords,xImageSums); + xProduct = _mm_madd_epi16(xImageAsWords, xImageAsWords); + xImageSqSums = _mm_add_epi32(xProduct, xImageSqSums); + xTemplateAsEightBytes=_mm_load_si128((__m128i*) templatepointer); + templatepointer += 16; + xTemplateAsWords = _mm_unpacklo_epi8(xTemplateAsEightBytes,xZero); + xProduct = _mm_madd_epi16(xImageAsWords, xTemplateAsWords); + xCrossSums = _mm_add_epi32(xProduct, xCrossSums); + xImageAsEightBytes=_mm_loadl_epi64((__m128i*) imagepointer); + imagepointer += cur_stride; + xImageAsWords = _mm_unpacklo_epi8(xImageAsEightBytes,xZero); + xImageSums = _mm_adds_epu16(xImageAsWords,xImageSums); + xProduct = _mm_madd_epi16(xImageAsWords, xImageAsWords); + xImageSqSums = _mm_add_epi32(xProduct, xImageSqSums); + xTemplateAsWords = _mm_unpackhi_epi8(xTemplateAsEightBytes,xZero); + xProduct = _mm_madd_epi16(xImageAsWords, xTemplateAsWords); + xCrossSums = _mm_add_epi32(xProduct, xCrossSums); + + xImageAsEightBytes=_mm_loadl_epi64((__m128i*) imagepointer); + imagepointer += cur_stride; + xImageAsWords = _mm_unpacklo_epi8(xImageAsEightBytes,xZero); + xImageSums = _mm_adds_epu16(xImageAsWords,xImageSums); + xProduct = _mm_madd_epi16(xImageAsWords, xImageAsWords); + xImageSqSums = _mm_add_epi32(xProduct, xImageSqSums); + xTemplateAsEightBytes=_mm_load_si128((__m128i*) templatepointer); + templatepointer += 16; + xTemplateAsWords = _mm_unpacklo_epi8(xTemplateAsEightBytes,xZero); + xProduct = _mm_madd_epi16(xImageAsWords, xTemplateAsWords); + xCrossSums = _mm_add_epi32(xProduct, xCrossSums); + xImageAsEightBytes=_mm_loadl_epi64((__m128i*) imagepointer); + imagepointer += cur_stride; + xImageAsWords = _mm_unpacklo_epi8(xImageAsEightBytes,xZero); + xImageSums = _mm_adds_epu16(xImageAsWords,xImageSums); + xProduct = _mm_madd_epi16(xImageAsWords, xImageAsWords); + xImageSqSums = _mm_add_epi32(xProduct, xImageSqSums); + xTemplateAsWords = _mm_unpackhi_epi8(xTemplateAsEightBytes,xZero); + xProduct = _mm_madd_epi16(xImageAsWords, xTemplateAsWords); + xCrossSums = _mm_add_epi32(xProduct, xCrossSums); + + xImageAsEightBytes=_mm_loadl_epi64((__m128i*) imagepointer); + imagepointer += cur_stride; + xImageAsWords = _mm_unpacklo_epi8(xImageAsEightBytes,xZero); + xImageSums = _mm_adds_epu16(xImageAsWords,xImageSums); + xProduct = _mm_madd_epi16(xImageAsWords, xImageAsWords); + xImageSqSums = _mm_add_epi32(xProduct, xImageSqSums); + xTemplateAsEightBytes=_mm_load_si128((__m128i*) templatepointer); + templatepointer += 16; + xTemplateAsWords = _mm_unpacklo_epi8(xTemplateAsEightBytes,xZero); + xProduct = _mm_madd_epi16(xImageAsWords, xTemplateAsWords); + xCrossSums = _mm_add_epi32(xProduct, xCrossSums); + xImageAsEightBytes=_mm_loadl_epi64((__m128i*) imagepointer); + xImageAsWords = _mm_unpacklo_epi8(xImageAsEightBytes,xZero); + xImageSums = _mm_adds_epu16(xImageAsWords,xImageSums); + xProduct = _mm_madd_epi16(xImageAsWords, xImageAsWords); + xImageSqSums = _mm_add_epi32(xProduct, xImageSqSums); + xTemplateAsWords = _mm_unpackhi_epi8(xTemplateAsEightBytes,xZero); + xProduct = _mm_madd_epi16(xImageAsWords, xTemplateAsWords); + xCrossSums = _mm_add_epi32(xProduct, xCrossSums); + + sumB = SumXMM_16(xImageSums); + sumAB = SumXMM_32(xCrossSums); + sumBB = SumXMM_32(xImageSqSums); + } + else +#endif + { + uint32_t sumB_uint = 0; + uint32_t sumBB_uint = 0; + uint32_t sumAB_uint = 0; + for(int y=0, r=0; y < patch_size_; ++y) + { + uint8_t* cur_patch_ptr = cur_patch + y*stride; + for(int x=0; x < patch_size_; ++x, ++r) + { + const uint8_t cur_px = cur_patch_ptr[x]; + sumB_uint += cur_px; + sumBB_uint += cur_px * cur_px; + sumAB_uint += cur_px * ref_patch_[r]; + } + } + sumB = sumB_uint; + sumBB = sumBB_uint; + sumAB = sumAB_uint; + } + return sumAA_ - 2*sumAB + sumBB - (sumA_*sumA_ - 2*sumA_*sumB + sumB*sumB)/patch_area_; + } +}; + +} // namespace patch_score +} // namespace vk + +#endif // VIKIT_PATCH_SCORE_H_ diff --git a/GPU_version/vio/include/vio/point.h b/GPU_version/vio/include/vio/point.h new file mode 100644 index 0000000..6d7c20b --- /dev/null +++ b/GPU_version/vio/include/vio/point.h @@ -0,0 +1,108 @@ +// This file is part of SVO - Semi-direct Visual Odometry. +// +// Copyright (C) 2014 Christian Forster +// (Robotics and Perception Group, University of Zurich, Switzerland). +// +// SVO is free software: you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the Free Software +// Foundation, either version 3 of the License, or any later version. +// +// SVO is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#ifndef SVO_POINT_H_ +#define SVO_POINT_H_ + +#include +#include + +namespace g2o { + class VertexSBAPointXYZ; +} +typedef g2o::VertexSBAPointXYZ g2oPoint; + +namespace vio { + +class Feature; + +typedef Matrix Matrix23d; + +/// A 3D point on the surface of the scene. +class Point : boost::noncopyable +{ +public: + EIGEN_MAKE_ALIGNED_OPERATOR_NEW + + enum PointType { + TYPE_DELETED, + TYPE_CANDIDATE, + TYPE_UNKNOWN, + TYPE_GOOD + }; + + static int point_counter_; //!< Counts the number of created points. Used to set the unique id. + int id_; //!< Unique ID of the point. + Vector3d pos_; //!< 3d pos of the point in the world coordinate frame. + Vector3d normal_; //!< Surface normal at point. + Matrix3d normal_information_; //!< Inverse covariance matrix of normal estimation. + bool normal_set_; //!< Flag whether the surface normal was estimated or not. + list obs_; //!< References to keyframes which observe the point. + size_t n_obs_; //!< Number of obervations: Keyframes AND successful reprojections in intermediate frames. + g2oPoint* v_pt_; //!< Temporary pointer to the point-vertex in g2o during bundle adjustment. + int last_published_ts_; //!< Timestamp of last publishing. + int last_projected_kf_id_; //!< Flag for the reprojection: don't reproject a pt twice. + PointType type_; //!< Quality of the point. + int n_failed_reproj_; //!< Number of failed reprojections. Used to assess the quality of the point. + int n_succeeded_reproj_; //!< Number of succeeded reprojections. Used to assess the quality of the point. + int last_structure_optim_; //!< Timestamp of last point optimization + + Point(const Vector3d& pos); + Point(const Vector3d& pos, Feature* ftr); + ~Point(); + + /// Add a reference to a frame. + void addFrameRef(Feature* ftr); + + /// Remove reference to a frame. + bool deleteFrameRef(Frame* frame); + + /// Initialize point normal. The inital estimate will point towards the frame. + void initNormal(); + + /// Check whether mappoint has reference to a frame. + Feature* findFrameRef(Frame* frame); + + /// Get Frame with similar viewpoint. + bool getCloseViewObs(const Vector2d& pos, Feature*& obs) const; + + /// Get number of observations. + inline size_t nRefs() const { return obs_.size(); } + + /// Optimize point position through minimizing the reprojection error. + void optimize(const size_t n_iter); + + /// Jacobian of point projection on unit plane (focal length = 1) in frame (f). + inline static void jacobian_xyz2uv( + const Vector3d& p_in_f, + const Matrix3d& R_f_w, + Matrix23d& point_jac) + { + const double z_inv = 1.0/p_in_f[2]; + const double z_inv_sq = z_inv*z_inv; + point_jac(0, 0) = z_inv; + point_jac(0, 1) = 0.0; + point_jac(0, 2) = -p_in_f[0] * z_inv_sq; + point_jac(1, 0) = 0.0; + point_jac(1, 1) = z_inv; + point_jac(1, 2) = -p_in_f[1] * z_inv_sq; + point_jac = - point_jac * R_f_w; + } +}; + +} // namespace vio + +#endif // SVO_POINT_H_ diff --git a/GPU_version/vio/include/vio/pose_optimizer.h b/GPU_version/vio/include/vio/pose_optimizer.h new file mode 100644 index 0000000..e6bc443 --- /dev/null +++ b/GPU_version/vio/include/vio/pose_optimizer.h @@ -0,0 +1,50 @@ +// This file is part of SVO - Semi-direct Visual Odometry. +// +// Copyright (C) 2014 Christian Forster +// (Robotics and Perception Group, University of Zurich, Switzerland). +// +// SVO is free software: you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the Free Software +// Foundation, either version 3 of the License, or any later version. +// +// SVO is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#ifndef SVO_POSE_OPTIMIZER_H_ +#define SVO_POSE_OPTIMIZER_H_ + +#include + +namespace vio { + +using namespace Eigen; +using namespace Sophus; +using namespace std; + +typedef Matrix Matrix6d; +typedef Matrix Matrix26d; +typedef Matrix Vector6d; + +class Point; + +/// Motion-only bundle adjustment. Minimize the reprojection error of a single frame. +namespace pose_optimizer { + +void optimizeGaussNewton( + const double reproj_thresh, + const size_t n_iter, + const bool verbose, + FramePtr& frame, + double& estimated_scale, + double& error_init, + double& error_final, + size_t& num_obs); + +} // namespace pose_optimizer +} // namespace vio + +#endif // SVO_POSE_OPTIMIZER_H_ diff --git a/GPU_version/vio/include/vio/reprojector.h b/GPU_version/vio/include/vio/reprojector.h new file mode 100644 index 0000000..1a60333 --- /dev/null +++ b/GPU_version/vio/include/vio/reprojector.h @@ -0,0 +1,101 @@ +// This file is part of SVO - Semi-direct Visual Odometry. +// +// Copyright (C) 2014 Christian Forster +// (Robotics and Perception Group, University of Zurich, Switzerland). +// +// SVO is free software: you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the Free Software +// Foundation, either version 3 of the License, or any later version. +// +// SVO is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#ifndef SVO_REPROJECTION_H_ +#define SVO_REPROJECTION_H_ + +#include +#include + +namespace vk { +class AbstractCamera; +} + +namespace vio { + +class Map; +class Point; + +/// Project points from the map into the image and find the corresponding +/// feature (corner). We don't search a match for every point but only for one +/// point per cell. Thereby, we achieve a homogeneously distributed set of +/// matched features and at the same time we can save processing time by not +/// projecting all points. +class Reprojector +{ +public: + EIGEN_MAKE_ALIGNED_OPERATOR_NEW + + /// Reprojector config parameters + struct Options { + size_t max_n_kfs; //!< max number of keyframes to reproject from + bool find_match_direct; + Options() + : max_n_kfs(10), + find_match_direct(true) + {} + } options_; + + size_t n_matches_; + size_t n_trials_; + + Reprojector(vk::AbstractCamera* cam, Map& map); + + ~Reprojector(); + + /// Project points from the map into the image. First finds keyframes with + /// overlapping field of view and projects only those map-points. + void reprojectMap( + FramePtr frame, + std::vector< std::pair >& overlap_kfs); + +private: + + /// A candidate is a point that projects into the image plane and for which we + /// will search a maching feature in the image. + struct Candidate { + EIGEN_MAKE_ALIGNED_OPERATOR_NEW + Point* pt; //!< 3D point. + Vector2d px; //!< projected 2D pixel location. + Candidate(Point* pt, Vector2d& px) : pt(pt), px(px) {} + }; + typedef std::list Cell; + typedef std::vector CandidateGrid; + + /// The grid stores a set of candidate matches. For every grid cell we try to find one match. + struct Grid + { + CandidateGrid cells; + vector cell_order; + int cell_size; + int grid_n_cols; + int grid_n_rows; + }; + + Grid grid_; + Matcher matcher_; + Map& map_; + + static bool pointQualityComparator(Candidate& lhs, Candidate& rhs); + void initializeGrid(vk::AbstractCamera* cam); + void resetGrid(); + bool reprojectCell(Cell& cell, FramePtr frame); + bool reprojectPoint(FramePtr frame, Point* point); +}; + +} // namespace vio + +#endif // SVO_REPROJECTION_H_ diff --git a/GPU_version/vio/include/vio/robust_cost.h b/GPU_version/vio/include/vio/robust_cost.h new file mode 100644 index 0000000..d03881a --- /dev/null +++ b/GPU_version/vio/include/vio/robust_cost.h @@ -0,0 +1,156 @@ +/** +* This file is part of dvo. +* +* Copyright 2012 Christian Kerl (Technical University of Munich) +* For more information see . +* +* dvo is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* dvo is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with dvo. If not, see . +*/ + +#ifndef VIKIT_ROBUST_COST_H_ +#define VIKIT_ROBUST_COST_H_ + +#include +#include +#include +namespace vk { +namespace robust_cost { + +// interface for scale estimators +class ScaleEstimator +{ +public: + virtual ~ScaleEstimator() {}; + virtual float compute(std::vector& errors) const = 0; +}; +typedef std::shared_ptr ScaleEstimatorPtr; + +class UnitScaleEstimator : public ScaleEstimator +{ +public: + UnitScaleEstimator() {} + virtual ~UnitScaleEstimator() {} + virtual float compute(std::vector& errors) const { return 1.0f; }; +}; + +// estimates scale by fitting a t-distribution to the data with the given degrees of freedom +class TDistributionScaleEstimator : public ScaleEstimator +{ +public: + TDistributionScaleEstimator(const float dof = DEFAULT_DOF); + virtual ~TDistributionScaleEstimator() {}; + virtual float compute(std::vector& errors) const; + + static const float DEFAULT_DOF; + static const float INITIAL_SIGMA; +protected: + float dof_; + float initial_sigma_; +}; + +// estimates scale by computing the median absolute deviation +class MADScaleEstimator : public ScaleEstimator +{ +public: + MADScaleEstimator() {}; + virtual ~MADScaleEstimator() {}; + virtual float compute(std::vector& errors) const; + +private: + static const float NORMALIZER;; +}; + +// estimates scale by computing the standard deviation +class NormalDistributionScaleEstimator : public ScaleEstimator +{ +public: + NormalDistributionScaleEstimator() {}; + virtual ~NormalDistributionScaleEstimator() {}; + virtual float compute(std::vector& errors) const; +private: +}; + +/** + * Interface for weight functions. A weight function is the first derivative of a symmetric robust function p(sqrt(t)). + * The errors are assumed to be normalized to unit variance. + * + * See: + * "Lucas-Kanade 20 Years On: A Unifying Framework: Part 2" - Page 23, Equation (54) + */ +class WeightFunction +{ +public: + virtual ~WeightFunction() {}; + virtual float value(const float& x) const = 0; + virtual void configure(const float& param) {}; +}; +typedef std::shared_ptr WeightFunctionPtr; + +class UnitWeightFunction : public WeightFunction +{ +public: + UnitWeightFunction() {}; + virtual ~UnitWeightFunction() {}; + virtual float value(const float& x) const { return 1.0f; }; +}; + +/** + * Tukey's hard re-descending function. + * + * See: + * http://en.wikipedia.org/wiki/Redescending_M-estimator + */ +class TukeyWeightFunction : public WeightFunction +{ +public: + TukeyWeightFunction(const float b = DEFAULT_B); + virtual ~TukeyWeightFunction() {}; + virtual float value(const float& x) const; + virtual void configure(const float& param); + + static const float DEFAULT_B; +private: + float b_square; +}; + +class TDistributionWeightFunction : public WeightFunction +{ +public: + TDistributionWeightFunction(const float dof = DEFAULT_DOF); + virtual ~TDistributionWeightFunction() {}; + virtual float value(const float& x) const; + virtual void configure(const float& param); + + static const float DEFAULT_DOF; +private: + float dof_; + float normalizer_; +}; + +class HuberWeightFunction : public WeightFunction +{ +public: + HuberWeightFunction(const float k = DEFAULT_K); + virtual ~HuberWeightFunction() {}; + virtual float value(const float& x) const; + virtual void configure(const float& param); + + static const float DEFAULT_K; +private: + float k; +}; + +} // namespace robust_cost +} // namespace vk +#endif // VIKIT_ROBUST_COST_H_ diff --git a/GPU_version/vio/include/vio/sparse_img_align.h b/GPU_version/vio/include/vio/sparse_img_align.h new file mode 100644 index 0000000..5962131 --- /dev/null +++ b/GPU_version/vio/include/vio/sparse_img_align.h @@ -0,0 +1,85 @@ +// This file is part of SVO - Semi-direct Visual Odometry. +// +// Copyright (C) 2014 Christian Forster +// (Robotics and Perception Group, University of Zurich, Switzerland). +// +// SVO is free software: you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the Free Software +// Foundation, either version 3 of the License, or any later version. +// +// SVO is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#ifndef SVO_SPARSE_IMG_ALIGN_H_ +#define SVO_SPARSE_IMG_ALIGN_H_ + +#include +#include + + +namespace vk { +class AbstractCamera; +} + +namespace vio { + +class Feature; + +/// Optimize the pose of the frame by minimizing the photometric error of feature patches. +class SparseImgAlign : public vk::NLLSSolver<3, SE2> +{ + static const int patch_halfsize_ = 12; + static const int patch_size_ = 12*patch_halfsize_; + static const int patch_area_ = patch_size_*patch_size_; +public: + EIGEN_MAKE_ALIGNED_OPERATOR_NEW + + cv::Mat resimg_; + + SparseImgAlign( + int n_levels, + int min_level, + int n_iter, + Method method, + bool display, + bool verbose); + + size_t run( + FramePtr ref_frame, + FramePtr cur_frame); + + /// Return fisher information matrix, i.e. the Hessian of the log-likelihood + /// at the converged state. + Matrix getFisherInformation(); + +protected: + FramePtr ref_frame_; //!< reference frame, has depth for gradient pixels. + FramePtr cur_frame_; //!< only the image is known! + int level_; //!< current pyramid level on which the optimization runs. + bool display_; //!< display residual image. + int max_level_; //!< coarsest pyramid level for the alignment. + int min_level_; //!< finest pyramid level for the alignment. + + // cache: + Matrix jacobian_cache_; + bool have_ref_patch_cache_; + cv::Mat ref_patch_cache_; + std::vector visible_fts_; + + void precomputeReferencePatches(); + virtual double computeResiduals(const SE2& model, bool linearize_system, bool compute_weight_scale = false); + virtual double computeResiduals(bool linearize_system, bool compute_weight_scale = false){}; + virtual int solve(); + virtual void update (const ModelType& old_model, ModelType& new_model); + virtual void update(){}; + virtual void startIteration(); + virtual void finishIteration(); +}; + +} // namespace vio + +#endif // SVO_SPARSE_IMG_ALIGN_H_ diff --git a/GPU_version/vio/include/vio/sparse_img_align_gpu.h b/GPU_version/vio/include/vio/sparse_img_align_gpu.h new file mode 100644 index 0000000..2655b22 --- /dev/null +++ b/GPU_version/vio/include/vio/sparse_img_align_gpu.h @@ -0,0 +1,82 @@ +// This file is part of SVO - Semi-direct Visual Odometry. +// +// Copyright (C) 2014 Christian Forster +// (Robotics and Perception Group, University of Zurich, Switzerland). +// +// SVO is free software: you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the Free Software +// Foundation, either version 3 of the License, or any later version. +// +// SVO is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#ifndef VIO_SPARSE_IMG_ALIGN_GPU_H_ +#define VIO_SPARSE_IMG_ALIGN_GPU_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace vio { + +class Feature; + +/// Optimize the pose of the frame by minimizing the photometric error of feature patches. +class SparseImgAlignGpu : public vk::NLLSSolver<3, SE2> +{ + static const int patch_halfsize_ = 12; + static const int patch_size_ = 12*patch_halfsize_; + static const int patch_area_ = patch_size_*patch_size_; +public: + + SparseImgAlignGpu( + int n_levels, + int min_level, + int n_iter, + Method method, + bool verbose, + opencl* residual); + + size_t run( + FramePtr ref_frame, + FramePtr cur_frame); + + +protected: + int level_; //!< current pyramid level on which the optimization runs. + int max_level_; //!< coarsest pyramid level for the alignment. + int min_level_; //!< finest pyramid level for the alignment. + size_t feature_counter_=0; + opencl* residual_= nullptr; + + // cache: + std::vector visible_fts_; + virtual double computeResiduals(const ModelType& model, + bool linearize_system, + bool compute_weight_scale) { + return 0.0; + }; + virtual double computeResiduals(bool linearize_system, bool compute_weight_scale = false); + virtual int solve(); + virtual void update(); + virtual void update(const ModelType& old_model, ModelType& new_model) { }; + virtual void startIteration(); + virtual void finishIteration(); +}; + +} // namespace vio + +#endif // VIO_SPARSE_IMG_ALIGN_GPU_H_ diff --git a/GPU_version/vio/include/vio/timer.h b/GPU_version/vio/include/vio/timer.h new file mode 100644 index 0000000..45bbc7f --- /dev/null +++ b/GPU_version/vio/include/vio/timer.h @@ -0,0 +1,81 @@ +#ifndef TIMER_H +#define TIMER_H + +#include +#include +#include + +namespace vk +{ + +class Timer +{ +private: + timeval start_time_; + double time_; + double accumulated_; +public: + + /// The constructor directly starts the timer. + Timer() : + time_(0.0), + accumulated_(0.0) + { + start(); + } + + ~Timer() + {} + + inline void start() + { + accumulated_ = 0.0; + gettimeofday(&start_time_, NULL); + } + + inline void resume() + { + gettimeofday(&start_time_, NULL); + } + + inline double stop() + { + timeval end_time; + gettimeofday(&end_time, NULL); + long seconds = end_time.tv_sec - start_time_.tv_sec; + long useconds = end_time.tv_usec - start_time_.tv_usec; + time_ = ((seconds) + useconds*0.000001) + accumulated_; + accumulated_ = time_; + return time_; + } + + inline double getTime() const + { + return time_; + } + + inline void reset() + { + time_ = 0.0; + accumulated_ = 0.0; + } + + static double getCurrentTime() + { + timeval time_now; + gettimeofday(&time_now, NULL); + return time_now.tv_sec + time_now.tv_usec*0.000001; + } + + static double getCurrentSecond() + { + timeval time_now; + gettimeofday(&time_now, NULL); + return time_now.tv_sec; + } + +}; + +} // end namespace vk + +#endif diff --git a/GPU_version/vio/include/vio/ukf.h b/GPU_version/vio/include/vio/ukf.h new file mode 100644 index 0000000..66b16b3 --- /dev/null +++ b/GPU_version/vio/include/vio/ukf.h @@ -0,0 +1,155 @@ +// +// Created by root on 6/8/21. +// +#ifndef VIO_UKF_H +#define VIO_UKF_H + +#include +#include +#include "vio/config.h" +#include +class Base{ +public: + Base(const Eigen::Matrix &init) { + state_=init; + cov_.setIdentity(); + cov_*=0.0001; + }; + virtual ~Base(){ + }; + void predict(double dx,double dz,double dpitch,double time){ + if(t_==0.0){ + t_=time; + return; + } + double dt=time-t_; + t_=time; + state_h_(2)=state_(2)+dt*dpitch; + state_h_(1)=state_(1)+dz*cos(state_(2))-dx*sin(state_(2)); + state_h_(0)=state_(0)+dx*cos(state_(2))+dz*sin(state_(2)); + Eigen::Matrix R; + R< G; + G<<1.0,0,-dx*sin(state_(2))+dz*cos(state_(2)), + 0,1.0,-dz*sin(state_(2))-dx*cos(state_(2)), + 0,0,1.0; + cov_h_=G*cov_*G.transpose()+R; + predict_up=true; + } + void correct(double ddx, double ddz, double dpitch, double time){ + Eigen::Matrix H; + Eigen::Matrix Q; + Eigen::Matrix E; + Eigen::Matrix k; + double dt=time-t_; + t_=time; + H<<1.0,0,0.5*pow(dt,2)*(ddz*cos(state_(2))-ddx*sin(state_(2))), + 0,1.0,-0.5*pow(dt,2)*(ddx*cos(state_(2))+ddz*sin(state_(2))), + 0,0,1.0; + Q< R; + R< G; + G<<1.0,0,0.5*pow(dt,2)*(ddz*cos(state_(2))-ddx*sin(state_(2))), + 0,1.0,-0.5*pow(dt,2)*(ddx*cos(state_(2))+ddz*sin(state_(2))), + 0,0,1.0; + cov_h_=G*cov_*G.transpose()+R; + yaw_t_1_=state_(2); + + } + void correct(double x, double z,double pitch,size_t match,double time){ + Eigen::Matrix H; + Eigen::Matrix Q; + Eigen::Matrix E; + Eigen::Matrix k; + t_=time; + ++match; + H<<1.0,0,0, + 0,1.0,0, + 0,0,1.0; + Q< cov_; + Eigen::Matrix state_; + bool predict_up=false; +private: + double t_=0.0; + Eigen::Matrix cov_h_; + Eigen::Matrix state_h_;//state{x,z,pitch} + double yaw_t_1_=0.0; + +}; + +class UKF { +public: + UKF(const Eigen::Matrix& init) : filter_(new Base(init)) { + }; + virtual ~UKF() { + delete filter_; + }; + void UpdateIMU(double x,double z,double pitch,const ros::Time& time) { + while(lock)usleep(5); + lock=true; + if(abs(x)<1.0)x=pow(x,3);//picked up from your code + if(abs(z)<1.0)z=pow(z,3);//picked up from your code + if(filter_->predict_up)filter_->correct(x,z,pitch,1e-9*time.toNSec()); + lock=false; + }; + void UpdateCmd(double x,double z,double pitch,const ros::Time& time) { + while(lock)usleep(5); + lock=true; + filter_->predict(x,z,pitch,1e-9*time.toNSec()); + lock=false; + }; + std::pair,vio::SE2_5> UpdateSvo(double x,double z,double pitch,size_t match,ros::Time& time) { + while(lock)usleep(5); + lock=true; + if(pitch<0.0) + pitch=M_PI-pitch; + else + pitch=pitch-M_PI; + if(filter_->predict_up)filter_->correct(-x,-z,pitch,match,1e-9*time.toNSec()); + lock=false; + double pitch_f; + if(filter_->state_(0)<0.0) + pitch_f=M_PI-filter_->state_(2); + else + pitch_f=filter_->state_(2)-M_PI; + return std::pair,vio::SE2_5>(filter_->cov_,vio::SE2_5(-filter_->state_(0),-filter_->state_(1),pitch_f)); + }; + std::pair,vio::SE2_5> get_location(){ + double pitch_f; + if(filter_->state_(0)<0.0) + pitch_f=M_PI-filter_->state_(2); + else + pitch_f=filter_->state_(2)-M_PI; + return std::pair,vio::SE2_5>(filter_->cov_,vio::SE2_5(-filter_->state_(0),-filter_->state_(1),pitch_f)); + } +private: + Base* filter_= nullptr; + bool lock=false; +}; +#endif //VIO_UKF_H diff --git a/GPU_version/vio/include/vio/vision.h b/GPU_version/vio/include/vio/vision.h new file mode 100644 index 0000000..1d0bea2 --- /dev/null +++ b/GPU_version/vio/include/vio/vision.h @@ -0,0 +1,80 @@ +/* + * vision.h + * + * Created on: May 14, 2013 + * Author: cforster + */ + +#ifndef VIKIT_VISION_H_ +#define VIKIT_VISION_H_ + +#include +#include +#include + +namespace vk +{ + +//! Return value between 0 and 1 +//! WARNING This function does not check whether the x/y is within the border +inline float +interpolateMat_32f(const cv::Mat& mat, float u, float v) +{ + assert(mat.type()==CV_32F); + float x = floor(u); + float y = floor(v); + float subpix_x = u-x; + float subpix_y = v-y; + float wx0 = 1.0-subpix_x; + float wx1 = subpix_x; + float wy0 = 1.0-subpix_y; + float wy1 = subpix_y; + + float val00 = mat.at(y,x); + float val10 = mat.at(y,x+1); + float val01 = mat.at(y+1,x); + float val11 = mat.at(y+1,x+1); + return (wx0*wy0)*val00 + (wx1*wy0)*val10 + (wx0*wy1)*val01 + (wx1*wy1)*val11; +} + +//! Return value between 0 and 255 +//! WARNING This function does not check whether the x/y is within the border +inline float +interpolateMat_8u(const cv::Mat& mat, float u, float v) +{ + if(mat.empty())return 0.0; + if(mat.type()!=CV_8U)return 0.0; + int x = floor(u); + int y = floor(v); + float subpix_x = u-x; + float subpix_y = v-y; + + float w00 = (1.0f-subpix_x)*(1.0f-subpix_y); + float w01 = (1.0f-subpix_x)*subpix_y; + float w10 = subpix_x*(1.0f-subpix_y); + float w11 = 1.0f - w00 - w01 - w10; + + const int stride = mat.step.p[0]; + unsigned char* ptr = mat.data + y*stride + x; + if(isnan(w00) || isnan(w01 )||isnan( w10) || isnan(w11) || isinf(w00) || isinf(w01)|| isinf(w10)|| isinf(w11))return 0.0; + if(ptr[0] == NULL || ptr[1]== NULL || ptr[stride]==NULL ||ptr[stride+1]==NULL)return 0.0; + return w00*ptr[0] + w01*ptr[stride] + w10*ptr[1] + w11*ptr[stride+1]; +} + +void halfSample(const cv::Mat& in, cv::Mat& out); + +float shiTomasiScore(const cv::Mat& img, int u, int v); + +void calcSharrDeriv(const cv::Mat& src, cv::Mat& dst); + +#ifdef __SSE2__ + +/// Used to convert a Kinect depthmap +/// Code by Christian Kerl DVO, GPL Licence +void convertRawDepthImageSse_16u_to_32f(cv::Mat& depth_16u, cv::Mat& depth_32f, float scale); + +#endif + +} // namespace vk + +#endif // VIKIT_VISION_H_ diff --git a/GPU_version/vio/include/vio/visualizer.h b/GPU_version/vio/include/vio/visualizer.h new file mode 100644 index 0000000..2fbf4d3 --- /dev/null +++ b/GPU_version/vio/include/vio/visualizer.h @@ -0,0 +1,62 @@ +// This file is part of SVO - Semi-direct Visual Odometry. +// +// Copyright (C) 2014 Christian Forster +// (Robotics and Perception Group, University of Zurich, Switzerland). +// +// SVO is free software: you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the Free Software +// Foundation, either version 3 of the License, or any later version. +// +// SVO is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#ifndef SVO_VISUALIZER_H_ +#define SVO_VISUALIZER_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace vio { + +class Frame; +class Point; +class Map; +class FrameHandlerMono; + +typedef boost::shared_ptr FramePtr; + +/// This class bundles all functions to publish visualisation messages. +class Visualizer +{ +public: + ros::NodeHandle pnh_; + size_t trace_id_; + ros::Publisher pub_frames_; + ros::Publisher pub_points_; + ros::Publisher pub_pose_with_cov_; + + Visualizer(); + + ~Visualizer() {}; + + void publishMinimal( + UKF& ukf, + const double timestamp); + +}; + +} // end namespace vio + +#endif /* SVO_VISUALIZER_H_ */ diff --git a/GPU_version/vio/kernel/compute-residual.cl b/GPU_version/vio/kernel/compute-residual.cl new file mode 100644 index 0000000..81d81d1 --- /dev/null +++ b/GPU_version/vio/kernel/compute-residual.cl @@ -0,0 +1,50 @@ +// Copyright (C) 2021 Majid Geravand +// Copyright (C) 2021 Gfuse + +// Enable OpenCL 32-bit integer atomic functions. +#pragma OPENCL EXTENSION cl_khr_global_int32_base_atomics : enable + +double2 world2cam(double f_x,double f_y,double c_x,double c_y,double s_, double x, double y,double z) +{ + double2 uv=(x/z,y/z); + double r = sqrt(pow(uv[0],2)+pow(uv[1],2)); + double factor=1.0; + if(s_ !=0 || r > 0.001)factor=(atan(r * 2.0 * tan(0.5 * s_)) / (r*s_)); + return double3(cx_ + fx_ * factor * uv[0],cy_ + fy_ * factor * uv[1]); +} +double3 xyz_cur(double cur_x,double cur_z,double cur_pitch,double ref_x,double ref_z,double ref_pitch,double3 ref_feature){ + if(ref_pitch<0.0) + ref_pitch=3.141592653589793238462643383279502884197169399375-ref_pitch; + else + ref_pitch=ref_pitch-3.1415926535897932384626433832795028841971693993; + double cc_ss=cos(cur_pitch)*cos(ref_pitch)-sin(cur_pitch)*sin(ref_pitch); + double sc_cs=cos(cur_pitch)*sin(ref_pitch)+cos(ref_pitch)*sin(cur_pitch); + return double3(cc_ss*ref_feature.x()+sc_cs*ref_feature.z()+cur_x-ref_x*cos(cur_pitch)-ref_z*sin(cur_pitch), + ref_feature.y(), + -1.0*sc_cs*ref_feature.x())+cc_ss*ref_feature.z()+cur_z+ref_x*sin(cur_pitch)-ref_z*cos(cur_pitch)); +} + +__kernel void compute-residual( + __read_only image2d_t image_cur, // current frame + __read_only image2d_t image_ref, // reference frame + __global double * cur_pose,//[reference frame pose{x,z,pitch}] + __global double * ref_pose,//[current frame pose{x,z,pitch}] + __global double3 * ref_feature, // feature on the reference frame, when we applied the distance calculation: xyz_ref((*it)->f*((*it)->point->pos_ - Eigen::Vector3d(ref_pos[0],0.0,ref_pos[1])).norm()); + __global int * level, + __global double * camera_model, // camera model [f_x,f_y,c_x,c_y,s_] + float * errors, + double * Hessian, + double * Jacobian, + double * chi +) { + // Prepare a suitable OpenCL image sampler. + sampler_t const sampler = CLK_ADDRESS_CLAMP | CLK_FILTER_NEAREST; + + // Use global work feature. + int const f = get_global_id(0); + ref_feature[f].x; + ref_feature[f].y; + ref_feature[f].z; + PATCH_SIZE; +} + diff --git a/GPU_version/vio/src/atan_camera.cpp b/GPU_version/vio/src/atan_camera.cpp index c86f027..b2ed822 100644 --- a/GPU_version/vio/src/atan_camera.cpp +++ b/GPU_version/vio/src/atan_camera.cpp @@ -7,8 +7,8 @@ #include -#include -#include +#include +#include namespace vk { diff --git a/GPU_version/vio/src/cl_class.cpp b/GPU_version/vio/src/cl_class.cpp index a26d455..e15f3fc 100644 --- a/GPU_version/vio/src/cl_class.cpp +++ b/GPU_version/vio/src/cl_class.cpp @@ -1,7 +1,7 @@ // // Created by root on 4/27/21. // -#include "gpu_svo/cl_class.h" +#include "vio/cl_class.h" opencl::opencl() { std::vector all_platforms; cl::Platform::get(&all_platforms); @@ -33,7 +33,7 @@ opencl::opencl() { read_cl fast(std::string(KERNEL_DIR)+"/fast-gray.cl"); sources.push_back({ fast.src_str, fast.size }); program=new cl::Program(*context, sources); - if(program->build({ device },"-DFAST_THRESH=40") !=0) + if(program->build({ device },"-DFAST_THRESH=40 -DPATCH_SIZE=4") !=0) std::cout << " Error building: " << program->getBuildInfo(device)<<'\n' <getBuildInfo(device) << '\n'; queue=new cl::CommandQueue(*context,device,0,NULL); diff --git a/GPU_version/vio/src/config.cpp b/GPU_version/vio/src/config.cpp index 5c3cab7..fe328c5 100644 --- a/GPU_version/vio/src/config.cpp +++ b/GPU_version/vio/src/config.cpp @@ -14,10 +14,10 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include -#include +#include +#include -namespace svo { +namespace vio { Config::Config() : trace_name(vk::getParam("svo/trace_name", "svo")), @@ -69,5 +69,5 @@ Config& Config::getInstance() return instance; } -} // namespace svo +} // namespace vio diff --git a/GPU_version/vio/src/depth_filter.cpp b/GPU_version/vio/src/depth_filter.cpp index c7ebf2c..45abf92 100644 --- a/GPU_version/vio/src/depth_filter.cpp +++ b/GPU_version/vio/src/depth_filter.cpp @@ -15,21 +15,21 @@ // along with this program. If not, see . #include -#include -#include -#include +#include +#include +#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include -namespace svo { +namespace vio { int Seed::batch_counter = 0; int Seed::seed_counter = 0; @@ -354,4 +354,4 @@ double DepthFilter::computeTau( return (t_norm*sin(beta_plus)/sin(PI-acos(f.dot(t)/t_norm)-beta_plus) - z); // ( triangle angles sum to PI and law of sines ) tau } -} // namespace svo +} // namespace vio diff --git a/GPU_version/vio/src/feature_alignment.cpp b/GPU_version/vio/src/feature_alignment.cpp index 918ab25..0d8b455 100644 --- a/GPU_version/vio/src/feature_alignment.cpp +++ b/GPU_version/vio/src/feature_alignment.cpp @@ -20,9 +20,9 @@ #ifdef __ARM_NEON__ #include #endif -#include +#include -namespace svo { +namespace vio { namespace feature_alignment { #define SUBPIX_VERBOSE 0 @@ -613,4 +613,4 @@ bool align2D_NEON ( } } // namespace feature_alignment -} // namespace svo +} // namespace vio diff --git a/GPU_version/vio/src/feature_detection.cpp b/GPU_version/vio/src/feature_detection.cpp index 333e602..d3eb264 100644 --- a/GPU_version/vio/src/feature_detection.cpp +++ b/GPU_version/vio/src/feature_detection.cpp @@ -14,11 +14,11 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include -#include -#include +#include +#include +#include -namespace svo { +namespace vio { namespace feature_detection { AbstractDetector::AbstractDetector( @@ -110,5 +110,5 @@ void FastDetector::detect( } } // namespace feature_detection -} // namespace svo +} // namespace vio diff --git a/GPU_version/vio/src/frame.cpp b/GPU_version/vio/src/frame.cpp index 30f085f..4bb2b9b 100644 --- a/GPU_version/vio/src/frame.cpp +++ b/GPU_version/vio/src/frame.cpp @@ -15,14 +15,14 @@ // along with this program. If not, see . #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include -namespace svo { +namespace vio { int Frame::frame_counter_ = 0; @@ -186,4 +186,4 @@ bool getSceneDepth(const Frame& frame, double& depth_mean, double& depth_min) } } // namespace frame_utils -} // namespace svo +} // namespace vio diff --git a/GPU_version/vio/src/frame_handler_base.cpp b/GPU_version/vio/src/frame_handler_base.cpp index a232ce3..9f41cbc 100644 --- a/GPU_version/vio/src/frame_handler_base.cpp +++ b/GPU_version/vio/src/frame_handler_base.cpp @@ -14,19 +14,19 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include +#include #include #include #include #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include -namespace svo +namespace vio { // definition of global and static variables which were declared in the header @@ -137,4 +137,4 @@ void FrameHandlerBase::optimizeStructure( } -} // namespace svo +} // namespace vio diff --git a/GPU_version/vio/src/frame_handler_mono.cpp b/GPU_version/vio/src/frame_handler_mono.cpp index 6399756..897432b 100644 --- a/GPU_version/vio/src/frame_handler_mono.cpp +++ b/GPU_version/vio/src/frame_handler_mono.cpp @@ -14,18 +14,18 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -namespace svo { +namespace vio { FrameHandlerMono::FrameHandlerMono(vk::AbstractCamera* cam,Eigen::Matrix& init) : FrameHandlerBase(), @@ -39,11 +39,33 @@ FrameHandlerMono::FrameHandlerMono(vk::AbstractCamera* cam,Eigen::Matrixmake_kernel("fast_gray"); cv::Mat img=cv::Mat(cv::Size(700, 500),CV_8UC1); gpu_fast_->write_buf(0,0,img); - cl_int2 corners_[350000]; + cl_int2 corners_[350000]={0}; gpu_fast_->write_buf(0,1,350000,corners_); int icorner[1]={0}; gpu_fast_->write_buf(0,2,1,icorner); gpu_fast_->write_buf(0,3,(1 << 18)); + gpu_fast_->make_kernel("compute-residual"); + gpu_fast_->write_buf(1,0,img); + gpu_fast_->write_buf(1,1,img); + double pose[3]={0}; + gpu_fast_->write_buf(1,2,3,pose); + gpu_fast_->write_buf(1,3,3,pose); + cl_double3 f[300]={0}; + gpu_fast_->write_buf(1,4,300,f); + int level=0; + gpu_fast_->write_buf(1,5,level); + double c[5]={0}; + gpu_fast_->write_buf(1,6,5,c); + float e[300]={0}; + gpu_fast_->write_buf(1,7,300,e); + float H[6]={0}; + gpu_fast_->write_buf(1,8,6,H); + float J[3]={0}; + gpu_fast_->write_buf(1,9,3,J); + double chi2=0.0; + gpu_fast_->write_buf(1,10,chi2); + imageAlign_=new SparseImgAlignGpu(Config::kltMaxLevel(), Config::kltMinLevel(), + 30, SparseImgAlign::GaussNewton, false,gpu_fast_); klt_homography_init_=new initialization::KltHomographyInit(gpu_fast_); initialize(); } @@ -143,6 +165,7 @@ FrameHandlerBase::UpdateResult FrameHandlerMono::processFrame() SparseImgAlign img_align(Config::kltMaxLevel(), Config::kltMinLevel(), 30, SparseImgAlign::LevenbergMarquardt, false, false); if(img_align.run(last_frame_, new_frame_)==0)return RESULT_FAILURE; + if(imageAlign_->run(last_frame_, new_frame_)==0)return RESULT_FAILURE; reprojector_.reprojectMap(new_frame_, overlap_kfs_); size_t sfba_n_edges_final=0; double sfba_thresh, sfba_error_init, sfba_error_final; @@ -299,4 +322,4 @@ void FrameHandlerMono::UpdateCmd(double* value,const ros::Time& time){ ukfPtr_.UpdateCmd(value[0],value[1],value[2],time); } -} // namespace svo +} // namespace vio diff --git a/GPU_version/vio/src/homography.cpp b/GPU_version/vio/src/homography.cpp index c73617d..4044496 100644 --- a/GPU_version/vio/src/homography.cpp +++ b/GPU_version/vio/src/homography.cpp @@ -12,7 +12,7 @@ * by: cforster */ -#include +#include #include #include diff --git a/GPU_version/vio/src/initialization.cpp b/GPU_version/vio/src/initialization.cpp index 379163f..8149b85 100644 --- a/GPU_version/vio/src/initialization.cpp +++ b/GPU_version/vio/src/initialization.cpp @@ -14,16 +14,16 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include -namespace svo { +namespace vio { namespace initialization { InitResult KltHomographyInit::addFirstFrame(FramePtr frame_ref) @@ -197,4 +197,4 @@ void computeHomography( } // namespace initialization -} // namespace svo +} // namespace vio diff --git a/GPU_version/vio/src/map.cpp b/GPU_version/vio/src/map.cpp index 9e4196e..b4734b3 100644 --- a/GPU_version/vio/src/map.cpp +++ b/GPU_version/vio/src/map.cpp @@ -15,13 +15,13 @@ // along with this program. If not, see . #include -#include -#include -#include -#include +#include +#include +#include +#include #include -namespace svo { +namespace vio { Map::Map() {} @@ -376,4 +376,4 @@ void mapStatistics(Map* map) } } // namespace map_debug -} // namespace svo +} // namespace vio diff --git a/GPU_version/vio/src/matcher.cpp b/GPU_version/vio/src/matcher.cpp index 1b025c9..ec16cd3 100644 --- a/GPU_version/vio/src/matcher.cpp +++ b/GPU_version/vio/src/matcher.cpp @@ -15,18 +15,18 @@ // along with this program. If not, see . #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -namespace svo { +namespace vio { namespace warp { @@ -324,4 +324,4 @@ bool Matcher::findEpipolarMatchDirect( return false; } -} // namespace svo +} // namespace vio diff --git a/GPU_version/vio/src/math_utils.cpp b/GPU_version/vio/src/math_utils.cpp index 9c265ec..bcaff29 100644 --- a/GPU_version/vio/src/math_utils.cpp +++ b/GPU_version/vio/src/math_utils.cpp @@ -5,7 +5,7 @@ * Author: cforster */ -#include +#include namespace vk { diff --git a/GPU_version/vio/src/output_helper.cpp b/GPU_version/vio/src/output_helper.cpp index 58aa0bf..cfb2cad 100644 --- a/GPU_version/vio/src/output_helper.cpp +++ b/GPU_version/vio/src/output_helper.cpp @@ -5,7 +5,7 @@ * Author: chrigi */ -#include +#include #include diff --git a/GPU_version/vio/src/point.cpp b/GPU_version/vio/src/point.cpp index cf12a1e..adb2c2b 100644 --- a/GPU_version/vio/src/point.cpp +++ b/GPU_version/vio/src/point.cpp @@ -15,12 +15,12 @@ // along with this program. If not, see . #include -#include -#include -#include -#include +#include +#include +#include +#include -namespace svo { +namespace vio { int Point::point_counter_ = 0; @@ -175,4 +175,4 @@ void Point::optimize(const size_t n_iter) #endif } -} // namespace svo +} // namespace vio diff --git a/GPU_version/vio/src/pose_optimizer.cpp b/GPU_version/vio/src/pose_optimizer.cpp index 3d45ab5..7ef9541 100644 --- a/GPU_version/vio/src/pose_optimizer.cpp +++ b/GPU_version/vio/src/pose_optimizer.cpp @@ -15,15 +15,15 @@ // along with this program. If not, see . #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include -namespace svo { +namespace vio { namespace pose_optimizer { void optimizeGaussNewton( @@ -175,4 +175,4 @@ void optimizeGaussNewton( } } // namespace pose_optimizer -} // namespace svo +} // namespace vio diff --git a/GPU_version/vio/src/reprojector.cpp b/GPU_version/vio/src/reprojector.cpp index 897ce59..15bda16 100644 --- a/GPU_version/vio/src/reprojector.cpp +++ b/GPU_version/vio/src/reprojector.cpp @@ -16,19 +16,19 @@ #include #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include -#include -#include -#include +#include +#include +#include -namespace svo { +namespace vio { Reprojector::Reprojector(vk::AbstractCamera* cam, Map& map) : map_(map) @@ -216,4 +216,4 @@ bool Reprojector::reprojectPoint(FramePtr frame, Point* point) return false; } -} // namespace svo +} // namespace vio diff --git a/GPU_version/vio/src/robust_cost.cpp b/GPU_version/vio/src/robust_cost.cpp index ec771ae..0090a69 100644 --- a/GPU_version/vio/src/robust_cost.cpp +++ b/GPU_version/vio/src/robust_cost.cpp @@ -20,8 +20,8 @@ #include #include -#include -#include +#include +#include namespace vk { namespace robust_cost { diff --git a/GPU_version/vio/src/sparse_img_align.cpp b/GPU_version/vio/src/sparse_img_align.cpp index 59c754c..e4aa55b 100644 --- a/GPU_version/vio/src/sparse_img_align.cpp +++ b/GPU_version/vio/src/sparse_img_align.cpp @@ -15,16 +15,16 @@ // along with this program. If not, see . #include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include -namespace svo { +namespace vio { SparseImgAlign::SparseImgAlign( int max_level, int min_level, int n_iter, @@ -99,8 +99,8 @@ void SparseImgAlign::precomputeReferencePatches() *visiblity_it = true; // cannot just take the 3d points coordinate because of the reprojection errors in the reference image!!! - const double depth(((*it)->point->pos_ - ref_pos).norm()); - const Vector3d xyz_ref((*it)->f*depth); + // const double depth(((*it)->point->pos_ - ref_pos).norm()); + const Vector3d xyz_ref((*it)->f*((*it)->point->pos_ - ref_pos).norm()); // evaluate projection jacobian Matrix frame_jac; @@ -171,8 +171,8 @@ double SparseImgAlign::computeResiduals( continue; // compute pixel location in cur img - const double depth = ((*it)->point->pos_ - ref_pos).norm(); - const Vector3d xyz_ref((*it)->f*depth); + //const double depth = ((*it)->point->pos_ - ref_pos).norm(); + const Vector3d xyz_ref((*it)->f*((*it)->point->pos_ - ref_pos).norm()); const Vector3d xyz_cur((T_cur_from_ref.rotation_matrix()(0,0)*xyz_ref.x())+(T_cur_from_ref.rotation_matrix()(0,1)*xyz_ref.z())+T_cur_from_ref.translation()(0), xyz_ref.y(), -1.0*(T_cur_from_ref.rotation_matrix()(1,0)*xyz_ref.x())+(T_cur_from_ref.rotation_matrix()(1,1)*xyz_ref.z())+T_cur_from_ref.translation()(1)); @@ -224,8 +224,6 @@ double SparseImgAlign::computeResiduals( const Vector3d J(jacobian_cache_.col(feature_counter*patch_area_ + pixel_counter)); H_.noalias() += J*J.transpose()*weight; Jres_.noalias() -= J*res*weight; - if(display_) - resimg_.at((int) v_cur+y-patch_halfsize_, (int) u_cur+x-patch_halfsize_) = res/255.0; } } } @@ -265,5 +263,5 @@ void SparseImgAlign::finishIteration() } } -} // namespace svo +} // namespace vio diff --git a/GPU_version/vio/src/sparse_img_align_gpu.cpp b/GPU_version/vio/src/sparse_img_align_gpu.cpp new file mode 100644 index 0000000..5a23ead --- /dev/null +++ b/GPU_version/vio/src/sparse_img_align_gpu.cpp @@ -0,0 +1,128 @@ +// This file is part of SVO - Semi-direct Visual Odometry. +// +// Copyright (C) 2014 Christian Forster +// (Robotics and Perception Group, University of Zurich, Switzerland). +// +// SVO is free software: you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the Free Software +// Foundation, either version 3 of the License, or any later version. +// +// SVO is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include + +namespace vio { + +SparseImgAlignGpu::SparseImgAlignGpu( + int max_level, int min_level, int n_iter, + Method method, bool verbose,opencl* residual) : + max_level_(max_level), + min_level_(min_level), + residual_(residual) +{ + n_iter_ = n_iter; + n_iter_init_ = n_iter_; + method_ = method; + verbose_ = verbose; + eps_ = 0.0001; +} + +size_t SparseImgAlignGpu::run(FramePtr ref_frame, FramePtr cur_frame) +{ + reset(); + + if(ref_frame->fts_.empty()) + { + return 0; + } + double* camera=ref_frame->cam_->params(); + double ref_pos[3]={ref_frame->pos()(0),ref_frame->pos()(1),ref_frame->T_f_w_.pitch()}; + double cur_pos[3]={cur_frame->pos()(0),cur_frame->pos()(1),cur_frame->T_f_w_.pitch()}; + residual_->reload_buf(1,2,cur_pos); + residual_->reload_buf(1,3,ref_pos); + residual_->reload_buf(1,6,camera); + cl_double3* features; + feature_counter_ = 0; // is used to compute the index of the cached jacobian + std::vector::iterator visiblity_it = visible_fts_.begin(); + for(auto it=ref_frame->fts_.begin(); it!=ref_frame->fts_.end(); + ++it, ++visiblity_it){ + if(!*visiblity_it) + continue; + const Vector3d xyz_ref((*it)->f*((*it)->point->pos_ - Eigen::Vector3d(ref_pos[0],0.0,ref_pos[1])).norm()); + features[feature_counter_].x=xyz_ref(0); + features[feature_counter_].y=xyz_ref(1); + features[feature_counter_].z=xyz_ref(2); + ++feature_counter_; + } + residual_->reload_buf(1,4,features); + SE2 T_cur(cur_frame->T_f_w_.se2());///TODO temporary, we can remove it + for(level_=max_level_; level_>=min_level_; --level_) + { + cv::Mat& cur_img = cur_frame->img_pyr_.at(level_); + cv::Mat& ref_img = ref_frame->img_pyr_.at(level_); + residual_->reload_buf(1,0,cur_img); + residual_->reload_buf(1,1,ref_img); + residual_->reload_buf(1,5,&level_); + mu_ = 1.0; + optimize(T_cur); + } + cur_frame->T_f_w_ = SE2_5(T_cur); + + return n_meas_/patch_area_; +} + +double SparseImgAlignGpu::computeResiduals( + bool linearize_system, + bool compute_weight_scale) +{ + double chi2=0.0; + residual_->reload_buf(1,10,&chi2); + /// TODO GPU compute based on the feature + residual_->run(1,feature_counter_); + if(compute_weight_scale && iter_ == 0) { + float error[feature_counter_]; + residual_->read(1,7,error); + std::vector errors(error,error+feature_counter_); + scale_ = scale_estimator_->compute(errors); + } + residual_->read(1,10,&chi2); + return chi2; +} + +int SparseImgAlignGpu::solve() +{ + double* H; + double* J; + residual_->read(1,8,H); + residual_->read(1,9,J); + x_ = Eigen::Matrix(H).ldlt().solve(Eigen::Matrix(J)); + if((bool) std::isnan((double) x_[0])) + return 0; + return 1; +} +void SparseImgAlignGpu::update() +{ +/// TODO the update situation may have a smarter solution + double* pos; + residual_->read(1,2,pos); + SE2 update = SE2(pos[2],Eigen::Vector2d(pos[0],pos[1])) * SE2::exp(-0.25*x_); + pos[0]=update.translation()(0); + pos[1]=update.translation()(1); + pos[2]=atan(update.so2().unit_complex().imag()/update.so2().unit_complex().real()); + residual_->reload_buf(1,2,pos); +} + +void SparseImgAlignGpu::startIteration() +{} + +void SparseImgAlignGpu::finishIteration() +{ +} + +} // namespace vio + diff --git a/GPU_version/vio/src/vision.cpp b/GPU_version/vio/src/vision.cpp index e1be729..1b93692 100644 --- a/GPU_version/vio/src/vision.cpp +++ b/GPU_version/vio/src/vision.cpp @@ -5,7 +5,7 @@ * Author: cforster */ -#include +#include #if __SSE2__ # include diff --git a/GPU_version/vio/src/visualizer.cpp b/GPU_version/vio/src/visualizer.cpp index 0434f0f..279d73c 100644 --- a/GPU_version/vio/src/visualizer.cpp +++ b/GPU_version/vio/src/visualizer.cpp @@ -14,19 +14,19 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include -#include -#include +#include +#include #include -#include +#include -namespace svo { +namespace vio { Visualizer:: Visualizer() : @@ -77,4 +77,4 @@ void Visualizer::publishMinimal( } } -} // end namespace gpu_svo +} // end namespace vio diff --git a/GPU_version/vio/src/vo_node.cpp b/GPU_version/vio/src/vo_node.cpp index a182007..2060ea0 100644 --- a/GPU_version/vio/src/vo_node.cpp +++ b/GPU_version/vio/src/vo_node.cpp @@ -17,8 +17,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include @@ -26,21 +26,21 @@ #include #include #include -#include -#include -#include +#include +#include +#include #include #include #include -#include +#include #if VIO_DEBUG -#include +#include #endif class VioNode { public: - svo::FrameHandlerMono* vo_; + vio::FrameHandlerMono* vo_; vk::AbstractCamera* cam_; VioNode(); ~VioNode(); @@ -54,7 +54,7 @@ public: bool start(vio::start::Request& req, vio::start::Response& res){ if(req.on==1){ start_=true; - if(vo_->stage()!=svo::FrameHandlerBase::STAGE_DEFAULT_FRAME) + if(vo_->stage()!=vio::FrameHandlerBase::STAGE_DEFAULT_FRAME) vo_->start(); else{ vo_->depthFilter()->startThread(); @@ -106,7 +106,7 @@ VioNode::VioNode() : throw std::runtime_error("Camera model not correctly specified."); Eigen::Matrix init; init<<1e-19,1e-19,1e-19; - vo_ = new svo::FrameHandlerMono(cam_,init); + vo_ = new vio::FrameHandlerMono(cam_,init); usleep(500); } diff --git a/GPU_version/vio/test/test_pipeline.cpp b/GPU_version/vio/test/test_pipeline.cpp index ede3b25..4365e8b 100644 --- a/GPU_version/vio/test/test_pipeline.cpp +++ b/GPU_version/vio/test/test_pipeline.cpp @@ -30,7 +30,7 @@ #include #include "test_utils.h" -namespace svo { +namespace vio { class BenchmarkNode { @@ -84,7 +84,7 @@ void BenchmarkNode::runFromFolder() } } -} // namespace svo +} // namespace vio int main(int argc, char** argv) { diff --git a/GPU_version/vio/test/test_pose_optimizer.cpp b/GPU_version/vio/test/test_pose_optimizer.cpp index 59e0b46..45118eb 100644 --- a/GPU_version/vio/test/test_pose_optimizer.cpp +++ b/GPU_version/vio/test/test_pose_optimizer.cpp @@ -29,7 +29,7 @@ namespace { -using namespace svo; +using namespace vio; using namespace Eigen; /// Pose Optimizer Test-Fixture diff --git a/GPU_version/vio/test/test_sparse_img_align.cpp b/GPU_version/vio/test/test_sparse_img_align.cpp index 1312da0..521c2ba 100644 --- a/GPU_version/vio/test/test_sparse_img_align.cpp +++ b/GPU_version/vio/test/test_sparse_img_align.cpp @@ -14,18 +14,17 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include -#include -#include -#include -#include +#include +#include +#include +#include #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include "test_utils.h" namespace { diff --git a/GPU_version/vio/test/test_utils.h b/GPU_version/vio/test/test_utils.h index 2759fe0..6de377a 100644 --- a/GPU_version/vio/test/test_utils.h +++ b/GPU_version/vio/test/test_utils.h @@ -24,7 +24,7 @@ # include #endif -namespace svo { +namespace vio { namespace test_utils { std::string getDatasetDir() @@ -51,7 +51,7 @@ std::string getTraceDir() } } // namespace test_utils -} // namespace svo +} // namespace vio #endif // TEST_UTILS_H_ From 348f55ef449aa8e24e589694984e7dd76ca4aa02 Mon Sep 17 00:00:00 2001 From: VahdPourAmin Date: Sat, 24 Jul 2021 08:03:06 +0200 Subject: [PATCH 03/12] opencl kernel --- .idea/misc.xml | 2 +- GPU_version/vio/kernel/compute-residual.cl | 163 ++++++++++++++++++++- 2 files changed, 159 insertions(+), 6 deletions(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index 339cee9..1dee752 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/GPU_version/vio/kernel/compute-residual.cl b/GPU_version/vio/kernel/compute-residual.cl index 81d81d1..ee59d25 100644 --- a/GPU_version/vio/kernel/compute-residual.cl +++ b/GPU_version/vio/kernel/compute-residual.cl @@ -24,6 +24,50 @@ double3 xyz_cur(double cur_x,double cur_z,double cur_pitch,double ref_x,double r -1.0*sc_cs*ref_feature.x())+cc_ss*ref_feature.z()+cur_z+ref_x*sin(cur_pitch)-ref_z*cos(cur_pitch)); } +double3 xyz_ref(double fts_pos_x,double fts_pos_y,double fts_pos_z,double ref_x,double ref_y,double ref_z) +{ + double x = sqrt(pow((fts_pos_x - ref_x), 2)); + double y = sqrt(pow((fts_pos_y - ref_y), 2)); + double z = sqrt(pow((fts_pos_z - ref_z), 2)); + return double3(x, y, z); +} + +void jacobian_xyz2uv(double3& xyz_in_f, double6& J) +{ + double x = xyz_in_f[0]; + double y = xyz_in_f[1]; + double z_inv = 1. / xyz_in_f[2]; + double z_inv_2 = z_inv * z_inv; + + J[0] = -z_inv; // -1/z + J[1] = x * z_inv_2; // x/z^2 + J[2] = -(1.0 + pow(x,2) / z_inv_2); // -(1.0 + x^2/z^2) + + J[3] = 1e-19; // 0 + J[4] = y * z_inv_2; // y/z^2 + J[5] = -x * y / z_inv_2; // -x*y/z^2 +} + +void compute_hessain(double3& j, double9& H, double w) +{ + H[0] += j[0] * j[0] * w; + H[1] += j[0] * j[1] * w; + H[2] += j[0] * j[2] * w; + H[3] += j[1] * j[0] * w; + H[4] += j[1] * j[1] * w; + H[5] += j[1] * j[2] * w; + H[6] += j[2] * j[0] * w; + H[7] += j[2] * j[1] * w; + H[8] += j[2] * j[2] * w; +} + +void compute_Jacobian(double3& j, double& Jacobian, double r, double w) +{ + Jacobian[0] -= j[0] * r * w; + Jacobian[1] -= j[1] * r * w; + Jacobian[2] -= j[2] * r * w; +} + __kernel void compute-residual( __read_only image2d_t image_cur, // current frame __read_only image2d_t image_ref, // reference frame @@ -37,14 +81,123 @@ __kernel void compute-residual( double * Jacobian, double * chi ) { + static const int PATCH_SIZE = 4; + static const int PATCH_HALFSIZE = 2; + static const int PATCH_AREA_ = PATCH_SIZE * PATCH_SIZE; + int border = PATCH_HALFSIZE + 1; + int stride = get_image_dim(image_cur)[0]; //width, height + double scale = pow(2, (-1.0 * level)); + double focal_length = camera_model[0]; + size_t feature_counter = 0; + double chi2 = 0.0; + int n_meas_ = 0; // Prepare a suitable OpenCL image sampler. sampler_t const sampler = CLK_ADDRESS_CLAMP | CLK_FILTER_NEAREST; // Use global work feature. - int const f = get_global_id(0); - ref_feature[f].x; - ref_feature[f].y; - ref_feature[f].z; - PATCH_SIZE; + int const f = get_global_id(0); + //ref_feature[f].x; + //ref_feature[f].y; + //ref_feature[f].z; + + double u_ref = ref_feature[f].x * scale; //?????? ref_feature[f].x + double v_ref = ref_feature[f].y * scale; //?????? ref_feature[f].y + int u_ref_i = floor(u_ref); + int v_ref_i = floor(v_ref); + + // if(ref_feature[f]->point == NULL || u_ref_i - border < 0 || v_ref_i - border < 0 || //??????? ref_feature[f]->point + if(u_ref_i - border < 0 || v_ref_i - border < 0 || + u_ref_i + border >= get_image_dim(image_ref)[0] || v_ref_i + border >= get_image_dim(image_ref)[1]) + return; + + xyz_reference = xyz_ref(ref_feature[f][0], ref_feature[f][1], ref_feature[f][2], ref_pose.x, ref_pose.y, ref_pose.z); // ref_pose.y ???? + // evaluate projection jacobian + double6 frame_jac; //2X3 + jacobian_xyz2uv(xyz_reference, frame_jac); + double subpix_u_ref = u_ref - u_ref_i; + double subpix_v_ref = v_ref - v_ref_i; + double w_ref_tl = (1.0 - subpix_u_ref) * (1.0 - subpix_v_ref); + double w_ref_tr = subpix_u_ref * (1.0 - subpix_v_ref); + double w_ref_bl = (1.0 - subpix_u_ref) * subpix_v_ref; + double w_ref_br = subpix_u_ref * subpix_v_ref; + size_t pixel_counter = 0; + /// compute residual ... + double3 xyz_current = xyz_cur(cur_pose.x, cur_pose.z, cur_pose.pitch, ref_pose.x ,ref_pose.z ,ref_pose.pitch, ref_feature[f]); + double2 uv_cur_pyr = world2cam(camera_model[0], camera_model[1], camera_model[2], camera_model[3], camera_model[4], + xyz_current[0], xyz_current[1], xyz_current[2]) * scale; + double u_cur = uv_cur_pyr[0]; + double v_cur = uv_cur_pyr[1]; + int u_cur_i = floor(u_cur); + int v_cur_i = floor(v_cur); + + // check if projection is within the image + if(u_cur_i < 0 || v_cur_i < 0 || u_cur_i - border < 0 || v_cur_i - border < 0 || + u_cur_i + border >= get_image_dim(image_cur)[0] || v_cur_i + border >= get_image_dim(image_cur)[0]) + return; + // compute bilateral interpolation weights for the current image + double subpix_u_cur = u_cur - u_cur_i; + double subpix_v_cur = v_cur - v_cur_i; + double w_cur_tl = (1.0 - subpix_u_cur) * (1.0 - subpix_v_cur); + double w_cur_tr = subpix_u_cur * (1.0 - subpix_v_cur); + double w_cur_bl = (1.0 - subpix_u_cur) * subpix_v_cur; + double w_cur_br = subpix_u_cur * subpix_v_cur; + + /// TODO - check & implementation + // float* ref_patch_cache_ptr = reinterpret_cast(ref_patch_cache_.data) + patch_area_*feature_counter; + /// ... compute residual + + // float* cache_ptr = reinterpret_cast(ref_patch_cache_.data) + patch_area_*feature_counter; + for(int y = 0; y < PATCH_SIZE; ++y) + { + /// TODO - check & implementation + // uint8_t* ref_img_ptr = (uint8_t*) ref_img.data + (v_ref_i+y-patch_halfsize_)*stride + (u_ref_i-patch_halfsize_); + // uint8_t* cur_img_ptr = (uint8_t*) image_cur.data + (v_cur_i + y - patch_halfsize_) * stride + (u_cur_i - patch_halfsize_); + + // for(int x = 0; x < PATCH_SIZE; ++x, ++pixel_counter, ++ref_img_ptr, ++cache_ptr) + // for(int x = 0; x < PATCH_SIZE; ++x, ++pixel_counter, ++cur_img_ptr, ++ref_patch_cache_ptr) + for(int x = 0; x < PATCH_SIZE; ++x, ++pixel_counter, ++ref_img_ptr, ++cur_img_ptr) + { + /// TODO - check & implementation + // precompute interpolated reference patch color + // *cache_ptr = w_ref_tl*ref_img_ptr[0] + w_ref_tr*ref_img_ptr[1] + w_ref_bl*ref_img_ptr[stride] + w_ref_br*ref_img_ptr[stride+1]; + + // we use the inverse compositional: thereby we can take the gradient always at the same position + // get gradient of warped image (~gradient at warped position) + double dx = 0.5f * ((w_ref_tl * ref_img_ptr[1] + w_ref_tr * ref_img_ptr[2] + w_ref_bl * ref_img_ptr[stride+1] + w_ref_br * ref_img_ptr[stride+2]) + -(w_ref_tl * ref_img_ptr[-1] + w_ref_tr * ref_img_ptr[0] + w_ref_bl * ref_img_ptr[stride-1] + w_ref_br * ref_img_ptr[stride])); + double dy = 0.5f * ((w_ref_tl * ref_img_ptr[stride] + w_ref_tr * ref_img_ptr[1+stride] + w_ref_bl * ref_img_ptr[stride*2] + w_ref_br * ref_img_ptr[stride*2+1]) + -(w_ref_tl * ref_img_ptr[-stride] + w_ref_tr * ref_img_ptr[1-stride] + w_ref_bl * ref_img_ptr[0] + w_ref_br * ref_img_ptr[1])); + + // compute residual + /// TODO - check & implementation + // double intensity_cur = w_cur_tl * cur_img_ptr[0] + w_cur_tr * cur_img_ptr[1] + w_cur_bl * cur_img_ptr[stride] + w_cur_br * cur_img_ptr[stride+1]; + double res = intensity_cur - (ref_patch_cache_ptr[x]); + + // used to compute scale for robust cost + if(compute_weight_scale) + errors[(y * PATCH_SIZE) + x] = fabs(res) + + // robustification + double weight = 2.0; + // if(use_weights_) { // use_weights_ dafault value is false + // weight = weight_function_->value(res/scale_); + // } + + chi2 += res * res * weight; + n_meas_++; + + // if(linearize_system) + // { + // compute Jacobian, weighted Hessian and weighted "steepest descend images" (times error) + double3 j_row0 = double3(dx * frame_jac[0], dx * frame_jac[1], dx * frame_jac[2]) + double3 j_row1 = double3(dy * frame_jac[3], dy * frame_jac[4], dy * frame_jac[5]) + double3 J(j_row0 + j_row1) * (focal_length / scale); + compute_hessain(j, Hessian, weight); // H_.noalias() += J * J.transpose() * weight; + compute_Jacobian(j, Jacobian, res, weight) // Jres_.noalias() -= J * res * weight; + // } + chi = chi2 / n_meas_; + feature_counter++; + } + } } From 5f0d64b756778ae97bc8f05b6b2005a0cfaa1e28 Mon Sep 17 00:00:00 2001 From: VahdPourAmin Date: Sat, 24 Jul 2021 12:17:42 +0200 Subject: [PATCH 04/12] opencl kernel compute residual --- GPU_version/vio/kernel/compute-residual.cl | 79 ++++++++++++++-------- 1 file changed, 49 insertions(+), 30 deletions(-) diff --git a/GPU_version/vio/kernel/compute-residual.cl b/GPU_version/vio/kernel/compute-residual.cl index ee59d25..501b558 100644 --- a/GPU_version/vio/kernel/compute-residual.cl +++ b/GPU_version/vio/kernel/compute-residual.cl @@ -32,40 +32,40 @@ double3 xyz_ref(double fts_pos_x,double fts_pos_y,double fts_pos_z,double ref_x, return double3(x, y, z); } -void jacobian_xyz2uv(double3& xyz_in_f, double6& J) +void jacobian_xyz2uv(double3& xyz_in_f, double* J) { double x = xyz_in_f[0]; double y = xyz_in_f[1]; double z_inv = 1. / xyz_in_f[2]; double z_inv_2 = z_inv * z_inv; - J[0] = -z_inv; // -1/z - J[1] = x * z_inv_2; // x/z^2 - J[2] = -(1.0 + pow(x,2) / z_inv_2); // -(1.0 + x^2/z^2) + *(J + 0) = -z_inv; // -1/z + *(J + 1) = x * z_inv_2; // x/z^2 + *(J + 2) = -(1.0 + pow(x,2) / z_inv_2); // -(1.0 + x^2/z^2) - J[3] = 1e-19; // 0 - J[4] = y * z_inv_2; // y/z^2 - J[5] = -x * y / z_inv_2; // -x*y/z^2 + *(J + 3) = 1e-19; // 0 + *(J + 4) = y * z_inv_2; // y/z^2 + *(J + 5) = -x * y / z_inv_2; // -x*y/z^2 } -void compute_hessain(double3& j, double9& H, double w) +void compute_hessain(double3 j, double* H, double w) { - H[0] += j[0] * j[0] * w; - H[1] += j[0] * j[1] * w; - H[2] += j[0] * j[2] * w; - H[3] += j[1] * j[0] * w; - H[4] += j[1] * j[1] * w; - H[5] += j[1] * j[2] * w; - H[6] += j[2] * j[0] * w; - H[7] += j[2] * j[1] * w; - H[8] += j[2] * j[2] * w; + *(H + 0) += j[0] * j[0] * w; + *(H + 1) += j[0] * j[1] * w; + *(H + 2) += j[0] * j[2] * w; + *(H + 3) += j[1] * j[0] * w; + *(H + 4) += j[1] * j[1] * w; + *(H + 5) += j[1] * j[2] * w; + *(H + 6) += j[2] * j[0] * w; + *(H + 7) += j[2] * j[1] * w; + *(H + 8) += j[2] * j[2] * w; } -void compute_Jacobian(double3& j, double& Jacobian, double r, double w) +void compute_Jacobian(double3 j, double* Jacobian, double r, double w) { - Jacobian[0] -= j[0] * r * w; - Jacobian[1] -= j[1] * r * w; - Jacobian[2] -= j[2] * r * w; + *(Jacobian + 0) -= j[0] * r * w; + *(Jacobian + 1) -= j[1] * r * w; + *(Jacobian + 2) -= j[2] * r * w; } __kernel void compute-residual( @@ -74,6 +74,7 @@ __kernel void compute-residual( __global double * cur_pose,//[reference frame pose{x,z,pitch}] __global double * ref_pose,//[current frame pose{x,z,pitch}] __global double3 * ref_feature, // feature on the reference frame, when we applied the distance calculation: xyz_ref((*it)->f*((*it)->point->pos_ - Eigen::Vector3d(ref_pos[0],0.0,ref_pos[1])).norm()); + __global double2 * featue_px, __global int * level, __global double * camera_model, // camera model [f_x,f_y,c_x,c_y,s_] float * errors, @@ -100,8 +101,8 @@ __kernel void compute-residual( //ref_feature[f].y; //ref_feature[f].z; - double u_ref = ref_feature[f].x * scale; //?????? ref_feature[f].x - double v_ref = ref_feature[f].y * scale; //?????? ref_feature[f].y + double u_ref = featue_px[f].x * scale; + double v_ref = featue_px[f].y * scale; int u_ref_i = floor(u_ref); int v_ref_i = floor(v_ref); @@ -112,7 +113,7 @@ __kernel void compute-residual( xyz_reference = xyz_ref(ref_feature[f][0], ref_feature[f][1], ref_feature[f][2], ref_pose.x, ref_pose.y, ref_pose.z); // ref_pose.y ???? // evaluate projection jacobian - double6 frame_jac; //2X3 + double* frame_jac = (double *) malloc(6 * sizeof(double)); // 2X3 jacobian_xyz2uv(xyz_reference, frame_jac); double subpix_u_ref = u_ref - u_ref_i; double subpix_v_ref = v_ref - v_ref_i; @@ -141,25 +142,34 @@ __kernel void compute-residual( double w_cur_tr = subpix_u_cur * (1.0 - subpix_v_cur); double w_cur_bl = (1.0 - subpix_u_cur) * subpix_v_cur; double w_cur_br = subpix_u_cur * subpix_v_cur; - - /// TODO - check & implementation - // float* ref_patch_cache_ptr = reinterpret_cast(ref_patch_cache_.data) + patch_area_*feature_counter; /// ... compute residual + /// TODO - check & implementation // float* cache_ptr = reinterpret_cast(ref_patch_cache_.data) + patch_area_*feature_counter; + // float* ref_patch_cache_ptr = reinterpret_cast(ref_patch_cache_.data) + patch_area_*feature_counter; + + for(int y = 0; y < PATCH_SIZE; ++y) { /// TODO - check & implementation + int ref_element_add = image_ref.data + (v_ref_i + y - PATCH_HALFSIZE) * stride + (u_ref_i - PATCH_HALFSIZE); + int cur_element_add = image_cur.data + (v_cur_i + y - PATCH_HALFSIZE) * stride + (u_cur_i - PATCH_HALFSIZE); // uint8_t* ref_img_ptr = (uint8_t*) ref_img.data + (v_ref_i+y-patch_halfsize_)*stride + (u_ref_i-patch_halfsize_); // uint8_t* cur_img_ptr = (uint8_t*) image_cur.data + (v_cur_i + y - patch_halfsize_) * stride + (u_cur_i - patch_halfsize_); // for(int x = 0; x < PATCH_SIZE; ++x, ++pixel_counter, ++ref_img_ptr, ++cache_ptr) // for(int x = 0; x < PATCH_SIZE; ++x, ++pixel_counter, ++cur_img_ptr, ++ref_patch_cache_ptr) - for(int x = 0; x < PATCH_SIZE; ++x, ++pixel_counter, ++ref_img_ptr, ++cur_img_ptr) + for(int x = 0; x < PATCH_SIZE; ++x, ++pixel_counter, ++ref_element, ++cur_element) { /// TODO - check & implementation // precompute interpolated reference patch color // *cache_ptr = w_ref_tl*ref_img_ptr[0] + w_ref_tr*ref_img_ptr[1] + w_ref_bl*ref_img_ptr[stride] + w_ref_br*ref_img_ptr[stride+1]; + int2 px_reftl = (ref_element_add % get_image_dim(image_ref)[0], ref_element_add / get_image_dim(image_ref)[0]); + int2 px_reftr = ((ref_element_add + 1) % get_image_dim(image_ref)[0], (ref_element_add + 1) / get_image_dim(image_ref)[0]); + int2 px_refbl = ((ref_element_add + stride) % get_image_dim(image_ref)[0], (ref_element_add + stride) / get_image_dim(image_ref)[0]); + int2 px_refbr = ((ref_element_add + stride + 1) % get_image_dim(image_ref)[0], (ref_element_add + stride + 1) / get_image_dim(image_ref)[0]); + double value = w_ref_tl * read_imageui(image_ref, sampler, px_reftl).x + w_ref_tr * read_imageui(image_ref, sampler, px_reftr).x + + w_ref_bl * read_imageui(image_ref, sampler, px_refbl).x + w_ref_br * read_imageui(image_ref, sampler, px_refbr).x; // we use the inverse compositional: thereby we can take the gradient always at the same position // get gradient of warped image (~gradient at warped position) @@ -171,10 +181,18 @@ __kernel void compute-residual( // compute residual /// TODO - check & implementation // double intensity_cur = w_cur_tl * cur_img_ptr[0] + w_cur_tr * cur_img_ptr[1] + w_cur_bl * cur_img_ptr[stride] + w_cur_br * cur_img_ptr[stride+1]; - double res = intensity_cur - (ref_patch_cache_ptr[x]); + int2 px_curtl = (cur_element_add % get_image_dim(image_cur)[0], cur_element_add / get_image_dim(image_cur)[0]); + int2 px_curtr = ((cur_element_add + 1) % get_image_dim(image_cur)[0], (cur_element_add + 1) / get_image_dim(image_cur)[0]); + int2 px_curbl = ((cur_element_add + stride) % get_image_dim(image_cur)[0], (cur_element_add + stride) / get_image_dim(image_cur)[0]); + int2 px_curbr = ((cur_element_add + stride + 1) % get_image_dim(image_cur)[0], (cur_element_add + stride + 1) / get_image_dim(image_cur)[0]); + double intensity_cur = w_cur_tl * read_imageui(image_cur, sampler, px_curtl).x + w_cur_tr * read_imageui(image_cur, sampler, px_curtr).x + + w_cur_bl * read_imageui(image_cur, sampler, px_curbl).x + w_cur_br * read_imageui(image_cur, sampler, px_curbr).x; + + // const float res = intensity_cur - (*ref_patch_cache_ptr); + double res = intensity_cur - value; // used to compute scale for robust cost - if(compute_weight_scale) + if(compute_weight_scale) //????????? compute_weight_scale ???????????? errors[(y * PATCH_SIZE) + x] = fabs(res) // robustification @@ -199,5 +217,6 @@ __kernel void compute-residual( feature_counter++; } } + } From ed5a9139ff2bb1baadcd09b9ea20e1e0de81175c Mon Sep 17 00:00:00 2001 From: gfuse Date: Sat, 24 Jul 2021 17:02:57 +0200 Subject: [PATCH 05/12] copy pixel value in kernel --- .../vio/include/gpu_svo/abstract_camera.h | 77 - GPU_version/vio/include/gpu_svo/aligned_mem.h | 127 - GPU_version/vio/include/gpu_svo/atan_camera.h | 91 - .../vio/include/gpu_svo/bundle_adjustment.h | 109 - .../vio/include/gpu_svo/camera_loader.h | 46 - GPU_version/vio/include/gpu_svo/cl.hpp | 12947 ---------------- GPU_version/vio/include/gpu_svo/cl_class.h | 191 - GPU_version/vio/include/gpu_svo/config.h | 182 - .../vio/include/gpu_svo/depth_filter.h | 170 - GPU_version/vio/include/gpu_svo/feature.h | 75 - .../vio/include/gpu_svo/feature_alignment.h | 63 - .../vio/include/gpu_svo/feature_detection.h | 111 - GPU_version/vio/include/gpu_svo/for_it.hpp | 87 - GPU_version/vio/include/gpu_svo/frame.h | 185 - .../vio/include/gpu_svo/frame_handler_base.h | 118 - .../vio/include/gpu_svo/frame_handler_mono.h | 109 - GPU_version/vio/include/gpu_svo/global.h | 120 - GPU_version/vio/include/gpu_svo/homography.h | 85 - .../vio/include/gpu_svo/initialization.h | 87 - GPU_version/vio/include/gpu_svo/map.h | 137 - GPU_version/vio/include/gpu_svo/matcher.h | 130 - GPU_version/vio/include/gpu_svo/math_utils.h | 171 - GPU_version/vio/include/gpu_svo/nlls_solver.h | 169 - .../vio/include/gpu_svo/nlls_solver_impl.hpp | 348 - .../vio/include/gpu_svo/output_helper.h | 90 - .../vio/include/gpu_svo/params_helper.h | 57 - GPU_version/vio/include/gpu_svo/patch_score.h | 225 - GPU_version/vio/include/gpu_svo/point.h | 108 - .../vio/include/gpu_svo/pose_optimizer.h | 50 - GPU_version/vio/include/gpu_svo/reprojector.h | 101 - GPU_version/vio/include/gpu_svo/robust_cost.h | 156 - .../vio/include/gpu_svo/sparse_img_align.h | 83 - GPU_version/vio/include/gpu_svo/timer.h | 81 - GPU_version/vio/include/gpu_svo/ukf.h | 155 - GPU_version/vio/include/gpu_svo/vision.h | 80 - GPU_version/vio/include/gpu_svo/visualizer.h | 62 - GPU_version/vio/src/frame_handler_mono.cpp | 14 +- GPU_version/vio/src/sparse_img_align_gpu.cpp | 18 +- 38 files changed, 19 insertions(+), 17196 deletions(-) delete mode 100644 GPU_version/vio/include/gpu_svo/abstract_camera.h delete mode 100644 GPU_version/vio/include/gpu_svo/aligned_mem.h delete mode 100644 GPU_version/vio/include/gpu_svo/atan_camera.h delete mode 100644 GPU_version/vio/include/gpu_svo/bundle_adjustment.h delete mode 100644 GPU_version/vio/include/gpu_svo/camera_loader.h delete mode 100644 GPU_version/vio/include/gpu_svo/cl.hpp delete mode 100644 GPU_version/vio/include/gpu_svo/cl_class.h delete mode 100644 GPU_version/vio/include/gpu_svo/config.h delete mode 100644 GPU_version/vio/include/gpu_svo/depth_filter.h delete mode 100644 GPU_version/vio/include/gpu_svo/feature.h delete mode 100644 GPU_version/vio/include/gpu_svo/feature_alignment.h delete mode 100644 GPU_version/vio/include/gpu_svo/feature_detection.h delete mode 100755 GPU_version/vio/include/gpu_svo/for_it.hpp delete mode 100644 GPU_version/vio/include/gpu_svo/frame.h delete mode 100644 GPU_version/vio/include/gpu_svo/frame_handler_base.h delete mode 100644 GPU_version/vio/include/gpu_svo/frame_handler_mono.h delete mode 100644 GPU_version/vio/include/gpu_svo/global.h delete mode 100644 GPU_version/vio/include/gpu_svo/homography.h delete mode 100644 GPU_version/vio/include/gpu_svo/initialization.h delete mode 100644 GPU_version/vio/include/gpu_svo/map.h delete mode 100644 GPU_version/vio/include/gpu_svo/matcher.h delete mode 100644 GPU_version/vio/include/gpu_svo/math_utils.h delete mode 100644 GPU_version/vio/include/gpu_svo/nlls_solver.h delete mode 100644 GPU_version/vio/include/gpu_svo/nlls_solver_impl.hpp delete mode 100644 GPU_version/vio/include/gpu_svo/output_helper.h delete mode 100644 GPU_version/vio/include/gpu_svo/params_helper.h delete mode 100644 GPU_version/vio/include/gpu_svo/patch_score.h delete mode 100644 GPU_version/vio/include/gpu_svo/point.h delete mode 100644 GPU_version/vio/include/gpu_svo/pose_optimizer.h delete mode 100644 GPU_version/vio/include/gpu_svo/reprojector.h delete mode 100644 GPU_version/vio/include/gpu_svo/robust_cost.h delete mode 100644 GPU_version/vio/include/gpu_svo/sparse_img_align.h delete mode 100644 GPU_version/vio/include/gpu_svo/timer.h delete mode 100644 GPU_version/vio/include/gpu_svo/ukf.h delete mode 100644 GPU_version/vio/include/gpu_svo/vision.h delete mode 100644 GPU_version/vio/include/gpu_svo/visualizer.h diff --git a/GPU_version/vio/include/gpu_svo/abstract_camera.h b/GPU_version/vio/include/gpu_svo/abstract_camera.h deleted file mode 100644 index 5d643dc..0000000 --- a/GPU_version/vio/include/gpu_svo/abstract_camera.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * abstract_camera.h - * - * Created on: Jul 23, 2012 - * Author: cforster - */ - -#ifndef ABSTRACT_CAMERA_H_ -#define ABSTRACT_CAMERA_H_ - -#include - -namespace vk -{ - -using namespace std; -using namespace Eigen; - -class AbstractCamera -{ -protected: - - int width_; // TODO cannot be const because of omni-camera model - int height_; - -public: - - AbstractCamera() {}; // need this constructor for omni camera - AbstractCamera(int width, int height) : width_(width), height_(height) {}; - - virtual ~AbstractCamera() {}; - - /// Project from pixels to world coordiantes. Returns a bearing vector of unit length. - virtual Vector3d - cam2world(const double& x, const double& y) const = 0; - - /// Project from pixels to world coordiantes. Returns a bearing vector of unit length. - virtual Vector3d - cam2world(const Vector2d& px) const = 0; - - virtual Vector2d - world2cam(const Vector3d& xyz_c) const = 0; - - /// projects unit plane coordinates to camera coordinates - virtual Vector2d - world2cam(const Vector2d& uv) const = 0; - - virtual double - errorMultiplier2() const = 0; - - virtual double - errorMultiplier() const = 0; - - inline int width() const { return width_; } - - inline int height() const { return height_; } - - inline bool isInFrame(const Vector2i & obs, int boundary=0) const - { - if(obs[0]>=boundary && obs[0]=boundary && obs[1]= boundary && obs[0] < width()/(1<= boundary && obs[1] // memset -#include // memset -#include -#include - -namespace vk { -namespace aligned_mem { - - /// Check if the pointer is aligned to the specified byte granularity - inline bool - is_aligned8(const void* ptr) - { - return ((reinterpret_cast(ptr)) & 0x7) == 0; - } - - inline bool - is_aligned16(const void* ptr) - { - return ((reinterpret_cast(ptr)) & 0xF) == 0; - } - - template struct placement_delete - { - enum { Size = (1<= Size) { - placement_delete::free(buf+Size,M-Size); - placement_delete::destruct(buf); - } else { - placement_delete::free(buf, M); - } - } - }; - - template struct placement_delete - { - static inline void free(T*, size_t ) {} - }; - - inline void * aligned_alloc(size_t count, size_t alignment){ - void * mem = NULL; - assert(posix_memalign(&mem, alignment, count) == 0); - return mem; - } - - inline void aligned_free(void * memory) { - free(memory); - } - - template - inline T * aligned_alloc(size_t count, size_t alignment){ - void * data = aligned_alloc(sizeof(T)* count, alignment); - return new (data) T[count]; - } - - template - inline void aligned_free(T * memory, size_t count){ - placement_delete::free(memory, count); - aligned_free(memory); - } - - template inline void memfill(T* data, int n, const T val) - { - T* de = data + n; - for(;data < de; data++) - *data=val; - } - - template<> inline void memfill(unsigned char* data, int n, const unsigned char val) - { - memset(data, val, n); - } - - template<> inline void memfill(signed char* data, int n, const signed char val) - { - memset(data, val, n); - } - - template<> inline void memfill(char* data, int n, const char val) - { - memset(data, val, n); - } - - template - struct AlignedMem { - T* mem; - size_t count; - AlignedMem(size_t c) : count(c) { - mem = aligned_alloc(count, N); - } - ~AlignedMem() { - aligned_free(mem, count); - } - T* data() { return mem; } - const T* data() const { return mem; } - }; - -} // namespace aligned_mem -} // namespace vikit - - -#endif // VIKIT_ALIGNED_MEM_H_ diff --git a/GPU_version/vio/include/gpu_svo/atan_camera.h b/GPU_version/vio/include/gpu_svo/atan_camera.h deleted file mode 100644 index 49550b2..0000000 --- a/GPU_version/vio/include/gpu_svo/atan_camera.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * atan_camera.h - * - * Created on: Aug 21, 2012 - * Author: cforster - * - * This class implements the FOV distortion model of Deverneay and Faugeras, - * Straight lines have to be straight, 2001. - * - * The code is an implementation of the ATAN class in PTAM by Georg Klein using Eigen. - */ - -#ifndef ATAN_CAMERA_H_ -#define ATAN_CAMERA_H_ - -#include -#include -#include -#include -#include - -namespace vk { - -using namespace std; -using namespace Eigen; - -class ATANCamera : public AbstractCamera { - -private: - double fx_, fy_; //!< focal length - double fx_inv_, fy_inv_; //!< inverse focal length - double cx_, cy_; //!< projection center - double s_, s_inv_; //!< distortion model coeff - double tans_; //!< distortion model coeff - double tans_inv_; //!< distortion model coeff - bool distortion_; //!< use distortion model? - - //! Radial distortion transformation factor: returns ration of distorted / undistorted radius. - inline double rtrans_factor(double r) const - { - if(r < 0.001 || s_ == 0.0) - return 1.0; - else - return (s_inv_* atan(r * tans_) / r); - }; - - //! Inverse radial distortion: returns un-distorted radius from distorted. - inline double invrtrans(double r) const - { - if(s_ == 0.0) - return r; - return (tan(r * s_) * tans_inv_); - }; - -public: - - ATANCamera(double width, double height, double fx, double fy, double dx, double dy, double s); - - ~ATANCamera(); - - virtual Vector3d - cam2world(const double& x, const double& y) const; - - virtual Vector3d - cam2world(const Vector2d& px) const; - - virtual Vector2d - world2cam(const Vector3d& xyz_c) const; - - virtual Vector2d - world2cam(const Vector2d& uv) const; - - const Vector2d focal_length() const - { - return Vector2d(fx_, fy_); - } - - virtual double errorMultiplier2() const - { - return fx_; - } - - virtual double errorMultiplier() const - { - return 4*fx_*fy_; - } -}; - -} // end namespace vk - -#endif /* ATAN_CAMERA_H_ */ diff --git a/GPU_version/vio/include/gpu_svo/bundle_adjustment.h b/GPU_version/vio/include/gpu_svo/bundle_adjustment.h deleted file mode 100644 index 9eb8a94..0000000 --- a/GPU_version/vio/include/gpu_svo/bundle_adjustment.h +++ /dev/null @@ -1,109 +0,0 @@ -// This file is part of SVO - Semi-direct Visual Odometry. -// -// Copyright (C) 2014 Christian Forster -// (Robotics and Perception Group, University of Zurich, Switzerland). -// -// SVO is free software: you can redistribute it and/or modify it under the -// terms of the GNU General Public License as published by the Free Software -// Foundation, either version 3 of the License, or any later version. -// -// SVO is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#ifndef SVO_BUNDLE_ADJUSTMENT_H_ -#define SVO_BUNDLE_ADJUSTMENT_H_ - -#include - -namespace g2o { -class EdgeProjectXYZ2UV; -class SparseOptimizer; -class VertexSE3Expmap; -class VertexSBAPointXYZ; -} - -namespace svo { - -typedef g2o::EdgeProjectXYZ2UV g2oEdgeSE3; -typedef g2o::VertexSE3Expmap g2oFrameSE3; -typedef g2o::VertexSBAPointXYZ g2oPoint; - -class Frame; -class Point; -class Feature; -class Map; - -/// Local, global and 2-view bundle adjustment with g2o -namespace ba { - -/// Temporary container to hold the g2o edge with reference to frame and point. -struct EdgeContainerSE3 -{ - g2oEdgeSE3* edge; - Frame* frame; - Feature* feature; - bool is_deleted; - EdgeContainerSE3(g2oEdgeSE3* e, Frame* frame, Feature* feature) : - edge(e), frame(frame), feature(feature), is_deleted(false) - {} -}; - -/// Optimize two camera frames and their observed 3D points. -/// Is used after initialization. -void twoViewBA(Frame* frame1, Frame* frame2, double reproj_thresh, Map* map); - -/// Local bundle adjustment. -/// Optimizes core_kfs and their observed map points while keeping the -/// neighbourhood fixed. -void localBA( - Frame* center_kf, - set* core_kfs, - Map* map, - size_t& n_incorrect_edges_1, - size_t& n_incorrect_edges_2, - double& init_error, - double& final_error); - -/// Global bundle adjustment. -/// Optimizes the whole map. Is currently not used in SVO. -void globalBA(Map* map); - -/// Initialize g2o with solver type, optimization strategy and camera model. -void setupG2o(g2o::SparseOptimizer * optimizer); - -/// Run the optimization on the provided graph. -void runSparseBAOptimizer( - g2o::SparseOptimizer* optimizer, - unsigned int num_iter, - double& init_error, - double& final_error); - -/// Create a g2o vertice from a keyframe object. -g2oFrameSE3* createG2oFrameSE3( - Frame* kf, - size_t id, - bool fixed); - -/// Creates a g2o vertice from a mappoint object. -g2oPoint* createG2oPoint( - Vector3d pos, - size_t id, - bool fixed); - -/// Creates a g2o edge between a g2o keyframe and mappoint vertice with the provided measurement. -g2oEdgeSE3* createG2oEdgeSE3( - g2oFrameSE3* v_kf, - g2oPoint* v_mp, - const Vector2d& f_up, - bool robust_kernel, - double huber_width, - double weight = 1); - -} // namespace ba -} // namespace svo - -#endif // SVO_BUNDLE_ADJUSTMENT_H_ diff --git a/GPU_version/vio/include/gpu_svo/camera_loader.h b/GPU_version/vio/include/gpu_svo/camera_loader.h deleted file mode 100644 index e9d5a94..0000000 --- a/GPU_version/vio/include/gpu_svo/camera_loader.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * camera_loader.h - * - * Created on: Feb 11, 2014 - * Author: cforster - */ - -#ifndef VIKIT_CAMERA_LOADER_H_ -#define VIKIT_CAMERA_LOADER_H_ - -#include -#include -#include -#include - -namespace vk { -namespace camera_loader { - -/// Load from ROS Namespace -bool loadFromRosNs(const std::string& ns, vk::AbstractCamera*& cam) -{ - bool res = true; - std::string cam_model(getParam(ns+"/cam_model")); - if(cam_model == "ATAN") - { - cam = new vk::ATANCamera( - getParam(ns+"/cam_width"), - getParam(ns+"/cam_height"), - getParam(ns+"/cam_fx"), - getParam(ns+"/cam_fy"), - getParam(ns+"/cam_cx"), - getParam(ns+"/cam_cy"), - getParam(ns+"/cam_d0")); - } - else - { - cam = NULL; - res = false; - } - return res; -} - -} // namespace camera_loader -} // namespace vk - -#endif // VIKIT_CAMERA_LOADER_H_ diff --git a/GPU_version/vio/include/gpu_svo/cl.hpp b/GPU_version/vio/include/gpu_svo/cl.hpp deleted file mode 100644 index 6634f8c..0000000 --- a/GPU_version/vio/include/gpu_svo/cl.hpp +++ /dev/null @@ -1,12947 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2008-2015 The Khronos Group Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and/or associated documentation files (the - * "Materials"), to deal in the Materials without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Materials, and to - * permit persons to whom the Materials are furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Materials. - * - * MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS - * KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS - * SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT - * https://www.khronos.org/registry/ - * - * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. - ******************************************************************************/ - -/*! \file - * - * \brief C++ bindings for OpenCL 1.0 (rev 48), OpenCL 1.1 (rev 33) and - * OpenCL 1.2 (rev 15) - * \author Benedict R. Gaster, Laurent Morichetti and Lee Howes - * - * Additions and fixes from: - * Brian Cole, March 3rd 2010 and April 2012 - * Matt Gruenke, April 2012. - * Bruce Merry, February 2013. - * Tom Deakin and Simon McIntosh-Smith, July 2013 - * - * \version 1.2.9 - * \date December 2015 - * - * Optional extension support - * - * cl - * cl_ext_device_fission - * #define USE_CL_DEVICE_FISSION - */ - -/*! \mainpage - * \section intro Introduction - * For many large applications C++ is the language of choice and so it seems - * reasonable to define C++ bindings for OpenCL. - * - * - * The interface is contained with a single C++ header file \em cl.hpp and all - * definitions are contained within the namespace \em cl. There is no additional - * requirement to include \em cl.h and to use either the C++ or original C - * bindings it is enough to simply include \em cl.hpp. - * - * The bindings themselves are lightweight and correspond closely to the - * underlying C API. Using the C++ bindings introduces no additional execution - * overhead. - * - * For detail documentation on the bindings see: - * - * The OpenCL C++ Wrapper API 1.2 (revision 09) - * http://www.khronos.org/registry/cl/specs/opencl-cplusplus-1.2.pdf - * - * \section example Example - * - * The following example shows a general use case for the C++ - * bindings, including support for the optional exception feature and - * also the supplied vector and string classes, see following sections for - * decriptions of these features. - * - * \code - * #define __CL_ENABLE_EXCEPTIONS - * - * #if defined(__APPLE__) || defined(__MACOSX) - * #include - * #else - * #include - * #endif - * #include - * #include - * #include - * - * const char * helloStr = "__kernel void " - * "hello(void) " - * "{ " - * " " - * "} "; - * - * int - * main(void) - * { - * cl_int err = CL_SUCCESS; - * try { - * - * std::vector platforms; - * cl::Platform::get(&platforms); - * if (platforms.size() == 0) { - * std::cout << "Platform size 0\n"; - * return -1; - * } - * - * cl_context_properties properties[] = - * { CL_CONTEXT_PLATFORM, (cl_context_properties)(platforms[0])(), 0}; - * cl::Context context(CL_DEVICE_TYPE_CPU, properties); - * - * std::vector devices = context.getInfo(); - * - * cl::Program::Sources source(1, - * std::make_pair(helloStr,strlen(helloStr))); - * cl::Program program_ = cl::Program(context, source); - * program_.build(devices); - * - * cl::Kernel kernel(program_, "hello", &err); - * - * cl::Event event; - * cl::CommandQueue queue(context, devices[0], 0, &err); - * queue.enqueueNDRangeKernel( - * kernel, - * cl::NullRange, - * cl::NDRange(4,4), - * cl::NullRange, - * NULL, - * &event); - * - * event.wait(); - * } - * catch (cl::Error err) { - * std::cerr - * << "ERROR: " - * << err.what() - * << "(" - * << err.err() - * << ")" - * << std::endl; - * } - * - * return EXIT_SUCCESS; - * } - * - * \endcode - * - */ -#ifndef CL_HPP_ -#define CL_HPP_ - -#ifdef _WIN32 - -#include - -#if defined(USE_DX_INTEROP) -#include -#include -#endif -#endif // _WIN32 - -#if defined(_MSC_VER) -#include -#endif // _MSC_VER - -// -#if defined(USE_CL_DEVICE_FISSION) -#include -#endif - -#if defined(__APPLE__) || defined(__MACOSX) -#include -#else -#include -#endif // !__APPLE__ - -#if (_MSC_VER >= 1700) || (__cplusplus >= 201103L) -#define CL_HPP_RVALUE_REFERENCES_SUPPORTED -#define CL_HPP_CPP11_ATOMICS_SUPPORTED -#include -#endif - -#if (__cplusplus >= 201103L) -#define CL_HPP_NOEXCEPT noexcept -#else -#define CL_HPP_NOEXCEPT -#endif - - -// To avoid accidentally taking ownership of core OpenCL types -// such as cl_kernel constructors are made explicit -// under OpenCL 1.2 -#if defined(CL_VERSION_1_2) && !defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) -#define __CL_EXPLICIT_CONSTRUCTORS explicit -#else // #if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) -#define __CL_EXPLICIT_CONSTRUCTORS -#endif // #if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) - -// Define deprecated prefixes and suffixes to ensure compilation -// in case they are not pre-defined -#if !defined(CL_EXT_PREFIX__VERSION_1_1_DEPRECATED) -#define CL_EXT_PREFIX__VERSION_1_1_DEPRECATED -#endif // #if !defined(CL_EXT_PREFIX__VERSION_1_1_DEPRECATED) -#if !defined(CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED) -#define CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED -#endif // #if !defined(CL_EXT_PREFIX__VERSION_1_1_DEPRECATED) - -#if !defined(CL_CALLBACK) -#define CL_CALLBACK -#endif //CL_CALLBACK - -#include -#include -#include - -#if defined(__CL_ENABLE_EXCEPTIONS) -#include -#endif // #if defined(__CL_ENABLE_EXCEPTIONS) - -#if !defined(__NO_STD_VECTOR) -#include -#endif - -#if !defined(__NO_STD_STRING) -#include -#endif - -#if defined(__ANDROID__) || defined(linux) || defined(__APPLE__) || defined(__MACOSX) -#include -#endif // linux - -#include - - -/*! \namespace cl - * - * \brief The OpenCL C++ bindings are defined within this namespace. - * - */ -namespace cl { - -class Memory; - -/** - * Deprecated APIs for 1.2 - */ -#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) || (defined(CL_VERSION_1_1) && !defined(CL_VERSION_1_2)) -#define __INIT_CL_EXT_FCN_PTR(name) \ - if(!pfn_##name) { \ - pfn_##name = (PFN_##name) \ - clGetExtensionFunctionAddress(#name); \ - if(!pfn_##name) { \ - } \ - } -#endif // #if defined(CL_VERSION_1_1) - -#if defined(CL_VERSION_1_2) -#define __INIT_CL_EXT_FCN_PTR_PLATFORM(platform, name) \ - if(!pfn_##name) { \ - pfn_##name = (PFN_##name) \ - clGetExtensionFunctionAddressForPlatform(platform, #name); \ - if(!pfn_##name) { \ - } \ - } -#endif // #if defined(CL_VERSION_1_1) - -class Program; -class Device; -class Context; -class CommandQueue; -class Memory; -class Buffer; - -#if defined(__CL_ENABLE_EXCEPTIONS) -/*! \brief Exception class - * - * This may be thrown by API functions when __CL_ENABLE_EXCEPTIONS is defined. - */ -class Error : public std::exception -{ -private: - cl_int err_; - const char * errStr_; -public: - /*! \brief Create a new CL error exception for a given error code - * and corresponding message. - * - * \param err error code value. - * - * \param errStr a descriptive string that must remain in scope until - * handling of the exception has concluded. If set, it - * will be returned by what(). - */ - Error(cl_int err, const char * errStr = NULL) : err_(err), errStr_(errStr) - {} - - ~Error() throw() {} - - /*! \brief Get error string associated with exception - * - * \return A memory pointer to the error message string. - */ - virtual const char * what() const throw () - { - if (errStr_ == NULL) { - return "empty"; - } - else { - return errStr_; - } - } - - /*! \brief Get error code associated with exception - * - * \return The error code. - */ - cl_int err(void) const { return err_; } -}; - -#define __ERR_STR(x) #x -#else -#define __ERR_STR(x) NULL -#endif // __CL_ENABLE_EXCEPTIONS - - -namespace detail -{ -#if defined(__CL_ENABLE_EXCEPTIONS) -static inline cl_int errHandler ( - cl_int err, - const char * errStr = NULL) -{ - if (err != CL_SUCCESS) { - throw Error(err, errStr); - } - return err; -} -#else -static inline cl_int errHandler (cl_int err, const char * errStr = NULL) -{ - (void) errStr; // suppress unused variable warning - return err; -} -#endif // __CL_ENABLE_EXCEPTIONS -} - - - -//! \cond DOXYGEN_DETAIL -#if !defined(__CL_USER_OVERRIDE_ERROR_STRINGS) -#define __GET_DEVICE_INFO_ERR __ERR_STR(clGetDeviceInfo) -#define __GET_PLATFORM_INFO_ERR __ERR_STR(clGetPlatformInfo) -#define __GET_DEVICE_IDS_ERR __ERR_STR(clGetDeviceIDs) -#define __GET_PLATFORM_IDS_ERR __ERR_STR(clGetPlatformIDs) -#define __GET_CONTEXT_INFO_ERR __ERR_STR(clGetContextInfo) -#define __GET_EVENT_INFO_ERR __ERR_STR(clGetEventInfo) -#define __GET_EVENT_PROFILE_INFO_ERR __ERR_STR(clGetEventProfileInfo) -#define __GET_MEM_OBJECT_INFO_ERR __ERR_STR(clGetMemObjectInfo) -#define __GET_IMAGE_INFO_ERR __ERR_STR(clGetImageInfo) -#define __GET_SAMPLER_INFO_ERR __ERR_STR(clGetSamplerInfo) -#define __GET_KERNEL_INFO_ERR __ERR_STR(clGetKernelInfo) -#if defined(CL_VERSION_1_2) -#define __GET_KERNEL_ARG_INFO_ERR __ERR_STR(clGetKernelArgInfo) -#endif // #if defined(CL_VERSION_1_2) -#define __GET_KERNEL_WORK_GROUP_INFO_ERR __ERR_STR(clGetKernelWorkGroupInfo) -#define __GET_PROGRAM_INFO_ERR __ERR_STR(clGetProgramInfo) -#define __GET_PROGRAM_BUILD_INFO_ERR __ERR_STR(clGetProgramBuildInfo) -#define __GET_COMMAND_QUEUE_INFO_ERR __ERR_STR(clGetCommandQueueInfo) - -#define __CREATE_CONTEXT_ERR __ERR_STR(clCreateContext) -#define __CREATE_CONTEXT_FROM_TYPE_ERR __ERR_STR(clCreateContextFromType) -#define __GET_SUPPORTED_IMAGE_FORMATS_ERR __ERR_STR(clGetSupportedImageFormats) - -#define __CREATE_BUFFER_ERR __ERR_STR(clCreateBuffer) -#define __COPY_ERR __ERR_STR(cl::copy) -#define __CREATE_SUBBUFFER_ERR __ERR_STR(clCreateSubBuffer) -#define __CREATE_GL_BUFFER_ERR __ERR_STR(clCreateFromGLBuffer) -#define __CREATE_GL_RENDER_BUFFER_ERR __ERR_STR(clCreateFromGLBuffer) -#define __GET_GL_OBJECT_INFO_ERR __ERR_STR(clGetGLObjectInfo) -#if defined(CL_VERSION_1_2) -#define __CREATE_IMAGE_ERR __ERR_STR(clCreateImage) -#define __CREATE_GL_TEXTURE_ERR __ERR_STR(clCreateFromGLTexture) -#define __IMAGE_DIMENSION_ERR __ERR_STR(Incorrect image dimensions) -#endif // #if defined(CL_VERSION_1_2) -#define __CREATE_SAMPLER_ERR __ERR_STR(clCreateSampler) -#define __SET_MEM_OBJECT_DESTRUCTOR_CALLBACK_ERR __ERR_STR(clSetMemObjectDestructorCallback) - -#define __CREATE_USER_EVENT_ERR __ERR_STR(clCreateUserEvent) -#define __SET_USER_EVENT_STATUS_ERR __ERR_STR(clSetUserEventStatus) -#define __SET_EVENT_CALLBACK_ERR __ERR_STR(clSetEventCallback) -#define __WAIT_FOR_EVENTS_ERR __ERR_STR(clWaitForEvents) - -#define __CREATE_KERNEL_ERR __ERR_STR(clCreateKernel) -#define __SET_KERNEL_ARGS_ERR __ERR_STR(clSetKernelArg) -#define __CREATE_PROGRAM_WITH_SOURCE_ERR __ERR_STR(clCreateProgramWithSource) -#define __CREATE_PROGRAM_WITH_BINARY_ERR __ERR_STR(clCreateProgramWithBinary) -#if defined(CL_VERSION_1_2) -#define __CREATE_PROGRAM_WITH_BUILT_IN_KERNELS_ERR __ERR_STR(clCreateProgramWithBuiltInKernels) -#endif // #if defined(CL_VERSION_1_2) -#define __BUILD_PROGRAM_ERR __ERR_STR(clBuildProgram) -#if defined(CL_VERSION_1_2) -#define __COMPILE_PROGRAM_ERR __ERR_STR(clCompileProgram) -#define __LINK_PROGRAM_ERR __ERR_STR(clLinkProgram) -#endif // #if defined(CL_VERSION_1_2) -#define __CREATE_KERNELS_IN_PROGRAM_ERR __ERR_STR(clCreateKernelsInProgram) - -#define __CREATE_COMMAND_QUEUE_ERR __ERR_STR(clCreateCommandQueue) -#define __SET_COMMAND_QUEUE_PROPERTY_ERR __ERR_STR(clSetCommandQueueProperty) -#define __ENQUEUE_READ_BUFFER_ERR __ERR_STR(clEnqueueReadBuffer) -#define __ENQUEUE_READ_BUFFER_RECT_ERR __ERR_STR(clEnqueueReadBufferRect) -#define __ENQUEUE_WRITE_BUFFER_ERR __ERR_STR(clEnqueueWriteBuffer) -#define __ENQUEUE_WRITE_BUFFER_RECT_ERR __ERR_STR(clEnqueueWriteBufferRect) -#define __ENQEUE_COPY_BUFFER_ERR __ERR_STR(clEnqueueCopyBuffer) -#define __ENQEUE_COPY_BUFFER_RECT_ERR __ERR_STR(clEnqueueCopyBufferRect) -#define __ENQUEUE_FILL_BUFFER_ERR __ERR_STR(clEnqueueFillBuffer) -#define __ENQUEUE_READ_IMAGE_ERR __ERR_STR(clEnqueueReadImage) -#define __ENQUEUE_WRITE_IMAGE_ERR __ERR_STR(clEnqueueWriteImage) -#define __ENQUEUE_COPY_IMAGE_ERR __ERR_STR(clEnqueueCopyImage) -#define __ENQUEUE_FILL_IMAGE_ERR __ERR_STR(clEnqueueFillImage) -#define __ENQUEUE_COPY_IMAGE_TO_BUFFER_ERR __ERR_STR(clEnqueueCopyImageToBuffer) -#define __ENQUEUE_COPY_BUFFER_TO_IMAGE_ERR __ERR_STR(clEnqueueCopyBufferToImage) -#define __ENQUEUE_MAP_BUFFER_ERR __ERR_STR(clEnqueueMapBuffer) -#define __ENQUEUE_MAP_IMAGE_ERR __ERR_STR(clEnqueueMapImage) -#define __ENQUEUE_UNMAP_MEM_OBJECT_ERR __ERR_STR(clEnqueueUnMapMemObject) -#define __ENQUEUE_NDRANGE_KERNEL_ERR __ERR_STR(clEnqueueNDRangeKernel) -#define __ENQUEUE_TASK_ERR __ERR_STR(clEnqueueTask) -#define __ENQUEUE_NATIVE_KERNEL __ERR_STR(clEnqueueNativeKernel) -#if defined(CL_VERSION_1_2) -#define __ENQUEUE_MIGRATE_MEM_OBJECTS_ERR __ERR_STR(clEnqueueMigrateMemObjects) -#endif // #if defined(CL_VERSION_1_2) - -#define __ENQUEUE_ACQUIRE_GL_ERR __ERR_STR(clEnqueueAcquireGLObjects) -#define __ENQUEUE_RELEASE_GL_ERR __ERR_STR(clEnqueueReleaseGLObjects) - - -#define __RETAIN_ERR __ERR_STR(Retain Object) -#define __RELEASE_ERR __ERR_STR(Release Object) -#define __FLUSH_ERR __ERR_STR(clFlush) -#define __FINISH_ERR __ERR_STR(clFinish) -#define __VECTOR_CAPACITY_ERR __ERR_STR(Vector capacity error) - -/** - * CL 1.2 version that uses device fission. - */ -#if defined(CL_VERSION_1_2) -#define __CREATE_SUB_DEVICES __ERR_STR(clCreateSubDevices) -#else -#define __CREATE_SUB_DEVICES __ERR_STR(clCreateSubDevicesEXT) -#endif // #if defined(CL_VERSION_1_2) - -/** - * Deprecated APIs for 1.2 - */ -#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) || (defined(CL_VERSION_1_1) && !defined(CL_VERSION_1_2)) -#define __ENQUEUE_MARKER_ERR __ERR_STR(clEnqueueMarker) -#define __ENQUEUE_WAIT_FOR_EVENTS_ERR __ERR_STR(clEnqueueWaitForEvents) -#define __ENQUEUE_BARRIER_ERR __ERR_STR(clEnqueueBarrier) -#define __UNLOAD_COMPILER_ERR __ERR_STR(clUnloadCompiler) -#define __CREATE_GL_TEXTURE_2D_ERR __ERR_STR(clCreateFromGLTexture2D) -#define __CREATE_GL_TEXTURE_3D_ERR __ERR_STR(clCreateFromGLTexture3D) -#define __CREATE_IMAGE2D_ERR __ERR_STR(clCreateImage2D) -#define __CREATE_IMAGE3D_ERR __ERR_STR(clCreateImage3D) -#endif // #if defined(CL_VERSION_1_1) - -#endif // __CL_USER_OVERRIDE_ERROR_STRINGS -//! \endcond - -/** - * CL 1.2 marker and barrier commands - */ -#if defined(CL_VERSION_1_2) -#define __ENQUEUE_MARKER_WAIT_LIST_ERR __ERR_STR(clEnqueueMarkerWithWaitList) -#define __ENQUEUE_BARRIER_WAIT_LIST_ERR __ERR_STR(clEnqueueBarrierWithWaitList) -#endif // #if defined(CL_VERSION_1_2) - -#if !defined(__USE_DEV_STRING) && !defined(__NO_STD_STRING) -typedef std::string STRING_CLASS; -#elif !defined(__USE_DEV_STRING) - -/*! \class string - * \brief Simple string class, that provides a limited subset of std::string - * functionality but avoids many of the issues that come with that class. - - * \note Deprecated. Please use std::string as default or - * re-define the string class to match the std::string - * interface by defining STRING_CLASS - */ -class CL_EXT_PREFIX__VERSION_1_1_DEPRECATED string -{ -private: - ::size_t size_; - char * str_; -public: - //! \brief Constructs an empty string, allocating no memory. - string(void) : size_(0), str_(NULL) - { - } - - /*! \brief Constructs a string populated from an arbitrary value of - * specified size. - * - * An extra '\0' is added, in case none was contained in str. - * - * \param str the initial value of the string instance. Note that '\0' - * characters receive no special treatment. If NULL, - * the string is left empty, with a size of 0. - * - * \param size the number of characters to copy from str. - */ - string(const char * str, ::size_t size) : - size_(size), - str_(NULL) - { - if( size > 0 ) { - str_ = new char[size_+1]; - if (str_ != NULL) { - memcpy(str_, str, size_ * sizeof(char)); - str_[size_] = '\0'; - } - else { - size_ = 0; - } - } - } - - /*! \brief Constructs a string populated from a null-terminated value. - * - * \param str the null-terminated initial value of the string instance. - * If NULL, the string is left empty, with a size of 0. - */ - string(const char * str) : - size_(0), - str_(NULL) - { - if( str ) { - size_= ::strlen(str); - } - if( size_ > 0 ) { - str_ = new char[size_ + 1]; - if (str_ != NULL) { - memcpy(str_, str, (size_ + 1) * sizeof(char)); - } - } - } - - void resize( ::size_t n ) - { - if( size_ == n ) { - return; - } - if (n == 0) { - if( str_ ) { - delete [] str_; - } - str_ = NULL; - size_ = 0; - } - else { - char *newString = new char[n + 1]; - ::size_t copySize = n; - if( size_ < n ) { - copySize = size_; - } - size_ = n; - - if(str_) { - memcpy(newString, str_, (copySize + 1) * sizeof(char)); - } - if( copySize < size_ ) { - memset(newString + copySize, 0, size_ - copySize); - } - newString[size_] = '\0'; - - delete [] str_; - str_ = newString; - } - } - - const char& operator[] ( ::size_t pos ) const - { - return str_[pos]; - } - - char& operator[] ( ::size_t pos ) - { - return str_[pos]; - } - - /*! \brief Copies the value of another string to this one. - * - * \param rhs the string to copy. - * - * \returns a reference to the modified instance. - */ - string& operator=(const string& rhs) - { - if (this == &rhs) { - return *this; - } - - if( str_ != NULL ) { - delete [] str_; - str_ = NULL; - size_ = 0; - } - - if (rhs.size_ == 0 || rhs.str_ == NULL) { - str_ = NULL; - size_ = 0; - } - else { - str_ = new char[rhs.size_ + 1]; - size_ = rhs.size_; - - if (str_ != NULL) { - memcpy(str_, rhs.str_, (size_ + 1) * sizeof(char)); - } - else { - size_ = 0; - } - } - - return *this; - } - - /*! \brief Constructs a string by copying the value of another instance. - * - * \param rhs the string to copy. - */ - string(const string& rhs) : - size_(0), - str_(NULL) - { - *this = rhs; - } - - //! \brief Destructor - frees memory used to hold the current value. - ~string() - { - delete[] str_; - str_ = NULL; - } - - //! \brief Queries the length of the string, excluding any added '\0's. - ::size_t size(void) const { return size_; } - - //! \brief Queries the length of the string, excluding any added '\0's. - ::size_t length(void) const { return size(); } - - /*! \brief Returns a pointer to the private copy held by this instance, - * or "" if empty/unset. - */ - const char * c_str(void) const { return (str_) ? str_ : "";} -} CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; -typedef cl::string STRING_CLASS; -#endif // #elif !defined(__USE_DEV_STRING) - -#if !defined(__USE_DEV_VECTOR) && !defined(__NO_STD_VECTOR) -#define VECTOR_CLASS std::vector -#elif !defined(__USE_DEV_VECTOR) -#define VECTOR_CLASS cl::vector - -#if !defined(__MAX_DEFAULT_VECTOR_SIZE) -#define __MAX_DEFAULT_VECTOR_SIZE 10 -#endif - -/*! \class vector - * \brief Fixed sized vector implementation that mirroring - * - * \note Deprecated. Please use std::vector as default or - * re-define the vector class to match the std::vector - * interface by defining VECTOR_CLASS - - * \note Not recommended for use with custom objects as - * current implementation will construct N elements - * - * std::vector functionality. - * \brief Fixed sized vector compatible with std::vector. - * - * \note - * This differs from std::vector<> not just in memory allocation, - * but also in terms of when members are constructed, destroyed, - * and assigned instead of being copy constructed. - * - * \param T type of element contained in the vector. - * - * \param N maximum size of the vector. - */ -template -class CL_EXT_PREFIX__VERSION_1_1_DEPRECATED vector -{ -private: - T data_[N]; - unsigned int size_; - -public: - //! \brief Constructs an empty vector with no memory allocated. - vector() : - size_(static_cast(0)) - {} - - //! \brief Deallocates the vector's memory and destroys all of its elements. - ~vector() - { - clear(); - } - - //! \brief Returns the number of elements currently contained. - unsigned int size(void) const - { - return size_; - } - - /*! \brief Empties the vector of all elements. - * \note - * This does not deallocate memory but will invoke destructors - * on contained elements. - */ - void clear() - { - while(!empty()) { - pop_back(); - } - } - - /*! \brief Appends an element after the last valid element. - * Calling this on a vector that has reached capacity will throw an - * exception if exceptions are enabled. - */ - void push_back (const T& x) - { - if (size() < N) { - new (&data_[size_]) T(x); - size_++; - } else { - detail::errHandler(CL_MEM_OBJECT_ALLOCATION_FAILURE, __VECTOR_CAPACITY_ERR); - } - } - - /*! \brief Removes the last valid element from the vector. - * Calling this on an empty vector will throw an exception - * if exceptions are enabled. - */ - void pop_back(void) - { - if (size_ != 0) { - --size_; - data_[size_].~T(); - } else { - detail::errHandler(CL_MEM_OBJECT_ALLOCATION_FAILURE, __VECTOR_CAPACITY_ERR); - } - } - - /*! \brief Constructs with a value copied from another. - * - * \param vec the vector to copy. - */ - vector(const vector& vec) : - size_(vec.size_) - { - if (size_ != 0) { - assign(vec.begin(), vec.end()); - } - } - - /*! \brief Constructs with a specified number of initial elements. - * - * \param size number of initial elements. - * - * \param val value of initial elements. - */ - vector(unsigned int size, const T& val = T()) : - size_(0) - { - for (unsigned int i = 0; i < size; i++) { - push_back(val); - } - } - - /*! \brief Overwrites the current content with that copied from another - * instance. - * - * \param rhs vector to copy. - * - * \returns a reference to this. - */ - vector& operator=(const vector& rhs) - { - if (this == &rhs) { - return *this; - } - - if (rhs.size_ != 0) { - assign(rhs.begin(), rhs.end()); - } else { - clear(); - } - - return *this; - } - - /*! \brief Tests equality against another instance. - * - * \param vec the vector against which to compare. - */ - bool operator==(vector &vec) - { - if (size() != vec.size()) { - return false; - } - - for( unsigned int i = 0; i < size(); ++i ) { - if( operator[](i) != vec[i] ) { - return false; - } - } - return true; - } - - //! \brief Conversion operator to T*. - operator T* () { return data_; } - - //! \brief Conversion operator to const T*. - operator const T* () const { return data_; } - - //! \brief Tests whether this instance has any elements. - bool empty (void) const - { - return size_==0; - } - - //! \brief Returns the maximum number of elements this instance can hold. - unsigned int max_size (void) const - { - return N; - } - - //! \brief Returns the maximum number of elements this instance can hold. - unsigned int capacity () const - { - return N; - } - - //! \brief Resizes the vector to the given size - void resize(unsigned int newSize, T fill = T()) - { - if (newSize > N) - { - detail::errHandler(CL_MEM_OBJECT_ALLOCATION_FAILURE, __VECTOR_CAPACITY_ERR); - } - else - { - while (size_ < newSize) - { - new (&data_[size_]) T(fill); - size_++; - } - while (size_ > newSize) - { - --size_; - data_[size_].~T(); - } - } - } - - /*! \brief Returns a reference to a given element. - * - * \param index which element to access. * - * \note - * The caller is responsible for ensuring index is >= 0 and < size(). - */ - T& operator[](int index) - { - return data_[index]; - } - - /*! \brief Returns a const reference to a given element. - * - * \param index which element to access. - * - * \note - * The caller is responsible for ensuring index is >= 0 and < size(). - */ - const T& operator[](int index) const - { - return data_[index]; - } - - /*! \brief Assigns elements of the vector based on a source iterator range. - * - * \param start Beginning iterator of source range - * \param end Enditerator of source range - * - * \note - * Will throw an exception if exceptions are enabled and size exceeded. - */ - template - void assign(I start, I end) - { - clear(); - while(start != end) { - push_back(*start); - start++; - } - } - - /*! \class iterator - * \brief Const iterator class for vectors - */ - class iterator - { - private: - const vector *vec_; - int index_; - - /** - * Internal iterator constructor to capture reference - * to the vector it iterates over rather than taking - * the vector by copy. - */ - iterator (const vector &vec, int index) : - vec_(&vec) - { - if( !vec.empty() ) { - index_ = index; - } else { - index_ = -1; - } - } - - public: - iterator(void) : - index_(-1), - vec_(NULL) - { - } - - iterator(const iterator& rhs) : - vec_(rhs.vec_), - index_(rhs.index_) - { - } - - ~iterator(void) {} - - static iterator begin(const cl::vector &vec) - { - iterator i(vec, 0); - - return i; - } - - static iterator end(const cl::vector &vec) - { - iterator i(vec, vec.size()); - - return i; - } - - bool operator==(iterator i) - { - return ((vec_ == i.vec_) && - (index_ == i.index_)); - } - - bool operator!=(iterator i) - { - return (!(*this==i)); - } - - iterator& operator++() - { - ++index_; - return *this; - } - - iterator operator++(int) - { - iterator retVal(*this); - ++index_; - return retVal; - } - - iterator& operator--() - { - --index_; - return *this; - } - - iterator operator--(int) - { - iterator retVal(*this); - --index_; - return retVal; - } - - const T& operator *() const - { - return (*vec_)[index_]; - } - }; - - iterator begin(void) - { - return iterator::begin(*this); - } - - iterator begin(void) const - { - return iterator::begin(*this); - } - - iterator end(void) - { - return iterator::end(*this); - } - - iterator end(void) const - { - return iterator::end(*this); - } - - T& front(void) - { - return data_[0]; - } - - T& back(void) - { - return data_[size_]; - } - - const T& front(void) const - { - return data_[0]; - } - - const T& back(void) const - { - return data_[size_-1]; - } -} CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; -#endif // #if !defined(__USE_DEV_VECTOR) && !defined(__NO_STD_VECTOR) - - - - - -namespace detail { -#define __DEFAULT_NOT_INITIALIZED 1 -#define __DEFAULT_BEING_INITIALIZED 2 -#define __DEFAULT_INITIALIZED 4 - - /* - * Compare and exchange primitives are needed for handling of defaults - */ - -#ifdef CL_HPP_CPP11_ATOMICS_SUPPORTED - inline int compare_exchange(std::atomic * dest, int exchange, int comparand) -#else // !CL_HPP_CPP11_ATOMICS_SUPPORTED - inline int compare_exchange(volatile int * dest, int exchange, int comparand) -#endif // !CL_HPP_CPP11_ATOMICS_SUPPORTED - { -#ifdef CL_HPP_CPP11_ATOMICS_SUPPORTED - std::atomic_compare_exchange_strong(dest, &comparand, exchange); - return comparand; -#elif _MSC_VER - return (int)(_InterlockedCompareExchange( - (volatile long*)dest, - (long)exchange, - (long)comparand)); -#else // !_MSC_VER && !CL_HPP_CPP11_ATOMICS_SUPPORTED - return (__sync_val_compare_and_swap( - dest, - comparand, - exchange)); -#endif // !CL_HPP_CPP11_ATOMICS_SUPPORTED - } - - inline void fence() { -#ifdef CL_HPP_CPP11_ATOMICS_SUPPORTED - std::atomic_thread_fence(std::memory_order_seq_cst); -#elif _MSC_VER // !CL_HPP_CPP11_ATOMICS_SUPPORTED - _ReadWriteBarrier(); -#else // !_MSC_VER && !CL_HPP_CPP11_ATOMICS_SUPPORTED - __sync_synchronize(); -#endif // !CL_HPP_CPP11_ATOMICS_SUPPORTED - } -} // namespace detail - - -/*! \brief class used to interface between C++ and - * OpenCL C calls that require arrays of size_t values, whose - * size is known statically. - */ -template -class size_t -{ -private: - ::size_t data_[N]; - -public: - //! \brief Initialize size_t to all 0s - size_t() - { - for( int i = 0; i < N; ++i ) { - data_[i] = 0; - } - } - - ::size_t& operator[](int index) - { - return data_[index]; - } - - const ::size_t& operator[](int index) const - { - return data_[index]; - } - - //! \brief Conversion operator to T*. - operator ::size_t* () { return data_; } - - //! \brief Conversion operator to const T*. - operator const ::size_t* () const { return data_; } -}; - -namespace detail { - -// Generic getInfoHelper. The final parameter is used to guide overload -// resolution: the actual parameter passed is an int, which makes this -// a worse conversion sequence than a specialization that declares the -// parameter as an int. -template -inline cl_int getInfoHelper(Functor f, cl_uint name, T* param, long) -{ - return f(name, sizeof(T), param, NULL); -} - -// Specialized getInfoHelper for VECTOR_CLASS params -template -inline cl_int getInfoHelper(Func f, cl_uint name, VECTOR_CLASS* param, long) -{ - ::size_t required; - cl_int err = f(name, 0, NULL, &required); - if (err != CL_SUCCESS) { - return err; - } - - T* value = (T*) alloca(required); - err = f(name, required, value, NULL); - if (err != CL_SUCCESS) { - return err; - } - - param->assign(&value[0], &value[required/sizeof(T)]); - return CL_SUCCESS; -} - -/* Specialization for reference-counted types. This depends on the - * existence of Wrapper::cl_type, and none of the other types having the - * cl_type member. Note that simplify specifying the parameter as Wrapper - * does not work, because when using a derived type (e.g. Context) the generic - * template will provide a better match. - */ -template -inline cl_int getInfoHelper(Func f, cl_uint name, VECTOR_CLASS* param, int, typename T::cl_type = 0) -{ - ::size_t required; - cl_int err = f(name, 0, NULL, &required); - if (err != CL_SUCCESS) { - return err; - } - - typename T::cl_type * value = (typename T::cl_type *) alloca(required); - err = f(name, required, value, NULL); - if (err != CL_SUCCESS) { - return err; - } - - ::size_t elements = required / sizeof(typename T::cl_type); - param->assign(&value[0], &value[elements]); - for (::size_t i = 0; i < elements; i++) - { - if (value[i] != NULL) - { - err = (*param)[i].retain(); - if (err != CL_SUCCESS) { - return err; - } - } - } - return CL_SUCCESS; -} - -// Specialized for getInfo -template -inline cl_int getInfoHelper(Func f, cl_uint name, VECTOR_CLASS* param, int) -{ - cl_int err = f(name, param->size() * sizeof(char *), &(*param)[0], NULL); - - if (err != CL_SUCCESS) { - return err; - } - - return CL_SUCCESS; -} - -// Specialized GetInfoHelper for STRING_CLASS params -template -inline cl_int getInfoHelper(Func f, cl_uint name, STRING_CLASS* param, long) -{ -#if defined(__NO_STD_VECTOR) || defined(__NO_STD_STRING) - ::size_t required; - cl_int err = f(name, 0, NULL, &required); - if (err != CL_SUCCESS) { - return err; - } - - char* value = (char*)alloca(required); - err = f(name, required, value, NULL); - if (err != CL_SUCCESS) { - return err; - } - - *param = value; - return CL_SUCCESS; -#else - ::size_t required; - cl_int err = f(name, 0, NULL, &required); - if (err != CL_SUCCESS) { - return err; - } - - // std::string has a constant data member - // a char vector does not - VECTOR_CLASS value(required); - err = f(name, required, value.data(), NULL); - if (err != CL_SUCCESS) { - return err; - } - if (param) { - param->assign(value.begin(), value.end()); - } -#endif - return CL_SUCCESS; -} - -// Specialized GetInfoHelper for cl::size_t params -template -inline cl_int getInfoHelper(Func f, cl_uint name, size_t* param, long) -{ - ::size_t required; - cl_int err = f(name, 0, NULL, &required); - if (err != CL_SUCCESS) { - return err; - } - - ::size_t* value = (::size_t*) alloca(required); - err = f(name, required, value, NULL); - if (err != CL_SUCCESS) { - return err; - } - - for(int i = 0; i < N; ++i) { - (*param)[i] = value[i]; - } - - return CL_SUCCESS; -} - -template struct ReferenceHandler; - -/* Specialization for reference-counted types. This depends on the - * existence of Wrapper::cl_type, and none of the other types having the - * cl_type member. Note that simplify specifying the parameter as Wrapper - * does not work, because when using a derived type (e.g. Context) the generic - * template will provide a better match. - */ -template -inline cl_int getInfoHelper(Func f, cl_uint name, T* param, int, typename T::cl_type = 0) -{ - typename T::cl_type value; - cl_int err = f(name, sizeof(value), &value, NULL); - if (err != CL_SUCCESS) { - return err; - } - *param = value; - if (value != NULL) - { - err = param->retain(); - if (err != CL_SUCCESS) { - return err; - } - } - return CL_SUCCESS; -} - -#define __PARAM_NAME_INFO_1_0(F) \ - F(cl_platform_info, CL_PLATFORM_PROFILE, STRING_CLASS) \ - F(cl_platform_info, CL_PLATFORM_VERSION, STRING_CLASS) \ - F(cl_platform_info, CL_PLATFORM_NAME, STRING_CLASS) \ - F(cl_platform_info, CL_PLATFORM_VENDOR, STRING_CLASS) \ - F(cl_platform_info, CL_PLATFORM_EXTENSIONS, STRING_CLASS) \ - \ - F(cl_device_info, CL_DEVICE_TYPE, cl_device_type) \ - F(cl_device_info, CL_DEVICE_VENDOR_ID, cl_uint) \ - F(cl_device_info, CL_DEVICE_MAX_COMPUTE_UNITS, cl_uint) \ - F(cl_device_info, CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS, cl_uint) \ - F(cl_device_info, CL_DEVICE_MAX_WORK_GROUP_SIZE, ::size_t) \ - F(cl_device_info, CL_DEVICE_MAX_WORK_ITEM_SIZES, VECTOR_CLASS< ::size_t>) \ - F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR, cl_uint) \ - F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT, cl_uint) \ - F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT, cl_uint) \ - F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG, cl_uint) \ - F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT, cl_uint) \ - F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE, cl_uint) \ - F(cl_device_info, CL_DEVICE_MAX_CLOCK_FREQUENCY, cl_uint) \ - F(cl_device_info, CL_DEVICE_ADDRESS_BITS, cl_uint) \ - F(cl_device_info, CL_DEVICE_MAX_READ_IMAGE_ARGS, cl_uint) \ - F(cl_device_info, CL_DEVICE_MAX_WRITE_IMAGE_ARGS, cl_uint) \ - F(cl_device_info, CL_DEVICE_MAX_MEM_ALLOC_SIZE, cl_ulong) \ - F(cl_device_info, CL_DEVICE_IMAGE2D_MAX_WIDTH, ::size_t) \ - F(cl_device_info, CL_DEVICE_IMAGE2D_MAX_HEIGHT, ::size_t) \ - F(cl_device_info, CL_DEVICE_IMAGE3D_MAX_WIDTH, ::size_t) \ - F(cl_device_info, CL_DEVICE_IMAGE3D_MAX_HEIGHT, ::size_t) \ - F(cl_device_info, CL_DEVICE_IMAGE3D_MAX_DEPTH, ::size_t) \ - F(cl_device_info, CL_DEVICE_IMAGE_SUPPORT, cl_bool) \ - F(cl_device_info, CL_DEVICE_MAX_PARAMETER_SIZE, ::size_t) \ - F(cl_device_info, CL_DEVICE_MAX_SAMPLERS, cl_uint) \ - F(cl_device_info, CL_DEVICE_MEM_BASE_ADDR_ALIGN, cl_uint) \ - F(cl_device_info, CL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE, cl_uint) \ - F(cl_device_info, CL_DEVICE_SINGLE_FP_CONFIG, cl_device_fp_config) \ - F(cl_device_info, CL_DEVICE_GLOBAL_MEM_CACHE_TYPE, cl_device_mem_cache_type) \ - F(cl_device_info, CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE, cl_uint)\ - F(cl_device_info, CL_DEVICE_GLOBAL_MEM_CACHE_SIZE, cl_ulong) \ - F(cl_device_info, CL_DEVICE_GLOBAL_MEM_SIZE, cl_ulong) \ - F(cl_device_info, CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE, cl_ulong) \ - F(cl_device_info, CL_DEVICE_MAX_CONSTANT_ARGS, cl_uint) \ - F(cl_device_info, CL_DEVICE_LOCAL_MEM_TYPE, cl_device_local_mem_type) \ - F(cl_device_info, CL_DEVICE_LOCAL_MEM_SIZE, cl_ulong) \ - F(cl_device_info, CL_DEVICE_ERROR_CORRECTION_SUPPORT, cl_bool) \ - F(cl_device_info, CL_DEVICE_PROFILING_TIMER_RESOLUTION, ::size_t) \ - F(cl_device_info, CL_DEVICE_ENDIAN_LITTLE, cl_bool) \ - F(cl_device_info, CL_DEVICE_AVAILABLE, cl_bool) \ - F(cl_device_info, CL_DEVICE_COMPILER_AVAILABLE, cl_bool) \ - F(cl_device_info, CL_DEVICE_EXECUTION_CAPABILITIES, cl_device_exec_capabilities) \ - F(cl_device_info, CL_DEVICE_QUEUE_PROPERTIES, cl_command_queue_properties) \ - F(cl_device_info, CL_DEVICE_PLATFORM, cl_platform_id) \ - F(cl_device_info, CL_DEVICE_NAME, STRING_CLASS) \ - F(cl_device_info, CL_DEVICE_VENDOR, STRING_CLASS) \ - F(cl_device_info, CL_DRIVER_VERSION, STRING_CLASS) \ - F(cl_device_info, CL_DEVICE_PROFILE, STRING_CLASS) \ - F(cl_device_info, CL_DEVICE_VERSION, STRING_CLASS) \ - F(cl_device_info, CL_DEVICE_EXTENSIONS, STRING_CLASS) \ - \ - F(cl_context_info, CL_CONTEXT_REFERENCE_COUNT, cl_uint) \ - F(cl_context_info, CL_CONTEXT_DEVICES, VECTOR_CLASS) \ - F(cl_context_info, CL_CONTEXT_PROPERTIES, VECTOR_CLASS) \ - \ - F(cl_event_info, CL_EVENT_COMMAND_QUEUE, cl::CommandQueue) \ - F(cl_event_info, CL_EVENT_COMMAND_TYPE, cl_command_type) \ - F(cl_event_info, CL_EVENT_REFERENCE_COUNT, cl_uint) \ - F(cl_event_info, CL_EVENT_COMMAND_EXECUTION_STATUS, cl_int) \ - \ - F(cl_profiling_info, CL_PROFILING_COMMAND_QUEUED, cl_ulong) \ - F(cl_profiling_info, CL_PROFILING_COMMAND_SUBMIT, cl_ulong) \ - F(cl_profiling_info, CL_PROFILING_COMMAND_START, cl_ulong) \ - F(cl_profiling_info, CL_PROFILING_COMMAND_END, cl_ulong) \ - \ - F(cl_mem_info, CL_MEM_TYPE, cl_mem_object_type) \ - F(cl_mem_info, CL_MEM_FLAGS, cl_mem_flags) \ - F(cl_mem_info, CL_MEM_SIZE, ::size_t) \ - F(cl_mem_info, CL_MEM_HOST_PTR, void*) \ - F(cl_mem_info, CL_MEM_MAP_COUNT, cl_uint) \ - F(cl_mem_info, CL_MEM_REFERENCE_COUNT, cl_uint) \ - F(cl_mem_info, CL_MEM_CONTEXT, cl::Context) \ - \ - F(cl_image_info, CL_IMAGE_FORMAT, cl_image_format) \ - F(cl_image_info, CL_IMAGE_ELEMENT_SIZE, ::size_t) \ - F(cl_image_info, CL_IMAGE_ROW_PITCH, ::size_t) \ - F(cl_image_info, CL_IMAGE_SLICE_PITCH, ::size_t) \ - F(cl_image_info, CL_IMAGE_WIDTH, ::size_t) \ - F(cl_image_info, CL_IMAGE_HEIGHT, ::size_t) \ - F(cl_image_info, CL_IMAGE_DEPTH, ::size_t) \ - \ - F(cl_sampler_info, CL_SAMPLER_REFERENCE_COUNT, cl_uint) \ - F(cl_sampler_info, CL_SAMPLER_CONTEXT, cl::Context) \ - F(cl_sampler_info, CL_SAMPLER_NORMALIZED_COORDS, cl_bool) \ - F(cl_sampler_info, CL_SAMPLER_ADDRESSING_MODE, cl_addressing_mode) \ - F(cl_sampler_info, CL_SAMPLER_FILTER_MODE, cl_filter_mode) \ - \ - F(cl_program_info, CL_PROGRAM_REFERENCE_COUNT, cl_uint) \ - F(cl_program_info, CL_PROGRAM_CONTEXT, cl::Context) \ - F(cl_program_info, CL_PROGRAM_NUM_DEVICES, cl_uint) \ - F(cl_program_info, CL_PROGRAM_DEVICES, VECTOR_CLASS) \ - F(cl_program_info, CL_PROGRAM_SOURCE, STRING_CLASS) \ - F(cl_program_info, CL_PROGRAM_BINARY_SIZES, VECTOR_CLASS< ::size_t>) \ - F(cl_program_info, CL_PROGRAM_BINARIES, VECTOR_CLASS) \ - \ - F(cl_program_build_info, CL_PROGRAM_BUILD_STATUS, cl_build_status) \ - F(cl_program_build_info, CL_PROGRAM_BUILD_OPTIONS, STRING_CLASS) \ - F(cl_program_build_info, CL_PROGRAM_BUILD_LOG, STRING_CLASS) \ - \ - F(cl_kernel_info, CL_KERNEL_FUNCTION_NAME, STRING_CLASS) \ - F(cl_kernel_info, CL_KERNEL_NUM_ARGS, cl_uint) \ - F(cl_kernel_info, CL_KERNEL_REFERENCE_COUNT, cl_uint) \ - F(cl_kernel_info, CL_KERNEL_CONTEXT, cl::Context) \ - F(cl_kernel_info, CL_KERNEL_PROGRAM, cl::Program) \ - \ - F(cl_kernel_work_group_info, CL_KERNEL_WORK_GROUP_SIZE, ::size_t) \ - F(cl_kernel_work_group_info, CL_KERNEL_COMPILE_WORK_GROUP_SIZE, cl::size_t<3>) \ - F(cl_kernel_work_group_info, CL_KERNEL_LOCAL_MEM_SIZE, cl_ulong) \ - \ - F(cl_command_queue_info, CL_QUEUE_CONTEXT, cl::Context) \ - F(cl_command_queue_info, CL_QUEUE_DEVICE, cl::Device) \ - F(cl_command_queue_info, CL_QUEUE_REFERENCE_COUNT, cl_uint) \ - F(cl_command_queue_info, CL_QUEUE_PROPERTIES, cl_command_queue_properties) - -#if defined(CL_VERSION_1_1) -#define __PARAM_NAME_INFO_1_1(F) \ - F(cl_context_info, CL_CONTEXT_NUM_DEVICES, cl_uint)\ - F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_HALF, cl_uint) \ - F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_CHAR, cl_uint) \ - F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_SHORT, cl_uint) \ - F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_INT, cl_uint) \ - F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_LONG, cl_uint) \ - F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_FLOAT, cl_uint) \ - F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_DOUBLE, cl_uint) \ - F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_HALF, cl_uint) \ - F(cl_device_info, CL_DEVICE_DOUBLE_FP_CONFIG, cl_device_fp_config) \ - F(cl_device_info, CL_DEVICE_HALF_FP_CONFIG, cl_device_fp_config) \ - F(cl_device_info, CL_DEVICE_HOST_UNIFIED_MEMORY, cl_bool) \ - F(cl_device_info, CL_DEVICE_OPENCL_C_VERSION, STRING_CLASS) \ - \ - F(cl_mem_info, CL_MEM_ASSOCIATED_MEMOBJECT, cl::Memory) \ - F(cl_mem_info, CL_MEM_OFFSET, ::size_t) \ - \ - F(cl_kernel_work_group_info, CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE, ::size_t) \ - F(cl_kernel_work_group_info, CL_KERNEL_PRIVATE_MEM_SIZE, cl_ulong) \ - \ - F(cl_event_info, CL_EVENT_CONTEXT, cl::Context) -#endif // CL_VERSION_1_1 - - -#if defined(CL_VERSION_1_2) -#define __PARAM_NAME_INFO_1_2(F) \ - F(cl_image_info, CL_IMAGE_BUFFER, cl::Buffer) \ - \ - F(cl_program_info, CL_PROGRAM_NUM_KERNELS, ::size_t) \ - F(cl_program_info, CL_PROGRAM_KERNEL_NAMES, STRING_CLASS) \ - \ - F(cl_program_build_info, CL_PROGRAM_BINARY_TYPE, cl_program_binary_type) \ - \ - F(cl_kernel_info, CL_KERNEL_ATTRIBUTES, STRING_CLASS) \ - \ - F(cl_kernel_arg_info, CL_KERNEL_ARG_ADDRESS_QUALIFIER, cl_kernel_arg_address_qualifier) \ - F(cl_kernel_arg_info, CL_KERNEL_ARG_ACCESS_QUALIFIER, cl_kernel_arg_access_qualifier) \ - F(cl_kernel_arg_info, CL_KERNEL_ARG_TYPE_NAME, STRING_CLASS) \ - F(cl_kernel_arg_info, CL_KERNEL_ARG_NAME, STRING_CLASS) \ - F(cl_kernel_arg_info, CL_KERNEL_ARG_TYPE_QUALIFIER, cl_kernel_arg_type_qualifier) \ - \ - F(cl_device_info, CL_DEVICE_PARENT_DEVICE, cl_device_id) \ - F(cl_device_info, CL_DEVICE_PARTITION_PROPERTIES, VECTOR_CLASS) \ - F(cl_device_info, CL_DEVICE_PARTITION_TYPE, VECTOR_CLASS) \ - F(cl_device_info, CL_DEVICE_REFERENCE_COUNT, cl_uint) \ - F(cl_device_info, CL_DEVICE_PREFERRED_INTEROP_USER_SYNC, ::size_t) \ - F(cl_device_info, CL_DEVICE_PARTITION_AFFINITY_DOMAIN, cl_device_affinity_domain) \ - F(cl_device_info, CL_DEVICE_BUILT_IN_KERNELS, STRING_CLASS) -#endif // #if defined(CL_VERSION_1_2) - -#if defined(USE_CL_DEVICE_FISSION) -#define __PARAM_NAME_DEVICE_FISSION(F) \ - F(cl_device_info, CL_DEVICE_PARENT_DEVICE_EXT, cl_device_id) \ - F(cl_device_info, CL_DEVICE_PARTITION_TYPES_EXT, VECTOR_CLASS) \ - F(cl_device_info, CL_DEVICE_AFFINITY_DOMAINS_EXT, VECTOR_CLASS) \ - F(cl_device_info, CL_DEVICE_REFERENCE_COUNT_EXT , cl_uint) \ - F(cl_device_info, CL_DEVICE_PARTITION_STYLE_EXT, VECTOR_CLASS) -#endif // USE_CL_DEVICE_FISSION - -template -struct param_traits {}; - -#define __CL_DECLARE_PARAM_TRAITS(token, param_name, T) \ -struct token; \ -template<> \ -struct param_traits \ -{ \ - enum { value = param_name }; \ - typedef T param_type; \ -}; - -__PARAM_NAME_INFO_1_0(__CL_DECLARE_PARAM_TRAITS) -#if defined(CL_VERSION_1_1) -__PARAM_NAME_INFO_1_1(__CL_DECLARE_PARAM_TRAITS) -#endif // CL_VERSION_1_1 -#if defined(CL_VERSION_1_2) -__PARAM_NAME_INFO_1_2(__CL_DECLARE_PARAM_TRAITS) -#endif // CL_VERSION_1_1 - -#if defined(USE_CL_DEVICE_FISSION) -__PARAM_NAME_DEVICE_FISSION(__CL_DECLARE_PARAM_TRAITS); -#endif // USE_CL_DEVICE_FISSION - -#ifdef CL_PLATFORM_ICD_SUFFIX_KHR -__CL_DECLARE_PARAM_TRAITS(cl_platform_info, CL_PLATFORM_ICD_SUFFIX_KHR, STRING_CLASS) -#endif - -#ifdef CL_DEVICE_PROFILING_TIMER_OFFSET_AMD -__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_PROFILING_TIMER_OFFSET_AMD, cl_ulong) -#endif - -#ifdef CL_DEVICE_GLOBAL_FREE_MEMORY_AMD -__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_GLOBAL_FREE_MEMORY_AMD, VECTOR_CLASS< ::size_t>) -#endif -#ifdef CL_DEVICE_SIMD_PER_COMPUTE_UNIT_AMD -__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_SIMD_PER_COMPUTE_UNIT_AMD, cl_uint) -#endif -#ifdef CL_DEVICE_SIMD_WIDTH_AMD -__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_SIMD_WIDTH_AMD, cl_uint) -#endif -#ifdef CL_DEVICE_SIMD_INSTRUCTION_WIDTH_AMD -__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_SIMD_INSTRUCTION_WIDTH_AMD, cl_uint) -#endif -#ifdef CL_DEVICE_WAVEFRONT_WIDTH_AMD -__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_WAVEFRONT_WIDTH_AMD, cl_uint) -#endif -#ifdef CL_DEVICE_GLOBAL_MEM_CHANNELS_AMD -__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_GLOBAL_MEM_CHANNELS_AMD, cl_uint) -#endif -#ifdef CL_DEVICE_GLOBAL_MEM_CHANNEL_BANKS_AMD -__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_GLOBAL_MEM_CHANNEL_BANKS_AMD, cl_uint) -#endif -#ifdef CL_DEVICE_GLOBAL_MEM_CHANNEL_BANK_WIDTH_AMD -__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_GLOBAL_MEM_CHANNEL_BANK_WIDTH_AMD, cl_uint) -#endif -#ifdef CL_DEVICE_LOCAL_MEM_SIZE_PER_COMPUTE_UNIT_AMD -__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_LOCAL_MEM_SIZE_PER_COMPUTE_UNIT_AMD, cl_uint) -#endif -#ifdef CL_DEVICE_LOCAL_MEM_BANKS_AMD -__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_LOCAL_MEM_BANKS_AMD, cl_uint) -#endif - -#ifdef CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV -__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV, cl_uint) -#endif -#ifdef CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV -__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV, cl_uint) -#endif -#ifdef CL_DEVICE_REGISTERS_PER_BLOCK_NV -__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_REGISTERS_PER_BLOCK_NV, cl_uint) -#endif -#ifdef CL_DEVICE_WARP_SIZE_NV -__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_WARP_SIZE_NV, cl_uint) -#endif -#ifdef CL_DEVICE_GPU_OVERLAP_NV -__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_GPU_OVERLAP_NV, cl_bool) -#endif -#ifdef CL_DEVICE_KERNEL_EXEC_TIMEOUT_NV -__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_KERNEL_EXEC_TIMEOUT_NV, cl_bool) -#endif -#ifdef CL_DEVICE_INTEGRATED_MEMORY_NV -__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_INTEGRATED_MEMORY_NV, cl_bool) -#endif - -// Convenience functions - -template -inline cl_int -getInfo(Func f, cl_uint name, T* param) -{ - return getInfoHelper(f, name, param, 0); -} - -template -struct GetInfoFunctor0 -{ - Func f_; const Arg0& arg0_; - cl_int operator ()( - cl_uint param, ::size_t size, void* value, ::size_t* size_ret) - { return f_(arg0_, param, size, value, size_ret); } -}; - -template -struct GetInfoFunctor1 -{ - Func f_; const Arg0& arg0_; const Arg1& arg1_; - cl_int operator ()( - cl_uint param, ::size_t size, void* value, ::size_t* size_ret) - { return f_(arg0_, arg1_, param, size, value, size_ret); } -}; - -template -inline cl_int -getInfo(Func f, const Arg0& arg0, cl_uint name, T* param) -{ - GetInfoFunctor0 f0 = { f, arg0 }; - return getInfoHelper(f0, name, param, 0); -} - -template -inline cl_int -getInfo(Func f, const Arg0& arg0, const Arg1& arg1, cl_uint name, T* param) -{ - GetInfoFunctor1 f0 = { f, arg0, arg1 }; - return getInfoHelper(f0, name, param, 0); -} - -template -struct ReferenceHandler -{ }; - -#if defined(CL_VERSION_1_2) -/** - * OpenCL 1.2 devices do have retain/release. - */ -template <> -struct ReferenceHandler -{ - /** - * Retain the device. - * \param device A valid device created using createSubDevices - * \return - * CL_SUCCESS if the function executed successfully. - * CL_INVALID_DEVICE if device was not a valid subdevice - * CL_OUT_OF_RESOURCES - * CL_OUT_OF_HOST_MEMORY - */ - static cl_int retain(cl_device_id device) - { return ::clRetainDevice(device); } - /** - * Retain the device. - * \param device A valid device created using createSubDevices - * \return - * CL_SUCCESS if the function executed successfully. - * CL_INVALID_DEVICE if device was not a valid subdevice - * CL_OUT_OF_RESOURCES - * CL_OUT_OF_HOST_MEMORY - */ - static cl_int release(cl_device_id device) - { return ::clReleaseDevice(device); } -}; -#else // #if defined(CL_VERSION_1_2) -/** - * OpenCL 1.1 devices do not have retain/release. - */ -template <> -struct ReferenceHandler -{ - // cl_device_id does not have retain(). - static cl_int retain(cl_device_id) - { return CL_SUCCESS; } - // cl_device_id does not have release(). - static cl_int release(cl_device_id) - { return CL_SUCCESS; } -}; -#endif // #if defined(CL_VERSION_1_2) - -template <> -struct ReferenceHandler -{ - // cl_platform_id does not have retain(). - static cl_int retain(cl_platform_id) - { return CL_SUCCESS; } - // cl_platform_id does not have release(). - static cl_int release(cl_platform_id) - { return CL_SUCCESS; } -}; - -template <> -struct ReferenceHandler -{ - static cl_int retain(cl_context context) - { return ::clRetainContext(context); } - static cl_int release(cl_context context) - { return ::clReleaseContext(context); } -}; - -template <> -struct ReferenceHandler -{ - static cl_int retain(cl_command_queue queue) - { return ::clRetainCommandQueue(queue); } - static cl_int release(cl_command_queue queue) - { return ::clReleaseCommandQueue(queue); } -}; - -template <> -struct ReferenceHandler -{ - static cl_int retain(cl_mem memory) - { return ::clRetainMemObject(memory); } - static cl_int release(cl_mem memory) - { return ::clReleaseMemObject(memory); } -}; - -template <> -struct ReferenceHandler -{ - static cl_int retain(cl_sampler sampler) - { return ::clRetainSampler(sampler); } - static cl_int release(cl_sampler sampler) - { return ::clReleaseSampler(sampler); } -}; - -template <> -struct ReferenceHandler -{ - static cl_int retain(cl_program program) - { return ::clRetainProgram(program); } - static cl_int release(cl_program program) - { return ::clReleaseProgram(program); } -}; - -template <> -struct ReferenceHandler -{ - static cl_int retain(cl_kernel kernel) - { return ::clRetainKernel(kernel); } - static cl_int release(cl_kernel kernel) - { return ::clReleaseKernel(kernel); } -}; - -template <> -struct ReferenceHandler -{ - static cl_int retain(cl_event event) - { return ::clRetainEvent(event); } - static cl_int release(cl_event event) - { return ::clReleaseEvent(event); } -}; - - -// Extracts version number with major in the upper 16 bits, minor in the lower 16 -static cl_uint getVersion(const char *versionInfo) -{ - int highVersion = 0; - int lowVersion = 0; - int index = 7; - while(versionInfo[index] != '.' ) { - highVersion *= 10; - highVersion += versionInfo[index]-'0'; - ++index; - } - ++index; - while(versionInfo[index] != ' ' && versionInfo[index] != '\0') { - lowVersion *= 10; - lowVersion += versionInfo[index]-'0'; - ++index; - } - return (highVersion << 16) | lowVersion; -} - -static cl_uint getPlatformVersion(cl_platform_id platform) -{ - ::size_t size = 0; - clGetPlatformInfo(platform, CL_PLATFORM_VERSION, 0, NULL, &size); - char *versionInfo = (char *) alloca(size); - clGetPlatformInfo(platform, CL_PLATFORM_VERSION, size, &versionInfo[0], &size); - return getVersion(versionInfo); -} - -static cl_uint getDevicePlatformVersion(cl_device_id device) -{ - cl_platform_id platform; - clGetDeviceInfo(device, CL_DEVICE_PLATFORM, sizeof(platform), &platform, NULL); - return getPlatformVersion(platform); -} - -#if defined(CL_VERSION_1_2) && defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) -static cl_uint getContextPlatformVersion(cl_context context) -{ - // The platform cannot be queried directly, so we first have to grab a - // device and obtain its context - ::size_t size = 0; - clGetContextInfo(context, CL_CONTEXT_DEVICES, 0, NULL, &size); - if (size == 0) - return 0; - cl_device_id *devices = (cl_device_id *) alloca(size); - clGetContextInfo(context, CL_CONTEXT_DEVICES, size, devices, NULL); - return getDevicePlatformVersion(devices[0]); -} -#endif // #if defined(CL_VERSION_1_2) && defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) - -template -class Wrapper -{ -public: - typedef T cl_type; - -protected: - cl_type object_; - -public: - Wrapper() : object_(NULL) { } - - Wrapper(const cl_type &obj) : object_(obj) { } - - ~Wrapper() - { - if (object_ != NULL) { release(); } - } - - Wrapper(const Wrapper& rhs) - { - object_ = rhs.object_; - if (object_ != NULL) { detail::errHandler(retain(), __RETAIN_ERR); } - } - -#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) - Wrapper(Wrapper&& rhs) CL_HPP_NOEXCEPT - { - object_ = rhs.object_; - rhs.object_ = NULL; - } -#endif - - Wrapper& operator = (const Wrapper& rhs) - { - if (this != &rhs) { - if (object_ != NULL) { detail::errHandler(release(), __RELEASE_ERR); } - object_ = rhs.object_; - if (object_ != NULL) { detail::errHandler(retain(), __RETAIN_ERR); } - } - return *this; - } - -#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) - Wrapper& operator = (Wrapper&& rhs) - { - if (this != &rhs) { - if (object_ != NULL) { detail::errHandler(release(), __RELEASE_ERR); } - object_ = rhs.object_; - rhs.object_ = NULL; - } - return *this; - } -#endif - - Wrapper& operator = (const cl_type &rhs) - { - if (object_ != NULL) { detail::errHandler(release(), __RELEASE_ERR); } - object_ = rhs; - return *this; - } - - cl_type operator ()() const { return object_; } - - cl_type& operator ()() { return object_; } - -protected: - template - friend inline cl_int getInfoHelper(Func, cl_uint, U*, int, typename U::cl_type); - - cl_int retain() const - { - return ReferenceHandler::retain(object_); - } - - cl_int release() const - { - return ReferenceHandler::release(object_); - } -}; - -template <> -class Wrapper -{ -public: - typedef cl_device_id cl_type; - -protected: - cl_type object_; - bool referenceCountable_; - - static bool isReferenceCountable(cl_device_id device) - { - bool retVal = false; - if (device != NULL) { - int version = getDevicePlatformVersion(device); - if(version > ((1 << 16) + 1)) { - retVal = true; - } - } - return retVal; - } - -public: - Wrapper() : object_(NULL), referenceCountable_(false) - { - } - - Wrapper(const cl_type &obj) : object_(obj), referenceCountable_(false) - { - referenceCountable_ = isReferenceCountable(obj); - } - - ~Wrapper() - { - if (object_ != NULL) { release(); } - } - - Wrapper(const Wrapper& rhs) - { - object_ = rhs.object_; - referenceCountable_ = isReferenceCountable(object_); - if (object_ != NULL) { detail::errHandler(retain(), __RETAIN_ERR); } - } - -#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) - Wrapper(Wrapper&& rhs) CL_HPP_NOEXCEPT - { - object_ = rhs.object_; - referenceCountable_ = rhs.referenceCountable_; - rhs.object_ = NULL; - rhs.referenceCountable_ = false; - } -#endif - - Wrapper& operator = (const Wrapper& rhs) - { - if (this != &rhs) { - if (object_ != NULL) { detail::errHandler(release(), __RELEASE_ERR); } - object_ = rhs.object_; - referenceCountable_ = rhs.referenceCountable_; - if (object_ != NULL) { detail::errHandler(retain(), __RETAIN_ERR); } - } - return *this; - } - -#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) - Wrapper& operator = (Wrapper&& rhs) - { - if (this != &rhs) { - if (object_ != NULL) { detail::errHandler(release(), __RELEASE_ERR); } - object_ = rhs.object_; - referenceCountable_ = rhs.referenceCountable_; - rhs.object_ = NULL; - rhs.referenceCountable_ = false; - } - return *this; - } -#endif - - Wrapper& operator = (const cl_type &rhs) - { - if (object_ != NULL) { detail::errHandler(release(), __RELEASE_ERR); } - object_ = rhs; - referenceCountable_ = isReferenceCountable(object_); - return *this; - } - - cl_type operator ()() const { return object_; } - - cl_type& operator ()() { return object_; } - -protected: - template - friend inline cl_int getInfoHelper(Func, cl_uint, U*, int, typename U::cl_type); - - template - friend inline cl_int getInfoHelper(Func, cl_uint, VECTOR_CLASS*, int, typename U::cl_type); - - cl_int retain() const - { - if( referenceCountable_ ) { - return ReferenceHandler::retain(object_); - } - else { - return CL_SUCCESS; - } - } - - cl_int release() const - { - if( referenceCountable_ ) { - return ReferenceHandler::release(object_); - } - else { - return CL_SUCCESS; - } - } -}; - -} // namespace detail -//! \endcond - -/*! \stuct ImageFormat - * \brief Adds constructors and member functions for cl_image_format. - * - * \see cl_image_format - */ -struct ImageFormat : public cl_image_format -{ - //! \brief Default constructor - performs no initialization. - ImageFormat(){} - - //! \brief Initializing constructor. - ImageFormat(cl_channel_order order, cl_channel_type type) - { - image_channel_order = order; - image_channel_data_type = type; - } - - //! \brief Assignment operator. - ImageFormat& operator = (const ImageFormat& rhs) - { - if (this != &rhs) { - this->image_channel_data_type = rhs.image_channel_data_type; - this->image_channel_order = rhs.image_channel_order; - } - return *this; - } -}; - -/*! \brief Class interface for cl_device_id. - * - * \note Copies of these objects are inexpensive, since they don't 'own' - * any underlying resources or data structures. - * - * \see cl_device_id - */ -class Device : public detail::Wrapper -{ -public: - //! \brief Default constructor - initializes to NULL. - Device() : detail::Wrapper() { } - - /*! \brief Constructor from cl_device_id. - * - * This simply copies the device ID value, which is an inexpensive operation. - */ - __CL_EXPLICIT_CONSTRUCTORS Device(const cl_device_id &device) : detail::Wrapper(device) { } - - /*! \brief Returns the first device on the default context. - * - * \see Context::getDefault() - */ - static Device getDefault(cl_int * err = NULL); - - /*! \brief Assignment operator from cl_device_id. - * - * This simply copies the device ID value, which is an inexpensive operation. - */ - Device& operator = (const cl_device_id& rhs) - { - detail::Wrapper::operator=(rhs); - return *this; - } - - /*! \brief Copy constructor to forward copy to the superclass correctly. - * Required for MSVC. - */ - Device(const Device& dev) : detail::Wrapper(dev) {} - - /*! \brief Copy assignment to forward copy to the superclass correctly. - * Required for MSVC. - */ - Device& operator = (const Device &dev) - { - detail::Wrapper::operator=(dev); - return *this; - } - -#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) - /*! \brief Move constructor to forward move to the superclass correctly. - * Required for MSVC. - */ - Device(Device&& dev) CL_HPP_NOEXCEPT : detail::Wrapper(std::move(dev)) {} - - /*! \brief Move assignment to forward move to the superclass correctly. - * Required for MSVC. - */ - Device& operator = (Device &&dev) - { - detail::Wrapper::operator=(std::move(dev)); - return *this; - } -#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) - - //! \brief Wrapper for clGetDeviceInfo(). - template - cl_int getInfo(cl_device_info name, T* param) const - { - return detail::errHandler( - detail::getInfo(&::clGetDeviceInfo, object_, name, param), - __GET_DEVICE_INFO_ERR); - } - - //! \brief Wrapper for clGetDeviceInfo() that returns by value. - template typename - detail::param_traits::param_type - getInfo(cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_device_info, name>::param_type param; - cl_int result = getInfo(name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } - - /** - * CL 1.2 version - */ -#if defined(CL_VERSION_1_2) - //! \brief Wrapper for clCreateSubDevicesEXT(). - cl_int createSubDevices( - const cl_device_partition_property * properties, - VECTOR_CLASS* devices) - { - cl_uint n = 0; - cl_int err = clCreateSubDevices(object_, properties, 0, NULL, &n); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __CREATE_SUB_DEVICES); - } - - cl_device_id* ids = (cl_device_id*) alloca(n * sizeof(cl_device_id)); - err = clCreateSubDevices(object_, properties, n, ids, NULL); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __CREATE_SUB_DEVICES); - } - - devices->assign(&ids[0], &ids[n]); - return CL_SUCCESS; - } -#endif // #if defined(CL_VERSION_1_2) - -/** - * CL 1.1 version that uses device fission. - */ -#if defined(CL_VERSION_1_1) -#if defined(USE_CL_DEVICE_FISSION) - cl_int createSubDevices( - const cl_device_partition_property_ext * properties, - VECTOR_CLASS* devices) - { - typedef CL_API_ENTRY cl_int - ( CL_API_CALL * PFN_clCreateSubDevicesEXT)( - cl_device_id /*in_device*/, - const cl_device_partition_property_ext * /* properties */, - cl_uint /*num_entries*/, - cl_device_id * /*out_devices*/, - cl_uint * /*num_devices*/ ) CL_EXT_SUFFIX__VERSION_1_1; - - static PFN_clCreateSubDevicesEXT pfn_clCreateSubDevicesEXT = NULL; - __INIT_CL_EXT_FCN_PTR(clCreateSubDevicesEXT); - - cl_uint n = 0; - cl_int err = pfn_clCreateSubDevicesEXT(object_, properties, 0, NULL, &n); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __CREATE_SUB_DEVICES); - } - - cl_device_id* ids = (cl_device_id*) alloca(n * sizeof(cl_device_id)); - err = pfn_clCreateSubDevicesEXT(object_, properties, n, ids, NULL); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __CREATE_SUB_DEVICES); - } - - devices->assign(&ids[0], &ids[n]); - return CL_SUCCESS; - } -#endif // #if defined(USE_CL_DEVICE_FISSION) -#endif // #if defined(CL_VERSION_1_1) -}; - -/*! \brief Class interface for cl_platform_id. - * - * \note Copies of these objects are inexpensive, since they don't 'own' - * any underlying resources or data structures. - * - * \see cl_platform_id - */ -class Platform : public detail::Wrapper -{ -public: - //! \brief Default constructor - initializes to NULL. - Platform() : detail::Wrapper() { } - - /*! \brief Constructor from cl_platform_id. - * - * This simply copies the platform ID value, which is an inexpensive operation. - */ - __CL_EXPLICIT_CONSTRUCTORS Platform(const cl_platform_id &platform) : detail::Wrapper(platform) { } - - /*! \brief Assignment operator from cl_platform_id. - * - * This simply copies the platform ID value, which is an inexpensive operation. - */ - Platform& operator = (const cl_platform_id& rhs) - { - detail::Wrapper::operator=(rhs); - return *this; - } - - //! \brief Wrapper for clGetPlatformInfo(). - cl_int getInfo(cl_platform_info name, STRING_CLASS* param) const - { - return detail::errHandler( - detail::getInfo(&::clGetPlatformInfo, object_, name, param), - __GET_PLATFORM_INFO_ERR); - } - - //! \brief Wrapper for clGetPlatformInfo() that returns by value. - template typename - detail::param_traits::param_type - getInfo(cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_platform_info, name>::param_type param; - cl_int result = getInfo(name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } - - /*! \brief Gets a list of devices for this platform. - * - * Wraps clGetDeviceIDs(). - */ - cl_int getDevices( - cl_device_type type, - VECTOR_CLASS* devices) const - { - cl_uint n = 0; - if( devices == NULL ) { - return detail::errHandler(CL_INVALID_ARG_VALUE, __GET_DEVICE_IDS_ERR); - } - cl_int err = ::clGetDeviceIDs(object_, type, 0, NULL, &n); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __GET_DEVICE_IDS_ERR); - } - - cl_device_id* ids = (cl_device_id*) alloca(n * sizeof(cl_device_id)); - err = ::clGetDeviceIDs(object_, type, n, ids, NULL); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __GET_DEVICE_IDS_ERR); - } - - devices->assign(&ids[0], &ids[n]); - return CL_SUCCESS; - } - -#if defined(USE_DX_INTEROP) - /*! \brief Get the list of available D3D10 devices. - * - * \param d3d_device_source. - * - * \param d3d_object. - * - * \param d3d_device_set. - * - * \param devices returns a vector of OpenCL D3D10 devices found. The cl::Device - * values returned in devices can be used to identify a specific OpenCL - * device. If \a devices argument is NULL, this argument is ignored. - * - * \return One of the following values: - * - CL_SUCCESS if the function is executed successfully. - * - * The application can query specific capabilities of the OpenCL device(s) - * returned by cl::getDevices. This can be used by the application to - * determine which device(s) to use. - * - * \note In the case that exceptions are enabled and a return value - * other than CL_SUCCESS is generated, then cl::Error exception is - * generated. - */ - cl_int getDevices( - cl_d3d10_device_source_khr d3d_device_source, - void * d3d_object, - cl_d3d10_device_set_khr d3d_device_set, - VECTOR_CLASS* devices) const - { - typedef CL_API_ENTRY cl_int (CL_API_CALL *PFN_clGetDeviceIDsFromD3D10KHR)( - cl_platform_id platform, - cl_d3d10_device_source_khr d3d_device_source, - void * d3d_object, - cl_d3d10_device_set_khr d3d_device_set, - cl_uint num_entries, - cl_device_id * devices, - cl_uint* num_devices); - - if( devices == NULL ) { - return detail::errHandler(CL_INVALID_ARG_VALUE, __GET_DEVICE_IDS_ERR); - } - - static PFN_clGetDeviceIDsFromD3D10KHR pfn_clGetDeviceIDsFromD3D10KHR = NULL; - __INIT_CL_EXT_FCN_PTR_PLATFORM(object_, clGetDeviceIDsFromD3D10KHR); - - cl_uint n = 0; - cl_int err = pfn_clGetDeviceIDsFromD3D10KHR( - object_, - d3d_device_source, - d3d_object, - d3d_device_set, - 0, - NULL, - &n); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __GET_DEVICE_IDS_ERR); - } - - cl_device_id* ids = (cl_device_id*) alloca(n * sizeof(cl_device_id)); - err = pfn_clGetDeviceIDsFromD3D10KHR( - object_, - d3d_device_source, - d3d_object, - d3d_device_set, - n, - ids, - NULL); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __GET_DEVICE_IDS_ERR); - } - - devices->assign(&ids[0], &ids[n]); - return CL_SUCCESS; - } -#endif - - /*! \brief Gets a list of available platforms. - * - * Wraps clGetPlatformIDs(). - */ - static cl_int get( - VECTOR_CLASS* platforms) - { - cl_uint n = 0; - - if( platforms == NULL ) { - return detail::errHandler(CL_INVALID_ARG_VALUE, __GET_PLATFORM_IDS_ERR); - } - - cl_int err = ::clGetPlatformIDs(0, NULL, &n); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __GET_PLATFORM_IDS_ERR); - } - - cl_platform_id* ids = (cl_platform_id*) alloca( - n * sizeof(cl_platform_id)); - err = ::clGetPlatformIDs(n, ids, NULL); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __GET_PLATFORM_IDS_ERR); - } - - platforms->assign(&ids[0], &ids[n]); - return CL_SUCCESS; - } - - /*! \brief Gets the first available platform. - * - * Wraps clGetPlatformIDs(), returning the first result. - */ - static cl_int get( - Platform * platform) - { - cl_uint n = 0; - - if( platform == NULL ) { - return detail::errHandler(CL_INVALID_ARG_VALUE, __GET_PLATFORM_IDS_ERR); - } - - cl_int err = ::clGetPlatformIDs(0, NULL, &n); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __GET_PLATFORM_IDS_ERR); - } - - cl_platform_id* ids = (cl_platform_id*) alloca( - n * sizeof(cl_platform_id)); - err = ::clGetPlatformIDs(n, ids, NULL); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __GET_PLATFORM_IDS_ERR); - } - - *platform = ids[0]; - return CL_SUCCESS; - } - - /*! \brief Gets the first available platform, returning it by value. - * - * Wraps clGetPlatformIDs(), returning the first result. - */ - static Platform get( - cl_int * errResult = NULL) - { - Platform platform; - cl_uint n = 0; - cl_int err = ::clGetPlatformIDs(0, NULL, &n); - if (err != CL_SUCCESS) { - detail::errHandler(err, __GET_PLATFORM_IDS_ERR); - if (errResult != NULL) { - *errResult = err; - } - return Platform(); - } - - cl_platform_id* ids = (cl_platform_id*) alloca( - n * sizeof(cl_platform_id)); - err = ::clGetPlatformIDs(n, ids, NULL); - - if (err != CL_SUCCESS) { - detail::errHandler(err, __GET_PLATFORM_IDS_ERR); - if (errResult != NULL) { - *errResult = err; - } - return Platform(); - } - - - return Platform(ids[0]); - } - - static Platform getDefault( - cl_int *errResult = NULL ) - { - return get(errResult); - } - - -#if defined(CL_VERSION_1_2) - //! \brief Wrapper for clUnloadCompiler(). - cl_int - unloadCompiler() - { - return ::clUnloadPlatformCompiler(object_); - } -#endif // #if defined(CL_VERSION_1_2) -}; // class Platform - -/** - * Deprecated APIs for 1.2 - */ -#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) || (defined(CL_VERSION_1_1) && !defined(CL_VERSION_1_2)) -/** - * Unload the OpenCL compiler. - * \note Deprecated for OpenCL 1.2. Use Platform::unloadCompiler instead. - */ -inline CL_EXT_PREFIX__VERSION_1_1_DEPRECATED cl_int -UnloadCompiler() CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; -inline cl_int -UnloadCompiler() -{ - return ::clUnloadCompiler(); -} -#endif // #if defined(CL_VERSION_1_1) - -/*! \brief Class interface for cl_context. - * - * \note Copies of these objects are shallow, meaning that the copy will refer - * to the same underlying cl_context as the original. For details, see - * clRetainContext() and clReleaseContext(). - * - * \see cl_context - */ -class Context - : public detail::Wrapper -{ -private: - -#ifdef CL_HPP_CPP11_ATOMICS_SUPPORTED - static std::atomic default_initialized_; -#else // !CL_HPP_CPP11_ATOMICS_SUPPORTED - static volatile int default_initialized_; -#endif // !CL_HPP_CPP11_ATOMICS_SUPPORTED - static Context default_; - static volatile cl_int default_error_; -public: - /*! \brief Constructs a context including a list of specified devices. - * - * Wraps clCreateContext(). - */ - Context( - const VECTOR_CLASS& devices, - cl_context_properties* properties = NULL, - void (CL_CALLBACK * notifyFptr)( - const char *, - const void *, - ::size_t, - void *) = NULL, - void* data = NULL, - cl_int* err = NULL) - { - cl_int error; - - ::size_t numDevices = devices.size(); - cl_device_id* deviceIDs = (cl_device_id*) alloca(numDevices * sizeof(cl_device_id)); - for( ::size_t deviceIndex = 0; deviceIndex < numDevices; ++deviceIndex ) { - deviceIDs[deviceIndex] = (devices[deviceIndex])(); - } - - object_ = ::clCreateContext( - properties, (cl_uint) numDevices, - deviceIDs, - notifyFptr, data, &error); - - detail::errHandler(error, __CREATE_CONTEXT_ERR); - if (err != NULL) { - *err = error; - } - } - - Context( - const Device& device, - cl_context_properties* properties = NULL, - void (CL_CALLBACK * notifyFptr)( - const char *, - const void *, - ::size_t, - void *) = NULL, - void* data = NULL, - cl_int* err = NULL) - { - cl_int error; - - cl_device_id deviceID = device(); - - object_ = ::clCreateContext( - properties, 1, - &deviceID, - notifyFptr, data, &error); - - detail::errHandler(error, __CREATE_CONTEXT_ERR); - if (err != NULL) { - *err = error; - } - } - - /*! \brief Constructs a context including all or a subset of devices of a specified type. - * - * Wraps clCreateContextFromType(). - */ - Context( - cl_device_type type, - cl_context_properties* properties = NULL, - void (CL_CALLBACK * notifyFptr)( - const char *, - const void *, - ::size_t, - void *) = NULL, - void* data = NULL, - cl_int* err = NULL) - { - cl_int error; - -#if !defined(__APPLE__) && !defined(__MACOS) - cl_context_properties prop[4] = {CL_CONTEXT_PLATFORM, 0, 0, 0 }; - - if (properties == NULL) { - // Get a valid platform ID as we cannot send in a blank one - VECTOR_CLASS platforms; - error = Platform::get(&platforms); - if (error != CL_SUCCESS) { - detail::errHandler(error, __CREATE_CONTEXT_FROM_TYPE_ERR); - if (err != NULL) { - *err = error; - } - return; - } - - // Check the platforms we found for a device of our specified type - cl_context_properties platform_id = 0; - for (unsigned int i = 0; i < platforms.size(); i++) { - - VECTOR_CLASS devices; - -#if defined(__CL_ENABLE_EXCEPTIONS) - try { -#endif - - error = platforms[i].getDevices(type, &devices); - -#if defined(__CL_ENABLE_EXCEPTIONS) - } catch (Error) {} - // Catch if exceptions are enabled as we don't want to exit if first platform has no devices of type - // We do error checking next anyway, and can throw there if needed -#endif - - // Only squash CL_SUCCESS and CL_DEVICE_NOT_FOUND - if (error != CL_SUCCESS && error != CL_DEVICE_NOT_FOUND) { - detail::errHandler(error, __CREATE_CONTEXT_FROM_TYPE_ERR); - if (err != NULL) { - *err = error; - } - } - - if (devices.size() > 0) { - platform_id = (cl_context_properties)platforms[i](); - break; - } - } - - if (platform_id == 0) { - detail::errHandler(CL_DEVICE_NOT_FOUND, __CREATE_CONTEXT_FROM_TYPE_ERR); - if (err != NULL) { - *err = CL_DEVICE_NOT_FOUND; - } - return; - } - - prop[1] = platform_id; - properties = &prop[0]; - } -#endif - object_ = ::clCreateContextFromType( - properties, type, notifyFptr, data, &error); - - detail::errHandler(error, __CREATE_CONTEXT_FROM_TYPE_ERR); - if (err != NULL) { - *err = error; - } - } - - /*! \brief Copy constructor to forward copy to the superclass correctly. - * Required for MSVC. - */ - Context(const Context& ctx) : detail::Wrapper(ctx) {} - - /*! \brief Copy assignment to forward copy to the superclass correctly. - * Required for MSVC. - */ - Context& operator = (const Context &ctx) - { - detail::Wrapper::operator=(ctx); - return *this; - } - -#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) - /*! \brief Move constructor to forward move to the superclass correctly. - * Required for MSVC. - */ - Context(Context&& ctx) CL_HPP_NOEXCEPT : detail::Wrapper(std::move(ctx)) {} - - /*! \brief Move assignment to forward move to the superclass correctly. - * Required for MSVC. - */ - Context& operator = (Context &&ctx) - { - detail::Wrapper::operator=(std::move(ctx)); - return *this; - } -#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) - - /*! \brief Returns a singleton context including all devices of CL_DEVICE_TYPE_DEFAULT. - * - * \note All calls to this function return the same cl_context as the first. - */ - static Context getDefault(cl_int * err = NULL) - { - int state = detail::compare_exchange( - &default_initialized_, - __DEFAULT_BEING_INITIALIZED, __DEFAULT_NOT_INITIALIZED); - - if (state & __DEFAULT_INITIALIZED) { - if (err != NULL) { - *err = default_error_; - } - return default_; - } - - if (state & __DEFAULT_BEING_INITIALIZED) { - // Assume writes will propagate eventually... - while(default_initialized_ != __DEFAULT_INITIALIZED) { - detail::fence(); - } - - if (err != NULL) { - *err = default_error_; - } - return default_; - } - - cl_int error; - default_ = Context( - CL_DEVICE_TYPE_DEFAULT, - NULL, - NULL, - NULL, - &error); - - detail::fence(); - - default_error_ = error; - // Assume writes will propagate eventually... - default_initialized_ = __DEFAULT_INITIALIZED; - - detail::fence(); - - if (err != NULL) { - *err = default_error_; - } - return default_; - - } - - //! \brief Default constructor - initializes to NULL. - Context() : detail::Wrapper() { } - - /*! \brief Constructor from cl_context - takes ownership. - * - * This effectively transfers ownership of a refcount on the cl_context - * into the new Context object. - */ - __CL_EXPLICIT_CONSTRUCTORS Context(const cl_context& context) : detail::Wrapper(context) { } - - /*! \brief Assignment operator from cl_context - takes ownership. - * - * This effectively transfers ownership of a refcount on the rhs and calls - * clReleaseContext() on the value previously held by this instance. - */ - Context& operator = (const cl_context& rhs) - { - detail::Wrapper::operator=(rhs); - return *this; - } - - //! \brief Wrapper for clGetContextInfo(). - template - cl_int getInfo(cl_context_info name, T* param) const - { - return detail::errHandler( - detail::getInfo(&::clGetContextInfo, object_, name, param), - __GET_CONTEXT_INFO_ERR); - } - - //! \brief Wrapper for clGetContextInfo() that returns by value. - template typename - detail::param_traits::param_type - getInfo(cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_context_info, name>::param_type param; - cl_int result = getInfo(name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } - - /*! \brief Gets a list of supported image formats. - * - * Wraps clGetSupportedImageFormats(). - */ - cl_int getSupportedImageFormats( - cl_mem_flags flags, - cl_mem_object_type type, - VECTOR_CLASS* formats) const - { - cl_uint numEntries; - - if (!formats) { - return CL_SUCCESS; - } - - cl_int err = ::clGetSupportedImageFormats( - object_, - flags, - type, - 0, - NULL, - &numEntries); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __GET_SUPPORTED_IMAGE_FORMATS_ERR); - } - - if (numEntries > 0) { - ImageFormat* value = (ImageFormat*) - alloca(numEntries * sizeof(ImageFormat)); - err = ::clGetSupportedImageFormats( - object_, - flags, - type, - numEntries, - (cl_image_format*)value, - NULL); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __GET_SUPPORTED_IMAGE_FORMATS_ERR); - } - - formats->assign(&value[0], &value[numEntries]); - } - else { - formats->clear(); - } - return CL_SUCCESS; - } -}; - -inline Device Device::getDefault(cl_int * err) -{ - cl_int error; - Device device; - - Context context = Context::getDefault(&error); - detail::errHandler(error, __CREATE_CONTEXT_ERR); - - if (error != CL_SUCCESS) { - if (err != NULL) { - *err = error; - } - } - else { - device = context.getInfo()[0]; - if (err != NULL) { - *err = CL_SUCCESS; - } - } - - return device; -} - - -#ifdef _WIN32 -#ifdef CL_HPP_CPP11_ATOMICS_SUPPORTED -__declspec(selectany) std::atomic Context::default_initialized_; -#else // !CL_HPP_CPP11_ATOMICS_SUPPORTED -__declspec(selectany) volatile int Context::default_initialized_ = __DEFAULT_NOT_INITIALIZED; -#endif // !CL_HPP_CPP11_ATOMICS_SUPPORTED -__declspec(selectany) Context Context::default_; -__declspec(selectany) volatile cl_int Context::default_error_ = CL_SUCCESS; -#else // !_WIN32 -#ifdef CL_HPP_CPP11_ATOMICS_SUPPORTED -__attribute__((weak)) std::atomic Context::default_initialized_; -#else // !CL_HPP_CPP11_ATOMICS_SUPPORTED -__attribute__((weak)) volatile int Context::default_initialized_ = __DEFAULT_NOT_INITIALIZED; -#endif // !CL_HPP_CPP11_ATOMICS_SUPPORTED -__attribute__((weak)) Context Context::default_; -__attribute__((weak)) volatile cl_int Context::default_error_ = CL_SUCCESS; -#endif // !_WIN32 - -/*! \brief Class interface for cl_event. - * - * \note Copies of these objects are shallow, meaning that the copy will refer - * to the same underlying cl_event as the original. For details, see - * clRetainEvent() and clReleaseEvent(). - * - * \see cl_event - */ -class Event : public detail::Wrapper -{ -public: - //! \brief Default constructor - initializes to NULL. - Event() : detail::Wrapper() { } - - /*! \brief Constructor from cl_event - takes ownership. - * - * This effectively transfers ownership of a refcount on the cl_event - * into the new Event object. - */ - __CL_EXPLICIT_CONSTRUCTORS Event(const cl_event& event) : detail::Wrapper(event) { } - - /*! \brief Assignment operator from cl_event - takes ownership. - * - * This effectively transfers ownership of a refcount on the rhs and calls - * clReleaseEvent() on the value previously held by this instance. - */ - Event& operator = (const cl_event& rhs) - { - detail::Wrapper::operator=(rhs); - return *this; - } - - //! \brief Wrapper for clGetEventInfo(). - template - cl_int getInfo(cl_event_info name, T* param) const - { - return detail::errHandler( - detail::getInfo(&::clGetEventInfo, object_, name, param), - __GET_EVENT_INFO_ERR); - } - - //! \brief Wrapper for clGetEventInfo() that returns by value. - template typename - detail::param_traits::param_type - getInfo(cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_event_info, name>::param_type param; - cl_int result = getInfo(name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } - - //! \brief Wrapper for clGetEventProfilingInfo(). - template - cl_int getProfilingInfo(cl_profiling_info name, T* param) const - { - return detail::errHandler(detail::getInfo( - &::clGetEventProfilingInfo, object_, name, param), - __GET_EVENT_PROFILE_INFO_ERR); - } - - //! \brief Wrapper for clGetEventProfilingInfo() that returns by value. - template typename - detail::param_traits::param_type - getProfilingInfo(cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_profiling_info, name>::param_type param; - cl_int result = getProfilingInfo(name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } - - /*! \brief Blocks the calling thread until this event completes. - * - * Wraps clWaitForEvents(). - */ - cl_int wait() const - { - return detail::errHandler( - ::clWaitForEvents(1, &object_), - __WAIT_FOR_EVENTS_ERR); - } - -#if defined(CL_VERSION_1_1) - /*! \brief Registers a user callback function for a specific command execution status. - * - * Wraps clSetEventCallback(). - */ - cl_int setCallback( - cl_int type, - void (CL_CALLBACK * pfn_notify)(cl_event, cl_int, void *), - void * user_data = NULL) - { - return detail::errHandler( - ::clSetEventCallback( - object_, - type, - pfn_notify, - user_data), - __SET_EVENT_CALLBACK_ERR); - } -#endif - - /*! \brief Blocks the calling thread until every event specified is complete. - * - * Wraps clWaitForEvents(). - */ - static cl_int - waitForEvents(const VECTOR_CLASS& events) - { - return detail::errHandler( - ::clWaitForEvents( - (cl_uint) events.size(), (events.size() > 0) ? (cl_event*)&events.front() : NULL), - __WAIT_FOR_EVENTS_ERR); - } -}; - -#if defined(CL_VERSION_1_1) -/*! \brief Class interface for user events (a subset of cl_event's). - * - * See Event for details about copy semantics, etc. - */ -class UserEvent : public Event -{ -public: - /*! \brief Constructs a user event on a given context. - * - * Wraps clCreateUserEvent(). - */ - UserEvent( - const Context& context, - cl_int * err = NULL) - { - cl_int error; - object_ = ::clCreateUserEvent( - context(), - &error); - - detail::errHandler(error, __CREATE_USER_EVENT_ERR); - if (err != NULL) { - *err = error; - } - } - - //! \brief Default constructor - initializes to NULL. - UserEvent() : Event() { } - - /*! \brief Sets the execution status of a user event object. - * - * Wraps clSetUserEventStatus(). - */ - cl_int setStatus(cl_int status) - { - return detail::errHandler( - ::clSetUserEventStatus(object_,status), - __SET_USER_EVENT_STATUS_ERR); - } -}; -#endif - -/*! \brief Blocks the calling thread until every event specified is complete. - * - * Wraps clWaitForEvents(). - */ -inline static cl_int -WaitForEvents(const VECTOR_CLASS& events) -{ - return detail::errHandler( - ::clWaitForEvents( - (cl_uint) events.size(), (events.size() > 0) ? (cl_event*)&events.front() : NULL), - __WAIT_FOR_EVENTS_ERR); -} - -/*! \brief Class interface for cl_mem. - * - * \note Copies of these objects are shallow, meaning that the copy will refer - * to the same underlying cl_mem as the original. For details, see - * clRetainMemObject() and clReleaseMemObject(). - * - * \see cl_mem - */ -class Memory : public detail::Wrapper -{ -public: - //! \brief Default constructor - initializes to NULL. - Memory() : detail::Wrapper() { } - - /*! \brief Constructor from cl_mem - takes ownership. - * - * This effectively transfers ownership of a refcount on the cl_mem - * into the new Memory object. - */ - __CL_EXPLICIT_CONSTRUCTORS Memory(const cl_mem& memory) : detail::Wrapper(memory) { } - - /*! \brief Assignment operator from cl_mem - takes ownership. - * - * This effectively transfers ownership of a refcount on the rhs and calls - * clReleaseMemObject() on the value previously held by this instance. - */ - Memory& operator = (const cl_mem& rhs) - { - detail::Wrapper::operator=(rhs); - return *this; - } - - /*! \brief Copy constructor to forward copy to the superclass correctly. - * Required for MSVC. - */ - Memory(const Memory& mem) : detail::Wrapper(mem) {} - - /*! \brief Copy assignment to forward copy to the superclass correctly. - * Required for MSVC. - */ - Memory& operator = (const Memory &mem) - { - detail::Wrapper::operator=(mem); - return *this; - } - -#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) - /*! \brief Move constructor to forward move to the superclass correctly. - * Required for MSVC. - */ - Memory(Memory&& mem) CL_HPP_NOEXCEPT : detail::Wrapper(std::move(mem)) {} - - /*! \brief Move assignment to forward move to the superclass correctly. - * Required for MSVC. - */ - Memory& operator = (Memory &&mem) - { - detail::Wrapper::operator=(std::move(mem)); - return *this; - } -#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) - - //! \brief Wrapper for clGetMemObjectInfo(). - template - cl_int getInfo(cl_mem_info name, T* param) const - { - return detail::errHandler( - detail::getInfo(&::clGetMemObjectInfo, object_, name, param), - __GET_MEM_OBJECT_INFO_ERR); - } - - //! \brief Wrapper for clGetMemObjectInfo() that returns by value. - template typename - detail::param_traits::param_type - getInfo(cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_mem_info, name>::param_type param; - cl_int result = getInfo(name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } - -#if defined(CL_VERSION_1_1) - /*! \brief Registers a callback function to be called when the memory object - * is no longer needed. - * - * Wraps clSetMemObjectDestructorCallback(). - * - * Repeated calls to this function, for a given cl_mem value, will append - * to the list of functions called (in reverse order) when memory object's - * resources are freed and the memory object is deleted. - * - * \note - * The registered callbacks are associated with the underlying cl_mem - * value - not the Memory class instance. - */ - cl_int setDestructorCallback( - void (CL_CALLBACK * pfn_notify)(cl_mem, void *), - void * user_data = NULL) - { - return detail::errHandler( - ::clSetMemObjectDestructorCallback( - object_, - pfn_notify, - user_data), - __SET_MEM_OBJECT_DESTRUCTOR_CALLBACK_ERR); - } -#endif - -}; - -// Pre-declare copy functions -class Buffer; -template< typename IteratorType > -cl_int copy( IteratorType startIterator, IteratorType endIterator, cl::Buffer &buffer ); -template< typename IteratorType > -cl_int copy( const cl::Buffer &buffer, IteratorType startIterator, IteratorType endIterator ); -template< typename IteratorType > -cl_int copy( const CommandQueue &queue, IteratorType startIterator, IteratorType endIterator, cl::Buffer &buffer ); -template< typename IteratorType > -cl_int copy( const CommandQueue &queue, const cl::Buffer &buffer, IteratorType startIterator, IteratorType endIterator ); - - -/*! \brief Class interface for Buffer Memory Objects. - * - * See Memory for details about copy semantics, etc. - * - * \see Memory - */ -class Buffer : public Memory -{ -public: - - /*! \brief Constructs a Buffer in a specified context. - * - * Wraps clCreateBuffer(). - * - * \param host_ptr Storage to be used if the CL_MEM_USE_HOST_PTR flag was - * specified. Note alignment & exclusivity requirements. - */ - Buffer( - const Context& context, - cl_mem_flags flags, - ::size_t size, - void* host_ptr = NULL, - cl_int* err = NULL) - { - cl_int error; - object_ = ::clCreateBuffer(context(), flags, size, host_ptr, &error); - - detail::errHandler(error, __CREATE_BUFFER_ERR); - if (err != NULL) { - *err = error; - } - } - - /*! \brief Constructs a Buffer in the default context. - * - * Wraps clCreateBuffer(). - * - * \param host_ptr Storage to be used if the CL_MEM_USE_HOST_PTR flag was - * specified. Note alignment & exclusivity requirements. - * - * \see Context::getDefault() - */ - Buffer( - cl_mem_flags flags, - ::size_t size, - void* host_ptr = NULL, - cl_int* err = NULL) - { - cl_int error; - - Context context = Context::getDefault(err); - - object_ = ::clCreateBuffer(context(), flags, size, host_ptr, &error); - - detail::errHandler(error, __CREATE_BUFFER_ERR); - if (err != NULL) { - *err = error; - } - } - - /*! - * \brief Construct a Buffer from a host container via iterators. - * IteratorType must be random access. - * If useHostPtr is specified iterators must represent contiguous data. - */ - template< typename IteratorType > - Buffer( - IteratorType startIterator, - IteratorType endIterator, - bool readOnly, - bool useHostPtr = false, - cl_int* err = NULL) - { - typedef typename std::iterator_traits::value_type DataType; - cl_int error; - - cl_mem_flags flags = 0; - if( readOnly ) { - flags |= CL_MEM_READ_ONLY; - } - else { - flags |= CL_MEM_READ_WRITE; - } - if( useHostPtr ) { - flags |= CL_MEM_USE_HOST_PTR; - } - - ::size_t size = sizeof(DataType)*(endIterator - startIterator); - - Context context = Context::getDefault(err); - - if( useHostPtr ) { - object_ = ::clCreateBuffer(context(), flags, size, static_cast(&*startIterator), &error); - } else { - object_ = ::clCreateBuffer(context(), flags, size, 0, &error); - } - - detail::errHandler(error, __CREATE_BUFFER_ERR); - if (err != NULL) { - *err = error; - } - - if( !useHostPtr ) { - error = cl::copy(startIterator, endIterator, *this); - detail::errHandler(error, __CREATE_BUFFER_ERR); - if (err != NULL) { - *err = error; - } - } - } - - /*! - * \brief Construct a Buffer from a host container via iterators using a specified context. - * IteratorType must be random access. - * If useHostPtr is specified iterators must represent contiguous data. - */ - template< typename IteratorType > - Buffer(const Context &context, IteratorType startIterator, IteratorType endIterator, - bool readOnly, bool useHostPtr = false, cl_int* err = NULL); - - /*! - * \brief Construct a Buffer from a host container via iterators using a specified queue. - * If useHostPtr is specified iterators must represent contiguous data. - */ - template< typename IteratorType > - Buffer(const CommandQueue &queue, IteratorType startIterator, IteratorType endIterator, - bool readOnly, bool useHostPtr = false, cl_int* err = NULL); - - //! \brief Default constructor - initializes to NULL. - Buffer() : Memory() { } - - /*! \brief Constructor from cl_mem - takes ownership. - * - * See Memory for further details. - */ - __CL_EXPLICIT_CONSTRUCTORS Buffer(const cl_mem& buffer) : Memory(buffer) { } - - /*! \brief Assignment from cl_mem - performs shallow copy. - * - * See Memory for further details. - */ - Buffer& operator = (const cl_mem& rhs) - { - Memory::operator=(rhs); - return *this; - } - - /*! \brief Copy constructor to forward copy to the superclass correctly. - * Required for MSVC. - */ - Buffer(const Buffer& buf) : Memory(buf) {} - - /*! \brief Copy assignment to forward copy to the superclass correctly. - * Required for MSVC. - */ - Buffer& operator = (const Buffer &buf) - { - Memory::operator=(buf); - return *this; - } - -#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) - /*! \brief Move constructor to forward move to the superclass correctly. - * Required for MSVC. - */ - Buffer(Buffer&& buf) CL_HPP_NOEXCEPT : Memory(std::move(buf)) {} - - /*! \brief Move assignment to forward move to the superclass correctly. - * Required for MSVC. - */ - Buffer& operator = (Buffer &&buf) - { - Memory::operator=(std::move(buf)); - return *this; - } -#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) - -#if defined(CL_VERSION_1_1) - /*! \brief Creates a new buffer object from this. - * - * Wraps clCreateSubBuffer(). - */ - Buffer createSubBuffer( - cl_mem_flags flags, - cl_buffer_create_type buffer_create_type, - const void * buffer_create_info, - cl_int * err = NULL) - { - Buffer result; - cl_int error; - result.object_ = ::clCreateSubBuffer( - object_, - flags, - buffer_create_type, - buffer_create_info, - &error); - - detail::errHandler(error, __CREATE_SUBBUFFER_ERR); - if (err != NULL) { - *err = error; - } - - return result; - } -#endif -}; - -#if defined (USE_DX_INTEROP) -/*! \brief Class interface for creating OpenCL buffers from ID3D10Buffer's. - * - * This is provided to facilitate interoperability with Direct3D. - * - * See Memory for details about copy semantics, etc. - * - * \see Memory - */ -class BufferD3D10 : public Buffer -{ -public: - typedef CL_API_ENTRY cl_mem (CL_API_CALL *PFN_clCreateFromD3D10BufferKHR)( - cl_context context, cl_mem_flags flags, ID3D10Buffer* buffer, - cl_int* errcode_ret); - - /*! \brief Constructs a BufferD3D10, in a specified context, from a - * given ID3D10Buffer. - * - * Wraps clCreateFromD3D10BufferKHR(). - */ - BufferD3D10( - const Context& context, - cl_mem_flags flags, - ID3D10Buffer* bufobj, - cl_int * err = NULL) - { - static PFN_clCreateFromD3D10BufferKHR pfn_clCreateFromD3D10BufferKHR = NULL; - -#if defined(CL_VERSION_1_2) - vector props = context.getInfo(); - cl_platform platform = -1; - for( int i = 0; i < props.size(); ++i ) { - if( props[i] == CL_CONTEXT_PLATFORM ) { - platform = props[i+1]; - } - } - __INIT_CL_EXT_FCN_PTR_PLATFORM(platform, clCreateFromD3D10BufferKHR); -#endif -#if defined(CL_VERSION_1_1) - __INIT_CL_EXT_FCN_PTR(clCreateFromD3D10BufferKHR); -#endif - - cl_int error; - object_ = pfn_clCreateFromD3D10BufferKHR( - context(), - flags, - bufobj, - &error); - - detail::errHandler(error, __CREATE_GL_BUFFER_ERR); - if (err != NULL) { - *err = error; - } - } - - //! \brief Default constructor - initializes to NULL. - BufferD3D10() : Buffer() { } - - /*! \brief Constructor from cl_mem - takes ownership. - * - * See Memory for further details. - */ - __CL_EXPLICIT_CONSTRUCTORS BufferD3D10(const cl_mem& buffer) : Buffer(buffer) { } - - /*! \brief Assignment from cl_mem - performs shallow copy. - * - * See Memory for further details. - */ - BufferD3D10& operator = (const cl_mem& rhs) - { - Buffer::operator=(rhs); - return *this; - } - - /*! \brief Copy constructor to forward copy to the superclass correctly. - * Required for MSVC. - */ - BufferD3D10(const BufferD3D10& buf) : Buffer(buf) {} - - /*! \brief Copy assignment to forward copy to the superclass correctly. - * Required for MSVC. - */ - BufferD3D10& operator = (const BufferD3D10 &buf) - { - Buffer::operator=(buf); - return *this; - } - -#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) - /*! \brief Move constructor to forward move to the superclass correctly. - * Required for MSVC. - */ - BufferD3D10(BufferD3D10&& buf) CL_HPP_NOEXCEPT : Buffer(std::move(buf)) {} - - /*! \brief Move assignment to forward move to the superclass correctly. - * Required for MSVC. - */ - BufferD3D10& operator = (BufferD3D10 &&buf) - { - Buffer::operator=(std::move(buf)); - return *this; - } -#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) -}; -#endif - -/*! \brief Class interface for GL Buffer Memory Objects. - * - * This is provided to facilitate interoperability with OpenGL. - * - * See Memory for details about copy semantics, etc. - * - * \see Memory - */ -class BufferGL : public Buffer -{ -public: - /*! \brief Constructs a BufferGL in a specified context, from a given - * GL buffer. - * - * Wraps clCreateFromGLBuffer(). - */ - BufferGL( - const Context& context, - cl_mem_flags flags, - cl_GLuint bufobj, - cl_int * err = NULL) - { - cl_int error; - object_ = ::clCreateFromGLBuffer( - context(), - flags, - bufobj, - &error); - - detail::errHandler(error, __CREATE_GL_BUFFER_ERR); - if (err != NULL) { - *err = error; - } - } - - //! \brief Default constructor - initializes to NULL. - BufferGL() : Buffer() { } - - /*! \brief Constructor from cl_mem - takes ownership. - * - * See Memory for further details. - */ - __CL_EXPLICIT_CONSTRUCTORS BufferGL(const cl_mem& buffer) : Buffer(buffer) { } - - /*! \brief Assignment from cl_mem - performs shallow copy. - * - * See Memory for further details. - */ - BufferGL& operator = (const cl_mem& rhs) - { - Buffer::operator=(rhs); - return *this; - } - - /*! \brief Copy constructor to forward copy to the superclass correctly. - * Required for MSVC. - */ - BufferGL(const BufferGL& buf) : Buffer(buf) {} - - /*! \brief Copy assignment to forward copy to the superclass correctly. - * Required for MSVC. - */ - BufferGL& operator = (const BufferGL &buf) - { - Buffer::operator=(buf); - return *this; - } - -#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) - /*! \brief Move constructor to forward move to the superclass correctly. - * Required for MSVC. - */ - BufferGL(BufferGL&& buf) CL_HPP_NOEXCEPT : Buffer(std::move(buf)) {} - - /*! \brief Move assignment to forward move to the superclass correctly. - * Required for MSVC. - */ - BufferGL& operator = (BufferGL &&buf) - { - Buffer::operator=(std::move(buf)); - return *this; - } -#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) - - //! \brief Wrapper for clGetGLObjectInfo(). - cl_int getObjectInfo( - cl_gl_object_type *type, - cl_GLuint * gl_object_name) - { - return detail::errHandler( - ::clGetGLObjectInfo(object_,type,gl_object_name), - __GET_GL_OBJECT_INFO_ERR); - } -}; - -/*! \brief C++ base class for Image Memory objects. - * - * See Memory for details about copy semantics, etc. - * - * \see Memory - */ -class Image : public Memory -{ -protected: - //! \brief Default constructor - initializes to NULL. - Image() : Memory() { } - - /*! \brief Constructor from cl_mem - takes ownership. - * - * See Memory for further details. - */ - __CL_EXPLICIT_CONSTRUCTORS Image(const cl_mem& image) : Memory(image) { } - - /*! \brief Assignment from cl_mem - performs shallow copy. - * - * See Memory for further details. - */ - Image& operator = (const cl_mem& rhs) - { - Memory::operator=(rhs); - return *this; - } - - /*! \brief Copy constructor to forward copy to the superclass correctly. - * Required for MSVC. - */ - Image(const Image& img) : Memory(img) {} - - /*! \brief Copy assignment to forward copy to the superclass correctly. - * Required for MSVC. - */ - Image& operator = (const Image &img) - { - Memory::operator=(img); - return *this; - } - -#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) - /*! \brief Move constructor to forward move to the superclass correctly. - * Required for MSVC. - */ - Image(Image&& img) CL_HPP_NOEXCEPT : Memory(std::move(img)) {} - - /*! \brief Move assignment to forward move to the superclass correctly. - * Required for MSVC. - */ - Image& operator = (Image &&img) - { - Memory::operator=(std::move(img)); - return *this; - } -#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) - -public: - //! \brief Wrapper for clGetImageInfo(). - template - cl_int getImageInfo(cl_image_info name, T* param) const - { - return detail::errHandler( - detail::getInfo(&::clGetImageInfo, object_, name, param), - __GET_IMAGE_INFO_ERR); - } - - //! \brief Wrapper for clGetImageInfo() that returns by value. - template typename - detail::param_traits::param_type - getImageInfo(cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_image_info, name>::param_type param; - cl_int result = getImageInfo(name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } -}; - -#if defined(CL_VERSION_1_2) -/*! \brief Class interface for 1D Image Memory objects. - * - * See Memory for details about copy semantics, etc. - * - * \see Memory - */ -class Image1D : public Image -{ -public: - /*! \brief Constructs a 1D Image in a specified context. - * - * Wraps clCreateImage(). - */ - Image1D( - const Context& context, - cl_mem_flags flags, - ImageFormat format, - ::size_t width, - void* host_ptr = NULL, - cl_int* err = NULL) - { - cl_int error; - cl_image_desc desc = - { - CL_MEM_OBJECT_IMAGE1D, - width, - 0, 0, 0, 0, 0, 0, 0, 0 - }; - object_ = ::clCreateImage( - context(), - flags, - &format, - &desc, - host_ptr, - &error); - - detail::errHandler(error, __CREATE_IMAGE_ERR); - if (err != NULL) { - *err = error; - } - } - - //! \brief Default constructor - initializes to NULL. - Image1D() { } - - /*! \brief Constructor from cl_mem - takes ownership. - * - * See Memory for further details. - */ - __CL_EXPLICIT_CONSTRUCTORS Image1D(const cl_mem& image1D) : Image(image1D) { } - - /*! \brief Assignment from cl_mem - performs shallow copy. - * - * See Memory for further details. - */ - Image1D& operator = (const cl_mem& rhs) - { - Image::operator=(rhs); - return *this; - } - - /*! \brief Copy constructor to forward copy to the superclass correctly. - * Required for MSVC. - */ - Image1D(const Image1D& img) : Image(img) {} - - /*! \brief Copy assignment to forward copy to the superclass correctly. - * Required for MSVC. - */ - Image1D& operator = (const Image1D &img) - { - Image::operator=(img); - return *this; - } - -#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) - /*! \brief Move constructor to forward move to the superclass correctly. - * Required for MSVC. - */ - Image1D(Image1D&& img) CL_HPP_NOEXCEPT : Image(std::move(img)) {} - - /*! \brief Move assignment to forward move to the superclass correctly. - * Required for MSVC. - */ - Image1D& operator = (Image1D &&img) - { - Image::operator=(std::move(img)); - return *this; - } -#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) -}; - -/*! \class Image1DBuffer - * \brief Image interface for 1D buffer images. - */ -class Image1DBuffer : public Image -{ -public: - Image1DBuffer( - const Context& context, - cl_mem_flags flags, - ImageFormat format, - ::size_t width, - const Buffer &buffer, - cl_int* err = NULL) - { - cl_int error; - cl_image_desc desc = - { - CL_MEM_OBJECT_IMAGE1D_BUFFER, - width, - 0, 0, 0, 0, 0, 0, 0, - buffer() - }; - object_ = ::clCreateImage( - context(), - flags, - &format, - &desc, - NULL, - &error); - - detail::errHandler(error, __CREATE_IMAGE_ERR); - if (err != NULL) { - *err = error; - } - } - - Image1DBuffer() { } - - __CL_EXPLICIT_CONSTRUCTORS Image1DBuffer(const cl_mem& image1D) : Image(image1D) { } - - Image1DBuffer& operator = (const cl_mem& rhs) - { - Image::operator=(rhs); - return *this; - } - - /*! \brief Copy constructor to forward copy to the superclass correctly. - * Required for MSVC. - */ - Image1DBuffer(const Image1DBuffer& img) : Image(img) {} - - /*! \brief Copy assignment to forward copy to the superclass correctly. - * Required for MSVC. - */ - Image1DBuffer& operator = (const Image1DBuffer &img) - { - Image::operator=(img); - return *this; - } - -#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) - /*! \brief Move constructor to forward move to the superclass correctly. - * Required for MSVC. - */ - Image1DBuffer(Image1DBuffer&& img) CL_HPP_NOEXCEPT : Image(std::move(img)) {} - - /*! \brief Move assignment to forward move to the superclass correctly. - * Required for MSVC. - */ - Image1DBuffer& operator = (Image1DBuffer &&img) - { - Image::operator=(std::move(img)); - return *this; - } -#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) -}; - -/*! \class Image1DArray - * \brief Image interface for arrays of 1D images. - */ -class Image1DArray : public Image -{ -public: - Image1DArray( - const Context& context, - cl_mem_flags flags, - ImageFormat format, - ::size_t arraySize, - ::size_t width, - ::size_t rowPitch, - void* host_ptr = NULL, - cl_int* err = NULL) - { - cl_int error; - cl_image_desc desc = - { - CL_MEM_OBJECT_IMAGE1D_ARRAY, - width, - 0, 0, // height, depth (unused) - arraySize, - rowPitch, - 0, 0, 0, 0 - }; - object_ = ::clCreateImage( - context(), - flags, - &format, - &desc, - host_ptr, - &error); - - detail::errHandler(error, __CREATE_IMAGE_ERR); - if (err != NULL) { - *err = error; - } - } - - Image1DArray() { } - - __CL_EXPLICIT_CONSTRUCTORS Image1DArray(const cl_mem& imageArray) : Image(imageArray) { } - - Image1DArray& operator = (const cl_mem& rhs) - { - Image::operator=(rhs); - return *this; - } - - /*! \brief Copy constructor to forward copy to the superclass correctly. - * Required for MSVC. - */ - Image1DArray(const Image1DArray& img) : Image(img) {} - - /*! \brief Copy assignment to forward copy to the superclass correctly. - * Required for MSVC. - */ - Image1DArray& operator = (const Image1DArray &img) - { - Image::operator=(img); - return *this; - } - -#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) - /*! \brief Move constructor to forward move to the superclass correctly. - * Required for MSVC. - */ - Image1DArray(Image1DArray&& img) CL_HPP_NOEXCEPT : Image(std::move(img)) {} - - /*! \brief Move assignment to forward move to the superclass correctly. - * Required for MSVC. - */ - Image1DArray& operator = (Image1DArray &&img) - { - Image::operator=(std::move(img)); - return *this; - } -#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) -}; -#endif // #if defined(CL_VERSION_1_2) - - -/*! \brief Class interface for 2D Image Memory objects. - * - * See Memory for details about copy semantics, etc. - * - * \see Memory - */ -class Image2D : public Image -{ -public: - /*! \brief Constructs a 1D Image in a specified context. - * - * Wraps clCreateImage(). - */ - Image2D( - const Context& context, - cl_mem_flags flags, - ImageFormat format, - ::size_t width, - ::size_t height, - ::size_t row_pitch = 0, - void* host_ptr = NULL, - cl_int* err = NULL) - { - cl_int error; - bool useCreateImage; - -#if defined(CL_VERSION_1_2) && defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) - // Run-time decision based on the actual platform - { - cl_uint version = detail::getContextPlatformVersion(context()); - useCreateImage = (version >= 0x10002); // OpenCL 1.2 or above - } -#elif defined(CL_VERSION_1_2) - useCreateImage = true; -#else - useCreateImage = false; -#endif - -#if defined(CL_VERSION_1_2) - if (useCreateImage) - { - cl_image_desc desc = - { - CL_MEM_OBJECT_IMAGE2D, - width, - height, - 0, 0, // depth, array size (unused) - row_pitch, - 0, 0, 0, 0 - }; - object_ = ::clCreateImage( - context(), - flags, - &format, - &desc, - host_ptr, - &error); - - detail::errHandler(error, __CREATE_IMAGE_ERR); - if (err != NULL) { - *err = error; - } - } -#endif // #if defined(CL_VERSION_1_2) -#if !defined(CL_VERSION_1_2) || defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) - if (!useCreateImage) - { - object_ = ::clCreateImage2D( - context(), flags,&format, width, height, row_pitch, host_ptr, &error); - - detail::errHandler(error, __CREATE_IMAGE2D_ERR); - if (err != NULL) { - *err = error; - } - } -#endif // #if !defined(CL_VERSION_1_2) || defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) - } - - //! \brief Default constructor - initializes to NULL. - Image2D() { } - - /*! \brief Constructor from cl_mem - takes ownership. - * - * See Memory for further details. - */ - __CL_EXPLICIT_CONSTRUCTORS Image2D(const cl_mem& image2D) : Image(image2D) { } - - /*! \brief Assignment from cl_mem - performs shallow copy. - * - * See Memory for further details. - */ - Image2D& operator = (const cl_mem& rhs) - { - Image::operator=(rhs); - return *this; - } - - /*! \brief Copy constructor to forward copy to the superclass correctly. - * Required for MSVC. - */ - Image2D(const Image2D& img) : Image(img) {} - - /*! \brief Copy assignment to forward copy to the superclass correctly. - * Required for MSVC. - */ - Image2D& operator = (const Image2D &img) - { - Image::operator=(img); - return *this; - } - -#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) - /*! \brief Move constructor to forward move to the superclass correctly. - * Required for MSVC. - */ - Image2D(Image2D&& img) CL_HPP_NOEXCEPT : Image(std::move(img)) {} - - /*! \brief Move assignment to forward move to the superclass correctly. - * Required for MSVC. - */ - Image2D& operator = (Image2D &&img) - { - Image::operator=(std::move(img)); - return *this; - } -#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) -}; - - -#if !defined(CL_VERSION_1_2) -/*! \brief Class interface for GL 2D Image Memory objects. - * - * This is provided to facilitate interoperability with OpenGL. - * - * See Memory for details about copy semantics, etc. - * - * \see Memory - * \note Deprecated for OpenCL 1.2. Please use ImageGL instead. - */ -class CL_EXT_PREFIX__VERSION_1_1_DEPRECATED Image2DGL CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED : public Image2D -{ -public: - /*! \brief Constructs an Image2DGL in a specified context, from a given - * GL Texture. - * - * Wraps clCreateFromGLTexture2D(). - */ - Image2DGL( - const Context& context, - cl_mem_flags flags, - cl_GLenum target, - cl_GLint miplevel, - cl_GLuint texobj, - cl_int * err = NULL) - { - cl_int error; - object_ = ::clCreateFromGLTexture2D( - context(), - flags, - target, - miplevel, - texobj, - &error); - - detail::errHandler(error, __CREATE_GL_TEXTURE_2D_ERR); - if (err != NULL) { - *err = error; - } - - } - - //! \brief Default constructor - initializes to NULL. - Image2DGL() : Image2D() { } - - /*! \brief Constructor from cl_mem - takes ownership. - * - * See Memory for further details. - */ - __CL_EXPLICIT_CONSTRUCTORS Image2DGL(const cl_mem& image) : Image2D(image) { } - - /*! \brief Assignment from cl_mem - performs shallow copy. - * - * See Memory for further details. - */ - Image2DGL& operator = (const cl_mem& rhs) - { - Image2D::operator=(rhs); - return *this; - } - - /*! \brief Copy constructor to forward copy to the superclass correctly. - * Required for MSVC. - */ - Image2DGL(const Image2DGL& img) : Image2D(img) {} - - /*! \brief Copy assignment to forward copy to the superclass correctly. - * Required for MSVC. - */ - Image2DGL& operator = (const Image2DGL &img) - { - Image2D::operator=(img); - return *this; - } - -#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) - /*! \brief Move constructor to forward move to the superclass correctly. - * Required for MSVC. - */ - Image2DGL(Image2DGL&& img) CL_HPP_NOEXCEPT : Image2D(std::move(img)) {} - - /*! \brief Move assignment to forward move to the superclass correctly. - * Required for MSVC. - */ - Image2DGL& operator = (Image2DGL &&img) - { - Image2D::operator=(std::move(img)); - return *this; - } -#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) -}; -#endif // #if !defined(CL_VERSION_1_2) - -#if defined(CL_VERSION_1_2) -/*! \class Image2DArray - * \brief Image interface for arrays of 2D images. - */ -class Image2DArray : public Image -{ -public: - Image2DArray( - const Context& context, - cl_mem_flags flags, - ImageFormat format, - ::size_t arraySize, - ::size_t width, - ::size_t height, - ::size_t rowPitch, - ::size_t slicePitch, - void* host_ptr = NULL, - cl_int* err = NULL) - { - cl_int error; - cl_image_desc desc = - { - CL_MEM_OBJECT_IMAGE2D_ARRAY, - width, - height, - 0, // depth (unused) - arraySize, - rowPitch, - slicePitch, - 0, 0, 0 - }; - object_ = ::clCreateImage( - context(), - flags, - &format, - &desc, - host_ptr, - &error); - - detail::errHandler(error, __CREATE_IMAGE_ERR); - if (err != NULL) { - *err = error; - } - } - - Image2DArray() { } - - __CL_EXPLICIT_CONSTRUCTORS Image2DArray(const cl_mem& imageArray) : Image(imageArray) { } - - Image2DArray& operator = (const cl_mem& rhs) - { - Image::operator=(rhs); - return *this; - } - - /*! \brief Copy constructor to forward copy to the superclass correctly. - * Required for MSVC. - */ - Image2DArray(const Image2DArray& img) : Image(img) {} - - /*! \brief Copy assignment to forward copy to the superclass correctly. - * Required for MSVC. - */ - Image2DArray& operator = (const Image2DArray &img) - { - Image::operator=(img); - return *this; - } - -#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) - /*! \brief Move constructor to forward move to the superclass correctly. - * Required for MSVC. - */ - Image2DArray(Image2DArray&& img) CL_HPP_NOEXCEPT : Image(std::move(img)) {} - - /*! \brief Move assignment to forward move to the superclass correctly. - * Required for MSVC. - */ - Image2DArray& operator = (Image2DArray &&img) - { - Image::operator=(std::move(img)); - return *this; - } -#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) -}; -#endif // #if defined(CL_VERSION_1_2) - -/*! \brief Class interface for 3D Image Memory objects. - * - * See Memory for details about copy semantics, etc. - * - * \see Memory - */ -class Image3D : public Image -{ -public: - /*! \brief Constructs a 3D Image in a specified context. - * - * Wraps clCreateImage(). - */ - Image3D( - const Context& context, - cl_mem_flags flags, - ImageFormat format, - ::size_t width, - ::size_t height, - ::size_t depth, - ::size_t row_pitch = 0, - ::size_t slice_pitch = 0, - void* host_ptr = NULL, - cl_int* err = NULL) - { - cl_int error; - bool useCreateImage; - -#if defined(CL_VERSION_1_2) && defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) - // Run-time decision based on the actual platform - { - cl_uint version = detail::getContextPlatformVersion(context()); - useCreateImage = (version >= 0x10002); // OpenCL 1.2 or above - } -#elif defined(CL_VERSION_1_2) - useCreateImage = true; -#else - useCreateImage = false; -#endif - -#if defined(CL_VERSION_1_2) - if (useCreateImage) - { - cl_image_desc desc = - { - CL_MEM_OBJECT_IMAGE3D, - width, - height, - depth, - 0, // array size (unused) - row_pitch, - slice_pitch, - 0, 0, 0 - }; - object_ = ::clCreateImage( - context(), - flags, - &format, - &desc, - host_ptr, - &error); - - detail::errHandler(error, __CREATE_IMAGE_ERR); - if (err != NULL) { - *err = error; - } - } -#endif // #if defined(CL_VERSION_1_2) -#if !defined(CL_VERSION_1_2) || defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) - if (!useCreateImage) - { - object_ = ::clCreateImage3D( - context(), flags, &format, width, height, depth, row_pitch, - slice_pitch, host_ptr, &error); - - detail::errHandler(error, __CREATE_IMAGE3D_ERR); - if (err != NULL) { - *err = error; - } - } -#endif // #if !defined(CL_VERSION_1_2) || defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) - } - - //! \brief Default constructor - initializes to NULL. - Image3D() : Image() { } - - /*! \brief Constructor from cl_mem - takes ownership. - * - * See Memory for further details. - */ - __CL_EXPLICIT_CONSTRUCTORS Image3D(const cl_mem& image3D) : Image(image3D) { } - - /*! \brief Assignment from cl_mem - performs shallow copy. - * - * See Memory for further details. - */ - Image3D& operator = (const cl_mem& rhs) - { - Image::operator=(rhs); - return *this; - } - - /*! \brief Copy constructor to forward copy to the superclass correctly. - * Required for MSVC. - */ - Image3D(const Image3D& img) : Image(img) {} - - /*! \brief Copy assignment to forward copy to the superclass correctly. - * Required for MSVC. - */ - Image3D& operator = (const Image3D &img) - { - Image::operator=(img); - return *this; - } - -#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) - /*! \brief Move constructor to forward move to the superclass correctly. - * Required for MSVC. - */ - Image3D(Image3D&& img) CL_HPP_NOEXCEPT : Image(std::move(img)) {} - - /*! \brief Move assignment to forward move to the superclass correctly. - * Required for MSVC. - */ - Image3D& operator = (Image3D &&img) - { - Image::operator=(std::move(img)); - return *this; - } -#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) -}; - -#if !defined(CL_VERSION_1_2) -/*! \brief Class interface for GL 3D Image Memory objects. - * - * This is provided to facilitate interoperability with OpenGL. - * - * See Memory for details about copy semantics, etc. - * - * \see Memory - */ -class Image3DGL : public Image3D -{ -public: - /*! \brief Constructs an Image3DGL in a specified context, from a given - * GL Texture. - * - * Wraps clCreateFromGLTexture3D(). - */ - Image3DGL( - const Context& context, - cl_mem_flags flags, - cl_GLenum target, - cl_GLint miplevel, - cl_GLuint texobj, - cl_int * err = NULL) - { - cl_int error; - object_ = ::clCreateFromGLTexture3D( - context(), - flags, - target, - miplevel, - texobj, - &error); - - detail::errHandler(error, __CREATE_GL_TEXTURE_3D_ERR); - if (err != NULL) { - *err = error; - } - } - - //! \brief Default constructor - initializes to NULL. - Image3DGL() : Image3D() { } - - /*! \brief Constructor from cl_mem - takes ownership. - * - * See Memory for further details. - */ - __CL_EXPLICIT_CONSTRUCTORS Image3DGL(const cl_mem& image) : Image3D(image) { } - - /*! \brief Assignment from cl_mem - performs shallow copy. - * - * See Memory for further details. - */ - Image3DGL& operator = (const cl_mem& rhs) - { - Image3D::operator=(rhs); - return *this; - } - - /*! \brief Copy constructor to forward copy to the superclass correctly. - * Required for MSVC. - */ - Image3DGL(const Image3DGL& img) : Image3D(img) {} - - /*! \brief Copy assignment to forward copy to the superclass correctly. - * Required for MSVC. - */ - Image3DGL& operator = (const Image3DGL &img) - { - Image3D::operator=(img); - return *this; - } - -#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) - /*! \brief Move constructor to forward move to the superclass correctly. - * Required for MSVC. - */ - Image3DGL(Image3DGL&& img) CL_HPP_NOEXCEPT : Image3D(std::move(img)) {} - - /*! \brief Move assignment to forward move to the superclass correctly. - * Required for MSVC. - */ - Image3DGL& operator = (Image3DGL &&img) - { - Image3D::operator=(std::move(img)); - return *this; - } -#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) -}; -#endif // #if !defined(CL_VERSION_1_2) - -#if defined(CL_VERSION_1_2) -/*! \class ImageGL - * \brief general image interface for GL interop. - * We abstract the 2D and 3D GL images into a single instance here - * that wraps all GL sourced images on the grounds that setup information - * was performed by OpenCL anyway. - */ -class ImageGL : public Image -{ -public: - ImageGL( - const Context& context, - cl_mem_flags flags, - cl_GLenum target, - cl_GLint miplevel, - cl_GLuint texobj, - cl_int * err = NULL) - { - cl_int error; - object_ = ::clCreateFromGLTexture( - context(), - flags, - target, - miplevel, - texobj, - &error); - - detail::errHandler(error, __CREATE_GL_TEXTURE_ERR); - if (err != NULL) { - *err = error; - } - } - - ImageGL() : Image() { } - - __CL_EXPLICIT_CONSTRUCTORS ImageGL(const cl_mem& image) : Image(image) { } - - ImageGL& operator = (const cl_mem& rhs) - { - Image::operator=(rhs); - return *this; - } - - /*! \brief Copy constructor to forward copy to the superclass correctly. - * Required for MSVC. - */ - ImageGL(const ImageGL& img) : Image(img) {} - - /*! \brief Copy assignment to forward copy to the superclass correctly. - * Required for MSVC. - */ - ImageGL& operator = (const ImageGL &img) - { - Image::operator=(img); - return *this; - } - -#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) - /*! \brief Move constructor to forward move to the superclass correctly. - * Required for MSVC. - */ - ImageGL(ImageGL&& img) CL_HPP_NOEXCEPT : Image(std::move(img)) {} - - /*! \brief Move assignment to forward move to the superclass correctly. - * Required for MSVC. - */ - ImageGL& operator = (ImageGL &&img) - { - Image::operator=(std::move(img)); - return *this; - } -#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) -}; -#endif // #if defined(CL_VERSION_1_2) - -/*! \brief Class interface for GL Render Buffer Memory Objects. -* -* This is provided to facilitate interoperability with OpenGL. -* -* See Memory for details about copy semantics, etc. -* -* \see Memory -*/ -class BufferRenderGL : -#if defined(CL_VERSION_1_2) - public ImageGL -#else // #if defined(CL_VERSION_1_2) - public Image2DGL -#endif //#if defined(CL_VERSION_1_2) -{ -public: - /*! \brief Constructs a BufferRenderGL in a specified context, from a given - * GL Renderbuffer. - * - * Wraps clCreateFromGLRenderbuffer(). - */ - BufferRenderGL( - const Context& context, - cl_mem_flags flags, - cl_GLuint bufobj, - cl_int * err = NULL) - { - cl_int error; - object_ = ::clCreateFromGLRenderbuffer( - context(), - flags, - bufobj, - &error); - - detail::errHandler(error, __CREATE_GL_RENDER_BUFFER_ERR); - if (err != NULL) { - *err = error; - } - } - - //! \brief Default constructor - initializes to NULL. -#if defined(CL_VERSION_1_2) - BufferRenderGL() : ImageGL() {}; -#else // #if defined(CL_VERSION_1_2) - BufferRenderGL() : Image2DGL() {}; -#endif //#if defined(CL_VERSION_1_2) - - /*! \brief Constructor from cl_mem - takes ownership. - * - * See Memory for further details. - */ -#if defined(CL_VERSION_1_2) - __CL_EXPLICIT_CONSTRUCTORS BufferRenderGL(const cl_mem& buffer) : ImageGL(buffer) { } -#else // #if defined(CL_VERSION_1_2) - __CL_EXPLICIT_CONSTRUCTORS BufferRenderGL(const cl_mem& buffer) : Image2DGL(buffer) { } -#endif //#if defined(CL_VERSION_1_2) - - - /*! \brief Assignment from cl_mem - performs shallow copy. - * - * See Memory for further details. - */ - BufferRenderGL& operator = (const cl_mem& rhs) - { -#if defined(CL_VERSION_1_2) - ImageGL::operator=(rhs); -#else // #if defined(CL_VERSION_1_2) - Image2DGL::operator=(rhs); -#endif //#if defined(CL_VERSION_1_2) - - return *this; - } - - /*! \brief Copy constructor to forward copy to the superclass correctly. - * Required for MSVC. - */ -#if defined(CL_VERSION_1_2) - BufferRenderGL(const BufferRenderGL& buf) : ImageGL(buf) {} -#else // #if defined(CL_VERSION_1_2) - BufferRenderGL(const BufferRenderGL& buf) : Image2DGL(buf) {} -#endif //#if defined(CL_VERSION_1_2) - - /*! \brief Copy assignment to forward copy to the superclass correctly. - * Required for MSVC. - */ - BufferRenderGL& operator = (const BufferRenderGL &rhs) - { -#if defined(CL_VERSION_1_2) - ImageGL::operator=(rhs); -#else // #if defined(CL_VERSION_1_2) - Image2DGL::operator=(rhs); -#endif //#if defined(CL_VERSION_1_2) - return *this; - } - -#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) - /*! \brief Move constructor to forward move to the superclass correctly. - * Required for MSVC. - */ -#if defined(CL_VERSION_1_2) - BufferRenderGL(BufferRenderGL&& buf) CL_HPP_NOEXCEPT : ImageGL(std::move(buf)) {} -#else // #if defined(CL_VERSION_1_2) - BufferRenderGL(BufferRenderGL&& buf) CL_HPP_NOEXCEPT : Image2DGL(std::move(buf)) {} -#endif //#if defined(CL_VERSION_1_2) - - - /*! \brief Move assignment to forward move to the superclass correctly. - * Required for MSVC. - */ - BufferRenderGL& operator = (BufferRenderGL &&buf) - { -#if defined(CL_VERSION_1_2) - ImageGL::operator=(std::move(buf)); -#else // #if defined(CL_VERSION_1_2) - Image2DGL::operator=(std::move(buf)); -#endif //#if defined(CL_VERSION_1_2) - - return *this; - } -#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) - - //! \brief Wrapper for clGetGLObjectInfo(). - cl_int getObjectInfo( - cl_gl_object_type *type, - cl_GLuint * gl_object_name) - { - return detail::errHandler( - ::clGetGLObjectInfo(object_, type, gl_object_name), - __GET_GL_OBJECT_INFO_ERR); - } -}; - -/*! \brief Class interface for cl_sampler. - * - * \note Copies of these objects are shallow, meaning that the copy will refer - * to the same underlying cl_sampler as the original. For details, see - * clRetainSampler() and clReleaseSampler(). - * - * \see cl_sampler - */ -class Sampler : public detail::Wrapper -{ -public: - //! \brief Default constructor - initializes to NULL. - Sampler() { } - - /*! \brief Constructs a Sampler in a specified context. - * - * Wraps clCreateSampler(). - */ - Sampler( - const Context& context, - cl_bool normalized_coords, - cl_addressing_mode addressing_mode, - cl_filter_mode filter_mode, - cl_int* err = NULL) - { - cl_int error; - object_ = ::clCreateSampler( - context(), - normalized_coords, - addressing_mode, - filter_mode, - &error); - - detail::errHandler(error, __CREATE_SAMPLER_ERR); - if (err != NULL) { - *err = error; - } - } - - /*! \brief Constructor from cl_sampler - takes ownership. - * - * This effectively transfers ownership of a refcount on the cl_sampler - * into the new Sampler object. - */ - __CL_EXPLICIT_CONSTRUCTORS Sampler(const cl_sampler& sampler) : detail::Wrapper(sampler) { } - - /*! \brief Assignment operator from cl_sampler - takes ownership. - * - * This effectively transfers ownership of a refcount on the rhs and calls - * clReleaseSampler() on the value previously held by this instance. - */ - Sampler& operator = (const cl_sampler& rhs) - { - detail::Wrapper::operator=(rhs); - return *this; - } - - /*! \brief Copy constructor to forward copy to the superclass correctly. - * Required for MSVC. - */ - Sampler(const Sampler& sam) : detail::Wrapper(sam) {} - - /*! \brief Copy assignment to forward copy to the superclass correctly. - * Required for MSVC. - */ - Sampler& operator = (const Sampler &sam) - { - detail::Wrapper::operator=(sam); - return *this; - } - -#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) - /*! \brief Move constructor to forward move to the superclass correctly. - * Required for MSVC. - */ - Sampler(Sampler&& sam) CL_HPP_NOEXCEPT : detail::Wrapper(std::move(sam)) {} - - /*! \brief Move assignment to forward move to the superclass correctly. - * Required for MSVC. - */ - Sampler& operator = (Sampler &&sam) - { - detail::Wrapper::operator=(std::move(sam)); - return *this; - } -#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) - - //! \brief Wrapper for clGetSamplerInfo(). - template - cl_int getInfo(cl_sampler_info name, T* param) const - { - return detail::errHandler( - detail::getInfo(&::clGetSamplerInfo, object_, name, param), - __GET_SAMPLER_INFO_ERR); - } - - //! \brief Wrapper for clGetSamplerInfo() that returns by value. - template typename - detail::param_traits::param_type - getInfo(cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_sampler_info, name>::param_type param; - cl_int result = getInfo(name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } -}; - -class Program; -class CommandQueue; -class Kernel; - -//! \brief Class interface for specifying NDRange values. -class NDRange -{ -private: - size_t<3> sizes_; - cl_uint dimensions_; - -public: - //! \brief Default constructor - resulting range has zero dimensions. - NDRange() - : dimensions_(0) - { } - - //! \brief Constructs one-dimensional range. - NDRange(::size_t size0) - : dimensions_(1) - { - sizes_[0] = size0; - } - - //! \brief Constructs two-dimensional range. - NDRange(::size_t size0, ::size_t size1) - : dimensions_(2) - { - sizes_[0] = size0; - sizes_[1] = size1; - } - - //! \brief Constructs three-dimensional range. - NDRange(::size_t size0, ::size_t size1, ::size_t size2) - : dimensions_(3) - { - sizes_[0] = size0; - sizes_[1] = size1; - sizes_[2] = size2; - } - - /*! \brief Conversion operator to const ::size_t *. - * - * \returns a pointer to the size of the first dimension. - */ - operator const ::size_t*() const { - return (const ::size_t*) sizes_; - } - - //! \brief Queries the number of dimensions in the range. - ::size_t dimensions() const { return dimensions_; } -}; - -//! \brief A zero-dimensional range. -static const NDRange NullRange; - -//! \brief Local address wrapper for use with Kernel::setArg -struct LocalSpaceArg -{ - ::size_t size_; -}; - -namespace detail { - -template -struct KernelArgumentHandler -{ - static ::size_t size(const T&) { return sizeof(T); } - static const T* ptr(const T& value) { return &value; } -}; - -template <> -struct KernelArgumentHandler -{ - static ::size_t size(const LocalSpaceArg& value) { return value.size_; } - static const void* ptr(const LocalSpaceArg&) { return NULL; } -}; - -} -//! \endcond - -/*! __local - * \brief Helper function for generating LocalSpaceArg objects. - * Deprecated. Replaced with Local. - */ -inline CL_EXT_PREFIX__VERSION_1_1_DEPRECATED LocalSpaceArg -__local(::size_t size) CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; -inline LocalSpaceArg -__local(::size_t size) -{ - LocalSpaceArg ret = { size }; - return ret; -} - -/*! Local - * \brief Helper function for generating LocalSpaceArg objects. - */ -inline LocalSpaceArg -Local(::size_t size) -{ - LocalSpaceArg ret = { size }; - return ret; -} - -//class KernelFunctor; - -/*! \brief Class interface for cl_kernel. - * - * \note Copies of these objects are shallow, meaning that the copy will refer - * to the same underlying cl_kernel as the original. For details, see - * clRetainKernel() and clReleaseKernel(). - * - * \see cl_kernel - */ -class Kernel : public detail::Wrapper -{ -public: - inline Kernel(const Program& program, const char* name, cl_int* err = NULL); - - //! \brief Default constructor - initializes to NULL. - Kernel() { } - - /*! \brief Constructor from cl_kernel - takes ownership. - * - * This effectively transfers ownership of a refcount on the cl_kernel - * into the new Kernel object. - */ - __CL_EXPLICIT_CONSTRUCTORS Kernel(const cl_kernel& kernel) : detail::Wrapper(kernel) { } - - /*! \brief Assignment operator from cl_kernel - takes ownership. - * - * This effectively transfers ownership of a refcount on the rhs and calls - * clReleaseKernel() on the value previously held by this instance. - */ - Kernel& operator = (const cl_kernel& rhs) - { - detail::Wrapper::operator=(rhs); - return *this; - } - - /*! \brief Copy constructor to forward copy to the superclass correctly. - * Required for MSVC. - */ - Kernel(const Kernel& kernel) : detail::Wrapper(kernel) {} - - /*! \brief Copy assignment to forward copy to the superclass correctly. - * Required for MSVC. - */ - Kernel& operator = (const Kernel &kernel) - { - detail::Wrapper::operator=(kernel); - return *this; - } - -#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) - /*! \brief Move constructor to forward move to the superclass correctly. - * Required for MSVC. - */ - Kernel(Kernel&& kernel) CL_HPP_NOEXCEPT : detail::Wrapper(std::move(kernel)) {} - - /*! \brief Move assignment to forward move to the superclass correctly. - * Required for MSVC. - */ - Kernel& operator = (Kernel &&kernel) - { - detail::Wrapper::operator=(std::move(kernel)); - return *this; - } -#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) - - template - cl_int getInfo(cl_kernel_info name, T* param) const - { - return detail::errHandler( - detail::getInfo(&::clGetKernelInfo, object_, name, param), - __GET_KERNEL_INFO_ERR); - } - - template typename - detail::param_traits::param_type - getInfo(cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_kernel_info, name>::param_type param; - cl_int result = getInfo(name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } - -#if defined(CL_VERSION_1_2) - template - cl_int getArgInfo(cl_uint argIndex, cl_kernel_arg_info name, T* param) const - { - return detail::errHandler( - detail::getInfo(&::clGetKernelArgInfo, object_, argIndex, name, param), - __GET_KERNEL_ARG_INFO_ERR); - } - - template typename - detail::param_traits::param_type - getArgInfo(cl_uint argIndex, cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_kernel_arg_info, name>::param_type param; - cl_int result = getArgInfo(argIndex, name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } -#endif // #if defined(CL_VERSION_1_2) - - template - cl_int getWorkGroupInfo( - const Device& device, cl_kernel_work_group_info name, T* param) const - { - return detail::errHandler( - detail::getInfo( - &::clGetKernelWorkGroupInfo, object_, device(), name, param), - __GET_KERNEL_WORK_GROUP_INFO_ERR); - } - - template typename - detail::param_traits::param_type - getWorkGroupInfo(const Device& device, cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_kernel_work_group_info, name>::param_type param; - cl_int result = getWorkGroupInfo(device, name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } - - template - cl_int setArg(cl_uint index, const T &value) - { - return detail::errHandler( - ::clSetKernelArg( - object_, - index, - detail::KernelArgumentHandler::size(value), - detail::KernelArgumentHandler::ptr(value)), - __SET_KERNEL_ARGS_ERR); - } - - cl_int setArg(cl_uint index, ::size_t size, const void* argPtr) - { - return detail::errHandler( - ::clSetKernelArg(object_, index, size, argPtr), - __SET_KERNEL_ARGS_ERR); - } -}; - -/*! \class Program - * \brief Program interface that implements cl_program. - */ -class Program : public detail::Wrapper -{ -public: - typedef VECTOR_CLASS > Binaries; - typedef VECTOR_CLASS > Sources; - - Program( - const STRING_CLASS& source, - bool build = false, - cl_int* err = NULL) - { - cl_int error; - - const char * strings = source.c_str(); - const ::size_t length = source.size(); - - Context context = Context::getDefault(err); - - object_ = ::clCreateProgramWithSource( - context(), (cl_uint)1, &strings, &length, &error); - - detail::errHandler(error, __CREATE_PROGRAM_WITH_SOURCE_ERR); - - if (error == CL_SUCCESS && build) { - - error = ::clBuildProgram( - object_, - 0, - NULL, - "", - NULL, - NULL); - - detail::errHandler(error, __BUILD_PROGRAM_ERR); - } - - if (err != NULL) { - *err = error; - } - } - - Program( - const Context& context, - const STRING_CLASS& source, - bool build = false, - cl_int* err = NULL) - { - cl_int error; - - const char * strings = source.c_str(); - const ::size_t length = source.size(); - - object_ = ::clCreateProgramWithSource( - context(), (cl_uint)1, &strings, &length, &error); - - detail::errHandler(error, __CREATE_PROGRAM_WITH_SOURCE_ERR); - - if (error == CL_SUCCESS && build) { - - error = ::clBuildProgram( - object_, - 0, - NULL, - "", - NULL, - NULL); - - detail::errHandler(error, __BUILD_PROGRAM_ERR); - } - - if (err != NULL) { - *err = error; - } - } - - Program( - const Context& context, - const Sources& sources, - cl_int* err = NULL) - { - cl_int error; - - const ::size_t n = (::size_t)sources.size(); - ::size_t* lengths = (::size_t*) alloca(n * sizeof(::size_t)); - const char** strings = (const char**) alloca(n * sizeof(const char*)); - - for (::size_t i = 0; i < n; ++i) { - strings[i] = sources[(int)i].first; - lengths[i] = sources[(int)i].second; - } - - object_ = ::clCreateProgramWithSource( - context(), (cl_uint)n, strings, lengths, &error); - - detail::errHandler(error, __CREATE_PROGRAM_WITH_SOURCE_ERR); - if (err != NULL) { - *err = error; - } - } - - /** - * Construct a program object from a list of devices and a per-device list of binaries. - * \param context A valid OpenCL context in which to construct the program. - * \param devices A vector of OpenCL device objects for which the program will be created. - * \param binaries A vector of pairs of a pointer to a binary object and its length. - * \param binaryStatus An optional vector that on completion will be resized to - * match the size of binaries and filled with values to specify if each binary - * was successfully loaded. - * Set to CL_SUCCESS if the binary was successfully loaded. - * Set to CL_INVALID_VALUE if the length is 0 or the binary pointer is NULL. - * Set to CL_INVALID_BINARY if the binary provided is not valid for the matching device. - * \param err if non-NULL will be set to CL_SUCCESS on successful operation or one of the following errors: - * CL_INVALID_CONTEXT if context is not a valid context. - * CL_INVALID_VALUE if the length of devices is zero; or if the length of binaries does not match the length of devices; - * or if any entry in binaries is NULL or has length 0. - * CL_INVALID_DEVICE if OpenCL devices listed in devices are not in the list of devices associated with context. - * CL_INVALID_BINARY if an invalid program binary was encountered for any device. binaryStatus will return specific status for each device. - * CL_OUT_OF_HOST_MEMORY if there is a failure to allocate resources required by the OpenCL implementation on the host. - */ - Program( - const Context& context, - const VECTOR_CLASS& devices, - const Binaries& binaries, - VECTOR_CLASS* binaryStatus = NULL, - cl_int* err = NULL) - { - cl_int error; - - const ::size_t numDevices = devices.size(); - - // Catch size mismatch early and return - if(binaries.size() != numDevices) { - error = CL_INVALID_VALUE; - detail::errHandler(error, __CREATE_PROGRAM_WITH_BINARY_ERR); - if (err != NULL) { - *err = error; - } - return; - } - - ::size_t* lengths = (::size_t*) alloca(numDevices * sizeof(::size_t)); - const unsigned char** images = (const unsigned char**) alloca(numDevices * sizeof(const unsigned char**)); - - for (::size_t i = 0; i < numDevices; ++i) { - images[i] = (const unsigned char*)binaries[i].first; - lengths[i] = binaries[(int)i].second; - } - - cl_device_id* deviceIDs = (cl_device_id*) alloca(numDevices * sizeof(cl_device_id)); - for( ::size_t deviceIndex = 0; deviceIndex < numDevices; ++deviceIndex ) { - deviceIDs[deviceIndex] = (devices[deviceIndex])(); - } - - if(binaryStatus) { - binaryStatus->resize(numDevices); - } - - object_ = ::clCreateProgramWithBinary( - context(), (cl_uint) devices.size(), - deviceIDs, - lengths, images, (binaryStatus != NULL && numDevices > 0) - ? &binaryStatus->front() - : NULL, &error); - - detail::errHandler(error, __CREATE_PROGRAM_WITH_BINARY_ERR); - if (err != NULL) { - *err = error; - } - } - - -#if defined(CL_VERSION_1_2) - /** - * Create program using builtin kernels. - * \param kernelNames Semi-colon separated list of builtin kernel names - */ - Program( - const Context& context, - const VECTOR_CLASS& devices, - const STRING_CLASS& kernelNames, - cl_int* err = NULL) - { - cl_int error; - - - ::size_t numDevices = devices.size(); - cl_device_id* deviceIDs = (cl_device_id*) alloca(numDevices * sizeof(cl_device_id)); - for( ::size_t deviceIndex = 0; deviceIndex < numDevices; ++deviceIndex ) { - deviceIDs[deviceIndex] = (devices[deviceIndex])(); - } - - object_ = ::clCreateProgramWithBuiltInKernels( - context(), - (cl_uint) devices.size(), - deviceIDs, - kernelNames.c_str(), - &error); - - detail::errHandler(error, __CREATE_PROGRAM_WITH_BUILT_IN_KERNELS_ERR); - if (err != NULL) { - *err = error; - } - } -#endif // #if defined(CL_VERSION_1_2) - - Program() { } - - __CL_EXPLICIT_CONSTRUCTORS Program(const cl_program& program) : detail::Wrapper(program) { } - - Program& operator = (const cl_program& rhs) - { - detail::Wrapper::operator=(rhs); - return *this; - } - - /*! \brief Copy constructor to forward copy to the superclass correctly. - * Required for MSVC. - */ - Program(const Program& program) : detail::Wrapper(program) {} - - /*! \brief Copy assignment to forward copy to the superclass correctly. - * Required for MSVC. - */ - Program& operator = (const Program &program) - { - detail::Wrapper::operator=(program); - return *this; - } - -#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) - /*! \brief Move constructor to forward move to the superclass correctly. - * Required for MSVC. - */ - Program(Program&& program) CL_HPP_NOEXCEPT : detail::Wrapper(std::move(program)) {} - - /*! \brief Move assignment to forward move to the superclass correctly. - * Required for MSVC. - */ - Program& operator = (Program &&program) - { - detail::Wrapper::operator=(std::move(program)); - return *this; - } -#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) - - cl_int build( - const VECTOR_CLASS& devices, - const char* options = NULL, - void (CL_CALLBACK * notifyFptr)(cl_program, void *) = NULL, - void* data = NULL) const - { - ::size_t numDevices = devices.size(); - cl_device_id* deviceIDs = (cl_device_id*) alloca(numDevices * sizeof(cl_device_id)); - for( ::size_t deviceIndex = 0; deviceIndex < numDevices; ++deviceIndex ) { - deviceIDs[deviceIndex] = (devices[deviceIndex])(); - } - - return detail::errHandler( - ::clBuildProgram( - object_, - (cl_uint) - devices.size(), - deviceIDs, - options, - notifyFptr, - data), - __BUILD_PROGRAM_ERR); - } - - cl_int build( - const char* options = NULL, - void (CL_CALLBACK * notifyFptr)(cl_program, void *) = NULL, - void* data = NULL) const - { - return detail::errHandler( - ::clBuildProgram( - object_, - 0, - NULL, - options, - notifyFptr, - data), - __BUILD_PROGRAM_ERR); - } - -#if defined(CL_VERSION_1_2) - cl_int compile( - const char* options = NULL, - void (CL_CALLBACK * notifyFptr)(cl_program, void *) = NULL, - void* data = NULL) const - { - return detail::errHandler( - ::clCompileProgram( - object_, - 0, - NULL, - options, - 0, - NULL, - NULL, - notifyFptr, - data), - __COMPILE_PROGRAM_ERR); - } -#endif - - template - cl_int getInfo(cl_program_info name, T* param) const - { - return detail::errHandler( - detail::getInfo(&::clGetProgramInfo, object_, name, param), - __GET_PROGRAM_INFO_ERR); - } - - template typename - detail::param_traits::param_type - getInfo(cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_program_info, name>::param_type param; - cl_int result = getInfo(name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } - - template - cl_int getBuildInfo( - const Device& device, cl_program_build_info name, T* param) const - { - return detail::errHandler( - detail::getInfo( - &::clGetProgramBuildInfo, object_, device(), name, param), - __GET_PROGRAM_BUILD_INFO_ERR); - } - - template typename - detail::param_traits::param_type - getBuildInfo(const Device& device, cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_program_build_info, name>::param_type param; - cl_int result = getBuildInfo(device, name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } - - cl_int createKernels(VECTOR_CLASS* kernels) - { - cl_uint numKernels; - cl_int err = ::clCreateKernelsInProgram(object_, 0, NULL, &numKernels); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __CREATE_KERNELS_IN_PROGRAM_ERR); - } - - Kernel* value = (Kernel*) alloca(numKernels * sizeof(Kernel)); - err = ::clCreateKernelsInProgram( - object_, numKernels, (cl_kernel*) value, NULL); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __CREATE_KERNELS_IN_PROGRAM_ERR); - } - - kernels->assign(&value[0], &value[numKernels]); - return CL_SUCCESS; - } -}; - -#if defined(CL_VERSION_1_2) -inline Program linkProgram( - Program input1, - Program input2, - const char* options = NULL, - void (CL_CALLBACK * notifyFptr)(cl_program, void *) = NULL, - void* data = NULL, - cl_int* err = NULL) -{ - cl_int error_local = CL_SUCCESS; - - cl_program programs[2] = { input1(), input2() }; - - Context ctx = input1.getInfo(&error_local); - if(error_local!=CL_SUCCESS) { - detail::errHandler(error_local, __LINK_PROGRAM_ERR); - } - - cl_program prog = ::clLinkProgram( - ctx(), - 0, - NULL, - options, - 2, - programs, - notifyFptr, - data, - &error_local); - - detail::errHandler(error_local,__COMPILE_PROGRAM_ERR); - if (err != NULL) { - *err = error_local; - } - - return Program(prog); -} - -inline Program linkProgram( - VECTOR_CLASS inputPrograms, - const char* options = NULL, - void (CL_CALLBACK * notifyFptr)(cl_program, void *) = NULL, - void* data = NULL, - cl_int* err = NULL) -{ - cl_int error_local = CL_SUCCESS; - - cl_program * programs = (cl_program*) alloca(inputPrograms.size() * sizeof(cl_program)); - - if (programs != NULL) { - for (unsigned int i = 0; i < inputPrograms.size(); i++) { - programs[i] = inputPrograms[i](); - } - } - - Context ctx; - if(inputPrograms.size() > 0) { - ctx = inputPrograms[0].getInfo(&error_local); - if(error_local!=CL_SUCCESS) { - detail::errHandler(error_local, __LINK_PROGRAM_ERR); - } - } - cl_program prog = ::clLinkProgram( - ctx(), - 0, - NULL, - options, - (cl_uint)inputPrograms.size(), - programs, - notifyFptr, - data, - &error_local); - - detail::errHandler(error_local,__COMPILE_PROGRAM_ERR); - if (err != NULL) { - *err = error_local; - } - - return Program(prog); -} -#endif - -template<> -inline VECTOR_CLASS cl::Program::getInfo(cl_int* err) const -{ - VECTOR_CLASS< ::size_t> sizes = getInfo(); - VECTOR_CLASS binaries; - for (VECTOR_CLASS< ::size_t>::iterator s = sizes.begin(); s != sizes.end(); ++s) - { - char *ptr = NULL; - if (*s != 0) - ptr = new char[*s]; - binaries.push_back(ptr); - } - - cl_int result = getInfo(CL_PROGRAM_BINARIES, &binaries); - if (err != NULL) { - *err = result; - } - return binaries; -} - -inline Kernel::Kernel(const Program& program, const char* name, cl_int* err) -{ - cl_int error; - - object_ = ::clCreateKernel(program(), name, &error); - detail::errHandler(error, __CREATE_KERNEL_ERR); - - if (err != NULL) { - *err = error; - } - -} - -/*! \class CommandQueue - * \brief CommandQueue interface for cl_command_queue. - */ -class CommandQueue : public detail::Wrapper -{ -private: -#ifdef CL_HPP_CPP11_ATOMICS_SUPPORTED - static std::atomic default_initialized_; -#else // !CL_HPP_CPP11_ATOMICS_SUPPORTED - static volatile int default_initialized_; -#endif // !CL_HPP_CPP11_ATOMICS_SUPPORTED - static CommandQueue default_; - static volatile cl_int default_error_; -public: - CommandQueue( - cl_command_queue_properties properties, - cl_int* err = NULL) - { - cl_int error; - - Context context = Context::getDefault(&error); - detail::errHandler(error, __CREATE_CONTEXT_ERR); - - if (error != CL_SUCCESS) { - if (err != NULL) { - *err = error; - } - } - else { - Device device = context.getInfo()[0]; - - object_ = ::clCreateCommandQueue( - context(), device(), properties, &error); - - detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR); - if (err != NULL) { - *err = error; - } - } - } - /*! - * \brief Constructs a CommandQueue for an implementation defined device in the given context - */ - explicit CommandQueue( - const Context& context, - cl_command_queue_properties properties = 0, - cl_int* err = NULL) - { - cl_int error; - VECTOR_CLASS devices; - error = context.getInfo(CL_CONTEXT_DEVICES, &devices); - - detail::errHandler(error, __CREATE_CONTEXT_ERR); - - if (error != CL_SUCCESS) - { - if (err != NULL) { - *err = error; - } - return; - } - - object_ = ::clCreateCommandQueue(context(), devices[0](), properties, &error); - - detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR); - - if (err != NULL) { - *err = error; - } - - } - - CommandQueue( - const Context& context, - const Device& device, - cl_command_queue_properties properties = 0, - cl_int* err = NULL) - { - cl_int error; - object_ = ::clCreateCommandQueue( - context(), device(), properties, &error); - - detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR); - if (err != NULL) { - *err = error; - } - } - - /*! \brief Copy constructor to forward copy to the superclass correctly. - * Required for MSVC. - */ - CommandQueue(const CommandQueue& queue) : detail::Wrapper(queue) {} - - /*! \brief Copy assignment to forward copy to the superclass correctly. - * Required for MSVC. - */ - CommandQueue& operator = (const CommandQueue &queue) - { - detail::Wrapper::operator=(queue); - return *this; - } - -#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) - /*! \brief Move constructor to forward move to the superclass correctly. - * Required for MSVC. - */ - CommandQueue(CommandQueue&& queue) CL_HPP_NOEXCEPT : detail::Wrapper(std::move(queue)) {} - - /*! \brief Move assignment to forward move to the superclass correctly. - * Required for MSVC. - */ - CommandQueue& operator = (CommandQueue &&queue) - { - detail::Wrapper::operator=(std::move(queue)); - return *this; - } -#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) - - static CommandQueue getDefault(cl_int * err = NULL) - { - int state = detail::compare_exchange( - &default_initialized_, - __DEFAULT_BEING_INITIALIZED, __DEFAULT_NOT_INITIALIZED); - - if (state & __DEFAULT_INITIALIZED) { - if (err != NULL) { - *err = default_error_; - } - return default_; - } - - if (state & __DEFAULT_BEING_INITIALIZED) { - // Assume writes will propagate eventually... - while(default_initialized_ != __DEFAULT_INITIALIZED) { - detail::fence(); - } - - if (err != NULL) { - *err = default_error_; - } - return default_; - } - - cl_int error; - - Context context = Context::getDefault(&error); - detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR); - - if (error != CL_SUCCESS) { - if (err != NULL) { - *err = error; - } - } - else { - Device device = context.getInfo()[0]; - - default_ = CommandQueue(context, device, 0, &error); - - detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR); - if (err != NULL) { - *err = error; - } - } - - detail::fence(); - - default_error_ = error; - // Assume writes will propagate eventually... - default_initialized_ = __DEFAULT_INITIALIZED; - - detail::fence(); - - if (err != NULL) { - *err = default_error_; - } - return default_; - - } - - CommandQueue() { } - - __CL_EXPLICIT_CONSTRUCTORS CommandQueue(const cl_command_queue& commandQueue) : detail::Wrapper(commandQueue) { } - - CommandQueue& operator = (const cl_command_queue& rhs) - { - detail::Wrapper::operator=(rhs); - return *this; - } - - template - cl_int getInfo(cl_command_queue_info name, T* param) const - { - return detail::errHandler( - detail::getInfo( - &::clGetCommandQueueInfo, object_, name, param), - __GET_COMMAND_QUEUE_INFO_ERR); - } - - template typename - detail::param_traits::param_type - getInfo(cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_command_queue_info, name>::param_type param; - cl_int result = getInfo(name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } - - cl_int enqueueReadBuffer( - const Buffer& buffer, - cl_bool blocking, - ::size_t offset, - ::size_t size, - void* ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueReadBuffer( - object_, buffer(), blocking, offset, size, - ptr, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_READ_BUFFER_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - cl_int enqueueWriteBuffer( - const Buffer& buffer, - cl_bool blocking, - ::size_t offset, - ::size_t size, - const void* ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueWriteBuffer( - object_, buffer(), blocking, offset, size, - ptr, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_WRITE_BUFFER_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - cl_int enqueueCopyBuffer( - const Buffer& src, - const Buffer& dst, - ::size_t src_offset, - ::size_t dst_offset, - ::size_t size, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueCopyBuffer( - object_, src(), dst(), src_offset, dst_offset, size, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQEUE_COPY_BUFFER_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - cl_int enqueueReadBufferRect( - const Buffer& buffer, - cl_bool blocking, - const size_t<3>& buffer_offset, - const size_t<3>& host_offset, - const size_t<3>& region, - ::size_t buffer_row_pitch, - ::size_t buffer_slice_pitch, - ::size_t host_row_pitch, - ::size_t host_slice_pitch, - void *ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueReadBufferRect( - object_, - buffer(), - blocking, - (const ::size_t *)buffer_offset, - (const ::size_t *)host_offset, - (const ::size_t *)region, - buffer_row_pitch, - buffer_slice_pitch, - host_row_pitch, - host_slice_pitch, - ptr, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_READ_BUFFER_RECT_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - cl_int enqueueWriteBufferRect( - const Buffer& buffer, - cl_bool blocking, - const size_t<3>& buffer_offset, - const size_t<3>& host_offset, - const size_t<3>& region, - ::size_t buffer_row_pitch, - ::size_t buffer_slice_pitch, - ::size_t host_row_pitch, - ::size_t host_slice_pitch, - const void *ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueWriteBufferRect( - object_, - buffer(), - blocking, - (const ::size_t *)buffer_offset, - (const ::size_t *)host_offset, - (const ::size_t *)region, - buffer_row_pitch, - buffer_slice_pitch, - host_row_pitch, - host_slice_pitch, - ptr, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_WRITE_BUFFER_RECT_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - cl_int enqueueCopyBufferRect( - const Buffer& src, - const Buffer& dst, - const size_t<3>& src_origin, - const size_t<3>& dst_origin, - const size_t<3>& region, - ::size_t src_row_pitch, - ::size_t src_slice_pitch, - ::size_t dst_row_pitch, - ::size_t dst_slice_pitch, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueCopyBufferRect( - object_, - src(), - dst(), - (const ::size_t *)src_origin, - (const ::size_t *)dst_origin, - (const ::size_t *)region, - src_row_pitch, - src_slice_pitch, - dst_row_pitch, - dst_slice_pitch, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQEUE_COPY_BUFFER_RECT_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - -#if defined(CL_VERSION_1_2) - /** - * Enqueue a command to fill a buffer object with a pattern - * of a given size. The pattern is specified a as vector. - * \tparam PatternType The datatype of the pattern field. - * The pattern type must be an accepted OpenCL data type. - */ - template - cl_int enqueueFillBuffer( - const Buffer& buffer, - PatternType pattern, - ::size_t offset, - ::size_t size, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueFillBuffer( - object_, - buffer(), - static_cast(&pattern), - sizeof(PatternType), - offset, - size, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_FILL_BUFFER_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } -#endif // #if defined(CL_VERSION_1_2) - - cl_int enqueueReadImage( - const Image& image, - cl_bool blocking, - const size_t<3>& origin, - const size_t<3>& region, - ::size_t row_pitch, - ::size_t slice_pitch, - void* ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueReadImage( - object_, image(), blocking, (const ::size_t *) origin, - (const ::size_t *) region, row_pitch, slice_pitch, ptr, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_READ_IMAGE_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - cl_int enqueueWriteImage( - const Image& image, - cl_bool blocking, - const size_t<3>& origin, - const size_t<3>& region, - ::size_t row_pitch, - ::size_t slice_pitch, - const void* ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueWriteImage( - object_, image(), blocking, (const ::size_t *) origin, - (const ::size_t *) region, row_pitch, slice_pitch, ptr, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_WRITE_IMAGE_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - cl_int enqueueCopyImage( - const Image& src, - const Image& dst, - const size_t<3>& src_origin, - const size_t<3>& dst_origin, - const size_t<3>& region, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueCopyImage( - object_, src(), dst(), (const ::size_t *) src_origin, - (const ::size_t *)dst_origin, (const ::size_t *) region, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_COPY_IMAGE_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - -#if defined(CL_VERSION_1_2) - /** - * Enqueue a command to fill an image object with a specified color. - * \param fillColor is the color to use to fill the image. - * This is a four component RGBA floating-point color value if - * the image channel data type is not an unnormalized signed or - * unsigned data type. - */ - cl_int enqueueFillImage( - const Image& image, - cl_float4 fillColor, - const size_t<3>& origin, - const size_t<3>& region, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueFillImage( - object_, - image(), - static_cast(&fillColor), - (const ::size_t *) origin, - (const ::size_t *) region, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_FILL_IMAGE_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - /** - * Enqueue a command to fill an image object with a specified color. - * \param fillColor is the color to use to fill the image. - * This is a four component RGBA signed integer color value if - * the image channel data type is an unnormalized signed integer - * type. - */ - cl_int enqueueFillImage( - const Image& image, - cl_int4 fillColor, - const size_t<3>& origin, - const size_t<3>& region, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueFillImage( - object_, - image(), - static_cast(&fillColor), - (const ::size_t *) origin, - (const ::size_t *) region, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_FILL_IMAGE_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - /** - * Enqueue a command to fill an image object with a specified color. - * \param fillColor is the color to use to fill the image. - * This is a four component RGBA unsigned integer color value if - * the image channel data type is an unnormalized unsigned integer - * type. - */ - cl_int enqueueFillImage( - const Image& image, - cl_uint4 fillColor, - const size_t<3>& origin, - const size_t<3>& region, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueFillImage( - object_, - image(), - static_cast(&fillColor), - (const ::size_t *) origin, - (const ::size_t *) region, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_FILL_IMAGE_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } -#endif // #if defined(CL_VERSION_1_2) - - cl_int enqueueCopyImageToBuffer( - const Image& src, - const Buffer& dst, - const size_t<3>& src_origin, - const size_t<3>& region, - ::size_t dst_offset, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueCopyImageToBuffer( - object_, src(), dst(), (const ::size_t *) src_origin, - (const ::size_t *) region, dst_offset, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_COPY_IMAGE_TO_BUFFER_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - cl_int enqueueCopyBufferToImage( - const Buffer& src, - const Image& dst, - ::size_t src_offset, - const size_t<3>& dst_origin, - const size_t<3>& region, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueCopyBufferToImage( - object_, src(), dst(), src_offset, - (const ::size_t *) dst_origin, (const ::size_t *) region, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_COPY_BUFFER_TO_IMAGE_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - void* enqueueMapBuffer( - const Buffer& buffer, - cl_bool blocking, - cl_map_flags flags, - ::size_t offset, - ::size_t size, - const VECTOR_CLASS* events = NULL, - Event* event = NULL, - cl_int* err = NULL) const - { - cl_event tmp; - cl_int error; - void * result = ::clEnqueueMapBuffer( - object_, buffer(), blocking, flags, offset, size, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL, - &error); - - detail::errHandler(error, __ENQUEUE_MAP_BUFFER_ERR); - if (err != NULL) { - *err = error; - } - if (event != NULL && error == CL_SUCCESS) - *event = tmp; - - return result; - } - - void* enqueueMapImage( - const Image& buffer, - cl_bool blocking, - cl_map_flags flags, - const size_t<3>& origin, - const size_t<3>& region, - ::size_t * row_pitch, - ::size_t * slice_pitch, - const VECTOR_CLASS* events = NULL, - Event* event = NULL, - cl_int* err = NULL) const - { - cl_event tmp; - cl_int error; - void * result = ::clEnqueueMapImage( - object_, buffer(), blocking, flags, - (const ::size_t *) origin, (const ::size_t *) region, - row_pitch, slice_pitch, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL, - &error); - - detail::errHandler(error, __ENQUEUE_MAP_IMAGE_ERR); - if (err != NULL) { - *err = error; - } - if (event != NULL && error == CL_SUCCESS) - *event = tmp; - return result; - } - - cl_int enqueueUnmapMemObject( - const Memory& memory, - void* mapped_ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueUnmapMemObject( - object_, memory(), mapped_ptr, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_UNMAP_MEM_OBJECT_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - -#if defined(CL_VERSION_1_2) - /** - * Enqueues a marker command which waits for either a list of events to complete, - * or all previously enqueued commands to complete. - * - * Enqueues a marker command which waits for either a list of events to complete, - * or if the list is empty it waits for all commands previously enqueued in command_queue - * to complete before it completes. This command returns an event which can be waited on, - * i.e. this event can be waited on to insure that all events either in the event_wait_list - * or all previously enqueued commands, queued before this command to command_queue, - * have completed. - */ - cl_int enqueueMarkerWithWaitList( - const VECTOR_CLASS *events = 0, - Event *event = 0) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueMarkerWithWaitList( - object_, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_MARKER_WAIT_LIST_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - /** - * A synchronization point that enqueues a barrier operation. - * - * Enqueues a barrier command which waits for either a list of events to complete, - * or if the list is empty it waits for all commands previously enqueued in command_queue - * to complete before it completes. This command blocks command execution, that is, any - * following commands enqueued after it do not execute until it completes. This command - * returns an event which can be waited on, i.e. this event can be waited on to insure that - * all events either in the event_wait_list or all previously enqueued commands, queued - * before this command to command_queue, have completed. - */ - cl_int enqueueBarrierWithWaitList( - const VECTOR_CLASS *events = 0, - Event *event = 0) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueBarrierWithWaitList( - object_, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_BARRIER_WAIT_LIST_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - /** - * Enqueues a command to indicate with which device a set of memory objects - * should be associated. - */ - cl_int enqueueMigrateMemObjects( - const VECTOR_CLASS &memObjects, - cl_mem_migration_flags flags, - const VECTOR_CLASS* events = NULL, - Event* event = NULL - ) const - { - cl_event tmp; - - cl_mem* localMemObjects = static_cast(alloca(memObjects.size() * sizeof(cl_mem))); - for( int i = 0; i < (int)memObjects.size(); ++i ) { - localMemObjects[i] = memObjects[i](); - } - - - cl_int err = detail::errHandler( - ::clEnqueueMigrateMemObjects( - object_, - (cl_uint)memObjects.size(), - static_cast(localMemObjects), - flags, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_UNMAP_MEM_OBJECT_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } -#endif // #if defined(CL_VERSION_1_2) - - cl_int enqueueNDRangeKernel( - const Kernel& kernel, - const NDRange& offset, - const NDRange& global, - const NDRange& local = NullRange, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueNDRangeKernel( - object_, kernel(), (cl_uint) global.dimensions(), - offset.dimensions() != 0 ? (const ::size_t*) offset : NULL, - (const ::size_t*) global, - local.dimensions() != 0 ? (const ::size_t*) local : NULL, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_NDRANGE_KERNEL_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - cl_int enqueueTask( - const Kernel& kernel, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueTask( - object_, kernel(), - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_TASK_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - cl_int enqueueNativeKernel( - void (CL_CALLBACK *userFptr)(void *), - std::pair args, - const VECTOR_CLASS* mem_objects = NULL, - const VECTOR_CLASS* mem_locs = NULL, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_mem * mems = (mem_objects != NULL && mem_objects->size() > 0) - ? (cl_mem*) alloca(mem_objects->size() * sizeof(cl_mem)) - : NULL; - - if (mems != NULL) { - for (unsigned int i = 0; i < mem_objects->size(); i++) { - mems[i] = ((*mem_objects)[i])(); - } - } - - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueNativeKernel( - object_, userFptr, args.first, args.second, - (mem_objects != NULL) ? (cl_uint) mem_objects->size() : 0, - mems, - (mem_locs != NULL && mem_locs->size() > 0) ? (const void **) &mem_locs->front() : NULL, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_NATIVE_KERNEL); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - -/** - * Deprecated APIs for 1.2 - */ -#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) || (defined(CL_VERSION_1_1) && !defined(CL_VERSION_1_2)) - CL_EXT_PREFIX__VERSION_1_1_DEPRECATED - cl_int enqueueMarker(Event* event = NULL) const CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueMarker( - object_, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_MARKER_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - CL_EXT_PREFIX__VERSION_1_1_DEPRECATED - cl_int enqueueWaitForEvents(const VECTOR_CLASS& events) const CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED - { - return detail::errHandler( - ::clEnqueueWaitForEvents( - object_, - (cl_uint) events.size(), - events.size() > 0 ? (const cl_event*) &events.front() : NULL), - __ENQUEUE_WAIT_FOR_EVENTS_ERR); - } -#endif // #if defined(CL_VERSION_1_1) - - cl_int enqueueAcquireGLObjects( - const VECTOR_CLASS* mem_objects = NULL, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueAcquireGLObjects( - object_, - (mem_objects != NULL) ? (cl_uint) mem_objects->size() : 0, - (mem_objects != NULL && mem_objects->size() > 0) ? (const cl_mem *) &mem_objects->front(): NULL, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_ACQUIRE_GL_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - cl_int enqueueReleaseGLObjects( - const VECTOR_CLASS* mem_objects = NULL, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueReleaseGLObjects( - object_, - (mem_objects != NULL) ? (cl_uint) mem_objects->size() : 0, - (mem_objects != NULL && mem_objects->size() > 0) ? (const cl_mem *) &mem_objects->front(): NULL, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_RELEASE_GL_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - -#if defined (USE_DX_INTEROP) -typedef CL_API_ENTRY cl_int (CL_API_CALL *PFN_clEnqueueAcquireD3D10ObjectsKHR)( - cl_command_queue command_queue, cl_uint num_objects, - const cl_mem* mem_objects, cl_uint num_events_in_wait_list, - const cl_event* event_wait_list, cl_event* event); -typedef CL_API_ENTRY cl_int (CL_API_CALL *PFN_clEnqueueReleaseD3D10ObjectsKHR)( - cl_command_queue command_queue, cl_uint num_objects, - const cl_mem* mem_objects, cl_uint num_events_in_wait_list, - const cl_event* event_wait_list, cl_event* event); - - cl_int enqueueAcquireD3D10Objects( - const VECTOR_CLASS* mem_objects = NULL, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - static PFN_clEnqueueAcquireD3D10ObjectsKHR pfn_clEnqueueAcquireD3D10ObjectsKHR = NULL; -#if defined(CL_VERSION_1_2) - cl_context context = getInfo(); - cl::Device device(getInfo()); - cl_platform_id platform = device.getInfo(); - __INIT_CL_EXT_FCN_PTR_PLATFORM(platform, clEnqueueAcquireD3D10ObjectsKHR); -#endif -#if defined(CL_VERSION_1_1) - __INIT_CL_EXT_FCN_PTR(clEnqueueAcquireD3D10ObjectsKHR); -#endif - - cl_event tmp; - cl_int err = detail::errHandler( - pfn_clEnqueueAcquireD3D10ObjectsKHR( - object_, - (mem_objects != NULL) ? (cl_uint) mem_objects->size() : 0, - (mem_objects != NULL && mem_objects->size() > 0) ? (const cl_mem *) &mem_objects->front(): NULL, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_ACQUIRE_GL_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - cl_int enqueueReleaseD3D10Objects( - const VECTOR_CLASS* mem_objects = NULL, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - static PFN_clEnqueueReleaseD3D10ObjectsKHR pfn_clEnqueueReleaseD3D10ObjectsKHR = NULL; -#if defined(CL_VERSION_1_2) - cl_context context = getInfo(); - cl::Device device(getInfo()); - cl_platform_id platform = device.getInfo(); - __INIT_CL_EXT_FCN_PTR_PLATFORM(platform, clEnqueueReleaseD3D10ObjectsKHR); -#endif // #if defined(CL_VERSION_1_2) -#if defined(CL_VERSION_1_1) - __INIT_CL_EXT_FCN_PTR(clEnqueueReleaseD3D10ObjectsKHR); -#endif // #if defined(CL_VERSION_1_1) - - cl_event tmp; - cl_int err = detail::errHandler( - pfn_clEnqueueReleaseD3D10ObjectsKHR( - object_, - (mem_objects != NULL) ? (cl_uint) mem_objects->size() : 0, - (mem_objects != NULL && mem_objects->size() > 0) ? (const cl_mem *) &mem_objects->front(): NULL, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_RELEASE_GL_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } -#endif - -/** - * Deprecated APIs for 1.2 - */ -#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) || (defined(CL_VERSION_1_1) && !defined(CL_VERSION_1_2)) - CL_EXT_PREFIX__VERSION_1_1_DEPRECATED - cl_int enqueueBarrier() const CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED - { - return detail::errHandler( - ::clEnqueueBarrier(object_), - __ENQUEUE_BARRIER_ERR); - } -#endif // #if defined(CL_VERSION_1_1) - - cl_int flush() const - { - return detail::errHandler(::clFlush(object_), __FLUSH_ERR); - } - - cl_int finish() const - { - return detail::errHandler(::clFinish(object_), __FINISH_ERR); - } -}; - -#ifdef _WIN32 -#ifdef CL_HPP_CPP11_ATOMICS_SUPPORTED -__declspec(selectany) std::atomic CommandQueue::default_initialized_; -#else // !CL_HPP_CPP11_ATOMICS_SUPPORTED -__declspec(selectany) volatile int CommandQueue::default_initialized_ = __DEFAULT_NOT_INITIALIZED; -#endif // !CL_HPP_CPP11_ATOMICS_SUPPORTED -__declspec(selectany) CommandQueue CommandQueue::default_; -__declspec(selectany) volatile cl_int CommandQueue::default_error_ = CL_SUCCESS; -#else // !_WIN32 -#ifdef CL_HPP_CPP11_ATOMICS_SUPPORTED -__attribute__((weak)) std::atomic CommandQueue::default_initialized_; -#else // !CL_HPP_CPP11_ATOMICS_SUPPORTED -__attribute__((weak)) volatile int CommandQueue::default_initialized_ = __DEFAULT_NOT_INITIALIZED; -#endif // !CL_HPP_CPP11_ATOMICS_SUPPORTED -__attribute__((weak)) CommandQueue CommandQueue::default_; -__attribute__((weak)) volatile cl_int CommandQueue::default_error_ = CL_SUCCESS; -#endif // !_WIN32 - -template< typename IteratorType > -Buffer::Buffer( - const Context &context, - IteratorType startIterator, - IteratorType endIterator, - bool readOnly, - bool useHostPtr, - cl_int* err) -{ - typedef typename std::iterator_traits::value_type DataType; - cl_int error; - - cl_mem_flags flags = 0; - if( readOnly ) { - flags |= CL_MEM_READ_ONLY; - } - else { - flags |= CL_MEM_READ_WRITE; - } - if( useHostPtr ) { - flags |= CL_MEM_USE_HOST_PTR; - } - - ::size_t size = sizeof(DataType)*(endIterator - startIterator); - - if( useHostPtr ) { - object_ = ::clCreateBuffer(context(), flags, size, static_cast(&*startIterator), &error); - } else { - object_ = ::clCreateBuffer(context(), flags, size, 0, &error); - } - - detail::errHandler(error, __CREATE_BUFFER_ERR); - if (err != NULL) { - *err = error; - } - - if( !useHostPtr ) { - CommandQueue queue(context, 0, &error); - detail::errHandler(error, __CREATE_BUFFER_ERR); - if (err != NULL) { - *err = error; - } - - error = cl::copy(queue, startIterator, endIterator, *this); - detail::errHandler(error, __CREATE_BUFFER_ERR); - if (err != NULL) { - *err = error; - } - } -} - -template< typename IteratorType > -Buffer::Buffer( - const CommandQueue &queue, - IteratorType startIterator, - IteratorType endIterator, - bool readOnly, - bool useHostPtr, - cl_int* err) -{ - typedef typename std::iterator_traits::value_type DataType; - cl_int error; - - cl_mem_flags flags = 0; - if (readOnly) { - flags |= CL_MEM_READ_ONLY; - } - else { - flags |= CL_MEM_READ_WRITE; - } - if (useHostPtr) { - flags |= CL_MEM_USE_HOST_PTR; - } - - ::size_t size = sizeof(DataType)*(endIterator - startIterator); - - Context context = queue.getInfo(); - - if (useHostPtr) { - object_ = ::clCreateBuffer(context(), flags, size, static_cast(&*startIterator), &error); - } - else { - object_ = ::clCreateBuffer(context(), flags, size, 0, &error); - } - - detail::errHandler(error, __CREATE_BUFFER_ERR); - if (err != NULL) { - *err = error; - } - - if (!useHostPtr) { - error = cl::copy(queue, startIterator, endIterator, *this); - detail::errHandler(error, __CREATE_BUFFER_ERR); - if (err != NULL) { - *err = error; - } - } -} - -inline cl_int enqueueReadBuffer( - const Buffer& buffer, - cl_bool blocking, - ::size_t offset, - ::size_t size, - void* ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) -{ - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - - if (error != CL_SUCCESS) { - return error; - } - - return queue.enqueueReadBuffer(buffer, blocking, offset, size, ptr, events, event); -} - -inline cl_int enqueueWriteBuffer( - const Buffer& buffer, - cl_bool blocking, - ::size_t offset, - ::size_t size, - const void* ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) -{ - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - - if (error != CL_SUCCESS) { - return error; - } - - return queue.enqueueWriteBuffer(buffer, blocking, offset, size, ptr, events, event); -} - -inline void* enqueueMapBuffer( - const Buffer& buffer, - cl_bool blocking, - cl_map_flags flags, - ::size_t offset, - ::size_t size, - const VECTOR_CLASS* events = NULL, - Event* event = NULL, - cl_int* err = NULL) -{ - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - detail::errHandler(error, __ENQUEUE_MAP_BUFFER_ERR); - if (err != NULL) { - *err = error; - } - - void * result = ::clEnqueueMapBuffer( - queue(), buffer(), blocking, flags, offset, size, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (cl_event*) event, - &error); - - detail::errHandler(error, __ENQUEUE_MAP_BUFFER_ERR); - if (err != NULL) { - *err = error; - } - return result; -} - -inline cl_int enqueueUnmapMemObject( - const Memory& memory, - void* mapped_ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) -{ - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - detail::errHandler(error, __ENQUEUE_MAP_BUFFER_ERR); - if (error != CL_SUCCESS) { - return error; - } - - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueUnmapMemObject( - queue(), memory(), mapped_ptr, - (events != NULL) ? (cl_uint) events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_UNMAP_MEM_OBJECT_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; -} - -inline cl_int enqueueCopyBuffer( - const Buffer& src, - const Buffer& dst, - ::size_t src_offset, - ::size_t dst_offset, - ::size_t size, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) -{ - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - - if (error != CL_SUCCESS) { - return error; - } - - return queue.enqueueCopyBuffer(src, dst, src_offset, dst_offset, size, events, event); -} - -/** - * Blocking copy operation between iterators and a buffer. - * Host to Device. - * Uses default command queue. - */ -template< typename IteratorType > -inline cl_int copy( IteratorType startIterator, IteratorType endIterator, cl::Buffer &buffer ) -{ - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - if (error != CL_SUCCESS) - return error; - - return cl::copy(queue, startIterator, endIterator, buffer); -} - -/** - * Blocking copy operation between iterators and a buffer. - * Device to Host. - * Uses default command queue. - */ -template< typename IteratorType > -inline cl_int copy( const cl::Buffer &buffer, IteratorType startIterator, IteratorType endIterator ) -{ - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - if (error != CL_SUCCESS) - return error; - - return cl::copy(queue, buffer, startIterator, endIterator); -} - -/** - * Blocking copy operation between iterators and a buffer. - * Host to Device. - * Uses specified queue. - */ -template< typename IteratorType > -inline cl_int copy( const CommandQueue &queue, IteratorType startIterator, IteratorType endIterator, cl::Buffer &buffer ) -{ - typedef typename std::iterator_traits::value_type DataType; - cl_int error; - - ::size_t length = endIterator-startIterator; - ::size_t byteLength = length*sizeof(DataType); - - DataType *pointer = - static_cast(queue.enqueueMapBuffer(buffer, CL_TRUE, CL_MAP_WRITE, 0, byteLength, 0, 0, &error)); - // if exceptions enabled, enqueueMapBuffer will throw - if( error != CL_SUCCESS ) { - return error; - } -#if defined(_MSC_VER) - std::copy( - startIterator, - endIterator, - stdext::checked_array_iterator( - pointer, length)); -#else - std::copy(startIterator, endIterator, pointer); -#endif - Event endEvent; - error = queue.enqueueUnmapMemObject(buffer, pointer, 0, &endEvent); - // if exceptions enabled, enqueueUnmapMemObject will throw - if( error != CL_SUCCESS ) { - return error; - } - endEvent.wait(); - return CL_SUCCESS; -} - -/** - * Blocking copy operation between iterators and a buffer. - * Device to Host. - * Uses specified queue. - */ -template< typename IteratorType > -inline cl_int copy( const CommandQueue &queue, const cl::Buffer &buffer, IteratorType startIterator, IteratorType endIterator ) -{ - typedef typename std::iterator_traits::value_type DataType; - cl_int error; - - ::size_t length = endIterator-startIterator; - ::size_t byteLength = length*sizeof(DataType); - - DataType *pointer = - static_cast(queue.enqueueMapBuffer(buffer, CL_TRUE, CL_MAP_READ, 0, byteLength, 0, 0, &error)); - // if exceptions enabled, enqueueMapBuffer will throw - if( error != CL_SUCCESS ) { - return error; - } - std::copy(pointer, pointer + length, startIterator); - Event endEvent; - error = queue.enqueueUnmapMemObject(buffer, pointer, 0, &endEvent); - // if exceptions enabled, enqueueUnmapMemObject will throw - if( error != CL_SUCCESS ) { - return error; - } - endEvent.wait(); - return CL_SUCCESS; -} - -#if defined(CL_VERSION_1_1) -inline cl_int enqueueReadBufferRect( - const Buffer& buffer, - cl_bool blocking, - const size_t<3>& buffer_offset, - const size_t<3>& host_offset, - const size_t<3>& region, - ::size_t buffer_row_pitch, - ::size_t buffer_slice_pitch, - ::size_t host_row_pitch, - ::size_t host_slice_pitch, - void *ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) -{ - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - - if (error != CL_SUCCESS) { - return error; - } - - return queue.enqueueReadBufferRect( - buffer, - blocking, - buffer_offset, - host_offset, - region, - buffer_row_pitch, - buffer_slice_pitch, - host_row_pitch, - host_slice_pitch, - ptr, - events, - event); -} - -inline cl_int enqueueWriteBufferRect( - const Buffer& buffer, - cl_bool blocking, - const size_t<3>& buffer_offset, - const size_t<3>& host_offset, - const size_t<3>& region, - ::size_t buffer_row_pitch, - ::size_t buffer_slice_pitch, - ::size_t host_row_pitch, - ::size_t host_slice_pitch, - const void *ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) -{ - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - - if (error != CL_SUCCESS) { - return error; - } - - return queue.enqueueWriteBufferRect( - buffer, - blocking, - buffer_offset, - host_offset, - region, - buffer_row_pitch, - buffer_slice_pitch, - host_row_pitch, - host_slice_pitch, - ptr, - events, - event); -} - -inline cl_int enqueueCopyBufferRect( - const Buffer& src, - const Buffer& dst, - const size_t<3>& src_origin, - const size_t<3>& dst_origin, - const size_t<3>& region, - ::size_t src_row_pitch, - ::size_t src_slice_pitch, - ::size_t dst_row_pitch, - ::size_t dst_slice_pitch, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) -{ - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - - if (error != CL_SUCCESS) { - return error; - } - - return queue.enqueueCopyBufferRect( - src, - dst, - src_origin, - dst_origin, - region, - src_row_pitch, - src_slice_pitch, - dst_row_pitch, - dst_slice_pitch, - events, - event); -} -#endif - -inline cl_int enqueueReadImage( - const Image& image, - cl_bool blocking, - const size_t<3>& origin, - const size_t<3>& region, - ::size_t row_pitch, - ::size_t slice_pitch, - void* ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) -{ - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - - if (error != CL_SUCCESS) { - return error; - } - - return queue.enqueueReadImage( - image, - blocking, - origin, - region, - row_pitch, - slice_pitch, - ptr, - events, - event); -} - -inline cl_int enqueueWriteImage( - const Image& image, - cl_bool blocking, - const size_t<3>& origin, - const size_t<3>& region, - ::size_t row_pitch, - ::size_t slice_pitch, - const void* ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) -{ - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - - if (error != CL_SUCCESS) { - return error; - } - - return queue.enqueueWriteImage( - image, - blocking, - origin, - region, - row_pitch, - slice_pitch, - ptr, - events, - event); -} - -inline cl_int enqueueCopyImage( - const Image& src, - const Image& dst, - const size_t<3>& src_origin, - const size_t<3>& dst_origin, - const size_t<3>& region, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) -{ - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - - if (error != CL_SUCCESS) { - return error; - } - - return queue.enqueueCopyImage( - src, - dst, - src_origin, - dst_origin, - region, - events, - event); -} - -inline cl_int enqueueCopyImageToBuffer( - const Image& src, - const Buffer& dst, - const size_t<3>& src_origin, - const size_t<3>& region, - ::size_t dst_offset, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) -{ - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - - if (error != CL_SUCCESS) { - return error; - } - - return queue.enqueueCopyImageToBuffer( - src, - dst, - src_origin, - region, - dst_offset, - events, - event); -} - -inline cl_int enqueueCopyBufferToImage( - const Buffer& src, - const Image& dst, - ::size_t src_offset, - const size_t<3>& dst_origin, - const size_t<3>& region, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) -{ - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - - if (error != CL_SUCCESS) { - return error; - } - - return queue.enqueueCopyBufferToImage( - src, - dst, - src_offset, - dst_origin, - region, - events, - event); -} - - -inline cl_int flush(void) -{ - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - - if (error != CL_SUCCESS) { - return error; - } - - return queue.flush(); -} - -inline cl_int finish(void) -{ - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - - if (error != CL_SUCCESS) { - return error; - } - - - return queue.finish(); -} - -// Kernel Functor support -// New interface as of September 2011 -// Requires the C++11 std::tr1::function (note do not support TR1) -// Visual Studio 2010 and GCC 4.2 - -struct EnqueueArgs -{ - CommandQueue queue_; - const NDRange offset_; - const NDRange global_; - const NDRange local_; - VECTOR_CLASS events_; - - EnqueueArgs(NDRange global) : - queue_(CommandQueue::getDefault()), - offset_(NullRange), - global_(global), - local_(NullRange) - { - - } - - EnqueueArgs(NDRange global, NDRange local) : - queue_(CommandQueue::getDefault()), - offset_(NullRange), - global_(global), - local_(local) - { - - } - - EnqueueArgs(NDRange offset, NDRange global, NDRange local) : - queue_(CommandQueue::getDefault()), - offset_(offset), - global_(global), - local_(local) - { - - } - - EnqueueArgs(Event e, NDRange global) : - queue_(CommandQueue::getDefault()), - offset_(NullRange), - global_(global), - local_(NullRange) - { - events_.push_back(e); - } - - EnqueueArgs(Event e, NDRange global, NDRange local) : - queue_(CommandQueue::getDefault()), - offset_(NullRange), - global_(global), - local_(local) - { - events_.push_back(e); - } - - EnqueueArgs(Event e, NDRange offset, NDRange global, NDRange local) : - queue_(CommandQueue::getDefault()), - offset_(offset), - global_(global), - local_(local) - { - events_.push_back(e); - } - - EnqueueArgs(const VECTOR_CLASS &events, NDRange global) : - queue_(CommandQueue::getDefault()), - offset_(NullRange), - global_(global), - local_(NullRange), - events_(events) - { - - } - - EnqueueArgs(const VECTOR_CLASS &events, NDRange global, NDRange local) : - queue_(CommandQueue::getDefault()), - offset_(NullRange), - global_(global), - local_(local), - events_(events) - { - - } - - EnqueueArgs(const VECTOR_CLASS &events, NDRange offset, NDRange global, NDRange local) : - queue_(CommandQueue::getDefault()), - offset_(offset), - global_(global), - local_(local), - events_(events) - { - - } - - EnqueueArgs(CommandQueue &queue, NDRange global) : - queue_(queue), - offset_(NullRange), - global_(global), - local_(NullRange) - { - - } - - EnqueueArgs(CommandQueue &queue, NDRange global, NDRange local) : - queue_(queue), - offset_(NullRange), - global_(global), - local_(local) - { - - } - - EnqueueArgs(CommandQueue &queue, NDRange offset, NDRange global, NDRange local) : - queue_(queue), - offset_(offset), - global_(global), - local_(local) - { - - } - - EnqueueArgs(CommandQueue &queue, Event e, NDRange global) : - queue_(queue), - offset_(NullRange), - global_(global), - local_(NullRange) - { - events_.push_back(e); - } - - EnqueueArgs(CommandQueue &queue, Event e, NDRange global, NDRange local) : - queue_(queue), - offset_(NullRange), - global_(global), - local_(local) - { - events_.push_back(e); - } - - EnqueueArgs(CommandQueue &queue, Event e, NDRange offset, NDRange global, NDRange local) : - queue_(queue), - offset_(offset), - global_(global), - local_(local) - { - events_.push_back(e); - } - - EnqueueArgs(CommandQueue &queue, const VECTOR_CLASS &events, NDRange global) : - queue_(queue), - offset_(NullRange), - global_(global), - local_(NullRange), - events_(events) - { - - } - - EnqueueArgs(CommandQueue &queue, const VECTOR_CLASS &events, NDRange global, NDRange local) : - queue_(queue), - offset_(NullRange), - global_(global), - local_(local), - events_(events) - { - - } - - EnqueueArgs(CommandQueue &queue, const VECTOR_CLASS &events, NDRange offset, NDRange global, NDRange local) : - queue_(queue), - offset_(offset), - global_(global), - local_(local), - events_(events) - { - - } -}; - -namespace detail { - -class NullType {}; - -template -struct SetArg -{ - static void set (Kernel kernel, T0 arg) - { - kernel.setArg(index, arg); - } -}; - -template -struct SetArg -{ - static void set (Kernel, NullType) - { - } -}; - -template < - typename T0, typename T1, typename T2, typename T3, - typename T4, typename T5, typename T6, typename T7, - typename T8, typename T9, typename T10, typename T11, - typename T12, typename T13, typename T14, typename T15, - typename T16, typename T17, typename T18, typename T19, - typename T20, typename T21, typename T22, typename T23, - typename T24, typename T25, typename T26, typename T27, - typename T28, typename T29, typename T30, typename T31 - -> -class KernelFunctorGlobal -{ -private: - Kernel kernel_; - -public: - KernelFunctorGlobal( - Kernel kernel) : - kernel_(kernel) - {} - - KernelFunctorGlobal( - const Program& program, - const STRING_CLASS name, - cl_int * err = NULL) : - kernel_(program, name.c_str(), err) - {} - - Event operator() ( - const EnqueueArgs& args, - T0 t0, - T1 t1 = NullType(), - T2 t2 = NullType(), - T3 t3 = NullType(), - T4 t4 = NullType(), - T5 t5 = NullType(), - T6 t6 = NullType(), - T7 t7 = NullType(), - T8 t8 = NullType(), - T9 t9 = NullType(), - T10 t10 = NullType(), - T11 t11 = NullType(), - T12 t12 = NullType(), - T13 t13 = NullType(), - T14 t14 = NullType(), - T15 t15 = NullType(), - T16 t16 = NullType(), - T17 t17 = NullType(), - T18 t18 = NullType(), - T19 t19 = NullType(), - T20 t20 = NullType(), - T21 t21 = NullType(), - T22 t22 = NullType(), - T23 t23 = NullType(), - T24 t24 = NullType(), - T25 t25 = NullType(), - T26 t26 = NullType(), - T27 t27 = NullType(), - T28 t28 = NullType(), - T29 t29 = NullType(), - T30 t30 = NullType(), - T31 t31 = NullType() - - ) - { - Event event; - SetArg<0, T0>::set(kernel_, t0); - SetArg<1, T1>::set(kernel_, t1); - SetArg<2, T2>::set(kernel_, t2); - SetArg<3, T3>::set(kernel_, t3); - SetArg<4, T4>::set(kernel_, t4); - SetArg<5, T5>::set(kernel_, t5); - SetArg<6, T6>::set(kernel_, t6); - SetArg<7, T7>::set(kernel_, t7); - SetArg<8, T8>::set(kernel_, t8); - SetArg<9, T9>::set(kernel_, t9); - SetArg<10, T10>::set(kernel_, t10); - SetArg<11, T11>::set(kernel_, t11); - SetArg<12, T12>::set(kernel_, t12); - SetArg<13, T13>::set(kernel_, t13); - SetArg<14, T14>::set(kernel_, t14); - SetArg<15, T15>::set(kernel_, t15); - SetArg<16, T16>::set(kernel_, t16); - SetArg<17, T17>::set(kernel_, t17); - SetArg<18, T18>::set(kernel_, t18); - SetArg<19, T19>::set(kernel_, t19); - SetArg<20, T20>::set(kernel_, t20); - SetArg<21, T21>::set(kernel_, t21); - SetArg<22, T22>::set(kernel_, t22); - SetArg<23, T23>::set(kernel_, t23); - SetArg<24, T24>::set(kernel_, t24); - SetArg<25, T25>::set(kernel_, t25); - SetArg<26, T26>::set(kernel_, t26); - SetArg<27, T27>::set(kernel_, t27); - SetArg<28, T28>::set(kernel_, t28); - SetArg<29, T29>::set(kernel_, t29); - SetArg<30, T30>::set(kernel_, t30); - SetArg<31, T31>::set(kernel_, t31); - - - args.queue_.enqueueNDRangeKernel( - kernel_, - args.offset_, - args.global_, - args.local_, - &args.events_, - &event); - - return event; - } - -}; - -//------------------------------------------------------------------------------------------------------ - - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18, - typename T19, - typename T20, - typename T21, - typename T22, - typename T23, - typename T24, - typename T25, - typename T26, - typename T27, - typename T28, - typename T29, - typename T30, - typename T31> -struct functionImplementation_ -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27, - T28, - T29, - T30, - T31> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 32)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27, - T28, - T29, - T30, - T31); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18, - T19 arg19, - T20 arg20, - T21 arg21, - T22 arg22, - T23 arg23, - T24 arg24, - T25 arg25, - T26 arg26, - T27 arg27, - T28 arg28, - T29 arg29, - T30 arg30, - T31 arg31) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18, - arg19, - arg20, - arg21, - arg22, - arg23, - arg24, - arg25, - arg26, - arg27, - arg28, - arg29, - arg30, - arg31); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18, - typename T19, - typename T20, - typename T21, - typename T22, - typename T23, - typename T24, - typename T25, - typename T26, - typename T27, - typename T28, - typename T29, - typename T30> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27, - T28, - T29, - T30, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27, - T28, - T29, - T30, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 31)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27, - T28, - T29, - T30); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18, - T19 arg19, - T20 arg20, - T21 arg21, - T22 arg22, - T23 arg23, - T24 arg24, - T25 arg25, - T26 arg26, - T27 arg27, - T28 arg28, - T29 arg29, - T30 arg30) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18, - arg19, - arg20, - arg21, - arg22, - arg23, - arg24, - arg25, - arg26, - arg27, - arg28, - arg29, - arg30); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18, - typename T19, - typename T20, - typename T21, - typename T22, - typename T23, - typename T24, - typename T25, - typename T26, - typename T27, - typename T28, - typename T29> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27, - T28, - T29, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27, - T28, - T29, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 30)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27, - T28, - T29); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18, - T19 arg19, - T20 arg20, - T21 arg21, - T22 arg22, - T23 arg23, - T24 arg24, - T25 arg25, - T26 arg26, - T27 arg27, - T28 arg28, - T29 arg29) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18, - arg19, - arg20, - arg21, - arg22, - arg23, - arg24, - arg25, - arg26, - arg27, - arg28, - arg29); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18, - typename T19, - typename T20, - typename T21, - typename T22, - typename T23, - typename T24, - typename T25, - typename T26, - typename T27, - typename T28> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27, - T28, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27, - T28, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 29)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27, - T28); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18, - T19 arg19, - T20 arg20, - T21 arg21, - T22 arg22, - T23 arg23, - T24 arg24, - T25 arg25, - T26 arg26, - T27 arg27, - T28 arg28) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18, - arg19, - arg20, - arg21, - arg22, - arg23, - arg24, - arg25, - arg26, - arg27, - arg28); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18, - typename T19, - typename T20, - typename T21, - typename T22, - typename T23, - typename T24, - typename T25, - typename T26, - typename T27> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 28)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18, - T19 arg19, - T20 arg20, - T21 arg21, - T22 arg22, - T23 arg23, - T24 arg24, - T25 arg25, - T26 arg26, - T27 arg27) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18, - arg19, - arg20, - arg21, - arg22, - arg23, - arg24, - arg25, - arg26, - arg27); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18, - typename T19, - typename T20, - typename T21, - typename T22, - typename T23, - typename T24, - typename T25, - typename T26> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 27)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18, - T19 arg19, - T20 arg20, - T21 arg21, - T22 arg22, - T23 arg23, - T24 arg24, - T25 arg25, - T26 arg26) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18, - arg19, - arg20, - arg21, - arg22, - arg23, - arg24, - arg25, - arg26); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18, - typename T19, - typename T20, - typename T21, - typename T22, - typename T23, - typename T24, - typename T25> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 26)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18, - T19 arg19, - T20 arg20, - T21 arg21, - T22 arg22, - T23 arg23, - T24 arg24, - T25 arg25) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18, - arg19, - arg20, - arg21, - arg22, - arg23, - arg24, - arg25); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18, - typename T19, - typename T20, - typename T21, - typename T22, - typename T23, - typename T24> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 25)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18, - T19 arg19, - T20 arg20, - T21 arg21, - T22 arg22, - T23 arg23, - T24 arg24) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18, - arg19, - arg20, - arg21, - arg22, - arg23, - arg24); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18, - typename T19, - typename T20, - typename T21, - typename T22, - typename T23> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 24)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18, - T19 arg19, - T20 arg20, - T21 arg21, - T22 arg22, - T23 arg23) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18, - arg19, - arg20, - arg21, - arg22, - arg23); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18, - typename T19, - typename T20, - typename T21, - typename T22> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 23)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18, - T19 arg19, - T20 arg20, - T21 arg21, - T22 arg22) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18, - arg19, - arg20, - arg21, - arg22); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18, - typename T19, - typename T20, - typename T21> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 22)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18, - T19 arg19, - T20 arg20, - T21 arg21) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18, - arg19, - arg20, - arg21); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18, - typename T19, - typename T20> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 21)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18, - T19 arg19, - T20 arg20) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18, - arg19, - arg20); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18, - typename T19> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 20)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18, - T19 arg19) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18, - arg19); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 19)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 18)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 17)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 16)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 15)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 14)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 13)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 12)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 11)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 10)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 9)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 8)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - T6, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 7)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - T5, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 6)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - T4, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 5)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4); - } - - -}; - -template< - typename T0, - typename T1, - typename T2, - typename T3> -struct functionImplementation_ -< T0, - T1, - T2, - T3, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 4)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3); - } - - -}; - -template< - typename T0, - typename T1, - typename T2> -struct functionImplementation_ -< T0, - T1, - T2, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 3)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2); - } - - -}; - -template< - typename T0, - typename T1> -struct functionImplementation_ -< T0, - T1, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - T1, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 2)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1) - { - return functor_( - enqueueArgs, - arg0, - arg1); - } - - -}; - -template< - typename T0> -struct functionImplementation_ -< T0, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> -{ - typedef detail::KernelFunctorGlobal< - T0, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - - #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 1)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); - #endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0) - { - return functor_( - enqueueArgs, - arg0); - } - - -}; - - - - - -} // namespace detail - -//---------------------------------------------------------------------------------------------- - -template < - typename T0, typename T1 = detail::NullType, typename T2 = detail::NullType, - typename T3 = detail::NullType, typename T4 = detail::NullType, - typename T5 = detail::NullType, typename T6 = detail::NullType, - typename T7 = detail::NullType, typename T8 = detail::NullType, - typename T9 = detail::NullType, typename T10 = detail::NullType, - typename T11 = detail::NullType, typename T12 = detail::NullType, - typename T13 = detail::NullType, typename T14 = detail::NullType, - typename T15 = detail::NullType, typename T16 = detail::NullType, - typename T17 = detail::NullType, typename T18 = detail::NullType, - typename T19 = detail::NullType, typename T20 = detail::NullType, - typename T21 = detail::NullType, typename T22 = detail::NullType, - typename T23 = detail::NullType, typename T24 = detail::NullType, - typename T25 = detail::NullType, typename T26 = detail::NullType, - typename T27 = detail::NullType, typename T28 = detail::NullType, - typename T29 = detail::NullType, typename T30 = detail::NullType, - typename T31 = detail::NullType - -> -struct make_kernel : - public detail::functionImplementation_< - T0, T1, T2, T3, - T4, T5, T6, T7, - T8, T9, T10, T11, - T12, T13, T14, T15, - T16, T17, T18, T19, - T20, T21, T22, T23, - T24, T25, T26, T27, - T28, T29, T30, T31 - - > -{ -public: - typedef detail::KernelFunctorGlobal< - T0, T1, T2, T3, - T4, T5, T6, T7, - T8, T9, T10, T11, - T12, T13, T14, T15, - T16, T17, T18, T19, - T20, T21, T22, T23, - T24, T25, T26, T27, - T28, T29, T30, T31 - - > FunctorType; - - make_kernel( - const Program& program, - const STRING_CLASS name, - cl_int * err = NULL) : - detail::functionImplementation_< - T0, T1, T2, T3, - T4, T5, T6, T7, - T8, T9, T10, T11, - T12, T13, T14, T15, - T16, T17, T18, T19, - T20, T21, T22, T23, - T24, T25, T26, T27, - T28, T29, T30, T31 - - >( - FunctorType(program, name, err)) - {} - - make_kernel( - const Kernel kernel) : - detail::functionImplementation_< - T0, T1, T2, T3, - T4, T5, T6, T7, - T8, T9, T10, T11, - T12, T13, T14, T15, - T16, T17, T18, T19, - T20, T21, T22, T23, - T24, T25, T26, T27, - T28, T29, T30, T31 - - >( - FunctorType(kernel)) - {} -}; - - -//---------------------------------------------------------------------------------------------------------------------- - -#undef __ERR_STR -#if !defined(__CL_USER_OVERRIDE_ERROR_STRINGS) -#undef __GET_DEVICE_INFO_ERR -#undef __GET_PLATFORM_INFO_ERR -#undef __GET_DEVICE_IDS_ERR -#undef __GET_CONTEXT_INFO_ERR -#undef __GET_EVENT_INFO_ERR -#undef __GET_EVENT_PROFILE_INFO_ERR -#undef __GET_MEM_OBJECT_INFO_ERR -#undef __GET_IMAGE_INFO_ERR -#undef __GET_SAMPLER_INFO_ERR -#undef __GET_KERNEL_INFO_ERR -#undef __GET_KERNEL_ARG_INFO_ERR -#undef __GET_KERNEL_WORK_GROUP_INFO_ERR -#undef __GET_PROGRAM_INFO_ERR -#undef __GET_PROGRAM_BUILD_INFO_ERR -#undef __GET_COMMAND_QUEUE_INFO_ERR - -#undef __CREATE_CONTEXT_ERR -#undef __CREATE_CONTEXT_FROM_TYPE_ERR -#undef __GET_SUPPORTED_IMAGE_FORMATS_ERR - -#undef __CREATE_BUFFER_ERR -#undef __CREATE_SUBBUFFER_ERR -#undef __CREATE_IMAGE2D_ERR -#undef __CREATE_IMAGE3D_ERR -#undef __CREATE_SAMPLER_ERR -#undef __SET_MEM_OBJECT_DESTRUCTOR_CALLBACK_ERR - -#undef __CREATE_USER_EVENT_ERR -#undef __SET_USER_EVENT_STATUS_ERR -#undef __SET_EVENT_CALLBACK_ERR -#undef __SET_PRINTF_CALLBACK_ERR - -#undef __WAIT_FOR_EVENTS_ERR - -#undef __CREATE_KERNEL_ERR -#undef __SET_KERNEL_ARGS_ERR -#undef __CREATE_PROGRAM_WITH_SOURCE_ERR -#undef __CREATE_PROGRAM_WITH_BINARY_ERR -#undef __CREATE_PROGRAM_WITH_BUILT_IN_KERNELS_ERR -#undef __BUILD_PROGRAM_ERR -#undef __CREATE_KERNELS_IN_PROGRAM_ERR - -#undef __CREATE_COMMAND_QUEUE_ERR -#undef __SET_COMMAND_QUEUE_PROPERTY_ERR -#undef __ENQUEUE_READ_BUFFER_ERR -#undef __ENQUEUE_WRITE_BUFFER_ERR -#undef __ENQUEUE_READ_BUFFER_RECT_ERR -#undef __ENQUEUE_WRITE_BUFFER_RECT_ERR -#undef __ENQEUE_COPY_BUFFER_ERR -#undef __ENQEUE_COPY_BUFFER_RECT_ERR -#undef __ENQUEUE_READ_IMAGE_ERR -#undef __ENQUEUE_WRITE_IMAGE_ERR -#undef __ENQUEUE_COPY_IMAGE_ERR -#undef __ENQUEUE_COPY_IMAGE_TO_BUFFER_ERR -#undef __ENQUEUE_COPY_BUFFER_TO_IMAGE_ERR -#undef __ENQUEUE_MAP_BUFFER_ERR -#undef __ENQUEUE_MAP_IMAGE_ERR -#undef __ENQUEUE_UNMAP_MEM_OBJECT_ERR -#undef __ENQUEUE_NDRANGE_KERNEL_ERR -#undef __ENQUEUE_TASK_ERR -#undef __ENQUEUE_NATIVE_KERNEL - -#undef __CL_EXPLICIT_CONSTRUCTORS - -#undef __UNLOAD_COMPILER_ERR -#endif //__CL_USER_OVERRIDE_ERROR_STRINGS - -#undef __CL_FUNCTION_TYPE - -// Extensions -/** - * Deprecated APIs for 1.2 - */ -#if defined(CL_VERSION_1_1) -#undef __INIT_CL_EXT_FCN_PTR -#endif // #if defined(CL_VERSION_1_1) -#undef __CREATE_SUB_DEVICES - -#if defined(USE_CL_DEVICE_FISSION) -#undef __PARAM_NAME_DEVICE_FISSION -#endif // USE_CL_DEVICE_FISSION - -#undef __DEFAULT_NOT_INITIALIZED -#undef __DEFAULT_BEING_INITIALIZED -#undef __DEFAULT_INITIALIZED - -#undef CL_HPP_RVALUE_REFERENCES_SUPPORTED -#undef CL_HPP_NOEXCEPT - -} // namespace cl - -#endif // CL_HPP_ diff --git a/GPU_version/vio/include/gpu_svo/cl_class.h b/GPU_version/vio/include/gpu_svo/cl_class.h deleted file mode 100644 index 915305e..0000000 --- a/GPU_version/vio/include/gpu_svo/cl_class.h +++ /dev/null @@ -1,191 +0,0 @@ -// -// Created by root on 4/27/21. -// - -#ifndef VIO_OPENCL_CL_CLASS_H -#define VIO_OPENCL_CL_CLASS_H -#include -#include -#include -#include -#include -#include -#include -#include - -class kernel{ -public: - kernel(cl::Program* program,std::string name){_kernel = new cl::Kernel(*program,name.c_str());}; - ~kernel(){ - _buffers.clear(); - _images.clear(); - }; - template - int32_t write(size_t id/*buffer ID*/,T* buf,cl::CommandQueue* queue,cl::Context* context,size_t buf_size){ - _buffers.push_back(std::pair,size_t>(std::pair(cl::Buffer(*context, CL_MEM_READ_WRITE, sizeof(T) * buf_size), - buf_size),id)); - cl_int err=queue->enqueueWriteBuffer(_buffers.back().first.first,CL_TRUE, 0, sizeof(T) * buf_size, buf); - if(err!=0){ - std::cerr<<"Error C:Kernel, F:write, L:enqueueWriteBuffer\n"<setArg(id,_buffers.back().first.first); - if(err!=0){ - std::cerr<<"Error C:Kernel, F:write, L3:setArg\n"<(cl::Image2D(*context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, - cl::ImageFormat(CL_R, CL_UNSIGNED_INT8), - buf.size().width, - buf.size().height, - 0, - reinterpret_cast(buf.data)),id)); - - cl_int err=_kernel->setArg(id,_images.back().first); - if(err!=0){ - std::cerr<<"Error C:Kernel, F:write image, L:setArg\n"< - int32_t reload(size_t id,T* buf,cl::CommandQueue* queue){ - try{ - if(id>_buffers.size())return CL_MAP_FAILURE; - for(auto i:_buffers)if(i.second==id) - queue->enqueueWriteBuffer(i.first.first,CL_TRUE, 0, sizeof(T) * i.first.second, buf); - return CL_SUCCESS; - }catch (std::exception& err){ - std::cerr<<"Reload buffer on GPU failed\n"<(buf.data)); - } - - return CL_SUCCESS; - }catch (std::exception& err){ - std::cerr<<"Reload buffer on GPU failed\n"< read(size_t id){ - for(auto i:_buffers)if(i.second==id)return i.first; - } - cl::Image2D read_img(size_t id){ - for(auto i:_images)if(i.second==id)return i.first; - } -private: - std::vector,size_t>> _buffers; - std::vector> _images; - -}; -class read_cl{ -public: - read_cl(std::string path){ - src_str=(char *)malloc(0x100000); - FILE *fp; - fp = fopen(path.c_str(), "r"); - size = fread(src_str, 1, 0x100000, fp); - fclose(fp); - } - void print(){ - std::cerr< - int32_t write_buf(size_t id1/*kernal ID*/,size_t id2/*buffer ID*/, int size,T* buf) { - try{ - _kernels.at(id1).write(id2,buf,queue,context,size); - return CL_SUCCESS; - }catch (std::exception& err){ - std::cerr<<"Write buffer on GPU failed\n"< - int32_t write_buf(size_t id1/*kernal ID*/,size_t id2/*buffer ID*/,T&& value){ - _kernels.at(id1)._kernel->setArg(id2,value); - }; - template - int32_t reload_buf(size_t id1/*kernal ID*/,size_t id2/*buffer ID*/,T* buf) { - try{ - _kernels.at(id1).reload(id2,buf,queue); - return CL_SUCCESS; - }catch (std::exception& err){ - std::cerr<<"Reload buffer on GPU failed\n"<1 && y>1){ - err=queue->enqueueNDRangeKernel(*_kernels.at(id1)._kernel, cl::NullRange/*offset*/, cl::NDRange(x,y,z)/*Global*/, cl::NullRange/*local*/); - }else if(z<2 && y>1){ - err=queue->enqueueNDRangeKernel(*_kernels.at(id1)._kernel, cl::NullRange/*offset*/, cl::NDRange(x,y)/*Global*/, cl::NullRange/*local*/); - }else{ - err=queue->enqueueNDRangeKernel(*_kernels.at(id1)._kernel, cl::NullRange/*offset*/, cl::NDRange(x)/*Global*/, cl::NullRange/*local*/); - }; - queue->finish(); - if(err!=0){ - std::cerr<<"kernel: "<<_kernels.at(id1)._kernel->getInfo(); - std::cerr<<" ,Args: "<<_kernels.at(id1)._kernel->getInfo()<<" ,Run out: "<getInfo();++i) - std::cerr<<"argument type "<getArgInfo(i)<<'\n'; - } - return err; - - } - template - void read(size_t id1/*kernal ID*/,size_t id2/*buffer ID*/, T* out){ - queue->enqueueReadBuffer(_kernels.at(id1).read(id2).first, CL_TRUE, 0, sizeof(T) * _kernels.at(id1).read(id2).second, out); - } - void clear_buf(); -private: - std::vector _kernels; - cl::Context* context = NULL; - cl::Device device; - cl::Program* program = NULL; - cl::CommandQueue* queue=NULL; -}; - -#endif //VIO_OPENCL_CL_CLASS_H diff --git a/GPU_version/vio/include/gpu_svo/config.h b/GPU_version/vio/include/gpu_svo/config.h deleted file mode 100644 index f6d710d..0000000 --- a/GPU_version/vio/include/gpu_svo/config.h +++ /dev/null @@ -1,182 +0,0 @@ -// This file is part of SVO - Semi-direct Visual Odometry. -// -// Copyright (C) 2014 Christian Forster -// (Robotics and Perception Group, University of Zurich, Switzerland). -// -// SVO is free software: you can redistribute it and/or modify it under the -// terms of the GNU General Public License as published by the Free Software -// Foundation, either version 3 of the License, or any later version. -// -// SVO is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#ifndef SVO_CONFIG_H_ -#define SVO_CONFIG_H_ - -#include -#include -#include - -namespace svo { - -using std::string; - -/// Global configuration file of SVO. -/// Implements the Singleton design pattern to allow global access and to ensure -/// that only one instance exists. -class Config -{ -public: - static Config& getInstance(); - - /// Base-name of the tracefiles. - static string& traceName() { return getInstance().trace_name; } - - /// Directory where the tracefiles are saved. - static string& traceDir() { return getInstance().trace_dir; } - - /// Number of pyramid levels used for features. - static size_t& nPyrLevels() { return getInstance().n_pyr_levels; } - - /// Use the IMU to get relative rotations. - static bool& useImu() { return getInstance().use_imu; } - - /// Number of keyframes in the core. The core-kfs are optimized through bundle adjustment. - static size_t& coreNKfs() { return getInstance().core_n_kfs; } - - /// Initial scale of the map. Depends on the distance the camera is moved for the initialization. - static double& mapScale() { return getInstance().map_scale; } - - /// Feature grid size of a cell in [px]. - static size_t& gridSize() { return getInstance().grid_size; } - - /// Initialization: Minimum required disparity between the first two frames. - static double& initMinDisparity() { return getInstance().init_min_disparity; } - - /// Initialization: Minimum number of tracked features. - static size_t& initMinTracked() { return getInstance().init_min_tracked; } - - /// Initialization: Minimum number of inliers after RANSAC. - static size_t& initMinInliers() { return getInstance().init_min_inliers; } - - /// Maximum level of the Lucas Kanade tracker. - static size_t& kltMaxLevel() { return getInstance().klt_max_level; } - - /// Minimum level of the Lucas Kanade tracker. - static size_t& kltMinLevel() { return getInstance().klt_min_level; } - - /// Reprojection threshold [px]. - static double& reprojThresh() { return getInstance().reproj_thresh; } - - /// Reprojection threshold after pose optimization. - static double& poseOptimThresh() { return getInstance().poseoptim_thresh; } - - /// Number of iterations in local bundle adjustment. - static size_t& poseOptimNumIter() { return getInstance().poseoptim_num_iter; } - - /// Maximum number of points to optimize at every iteration. - static size_t& structureOptimMaxPts() { return getInstance().structureoptim_max_pts; } - - /// Number of iterations in structure optimization. - static size_t& structureOptimNumIter() { return getInstance().structureoptim_num_iter; } - - /// Reprojection threshold after bundle adjustment. - static double& lobaThresh() { return getInstance().loba_thresh; } - - /// Threshold for the robust Huber kernel of the local bundle adjustment. - static double& lobaRobustHuberWidth() { return getInstance().loba_robust_huber_width; } - - /// Number of iterations in the local bundle adjustment. - static size_t& lobaNumIter() { return getInstance().loba_num_iter; } - - /// Minimum distance between two keyframes. Relative to the average height in the map. - static double& kfSelectMinDist() { return getInstance().kfselect_mindist; } - - /// Select only features with a minimum Harris corner score for triangulation. - static double& triangMinCornerScore() { return getInstance().triang_min_corner_score; } - - /// Subpixel refinement of reprojection and triangulation. Set to 0 if no subpix refinement required! - static size_t& subpixNIter() { return getInstance().subpix_n_iter; } - - /// Limit the number of keyframes in the map. This makes nslam essentially. - /// a Visual Odometry. Set to 0 if unlimited number of keyframes are allowed. - /// Minimum number of keyframes is 3. - static size_t& maxNKfs() { return getInstance().max_n_kfs; } - - /// How much (in milliseconds) is the camera delayed with respect to the imu. - static double& imgImuDelay() { return getInstance().img_imu_delay; } - - /// Maximum number of features that should be tracked. - static size_t& maxFts() { return getInstance().max_fts; } - - /// If the number of tracked features drops below this threshold. Tracking quality is bad. - static size_t& qualityMinFts() { return getInstance().quality_min_fts; } - - /// If within one frame, this amount of features are dropped. Tracking quality is bad. - static int& qualityMaxFtsDrop() { return getInstance().quality_max_drop_fts; } - - /// acc white noise in continuous. - static double& ACC_Noise() { return getInstance().ACC_noise; } - - /// Gro white noise in continuous. - static double& GYO_Noise() { return getInstance().GYO_noise; } - /// integration uncertainty continuous - static double& IUC() { return getInstance().iuc; } - /// acc bias in continuous - static double& ABC() { return getInstance().abc; } - /// gyro bias in continuous - static double& GBC() { return getInstance().gbc; } - /// error in the bias used for preintegration - static double& EBP() { return getInstance().ebp; } - /// the noise used for projection - static double& NRP() { return getInstance().nrp; } - static double& Svo_Ekf() { return getInstance().svo_ekf; } - static double& X_off() { return getInstance().acc_x_off; } - static double& Y_off() { return getInstance().acc_y_off; } - static double& Teta_off() { return getInstance().gyr_z_off; } - static double& Cmd_Cov() { return getInstance().cmd_cov; } - - -private: - Config(); - Config(Config const&); - void operator=(Config const&); - string trace_name; - string trace_dir; - size_t n_pyr_levels; - bool use_imu; - size_t core_n_kfs; - double map_scale; - size_t grid_size; - double init_min_disparity; - size_t init_min_tracked; - size_t init_min_inliers; - size_t klt_max_level; - size_t klt_min_level; - double reproj_thresh; - double poseoptim_thresh; - size_t poseoptim_num_iter; - size_t structureoptim_max_pts; - size_t structureoptim_num_iter; - double loba_thresh; - double loba_robust_huber_width; - size_t loba_num_iter; - double kfselect_mindist; - double triang_min_corner_score; - size_t triang_half_patch_size; - size_t subpix_n_iter; - size_t max_n_kfs; - double img_imu_delay; - size_t max_fts; - size_t quality_min_fts; - int quality_max_drop_fts; - double nrp,ebp,gbc,abc,iuc,ACC_noise,GYO_noise,svo_ekf,acc_x_off,acc_y_off,gyr_z_off,cmd_cov; -}; - -} // namespace svo - -#endif // SVO_CONFIG_H_ diff --git a/GPU_version/vio/include/gpu_svo/depth_filter.h b/GPU_version/vio/include/gpu_svo/depth_filter.h deleted file mode 100644 index 9e82df4..0000000 --- a/GPU_version/vio/include/gpu_svo/depth_filter.h +++ /dev/null @@ -1,170 +0,0 @@ -// This file is part of SVO - Semi-direct Visual Odometry. -// -// Copyright (C) 2014 Christian Forster -// (Robotics and Perception Group, University of Zurich, Switzerland). -// -// SVO is free software: you can redistribute it and/or modify it under the -// terms of the GNU General Public License as published by the Free Software -// Foundation, either version 3 of the License, or any later version. -// -// SVO is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#ifndef SVO_DEPTH_FILTER_H_ -#define SVO_DEPTH_FILTER_H_ - -#include -#include -#include -//#include -#include -#include -#include - -namespace svo { - -class Frame; -class Feature; -class Point; - -/// A seed is a probabilistic depth estimate for a single pixel. -struct Seed -{ - EIGEN_MAKE_ALIGNED_OPERATOR_NEW - - static int batch_counter; - static int seed_counter; - int batch_id; //!< Batch id is the id of the keyframe for which the seed was created. - int id; //!< Seed ID, only used for visualization. - Feature* ftr; //!< Feature in the keyframe for which the depth should be computed. - float a; //!< a of Beta distribution: When high, probability of inlier is large. - float b; //!< b of Beta distribution: When high, probability of outlier is large. - float mu; //!< Mean of normal distribution. - float z_range; //!< Max range of the possible depth. - float sigma2; //!< Variance of normal distribution. - Matrix2d patch_cov; //!< Patch covariance in reference image. - Seed(Feature* ftr, float depth_mean, float depth_min); -}; - -/// Depth filter implements the Bayesian Update proposed in: -/// "Video-based, Real-Time Multi View Stereo" by G. Vogiatzis and C. Hernández. -/// In Image and Vision Computing, 29(7):434-441, 2011. -/// -/// The class uses a callback mechanism such that it can be used also by other -/// algorithms than nslam and for simplified testing. -class DepthFilter -{ -public: - EIGEN_MAKE_ALIGNED_OPERATOR_NEW - - typedef boost::unique_lock lock_t; - typedef boost::function callback_t; - - /// Depth-filter config parameters - struct Options - { - bool check_ftr_angle; //!< gradient features are only updated if the epipolar line is orthogonal to the gradient. - bool epi_search_1d; //!< restrict Gauss Newton in the epipolar search to the epipolar line. - bool verbose; //!< display output. - bool use_photometric_disparity_error; //!< use photometric disparity error instead of 1px error in tau computation. - int max_n_kfs; //!< maximum number of keyframes for which we maintain seeds. - double sigma_i_sq; //!< image noise. - double seed_convergence_sigma2_thresh; //!< threshold on depth uncertainty for convergence. - Options() - : check_ftr_angle(false), - epi_search_1d(false), - verbose(false), - use_photometric_disparity_error(false), - max_n_kfs(10), - sigma_i_sq(5e-4), - seed_convergence_sigma2_thresh(200.0) - {} - } options_; - - DepthFilter( - feature_detection::DetectorPtr feature_detector, - callback_t seed_converged_cb); - - virtual ~DepthFilter(); - - /// Start this thread when seed updating should be in a parallel thread. - void startThread(); - - /// Stop the parallel thread that is running. - void stopThread(); - - /// Add frame to the queue to be processed. - void addFrame(FramePtr frame); - - /// Add new keyframe to the queue - void addKeyframe(FramePtr frame, double depth_mean, double depth_min); - - /// Remove all seeds which are initialized from the specified keyframe. This - /// function is used to make sure that no seeds points to a non-existent frame - /// when a frame is removed from the map. - void removeKeyframe(FramePtr frame); - - /// If the map is reset, call this function such that we don't have pointers - /// to old frames. - void reset(); - - /// Returns a copy of the seeds belonging to frame. Thread-safe. - /// Can be used to compute the Next-Best-View in parallel. - /// IMPORTANT! Make sure you hold a valid reference counting pointer to frame - /// so it is not being deleted while you use it. - void getSeedsCopy(const FramePtr& frame, std::list& seeds); - - /// Return a reference to the seeds. This is NOT THREAD SAFE! - //std::list& getSeeds() { return seeds_; } Bug 238 - std::list>& getSeeds() { return seeds_; } - - /// Bayes update of the seed, x is the measurement, tau2 the measurement uncertainty - static void updateSeed( - const float x, - const float tau2, - Seed* seed); - - /// Compute the uncertainty of the measurement. - static double computeTau( - const SE3& T_ref_cur, - const Vector3d& f, - const double z, - const double px_error_angle); - -protected: - feature_detection::DetectorPtr feature_detector_; - callback_t seed_converged_cb_; - std::list> seeds_; - boost::mutex seeds_mut_; - bool seeds_updating_halt_; //!< Set this value to true when seeds updating should be interrupted. - boost::thread* thread_; - std::queue frame_queue_; - boost::mutex frame_queue_mut_; - boost::condition_variable frame_queue_cond_; - FramePtr new_keyframe_; //!< Next keyframe to extract new seeds. - bool new_keyframe_set_; //!< Do we have a new keyframe to process?. - double new_keyframe_min_depth_; //!< Minimum depth in the new keyframe. Used for range in new seeds. - double new_keyframe_mean_depth_; //!< Maximum depth in the new keyframe. Used for range in new seeds. - Matcher matcher_; - uint seeds_cont_=0; - - /// Initialize new seeds from a frame. - void initializeSeeds(FramePtr frame); - - /// Update all seeds with a new measurement frame. - virtual void updateSeeds(FramePtr frame); - - /// When a new keyframe arrives, the frame queue should be cleared. - void clearFrameQueue(); - - /// A thread that is continuously updating the seeds. - void updateSeedsLoop(); -}; - -} // namespace svo - -#endif // SVO_DEPTH_FILTER_H_ diff --git a/GPU_version/vio/include/gpu_svo/feature.h b/GPU_version/vio/include/gpu_svo/feature.h deleted file mode 100644 index 2184c4b..0000000 --- a/GPU_version/vio/include/gpu_svo/feature.h +++ /dev/null @@ -1,75 +0,0 @@ -// This file is part of SVO - Semi-direct Visual Odometry. -// -// Copyright (C) 2014 Christian Forster -// (Robotics and Perception Group, University of Zurich, Switzerland). -// -// SVO is free software: you can redistribute it and/or modify it under the -// terms of the GNU General Public License as published by the Free Software -// Foundation, either version 3 of the License, or any later version. -// -// SVO is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#ifndef SVO_FEATURE_H_ -#define SVO_FEATURE_H_ - -#include - -namespace svo { - -/// A salient image region that is tracked across frames. -struct Feature -{ - EIGEN_MAKE_ALIGNED_OPERATOR_NEW - - enum FeatureType { - CORNER, - EDGELET - }; - - FeatureType type; //!< Type can be corner or edgelet. - Frame* frame; //!< Pointer to frame in which the feature was detected. - Vector2d px; //!< Coordinates in pixels on pyramid level 0. - Vector3d f; //!< Unit-bearing vector of the feature. - int level; //!< Image pyramid level where feature was extracted. - Point* point; //!< Pointer to 3D point which corresponds to the feature. - Vector2d grad; //!< Dominant gradient direction for edglets, normalized. - - Feature(Frame* _frame, const Vector2d& _px, int _level) : - type(CORNER), - frame(_frame), - px(_px), - f(frame->cam_->cam2world(px)), - level(_level), - point(NULL), - grad(1.0,0.0) - {} - - Feature(Frame* _frame, const Vector2d& _px, const Vector3d& _f, int _level) : - type(CORNER), - frame(_frame), - px(_px), - f(_f), - level(_level), - point(NULL), - grad(1.0,0.0) - {} - - Feature(Frame* _frame, Point* _point, const Vector2d& _px, const Vector3d& _f, int _level) : - type(CORNER), - frame(_frame), - px(_px), - f(_f), - level(_level), - point(_point), - grad(1.0,0.0) - {} -}; - -} // namespace svo - -#endif // SVO_FEATURE_H_ diff --git a/GPU_version/vio/include/gpu_svo/feature_alignment.h b/GPU_version/vio/include/gpu_svo/feature_alignment.h deleted file mode 100644 index e3b40a8..0000000 --- a/GPU_version/vio/include/gpu_svo/feature_alignment.h +++ /dev/null @@ -1,63 +0,0 @@ -// This file is part of SVO - Semi-direct Visual Odometry. -// -// Copyright (C) 2014 Christian Forster -// (Robotics and Perception Group, University of Zurich, Switzerland). -// -// SVO is free software: you can redistribute it and/or modify it under the -// terms of the GNU General Public License as published by the Free Software -// Foundation, either version 3 of the License, or any later version. -// -// SVO is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#ifndef SVO_FEATURE_ALIGNMENT_H_ -#define SVO_FEATURE_ALIGNMENT_H_ - -#include - -namespace svo { - -/// Subpixel refinement of a reference feature patch with the current image. -/// Implements the inverse-compositional approach (see "Lucas-Kanade 20 Years on" -/// paper by Baker. -namespace feature_alignment { - -bool align1D( - const cv::Mat& cur_img, - const Vector2f& dir, // direction in which the patch is allowed to move - uint8_t* ref_patch_with_border, - uint8_t* ref_patch, - const int n_iter, - Vector2d& cur_px_estimate, - double& h_inv); - -bool align2D( - const cv::Mat& cur_img, - uint8_t* ref_patch_with_border, - uint8_t* ref_patch, - const int n_iter, - Vector2d& cur_px_estimate, - bool no_simd = false); - -bool align2D_SSE2( - const cv::Mat& cur_img, - uint8_t* ref_patch_with_border, - uint8_t* ref_patch, - const int n_iter, - Vector2d& cur_px_estimate); - -bool align2D_NEON( - const cv::Mat& cur_img, - uint8_t* ref_patch_with_border, - uint8_t* ref_patch, - const int n_iter, - Vector2d& cur_px_estimate); - -} // namespace feature_alignment -} // namespace svo - -#endif // SVO_FEATURE_ALIGNMENT_H_ diff --git a/GPU_version/vio/include/gpu_svo/feature_detection.h b/GPU_version/vio/include/gpu_svo/feature_detection.h deleted file mode 100644 index 4dc5ec8..0000000 --- a/GPU_version/vio/include/gpu_svo/feature_detection.h +++ /dev/null @@ -1,111 +0,0 @@ -// This file is part of SVO - Semi-direct Visual Odometry. -// -// Copyright (C) 2014 Christian Forster -// (Robotics and Perception Group, University of Zurich, Switzerland). -// -// SVO is free software: you can redistribute it and/or modify it under the -// terms of the GNU General Public License as published by the Free Software -// Foundation, either version 3 of the License, or any later version. -// -// SVO is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#ifndef SVO_FEATURE_DETECTION_H_ -#define SVO_FEATURE_DETECTION_H_ - -#include -#include -#include - -namespace svo { - -/// Implementation of various feature detectors. -namespace feature_detection { - -/// Temporary container used for corner detection. Features are initialized from these. -struct Corner -{ - int x; //!< x-coordinate of corner in the image. - int y; //!< y-coordinate of corner in the image. - int level; //!< pyramid level of the corner. - float score; //!< shi-tomasi score of the corner. - float angle; //!< for gradient-features: dominant gradient angle. - Corner(int x, int y, float score, int level, float angle) : - x(x), y(y), level(level), score(score), angle(angle) - {} -}; -typedef vector Corners; - -/// All detectors should derive from this abstract class. -class AbstractDetector -{ -public: - AbstractDetector( - const int img_width, - const int img_height, - const int cell_size, - const int n_pyr_levels); - - virtual ~AbstractDetector() { - }; - - virtual void detect( - Frame* frame, - const ImgPyr& img_pyr, - const double detection_threshold, - Features& fts) = 0; - - /// Flag the grid cell as occupied - void setGridOccpuancy(const Vector2d& px); - - /// Set grid cells of existing features as occupied - void setExistingFeatures(const Features& fts); - -protected: - - static const int border_ = 8; //!< no feature should be within 8px of border. - const int cell_size_; - const int n_pyr_levels_; - const int grid_n_cols_; - const int grid_n_rows_; - vector grid_occupancy_; - - void resetGrid(); - - inline int getCellIndex(int x, int y, int level) - { - const int scale = (1< DetectorPtr; - -/// FAST detector by Edward Rosten. -class FastDetector : public AbstractDetector -{ -public: - FastDetector( - const int img_width, - const int img_height, - const int cell_size, - opencl* gpu_fast_, - const int n_pyr_levels); - - virtual ~FastDetector() {} - - virtual void detect( - Frame* frame, - const ImgPyr& img_pyr, - const double detection_threshold, - Features& fts); - opencl* gpu_fast_; -}; - -} // namespace feature_detection -} // namespace svo - -#endif // SVO_FEATURE_DETECTION_H_ diff --git a/GPU_version/vio/include/gpu_svo/for_it.hpp b/GPU_version/vio/include/gpu_svo/for_it.hpp deleted file mode 100755 index 808f3cf..0000000 --- a/GPU_version/vio/include/gpu_svo/for_it.hpp +++ /dev/null @@ -1,87 +0,0 @@ -// -// Created by root on 5/12/21. -// - -#ifndef GPU_SVO_FOR_IT_H -#define GPU_SVO_FOR_IT_H -#include -#include -#include - -//https://stackoverflow.com/questions/24881799/get-index-in-c11-foreach-loop -// Wrapper class -template -class for_impl -{ -public: - // The return value of the operator* of the iterator, this - // is what you will get inside of the for loop - struct item - { - size_t index; - typename T::value_type & item; - }; - typedef item value_type; - - // Custom iterator with minimal interface - struct iterator - { - iterator(typename T::iterator _it, size_t counter=0) : - it(_it), counter(counter) - {} - - iterator operator++() - { - return iterator(++it, ++counter); - } - - bool operator!=(iterator other) - { - return it != other.it; - } - - typename T::iterator::value_type item() - { - return *it; - } - - value_type operator*() - { - return value_type{counter, *it}; - } - - size_t index() - { - return counter; - } - - private: - typename T::iterator it; - size_t counter; - }; - - for_impl(T & t) : container(t) {} - - iterator begin() - { - return iterator(container.begin()); - } - - iterator end() - { - return iterator(container.end()); - } - -private: - T & container; -}; - - -// A templated free function allows you to create the wrapper class -// conveniently -template -for_impl _for(T & t) -{ - return for_impl(t); -} -#endif //GPU_SVO_FOR_IT_H diff --git a/GPU_version/vio/include/gpu_svo/frame.h b/GPU_version/vio/include/gpu_svo/frame.h deleted file mode 100644 index 3d1fd72..0000000 --- a/GPU_version/vio/include/gpu_svo/frame.h +++ /dev/null @@ -1,185 +0,0 @@ -// This file is part of SVO - Semi-direct Visual Odometry. -// -// Copyright (C) 2014 Christian Forster -// (Robotics and Perception Group, University of Zurich, Switzerland). -// -// SVO is free software: you can redistribute it and/or modify it under the -// terms of the GNU General Public License as published by the Free Software -// Foundation, either version 3 of the License, or any later version. -// -// SVO is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#ifndef SVO_FRAME_H_ -#define SVO_FRAME_H_ - -#include -#include -#include -#include -#include - -namespace g2o { -class VertexSE3Expmap; -} -typedef g2o::VertexSE3Expmap g2oFrameSE3; - -namespace svo { - -class Point; -struct Feature; - -typedef list Features; -typedef vector ImgPyr; - - -/// A frame saves the image, the associated features and the estimated pose. -class Frame : boost::noncopyable -{ -public: - EIGEN_MAKE_ALIGNED_OPERATOR_NEW - - static int frame_counter_; //!< Counts the number of created frames. Used to set the unique id. - int id_; //!< Unique id of the frame. - double timestamp_; //!< Timestamp of when the image was recorded. - vk::AbstractCamera* cam_; //!< Camera model. - SE2_5 T_f_w_; //!< Transform (f)rame from (w)orld. - Matrix Cov_; //!< Covariance. - ImgPyr img_pyr_; //!< Image Pyramid. - Features fts_; //!< List of features in the image. - vector key_pts_; //!< Five features and associated 3D points which are used to detect if two frames have overlapping field of view. - bool is_keyframe_; //!< Was this frames selected as keyframe? - g2oFrameSE3* v_kf_; //!< Temporary pointer to the g2o node object of the keyframe. - int last_published_ts_; //!< Timestamp of last publishing. - - Frame(vk::AbstractCamera* cam, const cv::Mat& img, double timestamp); - ~Frame(); - - /// Initialize new frame and create image pyramid. - void initFrame(const cv::Mat& img); - - /// Select this frame as keyframe. - void setKeyframe(); - - /// Add a feature to the image - void addFeature(Feature* ftr); - - /// The KeyPoints are those five features which are closest to the 4 image corners - /// and to the center and which have a 3D point assigned. These points are used - /// to quickly check whether two frames have overlapping field of view. - void setKeyPoints(); - - /// Check if we can select five better key-points. - void checkKeyPoints(Feature* ftr); - - /// If a point is deleted, we must remove the corresponding key-point. - void removeKeyPoint(Feature* ftr); - - /// Return number of point observations. - inline size_t nObs() const { return fts_.size(); } - - /// Check if a point in (w)orld coordinate frame is visible in the image. - bool isVisible(const Vector3d& xyz_w) const; - - /// Full resolution image stored in the frame. - inline const cv::Mat& img() const { return img_pyr_[0]; } - - /// Was this frame selected as keyframe? - inline bool isKeyframe() const { return is_keyframe_; } - - /// Transforms point coordinates in world-frame (w) to camera pixel coordinates (c). - inline Vector2d w2c(const Vector3d& xyz_w) const { - return cam_->world2cam( T_f_w_.se3()*xyz_w); - } - /// Transforms point coordinates in world-frame (w) to camera pixel coordinates (c). - inline Vector2d w2px(const Vector3d& xyz_w) const { return cam_->world2cam( xyz_w ); } - - /// Transforms pixel coordinates (c) to frame unit sphere coordinates (f). - inline Vector3d c2f(const Vector2d& px) const { return cam_->cam2world(px[0], px[1]); } - - /// Transforms pixel coordinates (c) to frame unit sphere coordinates (f). - inline Vector3d c2f(const double x, const double y) const { return cam_->cam2world(x, y); } - - /// Transforms point coordinates in world-frame (w) to camera-frams (f). - inline Vector3d w2f(const Vector3d& xyz_w) const { - return Vector3d(T_f_w_.se3()*xyz_w); - } - - /// Transforms point from frame unit sphere (f) frame to world coordinate frame (w). - inline Vector3d f2w(const Vector3d& f) const { - return getSE3Inv() * f; - } - - /// Projects Point from unit sphere (f) in camera pixels (c). - inline Vector2d f2c(const Vector3d& f) const { return cam_->world2cam( f ); } - - /// Return the pose of the frame in the (w)orld coordinate frame. - inline Vector2d pos() const { return T_f_w_.se2().translation(); } - - inline SE3 se3() const{ - return T_f_w_.se3(); - } - - inline SE3 getSE3Inv() const{ - Eigen::Matrix R; - R<& J) - { - const double x = xyz_in_f[0]; - const double y = xyz_in_f[1]; - const double z_inv = 1./xyz_in_f[2]; - const double z_inv_2 = z_inv*z_inv; - - J(0,0) = -z_inv; // -1/z - J(0,1) = x*z_inv_2; // x/z^2 - J(0,2) = -(1.0 + pow(x,2)/z_inv_2); // -(1.0 + x^2/z^2) - - J(1,0) = 1e-19; // 0 - J(1,1) = y*z_inv_2; // y/z^2 - J(1,2) = -x*y/z_inv_2; // -x*y/z^2 - } - inline static void jacobian_l2uv( - const Matrix& p, - Matrix& J){ - double A = -1.0*sqrt(p.z()); - double z_inv = -1/p.z(); - J(0,0) = z_inv; - J(0,1) = 1e-19; - J(0,2) = p.x()*A; - - J(1,0) = 1e-19; - J(1,1) = z_inv; - J(1,2) =A*p.y(); - } -}; - - -/// Some helper functions for the frame object. -namespace frame_utils { - -/// Creates an image pyramid of half-sampled images. -void createImgPyramid(const cv::Mat& img_level_0, int n_levels, ImgPyr& pyr); - -/// Get the average depth of the features in the image. -bool getSceneDepth(const Frame& frame, double& depth_mean, double& depth_min); - -} // namespace frame_utils -} // namespace svo - -#endif // SVO_FRAME_H_ diff --git a/GPU_version/vio/include/gpu_svo/frame_handler_base.h b/GPU_version/vio/include/gpu_svo/frame_handler_base.h deleted file mode 100644 index 99b4195..0000000 --- a/GPU_version/vio/include/gpu_svo/frame_handler_base.h +++ /dev/null @@ -1,118 +0,0 @@ -// This file is part of SVO - Semi-direct Visual Odometry. -// -// Copyright (C) 2014 Christian Forster -// (Robotics and Perception Group, University of Zurich, Switzerland). -// -// SVO is free software: you can redistribute it and/or modify it under the -// terms of the GNU General Public License as published by the Free Software -// Foundation, either version 3 of the License, or any later version. -// -// SVO is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#ifndef SVO_FRAME_HANDLER_BASE_H_ -#define SVO_FRAME_HANDLER_BASE_H_ - -#include -#include -#include -#include -#include -#include - -namespace vk -{ -class AbstractCamera; -//class PerformanceMonitor; -} - -namespace svo -{ -class Point; -class Matcher; -class DepthFilter; - -/// Base class for various VO pipelines. Manages the map and the state machine. -class FrameHandlerBase : boost::noncopyable -{ -public: - enum Stage { - STAGE_PAUSED, - STAGE_FIRST_FRAME, - STAGE_SECOND_FRAME, - STAGE_DEFAULT_FRAME, - STAGE_RELOCALIZING - }; - enum TrackingQuality { - TRACKING_INSUFFICIENT, - TRACKING_BAD, - TRACKING_GOOD - }; - enum UpdateResult { - RESULT_NO_KEYFRAME, - RESULT_IS_KEYFRAME, - RESULT_FAILURE - }; - - FrameHandlerBase(); - - virtual ~FrameHandlerBase(); - - /// Get the current map. - const Map& map() const { return map_; } - - /// Will reset the map as soon as the current frame is finished processing. - void reset() { set_reset_ = true; } - - /// Start processing. - void start() { set_start_ = true; } - - /// Get the current stage of the algorithm. - Stage stage() const { return stage_; } - - /// Get tracking quality. - TrackingQuality trackingQuality() const { return tracking_quality_; } - - /// Get the processing time of the previous iteration. - //double lastProcessingTime() const { return timer_.getTime(); } - - /// Get the number of feature observations of the last frame. - // size_t lastNumObservations() const { return num_obs_last_; } - -protected: - Stage stage_; //!< Current stage of the algorithm. - bool set_reset_; //!< Flag that the user can set. Will reset the system before the next iteration. - bool set_start_; //!< Flag the user can set to start the system when the next image is received. - Map map_; //!< Map of keyframes created by the slam system. - size_t num_obs_last_; //!< Number of observations in the previous frame. - TrackingQuality tracking_quality_; //!< An estimate of the tracking quality based on the number of tracked features. - - /// Before a frame is processed, this function is called. - bool startFrameProcessingCommon(const double timestamp); - - /// When a frame is finished processing, this function is called. - int finishFrameProcessingCommon( - const size_t update_id, - const UpdateResult dropout, - const size_t num_observations); - - /// Reset the map and frame handler to start from scratch. - void resetCommon(); - - /// Reset the frame handler. Implement in derived class. - virtual void resetAll() { resetCommon(); } - - /// Set the tracking quality based on the number of tracked features. - virtual void setTrackingQuality(const size_t num_observations); - - /// Optimize some of the observed 3D points. - virtual void optimizeStructure(FramePtr frame, size_t max_n_pts, int max_iter); -}; - -} // namespace nslam - -#endif // SVO_FRAME_HANDLER_BASE_H_ diff --git a/GPU_version/vio/include/gpu_svo/frame_handler_mono.h b/GPU_version/vio/include/gpu_svo/frame_handler_mono.h deleted file mode 100644 index 2e3b6ed..0000000 --- a/GPU_version/vio/include/gpu_svo/frame_handler_mono.h +++ /dev/null @@ -1,109 +0,0 @@ -// This file is part of SVO - Semi-direct Visual Odometry. -// -// Copyright (C) 2014 Christian Forster -// (Robotics and Perception Group, University of Zurich, Switzerland). -// -// SVO is free software: you can redistribute it and/or modify it under the -// terms of the GNU General Public License as published by the Free Software -// Foundation, either version 3 of the License, or any later version. -// -// SVO is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#ifndef SVO_FRAME_HANDLER_H_ -#define SVO_FRAME_HANDLER_H_ - -#include -#include -#include -#include -#include -#include -#include - -namespace svo { - -/// Monocular Visual Odometry Pipeline as described in the SVO paper. -class FrameHandlerMono : public FrameHandlerBase -{ -public: - EIGEN_MAKE_ALIGNED_OPERATOR_NEW - - FrameHandlerMono(vk::AbstractCamera* cam,Eigen::Matrix& init); - virtual ~FrameHandlerMono(); - - /// Provide an image. - void addImage(const cv::Mat& img, double timestamp,const ros::Time& time); - - /// Set the first frame (used for synthetic datasets in benchmark node) - void setFirstFrame(const FramePtr& first_frame); - - /// Get the last frame that has been processed. - FramePtr lastFrame() { return last_frame_; } - - /// Get the set of spatially closest keyframes of the last frame. - const set& coreKeyframes() { return core_kfs_; } - - /// Return the feature track to visualize the KLT tracking during initialization. - const vector& initFeatureTrackRefPx() const { return klt_homography_init_->px_ref_; } - const vector& initFeatureTrackCurPx() const { return klt_homography_init_->px_cur_; } - - /// Access the depth filter. - DepthFilter* depthFilter() const{ return depth_filter_; } - - /// An external place recognition module may know where to relocalize. - bool relocalizeFrameAtPose( - const int keyframe_id, - const SE3& T_kf_f, - const cv::Mat& img, - const double timestamp); - //std::shared_ptr imu_integPtr_; //Integration of IMU - void UpdateIMU(double* value,const ros::Time& time); - void UpdateCmd(double* value,const ros::Time& time); - UKF ukfPtr_; - -protected: - vk::AbstractCamera* cam_; //!< Camera model, can be ATAN, Pinhole or Ocam (see vikit). - Reprojector reprojector_; //!< Projects points from other keyframes into the current frame - FramePtr new_frame_; //!< Current frame. - FramePtr last_frame_; //!< Last frame, not necessarily a keyframe. - set core_kfs_; //!< Keyframes in the closer neighbourhood. - vector< pair > overlap_kfs_; //!< All keyframes with overlapping field of view. the paired number specifies how many common mappoints are observed TODO: why vector!? - initialization::KltHomographyInit* klt_homography_init_; //!< Used to estimate pose of the first two keyframes by estimating a homography. - DepthFilter* depth_filter_; //!< Depth estimation algorithm runs in a parallel thread and is used to initialize new 3D points. - opencl* gpu_fast_; - ros::Time time_; - - /// Initialize the visual odometry algorithm. - virtual void initialize(); - - /// Processes the first frame and sets it as a keyframe. - virtual UpdateResult processFirstFrame(); - - /// Processes all frames after the first frame until a keyframe is selected. - virtual UpdateResult processSecondFrame(); - - /// Processes all frames after the first two keyframes. - virtual UpdateResult processFrame(); - - /// Try relocalizing the frame at relative position to provided keyframe. - virtual UpdateResult relocalizeFrame( - const SE3& T_cur_ref, - FramePtr ref_keyframe); - - /// Reset the frame handler. Implement in derived class. - virtual void resetAll(); - - /// Keyframe selection criterion. - virtual bool needNewKf(double scene_depth_mean); - - void setCoreKfs(size_t n_closest); -}; - -} // namespace svo - -#endif // SVO_FRAME_HANDLER_H_ diff --git a/GPU_version/vio/include/gpu_svo/global.h b/GPU_version/vio/include/gpu_svo/global.h deleted file mode 100644 index 60d0f55..0000000 --- a/GPU_version/vio/include/gpu_svo/global.h +++ /dev/null @@ -1,120 +0,0 @@ -// This file is part of SVO - Semi-direct Visual Odometry. -// -// Copyright (C) 2014 Christian Forster -// (Robotics and Perception Group, University of Zurich, Switzerland). -// -// SVO is free software: you can redistribute it and/or modify it under the -// terms of the GNU General Public License as published by the Free Software -// Foundation, either version 3 of the License, or any later version. -// -// SVO is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#ifndef SVO_GLOBAL_H_ -#define SVO_GLOBAL_H_ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#ifndef RPG_SVO_VIKIT_IS_VECTOR_SPECIALIZED //Guard for rpg_vikit -#define RPG_SVO_VIKIT_IS_VECTOR_SPECIALIZED -EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Eigen::Vector3d) -EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Eigen::Vector2d) -#endif -#include -#define SVO_DEBUG_STREAM(x) ROS_DEBUG_STREAM(x) -#define SVO_INFO_STREAM(x) ROS_INFO_STREAM(x) -#define SVO_WARN_STREAM(x) ROS_WARN_STREAM(x) -#define SVO_WARN_STREAM_THROTTLE(rate, x) ROS_WARN_STREAM_THROTTLE(rate, x) -#define SVO_ERROR_STREAM(x) ROS_ERROR_STREAM(x) - - -namespace svo -{ - using namespace Eigen; - using namespace Sophus; - - const double EPS = 0.0000000001; - const double PI = 3.14159265; - class SE2_5: public SE2{ - public: - SE2_5(SE2&& se2):T2_(se2){ - } - SE2_5(SE2& se2):T2_(se2){ - } - SE2_5(SE3&& se3){ - Quaterniond q=se3.unit_quaternion().normalized(); - double pitch=asin(2.0*(q.w()*q.y()-q.z()*q.x())); - if (std::abs(pitch) >= 1) - pitch = std::copysign(M_PI / 2.0, pitch); // use 90 degrees if out of range - else - pitch = std::asin(pitch); - Eigen::Matrix R; - R<= 1) - pitch = std::copysign(M_PI / 2.0, pitch); // use 90 degrees if out of range - else - pitch = std::asin(pitch); - Eigen::Matrix R; - R< R; - R< R; - R< FramePtr; -} // namespace svo - -#endif // SVO_GLOBAL_H_ diff --git a/GPU_version/vio/include/gpu_svo/homography.h b/GPU_version/vio/include/gpu_svo/homography.h deleted file mode 100644 index 7f5a7b2..0000000 --- a/GPU_version/vio/include/gpu_svo/homography.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * homography.cpp - * Adaptation of PTAM-GPL HomographyInit class. - * https://github.com/Oxford-PTAM/PTAM-GPL - * Licence: GPLv3 - * Copyright 2008 Isis Innovation Limited - * - * Created on: Sep 2, 2012 - * by: cforster - * - * This class implements the homography decomposition of Faugeras and Lustman's - * 1988 tech report. Code converted to Eigen from PTAM. - * - */ - -#ifndef HOMOGRAPHY_H_ -#define HOMOGRAPHY_H_ - -#include -#include -#include -#include - -namespace vk { - -using namespace Eigen; -using namespace std; - -struct HomographyDecomposition -{ - Vector3d t; - Matrix3d R; - double d; - Vector3d n; - - // Resolved Composition - Sophus::SE3 T; //!< second from first - int score; -}; - -class Homography -{ -public: - EIGEN_MAKE_ALIGNED_OPERATOR_NEW - - Homography (const vector >& _fts1, - const vector >& _fts2, - double _error_multiplier2, - double _thresh_in_px); - - void - calcFromPlaneParams (const Vector3d & normal, - const Vector3d & point_on_plane); - - void - calcFromMatches (); - - size_t - computeMatchesInliers (); - - bool - computeSE3fromMatches (); - - bool - decompose (); - - void - findBestDecomposition (); - - double thresh; - double error_multiplier2; - const vector >& fts_c1; //!< Features on first image on unit plane - const vector >& fts_c2; //!< Features on second image on unit plane - vector inliers; - SE3 T_c2_from_c1; //!< Relative translation and rotation of two images - Matrix3d H_c2_from_c1; //!< Homography - vector decompositions; -}; - - - - -} /* end namespace vk */ - -#endif /* HOMOGRAPHY_H_ */ diff --git a/GPU_version/vio/include/gpu_svo/initialization.h b/GPU_version/vio/include/gpu_svo/initialization.h deleted file mode 100644 index 28fddbf..0000000 --- a/GPU_version/vio/include/gpu_svo/initialization.h +++ /dev/null @@ -1,87 +0,0 @@ -// This file is part of SVO - Semi-direct Visual Odometry. -// -// Copyright (C) 2014 Christian Forster -// (Robotics and Perception Group, University of Zurich, Switzerland). -// -// SVO is free software: you can redistribute it and/or modify it under the -// terms of the GNU General Public License as published by the Free Software -// Foundation, either version 3 of the License, or any later version. -// -// SVO is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#ifndef SVO_INITIALIZATION_H -#define SVO_INITIALIZATION_H - -#include -#include -//#include "../../gtsam/imu_integration.h" - -namespace svo { - -class FrameHandlerMono; - -/// Bootstrapping the map from the first two views. -namespace initialization { - -enum InitResult { FAILURE, NO_KEYFRAME, SUCCESS }; - -/// Tracks features using Lucas-Kanade tracker and then estimates a homography. -class KltHomographyInit { - friend class svo::FrameHandlerMono; -public: - EIGEN_MAKE_ALIGNED_OPERATOR_NEW - - FramePtr frame_ref_; - KltHomographyInit(opencl* gpu_fast_):gpu_fast_(gpu_fast_),T_cur_from_ref_(0.0,0.0,0.0) {}; - ~KltHomographyInit() {}; - InitResult addFirstFrame(FramePtr frame_ref); - InitResult addSecondFrame(FramePtr frame_ref); - void reset(); - -protected: - vector px_ref_; //!< keypoints to be tracked in reference frame. - vector px_cur_; //!< tracked keypoints in current frame. - vector f_ref_; //!< bearing vectors corresponding to the keypoints in the reference image. - vector f_cur_; //!< bearing vectors corresponding to the keypoints in the current image. - vector disparities_; //!< disparity between first and second frame. - vector inliers_; //!< inliers after the geometric check (e.g., Homography). - vector xyz_in_cur_; //!< 3D points computed during the geometric check. - SE2_5 T_cur_from_ref_; //!< computed transformation between the first two frames. - opencl* gpu_fast_; -}; - -/// Detect Fast corners in the image. -void detectFeatures( - FramePtr frame, - vector& px_vec, - vector& f_vec, - opencl* gpu_fast); - -/// Compute optical flow (Lucas Kanade) for selected keypoints. -void trackKlt( - FramePtr frame_ref, - FramePtr frame_cur, - vector& px_ref, - vector& px_cur, - vector& f_ref, - vector& f_cur, - vector& disparities); - -void computeHomography( - const vector& f_ref, - const vector& f_cur, - double focal_length, - double reprojection_threshold, - vector& inliers, - vector& xyz_in_cur, - SE2_5& T_cur_from_ref); - -} // namespace initialization -} // namespace svo - -#endif // SVO_INITIALIZATION_H diff --git a/GPU_version/vio/include/gpu_svo/map.h b/GPU_version/vio/include/gpu_svo/map.h deleted file mode 100644 index d4a02e0..0000000 --- a/GPU_version/vio/include/gpu_svo/map.h +++ /dev/null @@ -1,137 +0,0 @@ -// This file is part of SVO - Semi-direct Visual Odometry. -// -// Copyright (C) 2014 Christian Forster -// (Robotics and Perception Group, University of Zurich, Switzerland). -// -// SVO is free software: you can redistribute it and/or modify it under the -// terms of the GNU General Public License as published by the Free Software -// Foundation, either version 3 of the License, or any later version. -// -// SVO is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#ifndef SVO_MAP_H_ -#define SVO_MAP_H_ - -#include -#include -#include -#include - -namespace svo { - -class Point; -class Feature; -class Seed; - -/// Container for converged 3D points that are not already assigned to two keyframes. -class MapPointCandidates -{ -public: - typedef pair PointCandidate; - typedef list PointCandidateList; - - /// The depth-filter is running in a parallel thread and fills the canidate list. - /// This mutex controls concurrent access to point_candidates. - boost::mutex mut_; - - /// Candidate points are created from converged seeds. - /// Until the next keyframe, these points can be used for reprojection and pose optimization. - PointCandidateList candidates_; - list< Point* > trash_points_; - - MapPointCandidates(); - ~MapPointCandidates(); - - /// Add a candidate point. - void newCandidatePoint(Point* point, double depth_sigma2); - - /// Adds the feature to the frame and deletes candidate from list. - void addCandidatePointToFrame(FramePtr frame); - - /// Remove a candidate point from the list of candidates. - bool deleteCandidatePoint(Point* point); - - /// Remove all candidates that belong to a frame. - void removeFrameCandidates(FramePtr frame); - - /// Reset the candidate list, remove and delete all points. - void reset(); - - void deleteCandidate(PointCandidate& c); - - void emptyTrash(); -}; -static bool syn_=false; -/// Map object which saves all keyframes which are in a map. -class Map : boost::noncopyable -{ -public: - list< FramePtr > keyframes_; //!< List of keyframes in the map. - list< Point* > trash_points_; //!< A deleted point is moved to the trash bin. Now and then this is cleaned. One reason is that the visualizer must remove the points also. - MapPointCandidates point_candidates_; - - - Map(); - ~Map(); - - /// Reset the map. Delete all keyframes and reset the frame and point counters. - void reset(); - - /// Delete a point in the map and remove all references in keyframes to it. - void safeDeletePoint(Point* pt); - - /// Moves the point to the trash queue which is cleaned now and then. - void deletePoint(Point* pt); - - /// Moves the frame to the trash queue which is cleaned now and then. - bool safeDeleteFrame(FramePtr frame); - - /// Remove the references between a point and a frame. - void removePtFrameRef(Frame* frame, Feature* ftr); - - /// Add a new keyframe to the map. - void addKeyframe(FramePtr new_keyframe); - - /// Given a frame, return all keyframes which have an overlapping field of view. - void getCloseKeyframes(const FramePtr& frame, list< pair >& close_kfs) const; - - /// Return the keyframe which is spatially closest and has overlapping field of view. - FramePtr getClosestKeyframe(const FramePtr& frame) const; - - /// Return the keyframe which is furthest apart from pos. - FramePtr getFurthestKeyframe(const Vector2d& pos) const; - - bool getKeyframeById(const int id, FramePtr& frame) const; - - /// Transform the whole map with rotation R, translation t and scale s. - void transform(const Matrix2d& R, const Vector2d& t, const double& s); - - /// Empty trash bin of deleted keyframes and map points. We don't delete the - /// points immediately to ensure proper cleanup and to provide the visualizer - /// a list of objects which must be removed. - void emptyTrash(); - - /// Return the keyframe which was last inserted in the map. - inline FramePtr lastKeyframe() { return keyframes_.back(); } - - /// Return the number of keyframes in the map - inline size_t size() const { return keyframes_.size(); } -}; - -/// A collection of debug functions to check the data consistency. -namespace map_debug { - -void mapStatistics(Map* map); -void mapValidation(Map* map, int id); -void frameValidation(Frame* frame, int id); -void pointValidation(Point* point, int id); - -} // namespace map_debug -} // namespace svo - -#endif // SVO_MAP_H_ diff --git a/GPU_version/vio/include/gpu_svo/matcher.h b/GPU_version/vio/include/gpu_svo/matcher.h deleted file mode 100644 index 1d37b57..0000000 --- a/GPU_version/vio/include/gpu_svo/matcher.h +++ /dev/null @@ -1,130 +0,0 @@ -// This file is part of SVO - Semi-direct Visual Odometry. -// -// Copyright (C) 2014 Christian Forster -// (Robotics and Perception Group, University of Zurich, Switzerland). -// -// SVO is free software: you can redistribute it and/or modify it under the -// terms of the GNU General Public License as published by the Free Software -// Foundation, either version 3 of the License, or any later version. -// -// SVO is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#ifndef SVO_MATCHER_H_ -#define SVO_MATCHER_H_ - -#include - -namespace vk { - class AbstractCamera; - namespace patch_score { - template class ZMSSD; - } -} - -namespace svo { - -class Point; -class Frame; -class Feature; - -/// Warp a patch from the reference view to the current view. -namespace warp { - -void getWarpMatrixAffine( - const vk::AbstractCamera& cam_ref, - const vk::AbstractCamera& cam_cur, - const Vector2d& px_ref, - const Vector3d& f_ref, - const double depth_ref, - const SE3& T_cur_ref, - const int level_ref, - Matrix2d& A_cur_ref); - -int getBestSearchLevel( - const Matrix2d& A_cur_ref, - const int max_level); - -bool warpAffine( - const Matrix2d& A_cur_ref, - const cv::Mat& img_ref, - const Vector2d& px_ref, - const int level_ref, - const int level_cur, - const int halfpatch_size, - uint8_t* patch); - -} // namespace warp - -/// Patch-matcher for reprojection-matching and epipolar search in triangulation. -class Matcher -{ -public: - EIGEN_MAKE_ALIGNED_OPERATOR_NEW - - static const int halfpatch_size_ = 4; - static const int patch_size_ = 8; - - typedef vk::patch_score::ZMSSD PatchScore; - - struct Options - { - bool align_1d; //!< in epipolar search: align patch 1D along epipolar line - int align_max_iter; //!< number of iterations for aligning the feature patches in gauss newton - double max_epi_length_optim;//!< max length of epipolar line to skip epipolar search and directly go to img align - size_t max_epi_search_steps;//!< max number of evaluations along epipolar line - bool subpix_refinement; //!< do gauss newton feature patch alignment after epipolar search - bool epi_search_edgelet_filtering; - double epi_search_edgelet_max_angle; - Options() : - align_1d(false), - align_max_iter(10), - max_epi_length_optim(2.0), - max_epi_search_steps(1000), - subpix_refinement(true), - epi_search_edgelet_filtering(true), - epi_search_edgelet_max_angle(0.7) - {} - } options_; - - uint8_t patch_[patch_size_*patch_size_] __attribute__ ((aligned (16))); - uint8_t patch_with_border_[(patch_size_+2)*(patch_size_+2)] __attribute__ ((aligned (16))); - Matrix2d A_cur_ref_; //!< affine warp matrix - Vector2d epi_dir_; - double epi_length_; //!< length of epipolar line segment in pixels (only used for epipolar search) - double h_inv_; //!< hessian of 1d image alignment along epipolar line - int search_level_; - bool reject_; - Feature* ref_ftr_; - Vector2d px_cur_; - - Matcher() = default; - ~Matcher() = default; - - /// Find a match by directly applying subpix refinement. - /// IMPORTANT! This function assumes that px_cur is already set to an estimate that is within ~2-3 pixel of the final result! - bool findMatchDirect( - const Point& pt, - const Frame& frame, - Vector2d& px_cur); - - /// Find a match by searching along the epipolar line without using any features. - bool findEpipolarMatchDirect( - const Frame& ref_frame, - const Frame& cur_frame, - const Feature& ref_ftr, - const double d_estimate, - const double d_min, - const double d_max, - double& depth); - - void createPatchFromPatchWithBorder(); -}; - -} // namespace svo - -#endif // SVO_MATCHER_H_ diff --git a/GPU_version/vio/include/gpu_svo/math_utils.h b/GPU_version/vio/include/gpu_svo/math_utils.h deleted file mode 100644 index 6fffc38..0000000 --- a/GPU_version/vio/include/gpu_svo/math_utils.h +++ /dev/null @@ -1,171 +0,0 @@ -/* - * math_utils.h - * - * Created on: Jul 20, 2012 - * Author: cforster - */ - -#ifndef MATH_UTILS_H_ -#define MATH_UTILS_H_ - - -#include -#include -#include - -namespace vk -{ - -using namespace Eigen; -using namespace std; -using namespace Sophus; - -Vector3d triangulateFeatureNonLin( - const Matrix3d& R, - const Vector3d& t, - const Vector3d& feature1, - const Vector3d& feature2); - -/// Assumes the bearing vectors f_c and f_r are on the epipolar plane, i.e. -/// perfect triangulation without noise! -bool depthFromTriangulationExact( - const Matrix3d& R_r_c, - const Vector3d& t_r_c, - const Vector3d& f_r, - const Vector3d& f_c, - double& depth_in_r, - double& depth_in_c); - -double reprojError( - const Vector3d& f1, - const Vector3d& f2, - double error_multiplier2); - -double computeInliers( - const vector& features1, - const vector& features2, - const Matrix3d& R, - const Vector3d& t, - const double reproj_thresh, - double error_multiplier2, - vector& xyz_vec, - vector& inliers, - vector& outliers); - -void computeInliersOneView( - const vector & feature_sphere_vec, - const vector & xyz_vec, - const Matrix3d &R, - const Vector3d &t, - const double reproj_thresh, - const double error_multiplier2, - vector& inliers, - vector& outliers); - -//! Direct Cosine Matrix to Roll Pitch Yaw -Vector3d dcm2rpy(const Matrix3d &R); - -//! Roll Pitch Yaw to Direct Cosine Matrix -Matrix3d rpy2dcm(const Vector3d &rpy); - -//! Angle Axis parametrization to Quaternion -Quaterniond angax2quat(const Vector3d& n, const double& angle); - -//! Angle Axis parametrization to Matrix representation -Matrix3d angax2dcm(const Vector3d& n, const double& angle); - -double sampsonusError( - const Vector2d &v2Dash, - const Matrix3d& m3Essential, - const Vector2d& v2); - -inline Matrix3d sqew(const Vector3d& v) -{ - Matrix3d v_sqew; - v_sqew << 0, -v[2], v[1], - v[2], 0, -v[0], - -v[1], v[0], 0; - return v_sqew; -} - -inline double norm_max(const Eigen::VectorXd & v) -{ - double max = -1; - for (int i=0; imax){ - max = abs; - } - } - return max; -} - -inline Vector2d project2d(const Vector3d& v) -{ - return v.head<2>()/v[2]; -} - -inline Vector3d unproject2d(const Vector2d& v) -{ - return Vector3d(v[0], v[1], 1.0); -} - -inline Vector3d project3d(const Vector4d& v) -{ - return v.head<3>()/v[3]; -} - -inline Vector4d unproject3d(const Vector3d& v) -{ - return Vector4d(v[0], v[1], v[2], 1.0); -} - -template -T getMedian(vector& data_vec) -{ - assert(!data_vec.empty()); - typename vector::iterator it = data_vec.begin()+floor(data_vec.size()/2); - nth_element(data_vec.begin(), it, data_vec.end()); - return *it; -} - -inline double pyrFromZero_d(double x_0, int level) -{ - return x_0/(1< & frame_jac) -{ - const double x = xyz[0]; - const double y = xyz[1]; - const double z = xyz[2]; - const double z_2 = z*z; - - frame_jac(0,0) = -1./z *focal_length; - frame_jac(0,1) = 0; - frame_jac(0,2) = x/z_2 *focal_length; - frame_jac(0,3) = x*y/z_2 * focal_length; - frame_jac(0,4) = -(1+(x*x/z_2)) *focal_length; - frame_jac(0,5) = y/z *focal_length; - - frame_jac(1,0) = 0; - frame_jac(1,1) = -1./z *focal_length; - frame_jac(1,2) = y/z_2 *focal_length; - frame_jac(1,3) = (1+y*y/z_2) *focal_length; - frame_jac(1,4) = -x*y/z_2 *focal_length; - frame_jac(1,5) = -x/z *focal_length; -} - -} // end namespace vk - -#endif /* MATH_UTILS_H_ */ diff --git a/GPU_version/vio/include/gpu_svo/nlls_solver.h b/GPU_version/vio/include/gpu_svo/nlls_solver.h deleted file mode 100644 index cb6320b..0000000 --- a/GPU_version/vio/include/gpu_svo/nlls_solver.h +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Abstract Nonlinear Least-Squares Solver Class - * - * nlls_solver.h - * - * Created on: Nov 5, 2012 - * Author: cforster - */ - -#ifndef LM_SOLVER_H_ -#define LM_SOLVER_H_ - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace vk { - -using namespace std; -using namespace Eigen; - -/** - * \brief Abstract Class for solving nonlinear least-squares (NLLS) problems. - * - * The function implements two algorithms: Levenberg Marquardt and Gauss Newton - * - * Example implementations of this function can be found in the rpl_examples - * package: img_align_2d.cpp, img_align_3d.cpp - * - * Template Parameters: - * D : dimension of the residual - * T : type of the model, e.g. SE2, SE3 - */ - -template -class NLLSSolver { - -public: - typedef T ModelType; - enum Method{GaussNewton, LevenbergMarquardt}; - enum ScaleEstimatorType{UnitScale, TDistScale, MADScale, NormalScale}; - enum WeightFunctionType{UnitWeight, TDistWeight, TukeyWeight, HuberWeight}; - -protected: - Matrix H_; //!< Hessian approximation - Matrix Jres_; //!< Jacobian x Residual - Matrix x_; //!< update step - bool have_prior_; - ModelType prior_; - Matrix I_prior_; //!< Prior information matrix (inverse covariance) - double chi2_; - double rho_; - Method method_; - - /// If the flag linearize_system is set, the function must also compute the - /// Jacobian and set the member variables H_, Jres_ - virtual double - computeResiduals (const ModelType& model, - bool linearize_system, - bool compute_weight_scale) = 0; - - /// Solve the linear system H*x = Jres. This function must set the update - /// step in the member variable x_. Must return true if the system could be - /// solved and false if it was singular. - virtual int - solve () = 0; - - virtual void - update (const ModelType& old_model, ModelType& new_model) = 0; - - virtual void - applyPrior (const ModelType& current_model) { } - - virtual void - startIteration () { } - - virtual void - finishIteration () { } - - virtual void - finishTrial () { } - -public: - - /// Damping parameter. If mu > 0, coefficient matrix is positive definite, this - /// ensures that x is a descent direction. If mu is large, x is a short step in - /// the steepest direction. This is good if the current iterate is far from the - /// solution. If mu is small, LM approximates gauss newton iteration and we - /// have (almost) quadratic convergence in the final stages. - double mu_init_, mu_; - double nu_init_, nu_; //!< Increase factor of mu after fail - size_t n_iter_init_, n_iter_; //!< Number of Iterations - size_t n_trials_; //!< Number of trials - size_t n_trials_max_; //!< Max number of trials - size_t n_meas_; //!< Number of measurements - bool stop_; //!< Stop flag - bool verbose_; //!< Output Statistics - double eps_; //!< Stop if update norm is smaller than eps - size_t iter_; //!< Current Iteration - - // robust least squares - bool use_weights_; - float scale_; - robust_cost::ScaleEstimatorPtr scale_estimator_; - robust_cost::WeightFunctionPtr weight_function_; - - NLLSSolver() : - have_prior_(false), - method_(LevenbergMarquardt), - mu_init_(0.01f), - mu_(mu_init_), - nu_init_(2.0), - nu_(nu_init_), - n_iter_init_(15), - n_iter_(n_iter_init_), - n_trials_(0), - n_trials_max_(5), - n_meas_(0), - stop_(false), - verbose_(true), - eps_(0.0000000001), - iter_(0), - use_weights_(false), - scale_(0.0), - scale_estimator_(NULL), - weight_function_(NULL) - { } - - virtual ~NLLSSolver() {} - - /// Calls the GaussNewton or LevenbergMarquardt optimization strategy - void optimize(ModelType& model); - - /// Gauss Newton optimization strategy - void optimizeGaussNewton(ModelType& model); - - /// Levenberg Marquardt optimization strategy - void optimizeLevenbergMarquardt(ModelType& model); - - /// Specify the robust cost that should be used and the appropriate scale estimator - void setRobustCostFunction( - ScaleEstimatorType scale_estimator, - WeightFunctionType weight_function); - - /// Add prior to optimization. - void setPrior( - const ModelType& prior, - const Matrix& Information); - - /// Reset all parameters to restart the optimization - void reset(); - - /// Get the squared error - const double& getChi2() const; - - /// The Information matrix is equal to the inverse covariance matrix. - const Matrix& getInformationMatrix() const; -}; - -} // end namespace vk - -#include "gpu_svo/nlls_solver_impl.hpp" - -#endif /* LM_SOLVER_H_ */ diff --git a/GPU_version/vio/include/gpu_svo/nlls_solver_impl.hpp b/GPU_version/vio/include/gpu_svo/nlls_solver_impl.hpp deleted file mode 100644 index 2ce9302..0000000 --- a/GPU_version/vio/include/gpu_svo/nlls_solver_impl.hpp +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Abstract Nonlinear Least-Squares Solver Class - * - * nlls_solver.h - * - * Created on: Nov 5, 2012 - * Author: cforster - */ - -#ifndef LM_SOLVER_IMPL_HPP_ -#define LM_SOLVER_IMPL_HPP_ - -#include - -template -void vk::NLLSSolver::optimize(ModelType& model) -{ - if(method_ == GaussNewton) - optimizeGaussNewton(model); - else if(method_ == LevenbergMarquardt) - optimizeLevenbergMarquardt(model); -} - -template -void vk::NLLSSolver::optimizeGaussNewton(ModelType& model) -{ - // Compute weight scale - if(use_weights_) - computeResiduals(model, false, true); - - // Save the old model to rollback in case of unsuccessful update - ModelType old_model(model); - - // perform iterative estimation - for (iter_ = 0; iter_::Identity(D,D); - Jres_.setZero(); - - // compute initial error - n_meas_ = 0; - computeResiduals(model, true, false); - - // add damping term: - H_ += (H_.diagonal()*mu_).asDiagonal(); - - // add prior - if(have_prior_) - applyPrior(model); - - // solve the linear system - if(solve()) - { - // update the model - update(model, new_model); - - // compute error with new model and compare to old error - n_meas_ = 0; - new_chi2 = computeResiduals(new_model, true, false); - rho_ = chi2_-new_chi2; - } - else - { - // matrix was singular and could not be computed - cout << "Matrix is close to singular!" << endl; - cout << "H = " << H_ << endl; - cout << "Jres = " << Jres_ << endl; - rho_ = -1; - } - - if(rho_>0) - { - // update decrased the error -> success - model = new_model; - chi2_ = new_chi2; - stop_ = vk::norm_max(x_)<=eps_ ? true : false; - mu_ *= max(1./3., min(1.-pow(2*rho_-1,3), 2./3.)); - nu_ = 2.; - if(verbose_) - { - cout << "It. " << iter_ - << "\t Trial " << n_trials_ - << "\t Success" - << "\t n_meas = " << n_meas_ - << "\t new_chi2 = " << new_chi2 - << "\t mu = " << mu_ - << "\t nu = " << nu_ - << "\t x_norm = " << vk::norm_max(x_) - << endl; - } - } - else - { - if(sign){ - if(verbose_) - { - cout << "It. " << iter_ - << "\t Trial " << n_trials_ - << "\t Failure" - << "\t n_meas = " << n_meas_ - << "\t new_chi2 = " << new_chi2 - << "\t mu = " << mu_ - << "\t nu = " << nu_ - << "\t x_norm = " << vk::norm_max(x_) - << endl; - } - mu_ /= nu_; - nu_ /= 2.; - ++n_trials_; - if (n_trials_ >= n_trials_max_) - stop_ = true; - sign=false; - }else{ - if(verbose_) - { - cout << "It. " << iter_ - << "\t Trial " << n_trials_ - << "\t Failure" - << "\t n_meas = " << n_meas_ - << "\t new_chi2 = " << new_chi2 - << "\t mu = " << mu_ - << "\t nu = " << nu_ - << "\t x_norm = " << vk::norm_max(x_) - << endl; - } - mu_ *= nu_; - nu_ *= 2.; - ++n_trials_; - if (n_trials_ >= n_trials_max_) - stop_ = true; - sign=true; - } - - } - - finishTrial(); - - } while(!(rho_>0 || stop_)); - if (stop_) - break; - - finishIteration(); - } -} - - -template -void vk::NLLSSolver::setRobustCostFunction( - ScaleEstimatorType scale_estimator, - WeightFunctionType weight_function) -{ - switch(scale_estimator) - { - case TDistScale: - if(verbose_) - printf("Using TDistribution Scale Estimator\n"); - scale_estimator_.reset(new robust_cost::TDistributionScaleEstimator()); - use_weights_=true; - break; - case MADScale: - if(verbose_) - printf("Using MAD Scale Estimator\n"); - scale_estimator_.reset(new robust_cost::MADScaleEstimator()); - use_weights_=true; - break; - case NormalScale: - if(verbose_) - printf("Using Normal Scale Estimator\n"); - scale_estimator_.reset(new robust_cost::NormalDistributionScaleEstimator()); - use_weights_=true; - break; - default: - if(verbose_) - printf("Using Unit Scale Estimator\n"); - scale_estimator_.reset(new robust_cost::UnitScaleEstimator()); - use_weights_=false; - } - - switch(weight_function) - { - case TDistWeight: - if(verbose_) - printf("Using TDistribution Weight Function\n"); - weight_function_.reset(new robust_cost::TDistributionWeightFunction()); - break; - case TukeyWeight: - if(verbose_) - printf("Using Tukey Weight Function\n"); - weight_function_.reset(new robust_cost::TukeyWeightFunction()); - break; - case HuberWeight: - if(verbose_) - printf("Using Huber Weight Function\n"); - weight_function_.reset(new robust_cost::HuberWeightFunction()); - break; - default: - if(verbose_) - printf("Using Unit Weight Function\n"); - weight_function_.reset(new robust_cost::UnitWeightFunction()); - } -} - -template -void vk::NLLSSolver::setPrior( - const T& prior, - const Matrix& Information) -{ - have_prior_ = true; - prior_ = prior; - I_prior_ = Information; -} - -template -void vk::NLLSSolver::reset() -{ - have_prior_ = false; - chi2_ = 1e10; - mu_ = mu_init_; - nu_ = nu_init_; - n_meas_ = 0; - n_iter_ = n_iter_init_; - iter_ = 0; - stop_ = false; -} - -template -inline const double& vk::NLLSSolver::getChi2() const -{ - return chi2_; -} - -template -inline const vk::Matrix& vk::NLLSSolver::getInformationMatrix() const -{ - return H_; -} - -#endif /* LM_SOLVER_IMPL_HPP_ */ diff --git a/GPU_version/vio/include/gpu_svo/output_helper.h b/GPU_version/vio/include/gpu_svo/output_helper.h deleted file mode 100644 index b1572a8..0000000 --- a/GPU_version/vio/include/gpu_svo/output_helper.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * output_helper.h - * - * Created on: Jan 20, 2013 - * Author: cforster - */ - -#ifndef VIKIT_OUTPUT_HELPER_H_ -#define VIKIT_OUTPUT_HELPER_H_ - -#include -#include -#include -#include -#include - -using namespace std; -using namespace Eigen; - -void -publishTfTransform (const Sophus::SE3& T, const ros::Time& stamp, - const string& frame_id, const string& child_frame_id, - tf::TransformBroadcaster& br); - -void -publishPointMarker (ros::Publisher pub, - const Vector3d& pos, - const string& ns, - const ros::Time& timestamp, - int id, - int action, - double marker_scale, - const Vector3d& color, - ros::Duration lifetime = ros::Duration(0.0)); - -void -publishLineMarker (ros::Publisher pub, - const Vector3d& start, - const Vector3d& end, - const string& ns, - const ros::Time& timestamp, - int id, - int action, - double marker_scale, - const Vector3d& color, - ros::Duration lifetime = ros::Duration(0.0)); - -void -publishArrowMarker (ros::Publisher pub, - const Vector3d& pos, - const Vector3d& dir, - double scale, - const string& ns, - const ros::Time& timestamp, - int id, - int action, - double marker_scale, - const Vector3d& color); - -void -publishHexacopterMarker (ros::Publisher pub, - const string& frame_id, - const string& ns, - const ros::Time& timestamp, - int id, - int action, - double marker_scale, - const Vector3d& color); - -void -publishCameraMarker(ros::Publisher pub, - const string& frame_id, - const string& ns, - const ros::Time& timestamp, - int id, - double marker_scale, - const Vector3d& color); -void -publishFrameMarker (ros::Publisher pub, - const Matrix3d& rot, - const Vector3d& pos, - const string& ns, - const ros::Time& timestamp, - int id, - int action, - double marker_scale, - ros::Duration lifetime = ros::Duration(0.0)); - - -#endif /* VIKIT_OUTPUT_HELPER_H_ */ diff --git a/GPU_version/vio/include/gpu_svo/params_helper.h b/GPU_version/vio/include/gpu_svo/params_helper.h deleted file mode 100644 index f8a03dc..0000000 --- a/GPU_version/vio/include/gpu_svo/params_helper.h +++ /dev/null @@ -1,57 +0,0 @@ -// -// Created by root on 5/24/21. -// - -#ifndef GPU_SVO_PARAMS_HELPER_H -#define GPU_SVO_PARAMS_HELPER_H -/* - * ros_params_helper.h - * - * Created on: Feb 22, 2013 - * Author: cforster - * - * from libpointmatcher_ros - */ - -#include -#include - -namespace vk { - - inline - bool hasParam(const std::string& name) - { - return ros::param::has(name); - } - - template - T getParam(const std::string& name, const T& defaultValue) - { - T v; - if(ros::param::get(name, v)) - { - ROS_INFO_STREAM("Found parameter: " << name << ", value: " << v); - return v; - } - else - ROS_WARN_STREAM("Cannot find value for parameter: " << name << ", assigning default: " << defaultValue); - return defaultValue; - } - - template - T getParam(const std::string& name) - { - T v; - if(ros::param::get(name, v)) - { - ROS_INFO_STREAM("Found parameter: " << name << ", value: " << v); - return v; - } - else - ROS_ERROR_STREAM("Cannot find value for parameter: " << name); - return T(); - } - -} // namespace vk - -#endif //GPU_SVO_PARAMS_HELPER_H diff --git a/GPU_version/vio/include/gpu_svo/patch_score.h b/GPU_version/vio/include/gpu_svo/patch_score.h deleted file mode 100644 index 8f0516c..0000000 --- a/GPU_version/vio/include/gpu_svo/patch_score.h +++ /dev/null @@ -1,225 +0,0 @@ -/* - * patch_score.h - * - * Created on: Dec 5, 2013 - * Author: cforster - */ - -#ifndef VIKIT_PATCH_SCORE_H_ -#define VIKIT_PATCH_SCORE_H_ - -#include - -#if __SSE2__ -#include -#endif - -namespace vk { -namespace patch_score { - - -#if __SSE2__ -// Horizontal sum of uint16s stored in an XMM register -inline int SumXMM_16(__m128i &target) -{ - unsigned short int sums_store[8]; - _mm_storeu_si128((__m128i*)sums_store, target); - return sums_store[0] + sums_store[1] + sums_store[2] + sums_store[3] + - sums_store[4] + sums_store[5] + sums_store[6] + sums_store[7]; -} -// Horizontal sum of uint32s stored in an XMM register -inline int SumXMM_32(__m128i &target) -{ - unsigned int sums_store[4]; - _mm_storeu_si128((__m128i*)sums_store, target); - return sums_store[0] + sums_store[1] + sums_store[2] + sums_store[3]; -} -#endif - -/// Zero Mean Sum of Squared Differences Cost -template -class ZMSSD { -public: - - static const int patch_size_ = 2*HALF_PATCH_SIZE; - static const int patch_area_ = patch_size_*patch_size_; - static const int threshold_ = 2000*patch_area_; - uint8_t* ref_patch_; - int sumA_, sumAA_; - - ZMSSD(uint8_t* ref_patch) : - ref_patch_(ref_patch) - { - uint32_t sumA_uint=0, sumAA_uint=0; - for(int r = 0; r < patch_area_; r++) - { - uint8_t n = ref_patch_[r]; - sumA_uint += n; - sumAA_uint += n*n; - } - sumA_ = sumA_uint; - sumAA_ = sumAA_uint; - } - - static int threshold() { return threshold_; } - - int computeScore(uint8_t* cur_patch) const - { - uint32_t sumB_uint = 0; - uint32_t sumBB_uint = 0; - uint32_t sumAB_uint = 0; - for(int r = 0; r < patch_area_; r++) - { - const uint8_t cur_pixel = cur_patch[r]; - sumB_uint += cur_pixel; - sumBB_uint += cur_pixel*cur_pixel; - sumAB_uint += cur_pixel * ref_patch_[r]; - } - const int sumB = sumB_uint; - const int sumBB = sumBB_uint; - const int sumAB = sumAB_uint; - return sumAA_ - 2*sumAB + sumBB - (sumA_*sumA_ - 2*sumA_*sumB + sumB*sumB)/patch_area_; - } - - int computeScore(uint8_t* cur_patch, int stride) const - { - int sumB, sumBB, sumAB; -#if __SSE2__ - if(patch_size_ == 8) - { - // From PTAM-GPL, Copyright 2008 Isis Innovation Limited - __m128i xImageAsEightBytes; - __m128i xImageAsWords; - __m128i xTemplateAsEightBytes; - __m128i xTemplateAsWords; - __m128i xZero; - __m128i xImageSums; // These sums are 8xuint16 - __m128i xImageSqSums; // These sums are 4xint32 - __m128i xCrossSums; // These sums are 4xint32 - __m128i xProduct; - - xImageSums = _mm_setzero_si128(); - xImageSqSums = _mm_setzero_si128(); - xCrossSums = _mm_setzero_si128(); - xZero = _mm_setzero_si128(); - - uint8_t* imagepointer = cur_patch; - uint8_t* templatepointer = ref_patch_; - long unsigned int cur_stride = stride; - - xImageAsEightBytes=_mm_loadl_epi64((__m128i*) imagepointer); - imagepointer += cur_stride; - xImageAsWords = _mm_unpacklo_epi8(xImageAsEightBytes,xZero); - xImageSums = _mm_adds_epu16(xImageAsWords,xImageSums); - xProduct = _mm_madd_epi16(xImageAsWords, xImageAsWords); - xImageSqSums = _mm_add_epi32(xProduct, xImageSqSums); - xTemplateAsEightBytes=_mm_load_si128((__m128i*) templatepointer); - templatepointer += 16; - xTemplateAsWords = _mm_unpacklo_epi8(xTemplateAsEightBytes,xZero); - xProduct = _mm_madd_epi16(xImageAsWords, xTemplateAsWords); - xCrossSums = _mm_add_epi32(xProduct, xCrossSums); - xImageAsEightBytes=_mm_loadl_epi64((__m128i*) imagepointer); - imagepointer += cur_stride; - xImageAsWords = _mm_unpacklo_epi8(xImageAsEightBytes,xZero); - xImageSums = _mm_adds_epu16(xImageAsWords,xImageSums); - xProduct = _mm_madd_epi16(xImageAsWords, xImageAsWords); - xImageSqSums = _mm_add_epi32(xProduct, xImageSqSums); - xTemplateAsWords = _mm_unpackhi_epi8(xTemplateAsEightBytes,xZero); - xProduct = _mm_madd_epi16(xImageAsWords, xTemplateAsWords); - xCrossSums = _mm_add_epi32(xProduct, xCrossSums); - - xImageAsEightBytes=_mm_loadl_epi64((__m128i*) imagepointer); - imagepointer += cur_stride; - xImageAsWords = _mm_unpacklo_epi8(xImageAsEightBytes,xZero); - xImageSums = _mm_adds_epu16(xImageAsWords,xImageSums); - xProduct = _mm_madd_epi16(xImageAsWords, xImageAsWords); - xImageSqSums = _mm_add_epi32(xProduct, xImageSqSums); - xTemplateAsEightBytes=_mm_load_si128((__m128i*) templatepointer); - templatepointer += 16; - xTemplateAsWords = _mm_unpacklo_epi8(xTemplateAsEightBytes,xZero); - xProduct = _mm_madd_epi16(xImageAsWords, xTemplateAsWords); - xCrossSums = _mm_add_epi32(xProduct, xCrossSums); - xImageAsEightBytes=_mm_loadl_epi64((__m128i*) imagepointer); - imagepointer += cur_stride; - xImageAsWords = _mm_unpacklo_epi8(xImageAsEightBytes,xZero); - xImageSums = _mm_adds_epu16(xImageAsWords,xImageSums); - xProduct = _mm_madd_epi16(xImageAsWords, xImageAsWords); - xImageSqSums = _mm_add_epi32(xProduct, xImageSqSums); - xTemplateAsWords = _mm_unpackhi_epi8(xTemplateAsEightBytes,xZero); - xProduct = _mm_madd_epi16(xImageAsWords, xTemplateAsWords); - xCrossSums = _mm_add_epi32(xProduct, xCrossSums); - - xImageAsEightBytes=_mm_loadl_epi64((__m128i*) imagepointer); - imagepointer += cur_stride; - xImageAsWords = _mm_unpacklo_epi8(xImageAsEightBytes,xZero); - xImageSums = _mm_adds_epu16(xImageAsWords,xImageSums); - xProduct = _mm_madd_epi16(xImageAsWords, xImageAsWords); - xImageSqSums = _mm_add_epi32(xProduct, xImageSqSums); - xTemplateAsEightBytes=_mm_load_si128((__m128i*) templatepointer); - templatepointer += 16; - xTemplateAsWords = _mm_unpacklo_epi8(xTemplateAsEightBytes,xZero); - xProduct = _mm_madd_epi16(xImageAsWords, xTemplateAsWords); - xCrossSums = _mm_add_epi32(xProduct, xCrossSums); - xImageAsEightBytes=_mm_loadl_epi64((__m128i*) imagepointer); - imagepointer += cur_stride; - xImageAsWords = _mm_unpacklo_epi8(xImageAsEightBytes,xZero); - xImageSums = _mm_adds_epu16(xImageAsWords,xImageSums); - xProduct = _mm_madd_epi16(xImageAsWords, xImageAsWords); - xImageSqSums = _mm_add_epi32(xProduct, xImageSqSums); - xTemplateAsWords = _mm_unpackhi_epi8(xTemplateAsEightBytes,xZero); - xProduct = _mm_madd_epi16(xImageAsWords, xTemplateAsWords); - xCrossSums = _mm_add_epi32(xProduct, xCrossSums); - - xImageAsEightBytes=_mm_loadl_epi64((__m128i*) imagepointer); - imagepointer += cur_stride; - xImageAsWords = _mm_unpacklo_epi8(xImageAsEightBytes,xZero); - xImageSums = _mm_adds_epu16(xImageAsWords,xImageSums); - xProduct = _mm_madd_epi16(xImageAsWords, xImageAsWords); - xImageSqSums = _mm_add_epi32(xProduct, xImageSqSums); - xTemplateAsEightBytes=_mm_load_si128((__m128i*) templatepointer); - templatepointer += 16; - xTemplateAsWords = _mm_unpacklo_epi8(xTemplateAsEightBytes,xZero); - xProduct = _mm_madd_epi16(xImageAsWords, xTemplateAsWords); - xCrossSums = _mm_add_epi32(xProduct, xCrossSums); - xImageAsEightBytes=_mm_loadl_epi64((__m128i*) imagepointer); - xImageAsWords = _mm_unpacklo_epi8(xImageAsEightBytes,xZero); - xImageSums = _mm_adds_epu16(xImageAsWords,xImageSums); - xProduct = _mm_madd_epi16(xImageAsWords, xImageAsWords); - xImageSqSums = _mm_add_epi32(xProduct, xImageSqSums); - xTemplateAsWords = _mm_unpackhi_epi8(xTemplateAsEightBytes,xZero); - xProduct = _mm_madd_epi16(xImageAsWords, xTemplateAsWords); - xCrossSums = _mm_add_epi32(xProduct, xCrossSums); - - sumB = SumXMM_16(xImageSums); - sumAB = SumXMM_32(xCrossSums); - sumBB = SumXMM_32(xImageSqSums); - } - else -#endif - { - uint32_t sumB_uint = 0; - uint32_t sumBB_uint = 0; - uint32_t sumAB_uint = 0; - for(int y=0, r=0; y < patch_size_; ++y) - { - uint8_t* cur_patch_ptr = cur_patch + y*stride; - for(int x=0; x < patch_size_; ++x, ++r) - { - const uint8_t cur_px = cur_patch_ptr[x]; - sumB_uint += cur_px; - sumBB_uint += cur_px * cur_px; - sumAB_uint += cur_px * ref_patch_[r]; - } - } - sumB = sumB_uint; - sumBB = sumBB_uint; - sumAB = sumAB_uint; - } - return sumAA_ - 2*sumAB + sumBB - (sumA_*sumA_ - 2*sumA_*sumB + sumB*sumB)/patch_area_; - } -}; - -} // namespace patch_score -} // namespace vk - -#endif // VIKIT_PATCH_SCORE_H_ diff --git a/GPU_version/vio/include/gpu_svo/point.h b/GPU_version/vio/include/gpu_svo/point.h deleted file mode 100644 index 6b0f900..0000000 --- a/GPU_version/vio/include/gpu_svo/point.h +++ /dev/null @@ -1,108 +0,0 @@ -// This file is part of SVO - Semi-direct Visual Odometry. -// -// Copyright (C) 2014 Christian Forster -// (Robotics and Perception Group, University of Zurich, Switzerland). -// -// SVO is free software: you can redistribute it and/or modify it under the -// terms of the GNU General Public License as published by the Free Software -// Foundation, either version 3 of the License, or any later version. -// -// SVO is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#ifndef SVO_POINT_H_ -#define SVO_POINT_H_ - -#include -#include - -namespace g2o { - class VertexSBAPointXYZ; -} -typedef g2o::VertexSBAPointXYZ g2oPoint; - -namespace svo { - -class Feature; - -typedef Matrix Matrix23d; - -/// A 3D point on the surface of the scene. -class Point : boost::noncopyable -{ -public: - EIGEN_MAKE_ALIGNED_OPERATOR_NEW - - enum PointType { - TYPE_DELETED, - TYPE_CANDIDATE, - TYPE_UNKNOWN, - TYPE_GOOD - }; - - static int point_counter_; //!< Counts the number of created points. Used to set the unique id. - int id_; //!< Unique ID of the point. - Vector3d pos_; //!< 3d pos of the point in the world coordinate frame. - Vector3d normal_; //!< Surface normal at point. - Matrix3d normal_information_; //!< Inverse covariance matrix of normal estimation. - bool normal_set_; //!< Flag whether the surface normal was estimated or not. - list obs_; //!< References to keyframes which observe the point. - size_t n_obs_; //!< Number of obervations: Keyframes AND successful reprojections in intermediate frames. - g2oPoint* v_pt_; //!< Temporary pointer to the point-vertex in g2o during bundle adjustment. - int last_published_ts_; //!< Timestamp of last publishing. - int last_projected_kf_id_; //!< Flag for the reprojection: don't reproject a pt twice. - PointType type_; //!< Quality of the point. - int n_failed_reproj_; //!< Number of failed reprojections. Used to assess the quality of the point. - int n_succeeded_reproj_; //!< Number of succeeded reprojections. Used to assess the quality of the point. - int last_structure_optim_; //!< Timestamp of last point optimization - - Point(const Vector3d& pos); - Point(const Vector3d& pos, Feature* ftr); - ~Point(); - - /// Add a reference to a frame. - void addFrameRef(Feature* ftr); - - /// Remove reference to a frame. - bool deleteFrameRef(Frame* frame); - - /// Initialize point normal. The inital estimate will point towards the frame. - void initNormal(); - - /// Check whether mappoint has reference to a frame. - Feature* findFrameRef(Frame* frame); - - /// Get Frame with similar viewpoint. - bool getCloseViewObs(const Vector2d& pos, Feature*& obs) const; - - /// Get number of observations. - inline size_t nRefs() const { return obs_.size(); } - - /// Optimize point position through minimizing the reprojection error. - void optimize(const size_t n_iter); - - /// Jacobian of point projection on unit plane (focal length = 1) in frame (f). - inline static void jacobian_xyz2uv( - const Vector3d& p_in_f, - const Matrix3d& R_f_w, - Matrix23d& point_jac) - { - const double z_inv = 1.0/p_in_f[2]; - const double z_inv_sq = z_inv*z_inv; - point_jac(0, 0) = z_inv; - point_jac(0, 1) = 0.0; - point_jac(0, 2) = -p_in_f[0] * z_inv_sq; - point_jac(1, 0) = 0.0; - point_jac(1, 1) = z_inv; - point_jac(1, 2) = -p_in_f[1] * z_inv_sq; - point_jac = - point_jac * R_f_w; - } -}; - -} // namespace svo - -#endif // SVO_POINT_H_ diff --git a/GPU_version/vio/include/gpu_svo/pose_optimizer.h b/GPU_version/vio/include/gpu_svo/pose_optimizer.h deleted file mode 100644 index d0ad926..0000000 --- a/GPU_version/vio/include/gpu_svo/pose_optimizer.h +++ /dev/null @@ -1,50 +0,0 @@ -// This file is part of SVO - Semi-direct Visual Odometry. -// -// Copyright (C) 2014 Christian Forster -// (Robotics and Perception Group, University of Zurich, Switzerland). -// -// SVO is free software: you can redistribute it and/or modify it under the -// terms of the GNU General Public License as published by the Free Software -// Foundation, either version 3 of the License, or any later version. -// -// SVO is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#ifndef SVO_POSE_OPTIMIZER_H_ -#define SVO_POSE_OPTIMIZER_H_ - -#include - -namespace svo { - -using namespace Eigen; -using namespace Sophus; -using namespace std; - -typedef Matrix Matrix6d; -typedef Matrix Matrix26d; -typedef Matrix Vector6d; - -class Point; - -/// Motion-only bundle adjustment. Minimize the reprojection error of a single frame. -namespace pose_optimizer { - -void optimizeGaussNewton( - const double reproj_thresh, - const size_t n_iter, - const bool verbose, - FramePtr& frame, - double& estimated_scale, - double& error_init, - double& error_final, - size_t& num_obs); - -} // namespace pose_optimizer -} // namespace svo - -#endif // SVO_POSE_OPTIMIZER_H_ diff --git a/GPU_version/vio/include/gpu_svo/reprojector.h b/GPU_version/vio/include/gpu_svo/reprojector.h deleted file mode 100644 index 8d50c35..0000000 --- a/GPU_version/vio/include/gpu_svo/reprojector.h +++ /dev/null @@ -1,101 +0,0 @@ -// This file is part of SVO - Semi-direct Visual Odometry. -// -// Copyright (C) 2014 Christian Forster -// (Robotics and Perception Group, University of Zurich, Switzerland). -// -// SVO is free software: you can redistribute it and/or modify it under the -// terms of the GNU General Public License as published by the Free Software -// Foundation, either version 3 of the License, or any later version. -// -// SVO is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#ifndef SVO_REPROJECTION_H_ -#define SVO_REPROJECTION_H_ - -#include -#include - -namespace vk { -class AbstractCamera; -} - -namespace svo { - -class Map; -class Point; - -/// Project points from the map into the image and find the corresponding -/// feature (corner). We don't search a match for every point but only for one -/// point per cell. Thereby, we achieve a homogeneously distributed set of -/// matched features and at the same time we can save processing time by not -/// projecting all points. -class Reprojector -{ -public: - EIGEN_MAKE_ALIGNED_OPERATOR_NEW - - /// Reprojector config parameters - struct Options { - size_t max_n_kfs; //!< max number of keyframes to reproject from - bool find_match_direct; - Options() - : max_n_kfs(10), - find_match_direct(true) - {} - } options_; - - size_t n_matches_; - size_t n_trials_; - - Reprojector(vk::AbstractCamera* cam, Map& map); - - ~Reprojector(); - - /// Project points from the map into the image. First finds keyframes with - /// overlapping field of view and projects only those map-points. - void reprojectMap( - FramePtr frame, - std::vector< std::pair >& overlap_kfs); - -private: - - /// A candidate is a point that projects into the image plane and for which we - /// will search a maching feature in the image. - struct Candidate { - EIGEN_MAKE_ALIGNED_OPERATOR_NEW - Point* pt; //!< 3D point. - Vector2d px; //!< projected 2D pixel location. - Candidate(Point* pt, Vector2d& px) : pt(pt), px(px) {} - }; - typedef std::list Cell; - typedef std::vector CandidateGrid; - - /// The grid stores a set of candidate matches. For every grid cell we try to find one match. - struct Grid - { - CandidateGrid cells; - vector cell_order; - int cell_size; - int grid_n_cols; - int grid_n_rows; - }; - - Grid grid_; - Matcher matcher_; - Map& map_; - - static bool pointQualityComparator(Candidate& lhs, Candidate& rhs); - void initializeGrid(vk::AbstractCamera* cam); - void resetGrid(); - bool reprojectCell(Cell& cell, FramePtr frame); - bool reprojectPoint(FramePtr frame, Point* point); -}; - -} // namespace svo - -#endif // SVO_REPROJECTION_H_ diff --git a/GPU_version/vio/include/gpu_svo/robust_cost.h b/GPU_version/vio/include/gpu_svo/robust_cost.h deleted file mode 100644 index d03881a..0000000 --- a/GPU_version/vio/include/gpu_svo/robust_cost.h +++ /dev/null @@ -1,156 +0,0 @@ -/** -* This file is part of dvo. -* -* Copyright 2012 Christian Kerl (Technical University of Munich) -* For more information see . -* -* dvo is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* dvo is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with dvo. If not, see . -*/ - -#ifndef VIKIT_ROBUST_COST_H_ -#define VIKIT_ROBUST_COST_H_ - -#include -#include -#include -namespace vk { -namespace robust_cost { - -// interface for scale estimators -class ScaleEstimator -{ -public: - virtual ~ScaleEstimator() {}; - virtual float compute(std::vector& errors) const = 0; -}; -typedef std::shared_ptr ScaleEstimatorPtr; - -class UnitScaleEstimator : public ScaleEstimator -{ -public: - UnitScaleEstimator() {} - virtual ~UnitScaleEstimator() {} - virtual float compute(std::vector& errors) const { return 1.0f; }; -}; - -// estimates scale by fitting a t-distribution to the data with the given degrees of freedom -class TDistributionScaleEstimator : public ScaleEstimator -{ -public: - TDistributionScaleEstimator(const float dof = DEFAULT_DOF); - virtual ~TDistributionScaleEstimator() {}; - virtual float compute(std::vector& errors) const; - - static const float DEFAULT_DOF; - static const float INITIAL_SIGMA; -protected: - float dof_; - float initial_sigma_; -}; - -// estimates scale by computing the median absolute deviation -class MADScaleEstimator : public ScaleEstimator -{ -public: - MADScaleEstimator() {}; - virtual ~MADScaleEstimator() {}; - virtual float compute(std::vector& errors) const; - -private: - static const float NORMALIZER;; -}; - -// estimates scale by computing the standard deviation -class NormalDistributionScaleEstimator : public ScaleEstimator -{ -public: - NormalDistributionScaleEstimator() {}; - virtual ~NormalDistributionScaleEstimator() {}; - virtual float compute(std::vector& errors) const; -private: -}; - -/** - * Interface for weight functions. A weight function is the first derivative of a symmetric robust function p(sqrt(t)). - * The errors are assumed to be normalized to unit variance. - * - * See: - * "Lucas-Kanade 20 Years On: A Unifying Framework: Part 2" - Page 23, Equation (54) - */ -class WeightFunction -{ -public: - virtual ~WeightFunction() {}; - virtual float value(const float& x) const = 0; - virtual void configure(const float& param) {}; -}; -typedef std::shared_ptr WeightFunctionPtr; - -class UnitWeightFunction : public WeightFunction -{ -public: - UnitWeightFunction() {}; - virtual ~UnitWeightFunction() {}; - virtual float value(const float& x) const { return 1.0f; }; -}; - -/** - * Tukey's hard re-descending function. - * - * See: - * http://en.wikipedia.org/wiki/Redescending_M-estimator - */ -class TukeyWeightFunction : public WeightFunction -{ -public: - TukeyWeightFunction(const float b = DEFAULT_B); - virtual ~TukeyWeightFunction() {}; - virtual float value(const float& x) const; - virtual void configure(const float& param); - - static const float DEFAULT_B; -private: - float b_square; -}; - -class TDistributionWeightFunction : public WeightFunction -{ -public: - TDistributionWeightFunction(const float dof = DEFAULT_DOF); - virtual ~TDistributionWeightFunction() {}; - virtual float value(const float& x) const; - virtual void configure(const float& param); - - static const float DEFAULT_DOF; -private: - float dof_; - float normalizer_; -}; - -class HuberWeightFunction : public WeightFunction -{ -public: - HuberWeightFunction(const float k = DEFAULT_K); - virtual ~HuberWeightFunction() {}; - virtual float value(const float& x) const; - virtual void configure(const float& param); - - static const float DEFAULT_K; -private: - float k; -}; - -} // namespace robust_cost -} // namespace vk -#endif // VIKIT_ROBUST_COST_H_ diff --git a/GPU_version/vio/include/gpu_svo/sparse_img_align.h b/GPU_version/vio/include/gpu_svo/sparse_img_align.h deleted file mode 100644 index 1fbaace..0000000 --- a/GPU_version/vio/include/gpu_svo/sparse_img_align.h +++ /dev/null @@ -1,83 +0,0 @@ -// This file is part of SVO - Semi-direct Visual Odometry. -// -// Copyright (C) 2014 Christian Forster -// (Robotics and Perception Group, University of Zurich, Switzerland). -// -// SVO is free software: you can redistribute it and/or modify it under the -// terms of the GNU General Public License as published by the Free Software -// Foundation, either version 3 of the License, or any later version. -// -// SVO is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#ifndef SVO_SPARSE_IMG_ALIGN_H_ -#define SVO_SPARSE_IMG_ALIGN_H_ - -#include -#include - - -namespace vk { -class AbstractCamera; -} - -namespace svo { - -class Feature; - -/// Optimize the pose of the frame by minimizing the photometric error of feature patches. -class SparseImgAlign : public vk::NLLSSolver<3, SE2> -{ - static const int patch_halfsize_ = 12; - static const int patch_size_ = 12*patch_halfsize_; - static const int patch_area_ = patch_size_*patch_size_; -public: - EIGEN_MAKE_ALIGNED_OPERATOR_NEW - - cv::Mat resimg_; - - SparseImgAlign( - int n_levels, - int min_level, - int n_iter, - Method method, - bool display, - bool verbose); - - size_t run( - FramePtr ref_frame, - FramePtr cur_frame); - - /// Return fisher information matrix, i.e. the Hessian of the log-likelihood - /// at the converged state. - Matrix getFisherInformation(); - -protected: - FramePtr ref_frame_; //!< reference frame, has depth for gradient pixels. - FramePtr cur_frame_; //!< only the image is known! - int level_; //!< current pyramid level on which the optimization runs. - bool display_; //!< display residual image. - int max_level_; //!< coarsest pyramid level for the alignment. - int min_level_; //!< finest pyramid level for the alignment. - - // cache: - Matrix jacobian_cache_; - bool have_ref_patch_cache_; - cv::Mat ref_patch_cache_; - std::vector visible_fts_; - - void precomputeReferencePatches(); - virtual double computeResiduals(const SE2& model, bool linearize_system, bool compute_weight_scale = false); - virtual int solve(); - virtual void update (const ModelType& old_model, ModelType& new_model); - virtual void startIteration(); - virtual void finishIteration(); -}; - -} // namespace svo - -#endif // SVO_SPARSE_IMG_ALIGN_H_ diff --git a/GPU_version/vio/include/gpu_svo/timer.h b/GPU_version/vio/include/gpu_svo/timer.h deleted file mode 100644 index 45bbc7f..0000000 --- a/GPU_version/vio/include/gpu_svo/timer.h +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef TIMER_H -#define TIMER_H - -#include -#include -#include - -namespace vk -{ - -class Timer -{ -private: - timeval start_time_; - double time_; - double accumulated_; -public: - - /// The constructor directly starts the timer. - Timer() : - time_(0.0), - accumulated_(0.0) - { - start(); - } - - ~Timer() - {} - - inline void start() - { - accumulated_ = 0.0; - gettimeofday(&start_time_, NULL); - } - - inline void resume() - { - gettimeofday(&start_time_, NULL); - } - - inline double stop() - { - timeval end_time; - gettimeofday(&end_time, NULL); - long seconds = end_time.tv_sec - start_time_.tv_sec; - long useconds = end_time.tv_usec - start_time_.tv_usec; - time_ = ((seconds) + useconds*0.000001) + accumulated_; - accumulated_ = time_; - return time_; - } - - inline double getTime() const - { - return time_; - } - - inline void reset() - { - time_ = 0.0; - accumulated_ = 0.0; - } - - static double getCurrentTime() - { - timeval time_now; - gettimeofday(&time_now, NULL); - return time_now.tv_sec + time_now.tv_usec*0.000001; - } - - static double getCurrentSecond() - { - timeval time_now; - gettimeofday(&time_now, NULL); - return time_now.tv_sec; - } - -}; - -} // end namespace vk - -#endif diff --git a/GPU_version/vio/include/gpu_svo/ukf.h b/GPU_version/vio/include/gpu_svo/ukf.h deleted file mode 100644 index 6875b50..0000000 --- a/GPU_version/vio/include/gpu_svo/ukf.h +++ /dev/null @@ -1,155 +0,0 @@ -// -// Created by root on 6/8/21. -// -#ifndef GPU_SVO_UKF_H -#define GPU_SVO_UKF_H - -#include -#include -#include "gpu_svo/config.h" -#include -class Base{ -public: - Base(const Eigen::Matrix &init) { - state_=init; - cov_.setIdentity(); - cov_*=0.0001; - }; - virtual ~Base(){ - }; - void predict(double dx,double dz,double dpitch,double time){ - if(t_==0.0){ - t_=time; - return; - } - double dt=time-t_; - t_=time; - state_h_(2)=state_(2)+dt*dpitch; - state_h_(1)=state_(1)+dz*cos(state_(2))-dx*sin(state_(2)); - state_h_(0)=state_(0)+dx*cos(state_(2))+dz*sin(state_(2)); - Eigen::Matrix R; - R< G; - G<<1.0,0,-dx*sin(state_(2))+dz*cos(state_(2)), - 0,1.0,-dz*sin(state_(2))-dx*cos(state_(2)), - 0,0,1.0; - cov_h_=G*cov_*G.transpose()+R; - predict_up=true; - } - void correct(double ddx, double ddz, double dpitch, double time){ - Eigen::Matrix H; - Eigen::Matrix Q; - Eigen::Matrix E; - Eigen::Matrix k; - double dt=time-t_; - t_=time; - H<<1.0,0,0.5*pow(dt,2)*(ddz*cos(state_(2))-ddx*sin(state_(2))), - 0,1.0,-0.5*pow(dt,2)*(ddx*cos(state_(2))+ddz*sin(state_(2))), - 0,0,1.0; - Q< R; - R< G; - G<<1.0,0,0.5*pow(dt,2)*(ddz*cos(state_(2))-ddx*sin(state_(2))), - 0,1.0,-0.5*pow(dt,2)*(ddx*cos(state_(2))+ddz*sin(state_(2))), - 0,0,1.0; - cov_h_=G*cov_*G.transpose()+R; - yaw_t_1_=state_(2); - - } - void correct(double x, double z,double pitch,size_t match,double time){ - Eigen::Matrix H; - Eigen::Matrix Q; - Eigen::Matrix E; - Eigen::Matrix k; - t_=time; - ++match; - H<<1.0,0,0, - 0,1.0,0, - 0,0,1.0; - Q< cov_; - Eigen::Matrix state_; - bool predict_up=false; -private: - double t_=0.0; - Eigen::Matrix cov_h_; - Eigen::Matrix state_h_;//state{x,z,pitch} - double yaw_t_1_=0.0; - -}; - -class UKF { -public: - UKF(const Eigen::Matrix& init) : filter_(new Base(init)) { - }; - virtual ~UKF() { - delete filter_; - }; - void UpdateIMU(double x,double z,double pitch,const ros::Time& time) { - while(lock)usleep(5); - lock=true; - if(abs(x)<1.0)x=pow(x,3);//picked up from your code - if(abs(z)<1.0)z=pow(z,3);//picked up from your code - if(filter_->predict_up)filter_->correct(x,z,pitch,1e-9*time.toNSec()); - lock=false; - }; - void UpdateCmd(double x,double z,double pitch,const ros::Time& time) { - while(lock)usleep(5); - lock=true; - filter_->predict(x,z,pitch,1e-9*time.toNSec()); - lock=false; - }; - std::pair,svo::SE2_5> UpdateSvo(double x,double z,double pitch,size_t match,ros::Time& time) { - while(lock)usleep(5); - lock=true; - if(pitch<0.0) - pitch=M_PI-pitch; - else - pitch=pitch-M_PI; - if(filter_->predict_up)filter_->correct(-x,-z,pitch,match,1e-9*time.toNSec()); - lock=false; - double pitch_f; - if(filter_->state_(0)<0.0) - pitch_f=M_PI-filter_->state_(2); - else - pitch_f=filter_->state_(2)-M_PI; - return std::pair,svo::SE2_5>(filter_->cov_,svo::SE2_5(-filter_->state_(0),-filter_->state_(1),pitch_f)); - }; - std::pair,svo::SE2_5> get_location(){ - double pitch_f; - if(filter_->state_(0)<0.0) - pitch_f=M_PI-filter_->state_(2); - else - pitch_f=filter_->state_(2)-M_PI; - return std::pair,svo::SE2_5>(filter_->cov_,svo::SE2_5(-filter_->state_(0),-filter_->state_(1),pitch_f)); - } -private: - Base* filter_= nullptr; - bool lock=false; -}; -#endif //GPU_SVO_UKF_H diff --git a/GPU_version/vio/include/gpu_svo/vision.h b/GPU_version/vio/include/gpu_svo/vision.h deleted file mode 100644 index 3b95183..0000000 --- a/GPU_version/vio/include/gpu_svo/vision.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * vision.h - * - * Created on: May 14, 2013 - * Author: cforster - */ - -#ifndef VIKIT_VISION_H_ -#define VIKIT_VISION_H_ - -#include -#include -#include - -namespace vk -{ - -//! Return value between 0 and 1 -//! WARNING This function does not check whether the x/y is within the border -inline float -interpolateMat_32f(const cv::Mat& mat, float u, float v) -{ - assert(mat.type()==CV_32F); - float x = floor(u); - float y = floor(v); - float subpix_x = u-x; - float subpix_y = v-y; - float wx0 = 1.0-subpix_x; - float wx1 = subpix_x; - float wy0 = 1.0-subpix_y; - float wy1 = subpix_y; - - float val00 = mat.at(y,x); - float val10 = mat.at(y,x+1); - float val01 = mat.at(y+1,x); - float val11 = mat.at(y+1,x+1); - return (wx0*wy0)*val00 + (wx1*wy0)*val10 + (wx0*wy1)*val01 + (wx1*wy1)*val11; -} - -//! Return value between 0 and 255 -//! WARNING This function does not check whether the x/y is within the border -inline float -interpolateMat_8u(const cv::Mat& mat, float u, float v) -{ - if(mat.empty())return 0.0; - if(mat.type()!=CV_8U)return 0.0; - int x = floor(u); - int y = floor(v); - float subpix_x = u-x; - float subpix_y = v-y; - - float w00 = (1.0f-subpix_x)*(1.0f-subpix_y); - float w01 = (1.0f-subpix_x)*subpix_y; - float w10 = subpix_x*(1.0f-subpix_y); - float w11 = 1.0f - w00 - w01 - w10; - - const int stride = mat.step.p[0]; - unsigned char* ptr = mat.data + y*stride + x; - if(isnan(w00) || isnan(w01 )||isnan( w10) || isnan(w11) || isinf(w00) || isinf(w01)|| isinf(w10)|| isinf(w11))return 0.0; - if(ptr[0] == NULL || ptr[1]== NULL || ptr[stride]==NULL ||ptr[stride+1]==NULL)return 0.0; - return w00*ptr[0] + w01*ptr[stride] + w10*ptr[1] + w11*ptr[stride+1]; -} - -void halfSample(const cv::Mat& in, cv::Mat& out); - -float shiTomasiScore(const cv::Mat& img, int u, int v); - -void calcSharrDeriv(const cv::Mat& src, cv::Mat& dst); - -#ifdef __SSE2__ - -/// Used to convert a Kinect depthmap -/// Code by Christian Kerl DVO, GPL Licence -void convertRawDepthImageSse_16u_to_32f(cv::Mat& depth_16u, cv::Mat& depth_32f, float scale); - -#endif - -} // namespace vk - -#endif // VIKIT_VISION_H_ diff --git a/GPU_version/vio/include/gpu_svo/visualizer.h b/GPU_version/vio/include/gpu_svo/visualizer.h deleted file mode 100644 index 307c27e..0000000 --- a/GPU_version/vio/include/gpu_svo/visualizer.h +++ /dev/null @@ -1,62 +0,0 @@ -// This file is part of SVO - Semi-direct Visual Odometry. -// -// Copyright (C) 2014 Christian Forster -// (Robotics and Perception Group, University of Zurich, Switzerland). -// -// SVO is free software: you can redistribute it and/or modify it under the -// terms of the GNU General Public License as published by the Free Software -// Foundation, either version 3 of the License, or any later version. -// -// SVO is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#ifndef SVO_VISUALIZER_H_ -#define SVO_VISUALIZER_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace svo { - -class Frame; -class Point; -class Map; -class FrameHandlerMono; - -typedef boost::shared_ptr FramePtr; - -/// This class bundles all functions to publish visualisation messages. -class Visualizer -{ -public: - ros::NodeHandle pnh_; - size_t trace_id_; - ros::Publisher pub_frames_; - ros::Publisher pub_points_; - ros::Publisher pub_pose_with_cov_; - - Visualizer(); - - ~Visualizer() {}; - - void publishMinimal( - UKF& ukf, - const double timestamp); - -}; - -} // end namespace svo - -#endif /* SVO_VISUALIZER_H_ */ diff --git a/GPU_version/vio/src/frame_handler_mono.cpp b/GPU_version/vio/src/frame_handler_mono.cpp index 897432b..cf949ad 100644 --- a/GPU_version/vio/src/frame_handler_mono.cpp +++ b/GPU_version/vio/src/frame_handler_mono.cpp @@ -52,18 +52,20 @@ FrameHandlerMono::FrameHandlerMono(vk::AbstractCamera* cam,Eigen::Matrixwrite_buf(1,3,3,pose); cl_double3 f[300]={0}; gpu_fast_->write_buf(1,4,300,f); + cl_double2 px[300]={0}; + gpu_fast_->write_buf(1,5,300,px); int level=0; - gpu_fast_->write_buf(1,5,level); + gpu_fast_->write_buf(1,6,level); double c[5]={0}; - gpu_fast_->write_buf(1,6,5,c); + gpu_fast_->write_buf(1,7,5,c); float e[300]={0}; - gpu_fast_->write_buf(1,7,300,e); + gpu_fast_->write_buf(1,8,300,e); float H[6]={0}; - gpu_fast_->write_buf(1,8,6,H); + gpu_fast_->write_buf(1,9,6,H); float J[3]={0}; - gpu_fast_->write_buf(1,9,3,J); + gpu_fast_->write_buf(1,10,3,J); double chi2=0.0; - gpu_fast_->write_buf(1,10,chi2); + gpu_fast_->write_buf(1,11,chi2); imageAlign_=new SparseImgAlignGpu(Config::kltMaxLevel(), Config::kltMinLevel(), 30, SparseImgAlign::GaussNewton, false,gpu_fast_); klt_homography_init_=new initialization::KltHomographyInit(gpu_fast_); diff --git a/GPU_version/vio/src/sparse_img_align_gpu.cpp b/GPU_version/vio/src/sparse_img_align_gpu.cpp index 5a23ead..a7891d2 100644 --- a/GPU_version/vio/src/sparse_img_align_gpu.cpp +++ b/GPU_version/vio/src/sparse_img_align_gpu.cpp @@ -45,8 +45,9 @@ size_t SparseImgAlignGpu::run(FramePtr ref_frame, FramePtr cur_frame) double cur_pos[3]={cur_frame->pos()(0),cur_frame->pos()(1),cur_frame->T_f_w_.pitch()}; residual_->reload_buf(1,2,cur_pos); residual_->reload_buf(1,3,ref_pos); - residual_->reload_buf(1,6,camera); + residual_->reload_buf(1,7,camera); cl_double3* features; + cl_double2* featue_px; feature_counter_ = 0; // is used to compute the index of the cached jacobian std::vector::iterator visiblity_it = visible_fts_.begin(); for(auto it=ref_frame->fts_.begin(); it!=ref_frame->fts_.end(); @@ -57,9 +58,12 @@ size_t SparseImgAlignGpu::run(FramePtr ref_frame, FramePtr cur_frame) features[feature_counter_].x=xyz_ref(0); features[feature_counter_].y=xyz_ref(1); features[feature_counter_].z=xyz_ref(2); + featue_px[feature_counter_].x=(*it)->px(0); + featue_px[feature_counter_].y=(*it)->px(1); ++feature_counter_; } residual_->reload_buf(1,4,features); + residual_->reload_buf(1,5,featue_px); SE2 T_cur(cur_frame->T_f_w_.se2());///TODO temporary, we can remove it for(level_=max_level_; level_>=min_level_; --level_) { @@ -67,7 +71,7 @@ size_t SparseImgAlignGpu::run(FramePtr ref_frame, FramePtr cur_frame) cv::Mat& ref_img = ref_frame->img_pyr_.at(level_); residual_->reload_buf(1,0,cur_img); residual_->reload_buf(1,1,ref_img); - residual_->reload_buf(1,5,&level_); + residual_->reload_buf(1,6,&level_); mu_ = 1.0; optimize(T_cur); } @@ -81,16 +85,16 @@ double SparseImgAlignGpu::computeResiduals( bool compute_weight_scale) { double chi2=0.0; - residual_->reload_buf(1,10,&chi2); + residual_->reload_buf(1,11,&chi2); /// TODO GPU compute based on the feature residual_->run(1,feature_counter_); if(compute_weight_scale && iter_ == 0) { float error[feature_counter_]; - residual_->read(1,7,error); + residual_->read(1,8,error); std::vector errors(error,error+feature_counter_); scale_ = scale_estimator_->compute(errors); } - residual_->read(1,10,&chi2); + residual_->read(1,11,&chi2); return chi2; } @@ -98,8 +102,8 @@ int SparseImgAlignGpu::solve() { double* H; double* J; - residual_->read(1,8,H); - residual_->read(1,9,J); + residual_->read(1,9,H); + residual_->read(1,10,J); x_ = Eigen::Matrix(H).ldlt().solve(Eigen::Matrix(J)); if((bool) std::isnan((double) x_[0])) return 0; From a2802878f471c9e7c15115bd0235fb68dccff006 Mon Sep 17 00:00:00 2001 From: VahdPourAmin Date: Sat, 24 Jul 2021 22:00:49 +0200 Subject: [PATCH 06/12] opencl kernel clean and aproximately ready to test --- GPU_version/vio/kernel/compute-residual.cl | 172 ++++++++++----------- 1 file changed, 80 insertions(+), 92 deletions(-) diff --git a/GPU_version/vio/kernel/compute-residual.cl b/GPU_version/vio/kernel/compute-residual.cl index 501b558..662f14d 100644 --- a/GPU_version/vio/kernel/compute-residual.cl +++ b/GPU_version/vio/kernel/compute-residual.cl @@ -4,48 +4,44 @@ // Enable OpenCL 32-bit integer atomic functions. #pragma OPENCL EXTENSION cl_khr_global_int32_base_atomics : enable -double2 world2cam(double f_x,double f_y,double c_x,double c_y,double s_, double x, double y,double z) +double2 world2cam(double f_x, double f_y, double c_x, double c_y, double s_, double x, double y, double z) { - double2 uv=(x/z,y/z); - double r = sqrt(pow(uv[0],2)+pow(uv[1],2)); - double factor=1.0; - if(s_ !=0 || r > 0.001)factor=(atan(r * 2.0 * tan(0.5 * s_)) / (r*s_)); - return double3(cx_ + fx_ * factor * uv[0],cy_ + fy_ * factor * uv[1]); + double2 uv = (x/z, y/z); + double r = sqrt(pow(uv[0], 2) + pow(uv[1], 2)); + double factor = 1.0; + if(s_ != 0 || r > 0.001) + factor = (atan(r * 2.0 * tan(0.5 * s_)) / (r * s_)); + return double3(cx_ + fx_ * factor * uv[0], cy_ + fy_ * factor * uv[1]); } -double3 xyz_cur(double cur_x,double cur_z,double cur_pitch,double ref_x,double ref_z,double ref_pitch,double3 ref_feature){ - if(ref_pitch<0.0) - ref_pitch=3.141592653589793238462643383279502884197169399375-ref_pitch; + +double3 xyz_cur(double cur_x, double cur_z, double cur_pitch, double ref_x, double ref_z, double ref_pitch, double3 ref_feature) +{ + if(ref_pitch < 0.0) + ref_pitch = 3.141592653589793238462643383279502884197169399375 - ref_pitch; else - ref_pitch=ref_pitch-3.1415926535897932384626433832795028841971693993; - double cc_ss=cos(cur_pitch)*cos(ref_pitch)-sin(cur_pitch)*sin(ref_pitch); - double sc_cs=cos(cur_pitch)*sin(ref_pitch)+cos(ref_pitch)*sin(cur_pitch); - return double3(cc_ss*ref_feature.x()+sc_cs*ref_feature.z()+cur_x-ref_x*cos(cur_pitch)-ref_z*sin(cur_pitch), + ref_pitch = ref_pitch - 3.1415926535897932384626433832795028841971693993; + double cc_ss = cos(cur_pitch) * cos(ref_pitch) - sin(cur_pitch) * sin(ref_pitch); + double sc_cs = cos(cur_pitch) * sin(ref_pitch) + cos(ref_pitch) * sin(cur_pitch); + return double3(cc_ss * ref_feature.x() + sc_cs * ref_feature.z() + cur_x - ref_x * cos(cur_pitch) - ref_z * sin(cur_pitch), ref_feature.y(), - -1.0*sc_cs*ref_feature.x())+cc_ss*ref_feature.z()+cur_z+ref_x*sin(cur_pitch)-ref_z*cos(cur_pitch)); + -1.0 * sc_cs * ref_feature.x() + cc_ss * ref_feature.z() + cur_z + ref_x * sin(cur_pitch) - ref_z * cos(cur_pitch)); } -double3 xyz_ref(double fts_pos_x,double fts_pos_y,double fts_pos_z,double ref_x,double ref_y,double ref_z) +double3 xyz_ref(double fts_pos_x, double fts_pos_y, double fts_pos_z, double ref_x, double ref_y, double ref_z) { - double x = sqrt(pow((fts_pos_x - ref_x), 2)); - double y = sqrt(pow((fts_pos_y - ref_y), 2)); - double z = sqrt(pow((fts_pos_z - ref_z), 2)); - return double3(x, y, z); + return double3(sqrt(pow((fts_pos_x - ref_x), 2)), + sqrt(pow((fts_pos_y - ref_y), 2)), + sqrt(pow((fts_pos_z - ref_z), 2))); } -void jacobian_xyz2uv(double3& xyz_in_f, double* J) +void jacobian_xyz2uv(double3 xyz_in_f, double* J) { - double x = xyz_in_f[0]; - double y = xyz_in_f[1]; - double z_inv = 1. / xyz_in_f[2]; - double z_inv_2 = z_inv * z_inv; - - *(J + 0) = -z_inv; // -1/z - *(J + 1) = x * z_inv_2; // x/z^2 - *(J + 2) = -(1.0 + pow(x,2) / z_inv_2); // -(1.0 + x^2/z^2) - - *(J + 3) = 1e-19; // 0 - *(J + 4) = y * z_inv_2; // y/z^2 - *(J + 5) = -x * y / z_inv_2; // -x*y/z^2 + *(J + 0) = -(1. / xyz_in_f[2]); // -1/z + *(J + 1) = (xyz_in_f[0]) * ((1. / xyz_in_f[2]) * (1. / xyz_in_f[2])); // x/z^2 + *(J + 2) = -(1.0 + pow((xyz_in_f[0]),2) / ((1. / xyz_in_f[2]) * (1. / xyz_in_f[2]))); // -(1.0 + x^2/z^2) + *(J + 3) = 1e-19; // 0 + *(J + 4) = (xyz_in_f[1]) * ((1. / xyz_in_f[2]) * (1. / xyz_in_f[2])); // y/z^2 + *(J + 5) = -(xyz_in_f[0]) * (xyz_in_f[1]) / ((1. / xyz_in_f[2]) * (1. / xyz_in_f[2])); // -x*y/z^2 } void compute_hessain(double3 j, double* H, double w) @@ -88,33 +84,30 @@ __kernel void compute-residual( int border = PATCH_HALFSIZE + 1; int stride = get_image_dim(image_cur)[0]; //width, height double scale = pow(2, (-1.0 * level)); - double focal_length = camera_model[0]; - size_t feature_counter = 0; - double chi2 = 0.0; - int n_meas_ = 0; + size_t n_meas_ = 0; // Prepare a suitable OpenCL image sampler. sampler_t const sampler = CLK_ADDRESS_CLAMP | CLK_FILTER_NEAREST; // Use global work feature. int const f = get_global_id(0); - //ref_feature[f].x; - //ref_feature[f].y; - //ref_feature[f].z; + // check if reference with patch size is within image double u_ref = featue_px[f].x * scale; double v_ref = featue_px[f].y * scale; int u_ref_i = floor(u_ref); int v_ref_i = floor(v_ref); - // if(ref_feature[f]->point == NULL || u_ref_i - border < 0 || v_ref_i - border < 0 || //??????? ref_feature[f]->point - if(u_ref_i - border < 0 || v_ref_i - border < 0 || - u_ref_i + border >= get_image_dim(image_ref)[0] || v_ref_i + border >= get_image_dim(image_ref)[1]) + if(u_ref_i - (PATCH_HALFSIZE + 1) < 0 || v_ref_i - (PATCH_HALFSIZE + 1) < 0 || + u_ref_i + (PATCH_HALFSIZE + 1) >= get_image_dim(image_ref)[0] || v_ref_i + (PATCH_HALFSIZE + 1) >= get_image_dim(image_ref)[1]) return; - xyz_reference = xyz_ref(ref_feature[f][0], ref_feature[f][1], ref_feature[f][2], ref_pose.x, ref_pose.y, ref_pose.z); // ref_pose.y ???? + xyz_reference = xyz_ref(ref_feature[f][0], ref_feature[f][1], ref_feature[f][2], ref_pose.x, ref_pose.y, ref_pose.z); + // evaluate projection jacobian double* frame_jac = (double *) malloc(6 * sizeof(double)); // 2X3 jacobian_xyz2uv(xyz_reference, frame_jac); + + // compute bilateral interpolation weights for reference image double subpix_u_ref = u_ref - u_ref_i; double subpix_v_ref = v_ref - v_ref_i; double w_ref_tl = (1.0 - subpix_u_ref) * (1.0 - subpix_v_ref); @@ -122,7 +115,7 @@ __kernel void compute-residual( double w_ref_bl = (1.0 - subpix_u_ref) * subpix_v_ref; double w_ref_br = subpix_u_ref * subpix_v_ref; size_t pixel_counter = 0; - /// compute residual ... + double3 xyz_current = xyz_cur(cur_pose.x, cur_pose.z, cur_pose.pitch, ref_pose.x ,ref_pose.z ,ref_pose.pitch, ref_feature[f]); double2 uv_cur_pyr = world2cam(camera_model[0], camera_model[1], camera_model[2], camera_model[3], camera_model[4], xyz_current[0], xyz_current[1], xyz_current[2]) * scale; @@ -132,9 +125,10 @@ __kernel void compute-residual( int v_cur_i = floor(v_cur); // check if projection is within the image - if(u_cur_i < 0 || v_cur_i < 0 || u_cur_i - border < 0 || v_cur_i - border < 0 || - u_cur_i + border >= get_image_dim(image_cur)[0] || v_cur_i + border >= get_image_dim(image_cur)[0]) - return; + if(u_cur_i < 0 || v_cur_i < 0 || u_cur_i - (PATCH_HALFSIZE + 1) < 0 || v_cur_i - (PATCH_HALFSIZE + 1) < 0 || + u_cur_i + (PATCH_HALFSIZE + 1) >= get_image_dim(image_cur)[0] || v_cur_i + (PATCH_HALFSIZE + 1) >= get_image_dim(image_cur)[1]) + return; + // compute bilateral interpolation weights for the current image double subpix_u_cur = u_cur - u_cur_i; double subpix_v_cur = v_cur - v_cur_i; @@ -142,58 +136,53 @@ __kernel void compute-residual( double w_cur_tr = subpix_u_cur * (1.0 - subpix_v_cur); double w_cur_bl = (1.0 - subpix_u_cur) * subpix_v_cur; double w_cur_br = subpix_u_cur * subpix_v_cur; - /// ... compute residual - - /// TODO - check & implementation - // float* cache_ptr = reinterpret_cast(ref_patch_cache_.data) + patch_area_*feature_counter; - // float* ref_patch_cache_ptr = reinterpret_cast(ref_patch_cache_.data) + patch_area_*feature_counter; - for(int y = 0; y < PATCH_SIZE; ++y) { - /// TODO - check & implementation - int ref_element_add = image_ref.data + (v_ref_i + y - PATCH_HALFSIZE) * stride + (u_ref_i - PATCH_HALFSIZE); - int cur_element_add = image_cur.data + (v_cur_i + y - PATCH_HALFSIZE) * stride + (u_cur_i - PATCH_HALFSIZE); - // uint8_t* ref_img_ptr = (uint8_t*) ref_img.data + (v_ref_i+y-patch_halfsize_)*stride + (u_ref_i-patch_halfsize_); - // uint8_t* cur_img_ptr = (uint8_t*) image_cur.data + (v_cur_i + y - patch_halfsize_) * stride + (u_cur_i - patch_halfsize_); + int ref_element_addr = (v_ref_i + y - PATCH_HALFSIZE) * get_image_dim(image_ref)[0] + (u_ref_i - PATCH_HALFSIZE); + int cur_element_addr = (v_cur_i + y - PATCH_HALFSIZE) * get_image_dim(image_cur)[0] + (u_cur_i - PATCH_HALFSIZE); - // for(int x = 0; x < PATCH_SIZE; ++x, ++pixel_counter, ++ref_img_ptr, ++cache_ptr) - // for(int x = 0; x < PATCH_SIZE; ++x, ++pixel_counter, ++cur_img_ptr, ++ref_patch_cache_ptr) - for(int x = 0; x < PATCH_SIZE; ++x, ++pixel_counter, ++ref_element, ++cur_element) + for(int x = 0; x < PATCH_SIZE; ++x, ++pixel_counter, ++ref_element_addr, ++cur_element_addr) { - /// TODO - check & implementation // precompute interpolated reference patch color - // *cache_ptr = w_ref_tl*ref_img_ptr[0] + w_ref_tr*ref_img_ptr[1] + w_ref_bl*ref_img_ptr[stride] + w_ref_br*ref_img_ptr[stride+1]; - int2 px_reftl = (ref_element_add % get_image_dim(image_ref)[0], ref_element_add / get_image_dim(image_ref)[0]); - int2 px_reftr = ((ref_element_add + 1) % get_image_dim(image_ref)[0], (ref_element_add + 1) / get_image_dim(image_ref)[0]); - int2 px_refbl = ((ref_element_add + stride) % get_image_dim(image_ref)[0], (ref_element_add + stride) / get_image_dim(image_ref)[0]); - int2 px_refbr = ((ref_element_add + stride + 1) % get_image_dim(image_ref)[0], (ref_element_add + stride + 1) / get_image_dim(image_ref)[0]); + int2 px_reftl = ( ref_element_addr % get_image_dim(image_ref)[0], ref_element_addr / get_image_dim(image_ref)[0]); + int2 px_reftr = ((ref_element_addr + 1) % get_image_dim(image_ref)[0], (ref_element_addr + 1) / get_image_dim(image_ref)[0]); + int2 px_refbl = ((ref_element_addr + get_image_dim(image_ref)[0]) % get_image_dim(image_ref)[0], (ref_element_addr + get_image_dim(image_ref)[0]) / get_image_dim(image_ref)[0]); + int2 px_refbr = ((ref_element_addr + get_image_dim(image_ref)[0] + 1) % get_image_dim(image_ref)[0], (ref_element_addr + get_image_dim(image_ref)[0] + 1) / get_image_dim(image_ref)[0]); double value = w_ref_tl * read_imageui(image_ref, sampler, px_reftl).x + w_ref_tr * read_imageui(image_ref, sampler, px_reftr).x + w_ref_bl * read_imageui(image_ref, sampler, px_refbl).x + w_ref_br * read_imageui(image_ref, sampler, px_refbr).x; - // we use the inverse compositional: thereby we can take the gradient always at the same position - // get gradient of warped image (~gradient at warped position) - double dx = 0.5f * ((w_ref_tl * ref_img_ptr[1] + w_ref_tr * ref_img_ptr[2] + w_ref_bl * ref_img_ptr[stride+1] + w_ref_br * ref_img_ptr[stride+2]) - -(w_ref_tl * ref_img_ptr[-1] + w_ref_tr * ref_img_ptr[0] + w_ref_bl * ref_img_ptr[stride-1] + w_ref_br * ref_img_ptr[stride])); - double dy = 0.5f * ((w_ref_tl * ref_img_ptr[stride] + w_ref_tr * ref_img_ptr[1+stride] + w_ref_bl * ref_img_ptr[stride*2] + w_ref_br * ref_img_ptr[stride*2+1]) - -(w_ref_tl * ref_img_ptr[-stride] + w_ref_tr * ref_img_ptr[1-stride] + w_ref_bl * ref_img_ptr[0] + w_ref_br * ref_img_ptr[1])); + double dx = 0.5f * ((w_ref_tl * read_imageui(image_ref, sampler, ((ref_element_addr + 1) % get_image_dim(image_ref)[0], ((ref_element_addr + 1) / get_image_dim(image_ref)[0]))).x + + w_ref_tr * read_imageui(image_ref, sampler, ((ref_element_addr + 2) % get_image_dim(image_ref)[0], ((ref_element_addr + 2) / get_image_dim(image_ref)[0]))).x + + w_ref_bl * read_imageui(image_ref, sampler, ((ref_element_addr + (get_image_dim(image_ref)[0]) + 1) % get_image_dim(image_ref)[0], ((ref_element_addr + (get_image_dim(image_ref)[0]) + 1) / get_image_dim(image_ref)[0]))).x + + w_ref_br * read_imageui(image_ref, sampler, ((ref_element_addr + (get_image_dim(image_ref)[0]) + 2) % get_image_dim(image_ref)[0], ((ref_element_addr + (get_image_dim(image_ref)[0]) + 2) / get_image_dim(image_ref)[0]))).x) + -(w_ref_tl * read_imageui(image_ref, sampler, ((ref_element_addr - 1) % get_image_dim(image_ref)[0], ((ref_element_addr - 1) / get_image_dim(image_ref)[0]))).x + + w_ref_tr * read_imageui(image_ref, sampler, ((ref_element_addr + 0) % get_image_dim(image_ref)[0], ((ref_element_addr + 0) / get_image_dim(image_ref)[0]))).x + + w_ref_bl * read_imageui(image_ref, sampler, ((ref_element_addr + (get_image_dim(image_ref)[0]) - 1) % get_image_dim(image_ref)[0], ((ref_element_addr + (get_image_dim(image_ref)[0]) - 1) / get_image_dim(image_ref)[0]))).x + + w_ref_br * read_imageui(image_ref, sampler, ((ref_element_addr + (get_image_dim(image_ref)[0])) % get_image_dim(image_ref)[0], ((ref_element_addr + (get_image_dim(image_ref)[0])) / get_image_dim(image_ref)[0]))).x)); + + double dy = 0.5f * ((w_ref_tl * read_imageui(image_ref, sampler, ((ref_element_addr + (get_image_dim(image_ref)[0])) % get_image_dim(image_ref)[0], ((ref_element_addr + (get_image_dim(image_ref)[0])) / get_image_dim(image_ref)[0]))).x + + w_ref_tr * read_imageui(image_ref, sampler, ((ref_element_addr + (get_image_dim(image_ref)[0]) + 1) % get_image_dim(image_ref)[0], ((ref_element_addr + (get_image_dim(image_ref)[0]) + 1) / get_image_dim(image_ref)[0]))).x + + w_ref_bl * read_imageui(image_ref, sampler, ((ref_element_addr + (get_image_dim(image_ref)[0]) * 2) % get_image_dim(image_ref)[0], ((ref_element_addr + (get_image_dim(image_ref)[0]) * 2) / get_image_dim(image_ref)[0]))).x + + w_ref_br * read_imageui(image_ref, sampler, ((ref_element_addr + (get_image_dim(image_ref)[0]) * 2 + 1) % get_image_dim(image_ref)[0], ((ref_element_addr + (get_image_dim(image_ref)[0]) * 2 + 1) / get_image_dim(image_ref)[0]))).x) + -(w_ref_tl * read_imageui(image_ref, sampler, ((ref_element_addr + (-get_image_dim(image_ref)[0])) % get_image_dim(image_ref)[0], ((ref_element_addr + (-get_image_dim(image_ref)[0])) / get_image_dim(image_ref)[0]))).x + + w_ref_tr * read_imageui(image_ref, sampler, ((ref_element_addr + (1 - get_image_dim(image_ref)[0])) % get_image_dim(image_ref)[0], ((ref_element_addr + (1 - get_image_dim(image_ref)[0])) / get_image_dim(image_ref)[0]))).x + + w_ref_bl * read_imageui(image_ref, sampler, ((ref_element_addr + 0) % get_image_dim(image_ref)[0], ((ref_element_addr + 0) / get_image_dim(image_ref)[0]))).x + + w_ref_br * read_imageui(image_ref, sampler, ((ref_element_addr + 1) % get_image_dim(image_ref)[0], ((ref_element_addr + 1) / get_image_dim(image_ref)[0]))).x)); // compute residual - /// TODO - check & implementation - // double intensity_cur = w_cur_tl * cur_img_ptr[0] + w_cur_tr * cur_img_ptr[1] + w_cur_bl * cur_img_ptr[stride] + w_cur_br * cur_img_ptr[stride+1]; - int2 px_curtl = (cur_element_add % get_image_dim(image_cur)[0], cur_element_add / get_image_dim(image_cur)[0]); - int2 px_curtr = ((cur_element_add + 1) % get_image_dim(image_cur)[0], (cur_element_add + 1) / get_image_dim(image_cur)[0]); - int2 px_curbl = ((cur_element_add + stride) % get_image_dim(image_cur)[0], (cur_element_add + stride) / get_image_dim(image_cur)[0]); - int2 px_curbr = ((cur_element_add + stride + 1) % get_image_dim(image_cur)[0], (cur_element_add + stride + 1) / get_image_dim(image_cur)[0]); + int2 px_curtl = ( cur_element_addr % get_image_dim(image_cur)[0], cur_element_add / get_image_dim(image_cur)[0]); + int2 px_curtr = ((cur_element_addr + 1) % get_image_dim(image_cur)[0], (cur_element_add + 1) / get_image_dim(image_cur)[0]); + int2 px_curbl = ((cur_element_addr + (get_image_dim(image_cur)[0])) % get_image_dim(image_cur)[0], (cur_element_add + (get_image_dim(image_cur)[0])) / get_image_dim(image_cur)[0]); + int2 px_curbr = ((cur_element_addr + (get_image_dim(image_cur)[0]) + 1) % get_image_dim(image_cur)[0], (cur_element_add + (get_image_dim(image_cur)[0]) + 1) / get_image_dim(image_cur)[0]); double intensity_cur = w_cur_tl * read_imageui(image_cur, sampler, px_curtl).x + w_cur_tr * read_imageui(image_cur, sampler, px_curtr).x + w_cur_bl * read_imageui(image_cur, sampler, px_curbl).x + w_cur_br * read_imageui(image_cur, sampler, px_curbr).x; - // const float res = intensity_cur - (*ref_patch_cache_ptr); double res = intensity_cur - value; // used to compute scale for robust cost - if(compute_weight_scale) //????????? compute_weight_scale ???????????? - errors[(y * PATCH_SIZE) + x] = fabs(res) + // if(compute_weight_scale) + errors[f * pow(PATCH_SIZE, 2) + (y * PATCH_SIZE) + x] = fabs(res); // robustification double weight = 2.0; @@ -201,22 +190,21 @@ __kernel void compute-residual( // weight = weight_function_->value(res/scale_); // } - chi2 += res * res * weight; + *chi += res * res * weight; n_meas_++; // if(linearize_system) // { - // compute Jacobian, weighted Hessian and weighted "steepest descend images" (times error) - double3 j_row0 = double3(dx * frame_jac[0], dx * frame_jac[1], dx * frame_jac[2]) - double3 j_row1 = double3(dy * frame_jac[3], dy * frame_jac[4], dy * frame_jac[5]) - double3 J(j_row0 + j_row1) * (focal_length / scale); - compute_hessain(j, Hessian, weight); // H_.noalias() += J * J.transpose() * weight; - compute_Jacobian(j, Jacobian, res, weight) // Jres_.noalias() -= J * res * weight; + // compute Jacobian, weighted Hessian and weighted "steepest descend images" (times error) + double3 j_row0 = double3(dx * frame_jac[0], dx * frame_jac[1], dx * frame_jac[2]) + double3 j_row1 = double3(dy * frame_jac[3], dy * frame_jac[4], dy * frame_jac[5]) + double3 J((j_row0 + j_row1) * (camera_model[0] / scale)); + compute_hessain(J, Hessian, weight); // H_.noalias() += J * J.transpose() * weight; + compute_Jacobian(J, Jacobian, res, weight) // Jres_.noalias() -= J * res * weight; // } - chi = chi2 / n_meas_; - feature_counter++; } } - + *chi = *chi / n_meas_; + free(frame_jac); } From dd3cf3de05ae6aa0336d598d89e05b684f78178d Mon Sep 17 00:00:00 2001 From: VahdPourAmin Date: Sun, 25 Jul 2021 08:50:54 +0200 Subject: [PATCH 07/12] opencl kernel clean and aproximately ready to test --- GPU_version/vio/include/vio/frame.h | 2 +- GPU_version/vio/kernel/compute-residual.cl | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/GPU_version/vio/include/vio/frame.h b/GPU_version/vio/include/vio/frame.h index 7408805..b8c10d7 100644 --- a/GPU_version/vio/include/vio/frame.h +++ b/GPU_version/vio/include/vio/frame.h @@ -148,7 +148,7 @@ public: J(0,0) = -z_inv; // -1/z J(0,1) = x*z_inv_2; // x/z^2 - J(0,2) = -(1.0 + pow(x,2)/z_inv_2); // -(1.0 + x^2/z^2) + J(0,2) = -(1.0 + pow(x,2)*z_inv_2); // -(1.0 + x^2/z^2) J(1,0) = 1e-19; // 0 J(1,1) = y*z_inv_2; // y/z^2 diff --git a/GPU_version/vio/kernel/compute-residual.cl b/GPU_version/vio/kernel/compute-residual.cl index 662f14d..189a608 100644 --- a/GPU_version/vio/kernel/compute-residual.cl +++ b/GPU_version/vio/kernel/compute-residual.cl @@ -22,9 +22,9 @@ double3 xyz_cur(double cur_x, double cur_z, double cur_pitch, double ref_x, doub ref_pitch = ref_pitch - 3.1415926535897932384626433832795028841971693993; double cc_ss = cos(cur_pitch) * cos(ref_pitch) - sin(cur_pitch) * sin(ref_pitch); double sc_cs = cos(cur_pitch) * sin(ref_pitch) + cos(ref_pitch) * sin(cur_pitch); - return double3(cc_ss * ref_feature.x() + sc_cs * ref_feature.z() + cur_x - ref_x * cos(cur_pitch) - ref_z * sin(cur_pitch), - ref_feature.y(), - -1.0 * sc_cs * ref_feature.x() + cc_ss * ref_feature.z() + cur_z + ref_x * sin(cur_pitch) - ref_z * cos(cur_pitch)); + return double3(cc_ss * ref_feature.x + sc_cs * ref_feature.z + cur_x - ref_x * cos(cur_pitch) - ref_z * sin(cur_pitch), + ref_feature.y, + -1.0 * sc_cs * ref_feature.x + cc_ss * ref_feature.z + cur_z + ref_x * sin(cur_pitch) - ref_z * cos(cur_pitch)); } double3 xyz_ref(double fts_pos_x, double fts_pos_y, double fts_pos_z, double ref_x, double ref_y, double ref_z) @@ -38,7 +38,7 @@ void jacobian_xyz2uv(double3 xyz_in_f, double* J) { *(J + 0) = -(1. / xyz_in_f[2]); // -1/z *(J + 1) = (xyz_in_f[0]) * ((1. / xyz_in_f[2]) * (1. / xyz_in_f[2])); // x/z^2 - *(J + 2) = -(1.0 + pow((xyz_in_f[0]),2) / ((1. / xyz_in_f[2]) * (1. / xyz_in_f[2]))); // -(1.0 + x^2/z^2) + *(J + 2) = -(1.0 + pow((xyz_in_f[0]),2) * ((1. / xyz_in_f[2]) * (1. / xyz_in_f[2]))); // -(1.0 + x^2/z^2) *(J + 3) = 1e-19; // 0 *(J + 4) = (xyz_in_f[1]) * ((1. / xyz_in_f[2]) * (1. / xyz_in_f[2])); // y/z^2 *(J + 5) = -(xyz_in_f[0]) * (xyz_in_f[1]) / ((1. / xyz_in_f[2]) * (1. / xyz_in_f[2])); // -x*y/z^2 From bf9fed0c3e3ea93c6e3cc3ef3c5c5c093f3ac28e Mon Sep 17 00:00:00 2001 From: gfuse Date: Tue, 3 Aug 2021 20:21:38 +0200 Subject: [PATCH 08/12] debug kernel --- GPU_version/vio/include/vio/cl_class.h | 4 +-- GPU_version/vio/kernel/compute-residual.cl | 34 ++++++++++----------- GPU_version/vio/out.txt | Bin 885008 -> 31796 bytes GPU_version/vio/src/cl_class.cpp | 4 ++- GPU_version/vio/src/frame_handler_mono.cpp | 2 +- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/GPU_version/vio/include/vio/cl_class.h b/GPU_version/vio/include/vio/cl_class.h index 7088a56..9ff34e5 100644 --- a/GPU_version/vio/include/vio/cl_class.h +++ b/GPU_version/vio/include/vio/cl_class.h @@ -31,7 +31,7 @@ public: } err=_kernel->setArg(id,_buffers.back().first.first); if(err!=0){ - std::cerr<<"Error C:Kernel, F:write, L3:setArg\n"<setArg(id,_images.back().first); if(err!=0){ - std::cerr<<"Error C:Kernel, F:write image, L:setArg\n"< 0.001) factor = (atan(r * 2.0 * tan(0.5 * s_)) / (r * s_)); - return double3(cx_ + fx_ * factor * uv[0], cy_ + fy_ * factor * uv[1]); + return (double2)(c_x + f_x * factor * x/z, c_y + f_y * factor * y/z); } double3 xyz_cur(double cur_x, double cur_z, double cur_pitch, double ref_x, double ref_z, double ref_pitch, double3 ref_feature) @@ -22,14 +21,14 @@ double3 xyz_cur(double cur_x, double cur_z, double cur_pitch, double ref_x, doub ref_pitch = ref_pitch - 3.1415926535897932384626433832795028841971693993; double cc_ss = cos(cur_pitch) * cos(ref_pitch) - sin(cur_pitch) * sin(ref_pitch); double sc_cs = cos(cur_pitch) * sin(ref_pitch) + cos(ref_pitch) * sin(cur_pitch); - return double3(cc_ss * ref_feature.x + sc_cs * ref_feature.z + cur_x - ref_x * cos(cur_pitch) - ref_z * sin(cur_pitch), + return (double3)(cc_ss * ref_feature.x + sc_cs * ref_feature.z + cur_x - ref_x * cos(cur_pitch) - ref_z * sin(cur_pitch), ref_feature.y, -1.0 * sc_cs * ref_feature.x + cc_ss * ref_feature.z + cur_z + ref_x * sin(cur_pitch) - ref_z * cos(cur_pitch)); } double3 xyz_ref(double fts_pos_x, double fts_pos_y, double fts_pos_z, double ref_x, double ref_y, double ref_z) { - return double3(sqrt(pow((fts_pos_x - ref_x), 2)), + return (double3)(sqrt(pow((fts_pos_x - ref_x), 2)), sqrt(pow((fts_pos_y - ref_y), 2)), sqrt(pow((fts_pos_z - ref_z), 2))); } @@ -64,26 +63,25 @@ void compute_Jacobian(double3 j, double* Jacobian, double r, double w) *(Jacobian + 2) -= j[2] * r * w; } -__kernel void compute-residual( +__kernel void compute_residual( __read_only image2d_t image_cur, // current frame __read_only image2d_t image_ref, // reference frame __global double * cur_pose,//[reference frame pose{x,z,pitch}] __global double * ref_pose,//[current frame pose{x,z,pitch}] __global double3 * ref_feature, // feature on the reference frame, when we applied the distance calculation: xyz_ref((*it)->f*((*it)->point->pos_ - Eigen::Vector3d(ref_pos[0],0.0,ref_pos[1])).norm()); __global double2 * featue_px, - __global int * level, + int level, __global double * camera_model, // camera model [f_x,f_y,c_x,c_y,s_] - float * errors, - double * Hessian, - double * Jacobian, - double * chi -) { - static const int PATCH_SIZE = 4; - static const int PATCH_HALFSIZE = 2; - static const int PATCH_AREA_ = PATCH_SIZE * PATCH_SIZE; + __global float * errors, + __global double * Hessian, + __global double * Jacobian, + double chi +) +{ + const int PATCH_AREA_ = PATCH_SIZE * PATCH_SIZE; int border = PATCH_HALFSIZE + 1; int stride = get_image_dim(image_cur)[0]; //width, height - double scale = pow(2, (-1.0 * level)); + double scale = pown(2.0, -level); size_t n_meas_ = 0; // Prepare a suitable OpenCL image sampler. sampler_t const sampler = CLK_ADDRESS_CLAMP | CLK_FILTER_NEAREST; @@ -101,7 +99,7 @@ __kernel void compute-residual( u_ref_i + (PATCH_HALFSIZE + 1) >= get_image_dim(image_ref)[0] || v_ref_i + (PATCH_HALFSIZE + 1) >= get_image_dim(image_ref)[1]) return; - xyz_reference = xyz_ref(ref_feature[f][0], ref_feature[f][1], ref_feature[f][2], ref_pose.x, ref_pose.y, ref_pose.z); + double3 xyz_reference = xyz_ref(ref_feature[f][0], ref_feature[f][1], ref_feature[f][2], ref_pose[0], ref_pose[1], ref_pose[2]); // evaluate projection jacobian double* frame_jac = (double *) malloc(6 * sizeof(double)); // 2X3 @@ -116,7 +114,7 @@ __kernel void compute-residual( double w_ref_br = subpix_u_ref * subpix_v_ref; size_t pixel_counter = 0; - double3 xyz_current = xyz_cur(cur_pose.x, cur_pose.z, cur_pose.pitch, ref_pose.x ,ref_pose.z ,ref_pose.pitch, ref_feature[f]); + double3 xyz_current = xyz_cur(cur_pose.x, cur_pose.z, cur_pose.pitch, ref_pose[0] ,ref_pose[1] ,ref_pose[2], ref_feature[f]); double2 uv_cur_pyr = world2cam(camera_model[0], camera_model[1], camera_model[2], camera_model[3], camera_model[4], xyz_current[0], xyz_current[1], xyz_current[2]) * scale; double u_cur = uv_cur_pyr[0]; diff --git a/GPU_version/vio/out.txt b/GPU_version/vio/out.txt index b027790bc0b9740a3192c24c3ab5c034df12ab92..8447d6114a8abe41392eac2b1920d1bc060d267e 100644 GIT binary patch literal 31796 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 literal 885008 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 bU3slWv`XZ*q`|wvM%N#e4i2&pRSH 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⋙Ty{;-K<|toijyK0T6|bbzS!$t3_VW)t0^;EhmM98YWwDA`qMh zjnp5^R>Dxx18OQ6Nl1f#hdH+)+tEt|zKN*}2(%ug7maEiZzIqu@njRm&Fy*!CVZ%! z)WdXq55Y67jF!aqlSc&EK7bo_XZ9$xzIE0F!_ukH?}<7Lv}4U*u&H=iV9c2DqNclXL}_6B4DvN0#QOV!hc!O0Ti{^3&E7u@hN!cE`;)GrcZJQ{3)7jjc`CDUTiX8WWa+PAVCA5Fu4R;uFXb^F68ALm!gD zJ|r`x^J6eanK<6yp_sS9kd$d&Ke9LciKHRNDM-DYFltChDZ@`@6=zc&V;)SDWWHO;e29cOeMY5+&f?Q3Md9CV~Cu+Hqbe*SC z9&3!vw=&T)^^O@~l8Nf6z4a-ik;sL(Dw)V}^)1j`gKhhG$d;JA0tAwvHR+s<#+Z>aFiP+&0>hvpfJ^iv};4 zCpbLz{BF-0)&x_i?iAh&gxbg60zQ=UeEmZ?Z(|X(Dr$uWhczXjU{i%4TLZykKHV+b z&&h^|!{9s$C%CBVk9BTVL3eU7NyH3fmd@^@yaPH3RkjNs~Hb|Y2 zn3^;mMB?CSrcqWRqE7}jUs}iwkqZ=q_!7cH_@y0@$RMVC-s7jgTobWfw}+DpABPfR zIg4scP()0Ul!>m8vkccyLUEe#|8~MWsSN#~wFloJ+Baa)%`hm?%*OJKZ#APMeXP<8 zC~k=Y2c=D!CiVVibR}rO1?x_~LHv!gk){su>eOiD>QY6PBhOifb6VidEWMY4PZ5y@8 z#BDG>7Ndd~9(5ocPab+^e$s{?*3Hv|cbGFWhEc0k%7ny(==pPA5ln}duAg;*b^7sA zC}s(+B9WkCfQuWr=7w$#66KJfXOqnKsA}4+M7|+al%4^PsLOjKcB1Z3@ztIy{X~_b zbXe@p?1UoUnCM&4Xs-!zK1$X!`7L3!6*MQ^iB9r3Qo?oyM#e=<)JP0*>Zx>UyuKNV zH5RUxUPnU?(Ut$SPo^pe)R@(nR)Y>`ttGF8zJ!MUBzB_xC%gIXK%d84JodbFbaI}7 zz-^vSf7=O!ZGuk{A8L^jIsIN$ zS$onavS{mV2C0acg4YuuqP5e+fL4_GnH+6-Pb>$tA3e#vukEBp?ff5l&e;S?aQJWU zR7RJ*;C1GwkiKin#OvY z5rR_1YOF~!Yf>VbL06{T+TWXEmh>qZOthEJjN@NKp(0Z90ox}z0!QpbceY-w{ zwxQ79R+fSI&!FLu%jlf!H?3EMAV$4ai{SaDD4gbdG|ijGoPi%c8-)@QvC>li94myuS!C-$2c|Ajce}0kQ^-fNfKfw2~D55ksLnda*sxd-_yyw)$E*8cxf;^*U93Q zbe^*o97=yTnYhSEJa0T{=CKDY?w?-KC$5T;Bd)J^jFanS;I4FwIN!kDehrEljm2NR z7Y7ZOyj)Q}LF;ryW%BMNCDVF;6N=M>k@(w$=TV2PIcjKVObCmuhW)+4xa#Yr3G^V^etlJ0BC>J_`hv=GsJO6eQF##<^A}a8VcX=WcJCGf+l|P|fR#lFC z9dZ}0yE8izkqLORuSIMiDCK`M3TfG-pFoo`KG9}a+>?uM;wyuCmQ&>|rh4un(UVJZbNaOTd4OcYVLA}u>v=1WmQ3H0igI{j z!OCPpAy>I_@3d7V9Zsjrq49TbDzoV8InF?!?_K6})Gk-N*X3t?h*+)Ptl3YT0D=R^H z5Ba3?^+%DxF;?25g!&vnr~xB-Ji#61)d;)D-;aTCo^Ir3^b=)NdX|k{+%%7DMS5< zuM7~l#dP11^#&fLk&!rD*5p_N8~)R(4Q5e*CdAE;_7!RR;++pvQOU#gheoI0wy|uJ z0dd*Er6kTKK1!NUJLrQpfrE8m9Tz zUr#K<$y9z+LU#fM8-+OW}I#CWKVpk&>r0wXP zAm>wPFS1aNxc@U*C`!j4a{EaZ>gtdR6(k9cLQfh`?H($zW37&*+rAkus9~OthbgLt$m*(xD arcBKwv&chAEys|*JBi^9x8}XGHU9@wzELCq diff --git a/GPU_version/vio/src/cl_class.cpp b/GPU_version/vio/src/cl_class.cpp index e15f3fc..033ac11 100644 --- a/GPU_version/vio/src/cl_class.cpp +++ b/GPU_version/vio/src/cl_class.cpp @@ -32,8 +32,10 @@ opencl::opencl() { cl::Program::Sources sources; read_cl fast(std::string(KERNEL_DIR)+"/fast-gray.cl"); sources.push_back({ fast.src_str, fast.size }); + read_cl compute_residual(std::string(KERNEL_DIR)+"/compute-residual.cl"); + sources.push_back({ compute_residual.src_str, compute_residual.size }); program=new cl::Program(*context, sources); - if(program->build({ device },"-DFAST_THRESH=40 -DPATCH_SIZE=4") !=0) + if(program->build({ device },"-DFAST_THRESH=40 -DPATCH_SIZE=4 -DPATCH_HALFSIZE=2") !=0) std::cout << " Error building: " << program->getBuildInfo(device)<<'\n' <getBuildInfo(device) << '\n'; queue=new cl::CommandQueue(*context,device,0,NULL); diff --git a/GPU_version/vio/src/frame_handler_mono.cpp b/GPU_version/vio/src/frame_handler_mono.cpp index cf949ad..9cb1471 100644 --- a/GPU_version/vio/src/frame_handler_mono.cpp +++ b/GPU_version/vio/src/frame_handler_mono.cpp @@ -44,7 +44,7 @@ FrameHandlerMono::FrameHandlerMono(vk::AbstractCamera* cam,Eigen::Matrixwrite_buf(0,2,1,icorner); gpu_fast_->write_buf(0,3,(1 << 18)); - gpu_fast_->make_kernel("compute-residual"); + gpu_fast_->make_kernel("compute_residual"); gpu_fast_->write_buf(1,0,img); gpu_fast_->write_buf(1,1,img); double pose[3]={0}; From 47e2993ed8051cbb88c74ef8985d181cb7fbb35a Mon Sep 17 00:00:00 2001 From: gfuse Date: Wed, 4 Aug 2021 18:18:21 +0200 Subject: [PATCH 09/12] debug kernel --- GPU_version/vio/include/vio/atan_camera.h | 1 + GPU_version/vio/kernel/compute-residual.cl | 157 +++++++++---------- GPU_version/vio/launch/Px30.launch | 2 +- GPU_version/vio/out.txt | Bin 31796 -> 5883 bytes GPU_version/vio/src/atan_camera.cpp | 5 +- GPU_version/vio/src/frame_handler_mono.cpp | 21 +-- GPU_version/vio/src/sparse_img_align_gpu.cpp | 29 ++-- 7 files changed, 108 insertions(+), 107 deletions(-) diff --git a/GPU_version/vio/include/vio/atan_camera.h b/GPU_version/vio/include/vio/atan_camera.h index 97c2f75..943b668 100644 --- a/GPU_version/vio/include/vio/atan_camera.h +++ b/GPU_version/vio/include/vio/atan_camera.h @@ -14,6 +14,7 @@ #define ATAN_CAMERA_H_ #include +#include #include #include #include diff --git a/GPU_version/vio/kernel/compute-residual.cl b/GPU_version/vio/kernel/compute-residual.cl index 2817e39..d02fd2b 100644 --- a/GPU_version/vio/kernel/compute-residual.cl +++ b/GPU_version/vio/kernel/compute-residual.cl @@ -22,15 +22,15 @@ double3 xyz_cur(double cur_x, double cur_z, double cur_pitch, double ref_x, doub double cc_ss = cos(cur_pitch) * cos(ref_pitch) - sin(cur_pitch) * sin(ref_pitch); double sc_cs = cos(cur_pitch) * sin(ref_pitch) + cos(ref_pitch) * sin(cur_pitch); return (double3)(cc_ss * ref_feature.x + sc_cs * ref_feature.z + cur_x - ref_x * cos(cur_pitch) - ref_z * sin(cur_pitch), - ref_feature.y, - -1.0 * sc_cs * ref_feature.x + cc_ss * ref_feature.z + cur_z + ref_x * sin(cur_pitch) - ref_z * cos(cur_pitch)); + ref_feature.y, + -1.0 * sc_cs * ref_feature.x + cc_ss * ref_feature.z + cur_z + ref_x * sin(cur_pitch) - ref_z * cos(cur_pitch)); } double3 xyz_ref(double fts_pos_x, double fts_pos_y, double fts_pos_z, double ref_x, double ref_y, double ref_z) { return (double3)(sqrt(pow((fts_pos_x - ref_x), 2)), - sqrt(pow((fts_pos_y - ref_y), 2)), - sqrt(pow((fts_pos_z - ref_z), 2))); + sqrt(pow((fts_pos_y - ref_y), 2)), + sqrt(pow((fts_pos_z - ref_z), 2))); } void jacobian_xyz2uv(double3 xyz_in_f, double* J) @@ -43,7 +43,7 @@ void jacobian_xyz2uv(double3 xyz_in_f, double* J) *(J + 5) = -(xyz_in_f[0]) * (xyz_in_f[1]) / ((1. / xyz_in_f[2]) * (1. / xyz_in_f[2])); // -x*y/z^2 } -void compute_hessain(double3 j, double* H, double w) +void compute_hessain(double3 j, __global double* H, double w) { *(H + 0) += j[0] * j[0] * w; *(H + 1) += j[0] * j[1] * w; @@ -56,7 +56,7 @@ void compute_hessain(double3 j, double* H, double w) *(H + 8) += j[2] * j[2] * w; } -void compute_Jacobian(double3 j, double* Jacobian, double r, double w) +void compute_Jacobian(double3 j, __global double* Jacobian, double r, double w) { *(Jacobian + 0) -= j[0] * r * w; *(Jacobian + 1) -= j[1] * r * w; @@ -64,30 +64,30 @@ void compute_Jacobian(double3 j, double* Jacobian, double r, double w) } __kernel void compute_residual( - __read_only image2d_t image_cur, // current frame - __read_only image2d_t image_ref, // reference frame - __global double * cur_pose,//[reference frame pose{x,z,pitch}] - __global double * ref_pose,//[current frame pose{x,z,pitch}] - __global double3 * ref_feature, // feature on the reference frame, when we applied the distance calculation: xyz_ref((*it)->f*((*it)->point->pos_ - Eigen::Vector3d(ref_pos[0],0.0,ref_pos[1])).norm()); - __global double2 * featue_px, - int level, - __global double * camera_model, // camera model [f_x,f_y,c_x,c_y,s_] - __global float * errors, - __global double * Hessian, - __global double * Jacobian, - double chi + __read_only image2d_t image_cur, // current frame + __read_only image2d_t image_ref, // reference frame + __global double * cur_pose,//[reference frame pose{x,z,pitch}] + __global double * ref_pose,//[current frame pose{x,z,pitch}] + __global double3 * ref_feature, // feature on the reference frame, when we applied the distance calculation: xyz_ref((*it)->f*((*it)->point->pos_ - Eigen::Vector3d(ref_pos[0],0.0,ref_pos[1])).norm()); + __global double2 * featue_px, + __global int * level, + __global double * camera_model, // camera model [f_x,f_y,c_x,c_y,s_] + __global float * errors, + __global double * Hessian, + __global double * Jacobian, + __global double * chi ) { const int PATCH_AREA_ = PATCH_SIZE * PATCH_SIZE; int border = PATCH_HALFSIZE + 1; int stride = get_image_dim(image_cur)[0]; //width, height - double scale = pown(2.0, -level); + double scale = pow(2.0, -level[0]); size_t n_meas_ = 0; // Prepare a suitable OpenCL image sampler. sampler_t const sampler = CLK_ADDRESS_CLAMP | CLK_FILTER_NEAREST; // Use global work feature. - int const f = get_global_id(0); + int f = get_global_id(0); // check if reference with patch size is within image double u_ref = featue_px[f].x * scale; @@ -96,14 +96,14 @@ __kernel void compute_residual( int v_ref_i = floor(v_ref); if(u_ref_i - (PATCH_HALFSIZE + 1) < 0 || v_ref_i - (PATCH_HALFSIZE + 1) < 0 || - u_ref_i + (PATCH_HALFSIZE + 1) >= get_image_dim(image_ref)[0] || v_ref_i + (PATCH_HALFSIZE + 1) >= get_image_dim(image_ref)[1]) - return; + u_ref_i + (PATCH_HALFSIZE + 1) >= get_image_dim(image_ref)[0] || v_ref_i + (PATCH_HALFSIZE + 1) >= get_image_dim(image_ref)[1]) + return; double3 xyz_reference = xyz_ref(ref_feature[f][0], ref_feature[f][1], ref_feature[f][2], ref_pose[0], ref_pose[1], ref_pose[2]); // evaluate projection jacobian - double* frame_jac = (double *) malloc(6 * sizeof(double)); // 2X3 - jacobian_xyz2uv(xyz_reference, frame_jac); + double frame_jac[6]; // 2X3 + jacobian_xyz2uv(xyz_reference, &frame_jac); // compute bilateral interpolation weights for reference image double subpix_u_ref = u_ref - u_ref_i; @@ -114,7 +114,7 @@ __kernel void compute_residual( double w_ref_br = subpix_u_ref * subpix_v_ref; size_t pixel_counter = 0; - double3 xyz_current = xyz_cur(cur_pose.x, cur_pose.z, cur_pose.pitch, ref_pose[0] ,ref_pose[1] ,ref_pose[2], ref_feature[f]); + double3 xyz_current = xyz_cur(cur_pose[0], cur_pose[1], cur_pose[2], ref_pose[0] ,ref_pose[1] ,ref_pose[2], ref_feature[f]); double2 uv_cur_pyr = world2cam(camera_model[0], camera_model[1], camera_model[2], camera_model[3], camera_model[4], xyz_current[0], xyz_current[1], xyz_current[2]) * scale; double u_cur = uv_cur_pyr[0]; @@ -124,8 +124,8 @@ __kernel void compute_residual( // check if projection is within the image if(u_cur_i < 0 || v_cur_i < 0 || u_cur_i - (PATCH_HALFSIZE + 1) < 0 || v_cur_i - (PATCH_HALFSIZE + 1) < 0 || - u_cur_i + (PATCH_HALFSIZE + 1) >= get_image_dim(image_cur)[0] || v_cur_i + (PATCH_HALFSIZE + 1) >= get_image_dim(image_cur)[1]) - return; + u_cur_i + (PATCH_HALFSIZE + 1) >= get_image_dim(image_cur)[0] || v_cur_i + (PATCH_HALFSIZE + 1) >= get_image_dim(image_cur)[1]) + return; // compute bilateral interpolation weights for the current image double subpix_u_cur = u_cur - u_cur_i; @@ -142,67 +142,66 @@ __kernel void compute_residual( for(int x = 0; x < PATCH_SIZE; ++x, ++pixel_counter, ++ref_element_addr, ++cur_element_addr) { - // precompute interpolated reference patch color - int2 px_reftl = ( ref_element_addr % get_image_dim(image_ref)[0], ref_element_addr / get_image_dim(image_ref)[0]); - int2 px_reftr = ((ref_element_addr + 1) % get_image_dim(image_ref)[0], (ref_element_addr + 1) / get_image_dim(image_ref)[0]); - int2 px_refbl = ((ref_element_addr + get_image_dim(image_ref)[0]) % get_image_dim(image_ref)[0], (ref_element_addr + get_image_dim(image_ref)[0]) / get_image_dim(image_ref)[0]); - int2 px_refbr = ((ref_element_addr + get_image_dim(image_ref)[0] + 1) % get_image_dim(image_ref)[0], (ref_element_addr + get_image_dim(image_ref)[0] + 1) / get_image_dim(image_ref)[0]); - double value = w_ref_tl * read_imageui(image_ref, sampler, px_reftl).x + w_ref_tr * read_imageui(image_ref, sampler, px_reftr).x + - w_ref_bl * read_imageui(image_ref, sampler, px_refbl).x + w_ref_br * read_imageui(image_ref, sampler, px_refbr).x; + // precompute interpolated reference patch color + int2 px_reftl = (int2)( ref_element_addr % get_image_dim(image_ref)[0], ref_element_addr / get_image_dim(image_ref)[0]); + int2 px_reftr = (int2)((ref_element_addr + 1) % get_image_dim(image_ref)[0], (ref_element_addr + 1) / get_image_dim(image_ref)[0]); + int2 px_refbl = (int2)((ref_element_addr + get_image_dim(image_ref)[0]) % get_image_dim(image_ref)[0], (ref_element_addr + get_image_dim(image_ref)[0]) / get_image_dim(image_ref)[0]); + int2 px_refbr = (int2)((ref_element_addr + get_image_dim(image_ref)[0] + 1) % get_image_dim(image_ref)[0], (ref_element_addr + get_image_dim(image_ref)[0] + 1) / get_image_dim(image_ref)[0]); + double value = w_ref_tl * read_imageui(image_ref, sampler, px_reftl).x + w_ref_tr * read_imageui(image_ref, sampler, px_reftr).x + + w_ref_bl * read_imageui(image_ref, sampler, px_refbl).x + w_ref_br * read_imageui(image_ref, sampler, px_refbr).x; - double dx = 0.5f * ((w_ref_tl * read_imageui(image_ref, sampler, ((ref_element_addr + 1) % get_image_dim(image_ref)[0], ((ref_element_addr + 1) / get_image_dim(image_ref)[0]))).x + - w_ref_tr * read_imageui(image_ref, sampler, ((ref_element_addr + 2) % get_image_dim(image_ref)[0], ((ref_element_addr + 2) / get_image_dim(image_ref)[0]))).x + - w_ref_bl * read_imageui(image_ref, sampler, ((ref_element_addr + (get_image_dim(image_ref)[0]) + 1) % get_image_dim(image_ref)[0], ((ref_element_addr + (get_image_dim(image_ref)[0]) + 1) / get_image_dim(image_ref)[0]))).x + - w_ref_br * read_imageui(image_ref, sampler, ((ref_element_addr + (get_image_dim(image_ref)[0]) + 2) % get_image_dim(image_ref)[0], ((ref_element_addr + (get_image_dim(image_ref)[0]) + 2) / get_image_dim(image_ref)[0]))).x) - -(w_ref_tl * read_imageui(image_ref, sampler, ((ref_element_addr - 1) % get_image_dim(image_ref)[0], ((ref_element_addr - 1) / get_image_dim(image_ref)[0]))).x + - w_ref_tr * read_imageui(image_ref, sampler, ((ref_element_addr + 0) % get_image_dim(image_ref)[0], ((ref_element_addr + 0) / get_image_dim(image_ref)[0]))).x + - w_ref_bl * read_imageui(image_ref, sampler, ((ref_element_addr + (get_image_dim(image_ref)[0]) - 1) % get_image_dim(image_ref)[0], ((ref_element_addr + (get_image_dim(image_ref)[0]) - 1) / get_image_dim(image_ref)[0]))).x + - w_ref_br * read_imageui(image_ref, sampler, ((ref_element_addr + (get_image_dim(image_ref)[0])) % get_image_dim(image_ref)[0], ((ref_element_addr + (get_image_dim(image_ref)[0])) / get_image_dim(image_ref)[0]))).x)); + double dx = 0.5f * ((w_ref_tl * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + 1) % get_image_dim(image_ref)[0], ((ref_element_addr + 1) / get_image_dim(image_ref)[0]))).x + + w_ref_tr * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + 2) % get_image_dim(image_ref)[0], ((ref_element_addr + 2) / get_image_dim(image_ref)[0]))).x + + w_ref_bl * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + (get_image_dim(image_ref)[0]) + 1) % get_image_dim(image_ref)[0], ((ref_element_addr + (get_image_dim(image_ref)[0]) + 1) / get_image_dim(image_ref)[0]))).x + + w_ref_br * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + (get_image_dim(image_ref)[0]) + 2) % get_image_dim(image_ref)[0], ((ref_element_addr + (get_image_dim(image_ref)[0]) + 2) / get_image_dim(image_ref)[0]))).x) + -(w_ref_tl * read_imageui(image_ref, sampler, (int2) ((ref_element_addr - 1) % get_image_dim(image_ref)[0], ((ref_element_addr - 1) / get_image_dim(image_ref)[0]))).x + + w_ref_tr * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + 0) % get_image_dim(image_ref)[0], ((ref_element_addr + 0) / get_image_dim(image_ref)[0]))).x + + w_ref_bl * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + (get_image_dim(image_ref)[0]) - 1) % get_image_dim(image_ref)[0], ((ref_element_addr + (get_image_dim(image_ref)[0]) - 1) / get_image_dim(image_ref)[0]))).x + + w_ref_br * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + (get_image_dim(image_ref)[0])) % get_image_dim(image_ref)[0], ((ref_element_addr + (get_image_dim(image_ref)[0])) / get_image_dim(image_ref)[0]))).x)); - double dy = 0.5f * ((w_ref_tl * read_imageui(image_ref, sampler, ((ref_element_addr + (get_image_dim(image_ref)[0])) % get_image_dim(image_ref)[0], ((ref_element_addr + (get_image_dim(image_ref)[0])) / get_image_dim(image_ref)[0]))).x + - w_ref_tr * read_imageui(image_ref, sampler, ((ref_element_addr + (get_image_dim(image_ref)[0]) + 1) % get_image_dim(image_ref)[0], ((ref_element_addr + (get_image_dim(image_ref)[0]) + 1) / get_image_dim(image_ref)[0]))).x + - w_ref_bl * read_imageui(image_ref, sampler, ((ref_element_addr + (get_image_dim(image_ref)[0]) * 2) % get_image_dim(image_ref)[0], ((ref_element_addr + (get_image_dim(image_ref)[0]) * 2) / get_image_dim(image_ref)[0]))).x + - w_ref_br * read_imageui(image_ref, sampler, ((ref_element_addr + (get_image_dim(image_ref)[0]) * 2 + 1) % get_image_dim(image_ref)[0], ((ref_element_addr + (get_image_dim(image_ref)[0]) * 2 + 1) / get_image_dim(image_ref)[0]))).x) - -(w_ref_tl * read_imageui(image_ref, sampler, ((ref_element_addr + (-get_image_dim(image_ref)[0])) % get_image_dim(image_ref)[0], ((ref_element_addr + (-get_image_dim(image_ref)[0])) / get_image_dim(image_ref)[0]))).x + - w_ref_tr * read_imageui(image_ref, sampler, ((ref_element_addr + (1 - get_image_dim(image_ref)[0])) % get_image_dim(image_ref)[0], ((ref_element_addr + (1 - get_image_dim(image_ref)[0])) / get_image_dim(image_ref)[0]))).x + - w_ref_bl * read_imageui(image_ref, sampler, ((ref_element_addr + 0) % get_image_dim(image_ref)[0], ((ref_element_addr + 0) / get_image_dim(image_ref)[0]))).x + - w_ref_br * read_imageui(image_ref, sampler, ((ref_element_addr + 1) % get_image_dim(image_ref)[0], ((ref_element_addr + 1) / get_image_dim(image_ref)[0]))).x)); + double dy = 0.5f * ((w_ref_tl * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + (get_image_dim(image_ref)[0])) % get_image_dim(image_ref)[0], ((ref_element_addr + (get_image_dim(image_ref)[0])) / get_image_dim(image_ref)[0]))).x + + w_ref_tr * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + (get_image_dim(image_ref)[0]) + 1) % get_image_dim(image_ref)[0], ((ref_element_addr + (get_image_dim(image_ref)[0]) + 1) / get_image_dim(image_ref)[0]))).x + + w_ref_bl * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + (get_image_dim(image_ref)[0]) * 2) % get_image_dim(image_ref)[0], ((ref_element_addr + (get_image_dim(image_ref)[0]) * 2) / get_image_dim(image_ref)[0]))).x + + w_ref_br * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + (get_image_dim(image_ref)[0]) * 2 + 1) % get_image_dim(image_ref)[0], ((ref_element_addr + (get_image_dim(image_ref)[0]) * 2 + 1) / get_image_dim(image_ref)[0]))).x) + -(w_ref_tl * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + (-get_image_dim(image_ref)[0])) % get_image_dim(image_ref)[0], ((ref_element_addr + (-get_image_dim(image_ref)[0])) / get_image_dim(image_ref)[0]))).x + + w_ref_tr * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + (1 - get_image_dim(image_ref)[0])) % get_image_dim(image_ref)[0], ((ref_element_addr + (1 - get_image_dim(image_ref)[0])) / get_image_dim(image_ref)[0]))).x + + w_ref_bl * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + 0) % get_image_dim(image_ref)[0], ((ref_element_addr + 0) / get_image_dim(image_ref)[0]))).x + + w_ref_br * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + 1) % get_image_dim(image_ref)[0], ((ref_element_addr + 1) / get_image_dim(image_ref)[0]))).x)); - // compute residual - int2 px_curtl = ( cur_element_addr % get_image_dim(image_cur)[0], cur_element_add / get_image_dim(image_cur)[0]); - int2 px_curtr = ((cur_element_addr + 1) % get_image_dim(image_cur)[0], (cur_element_add + 1) / get_image_dim(image_cur)[0]); - int2 px_curbl = ((cur_element_addr + (get_image_dim(image_cur)[0])) % get_image_dim(image_cur)[0], (cur_element_add + (get_image_dim(image_cur)[0])) / get_image_dim(image_cur)[0]); - int2 px_curbr = ((cur_element_addr + (get_image_dim(image_cur)[0]) + 1) % get_image_dim(image_cur)[0], (cur_element_add + (get_image_dim(image_cur)[0]) + 1) / get_image_dim(image_cur)[0]); - double intensity_cur = w_cur_tl * read_imageui(image_cur, sampler, px_curtl).x + w_cur_tr * read_imageui(image_cur, sampler, px_curtr).x + - w_cur_bl * read_imageui(image_cur, sampler, px_curbl).x + w_cur_br * read_imageui(image_cur, sampler, px_curbr).x; + // compute residual + int2 px_curtl = ( cur_element_addr % get_image_dim(image_cur)[0], cur_element_addr / get_image_dim(image_cur)[0]); + int2 px_curtr = ((cur_element_addr + 1) % get_image_dim(image_cur)[0], (cur_element_addr + 1) / get_image_dim(image_cur)[0]); + int2 px_curbl = ((cur_element_addr + (get_image_dim(image_cur)[0])) % get_image_dim(image_cur)[0], (cur_element_addr + (get_image_dim(image_cur)[0])) / get_image_dim(image_cur)[0]); + int2 px_curbr = ((cur_element_addr + (get_image_dim(image_cur)[0]) + 1) % get_image_dim(image_cur)[0], (cur_element_addr + (get_image_dim(image_cur)[0]) + 1) / get_image_dim(image_cur)[0]); + double intensity_cur = w_cur_tl * read_imageui(image_cur, sampler, px_curtl).x + w_cur_tr * read_imageui(image_cur, sampler, px_curtr).x + + w_cur_bl * read_imageui(image_cur, sampler, px_curbl).x + w_cur_br * read_imageui(image_cur, sampler, px_curbr).x; - double res = intensity_cur - value; + double res = intensity_cur - value; - // used to compute scale for robust cost - // if(compute_weight_scale) - errors[f * pow(PATCH_SIZE, 2) + (y * PATCH_SIZE) + x] = fabs(res); + // used to compute scale for robust cost + // if(compute_weight_scale) + errors[(int)(f * pow((double)PATCH_SIZE, 2.0) + (y * PATCH_SIZE) + x)] = fabs(res); - // robustification - double weight = 2.0; - // if(use_weights_) { // use_weights_ dafault value is false - // weight = weight_function_->value(res/scale_); - // } + // robustification + double weight = 2.0; + // if(use_weights_) { // use_weights_ dafault value is false + // weight = weight_function_->value(res/scale_); + // } - *chi += res * res * weight; - n_meas_++; + chi[0] += res * res * weight; + n_meas_++; - // if(linearize_system) - // { - // compute Jacobian, weighted Hessian and weighted "steepest descend images" (times error) - double3 j_row0 = double3(dx * frame_jac[0], dx * frame_jac[1], dx * frame_jac[2]) - double3 j_row1 = double3(dy * frame_jac[3], dy * frame_jac[4], dy * frame_jac[5]) - double3 J((j_row0 + j_row1) * (camera_model[0] / scale)); - compute_hessain(J, Hessian, weight); // H_.noalias() += J * J.transpose() * weight; - compute_Jacobian(J, Jacobian, res, weight) // Jres_.noalias() -= J * res * weight; - // } + // if(linearize_system) + // { + // compute Jacobian, weighted Hessian and weighted "steepest descend images" (times error) + double3 j_row0 = (double3)((dx * frame_jac[0]), (dx * frame_jac[1]), (dx * frame_jac[2])); + double3 j_row1 = (double3)((dy * frame_jac[3]), (dy * frame_jac[4]), (dy * frame_jac[5])); + double3 J = ((j_row0 + j_row1) * (camera_model[0] / scale)); + compute_hessain(J, Hessian, weight); // H_.noalias() += J * J.transpose() * weight; + compute_Jacobian(J, Jacobian, res, weight); // Jres_.noalias() -= J * res * weight; + // } } } - *chi = *chi / n_meas_; - free(frame_jac); + chi[0] = chi[0] / n_meas_; } diff --git a/GPU_version/vio/launch/Px30.launch b/GPU_version/vio/launch/Px30.launch index 36114e8..b66a344 100644 --- a/GPU_version/vio/launch/Px30.launch +++ b/GPU_version/vio/launch/Px30.launch @@ -1,6 +1,6 @@ - + diff --git a/GPU_version/vio/out.txt b/GPU_version/vio/out.txt index 8447d6114a8abe41392eac2b1920d1bc060d267e..ab3b540fa51ae81430eba7a1f2fcb09d85adb652 100644 GIT binary patch literal 5883 zcmb_gTXW(#7T&k5;xF`z9=o>|Bgv9%GdmA7O=qYfkbYDbV~gO8ZFy{y%l`U3 zvOz!^aHcA$A_cm9=OUeRzN1gKIK4&V>G#SpQ=bE|3ptgvX*@`xE@SD0bED_JB~>_!d%BWhxr^w)yiNBhFc&h z=bppyImnfaA6AvYWNsU#O{ho7Sv8k01`k_I*uthQirNlmE@kHwUB2#ty3`hew16_( zb20JGfrbZ~dJYr31(ajrIL_IV5BD`?p39is1}ZqQ-LvLL*qBc&OoZ#SVLI4xs6MB~ zj~R-yxQc@${-2D_?&BCU#ysvG^IG|&dJjb$`6b{Ob?oyu1{_8~U3T;wG@@3`Pvgvw z;u7L0u6FKghxTj;%cG7vfUb%le3X&Vncz01ITsM-C*6>%QmVX)Q@>gjvfKqFYjLlG zIi})hNNSDCs#u5By4ZlH!Hb_)rO}(Ws10^8j%|AC^b&O+_}M!3W5`towH1`RggGZc zAD5*}WLO^}oZ&8+V7RE~-9c;u3fo7+NxMVapZOrb=t|p^Wx^GM9t?+mrs8rJbl5tds5o(5&KN%F z*^57BKSAQwL-n)+tgqAeSeM)+sFtco z5nShcD7@pWlF8@!7c{)OLGyJ6u_+NOK(kzC!^!9C%P(k<=Sds}Rjjh|Z=Lfn%{KJg zH*`@1`6>=!$8h3*8~qp$NB(qhIqD-L^JZ@u5)`9b{K7q`lKXpRSEDH)4E-OY`C>eq z_BX1bA+jxu_LqLW8BebL@zno)G@p(pi$1zfRQL#_LhJ6!608d<>BrjWUz)ifdJ3{o zMn5eIR}!|qYw3L)#RY^i2niB@f8)M(!`bE4cru#%gCB$OWbkzYt{{8PnaqZRiGMk| z^cUm*z?|UR7JKs-liAmU1)eJ$3haluC-{+TF-l$H+Tv(nYtB_xL9t6cJu`GB0cliQ zFoNBq7qEd)xw(BCP?fh}GKgk;T2mFN^bk{zoX3Q^j9r4ovBbV*oR!Msa0fh8g`5Hj zg_12_{WyI%DFH~IM)HL2Yi{Wv>1%+B* zF!C1^Jjo(>kjPLN6qkL7YL|d|=-;b2fgZrd2xty?Dn*6-a}9wOSqS|;xkej$g8In8 z;%J@f0Cqw|972Z3fdzS5qkF}k6j>jptHF;`I@1*AmwWveg zkF=dSLV!tB-{3as9E`U=^xSRe5Gb%{{toHFf|c|mZHJZsoGh6KWnN$E-#wvRr9q*lNE29qKko>k(wsk+gxDMtFv5ZadUY&nE%oFb@SH& zmM|L3(bZrM1nU}jQV0D5)j~U+H-jKWcN>N3qf{m;io<#>3~zJ=QeqKiIrXr%!_eqH zf?H*VHzZRp$7ay*W4#uLv6(OpuukY^6!Q9;CieLBCewo~yxaV?fvQFBBpx(vFlU6C z?x>IGZuD(y+DB~9u48=)Ftpuvvj94B=wY;`M&R-8w2%1SlBNaF&TKrqWhdc_HjCA7 zEH$8+cx@*1JITRBgzF>GZyg8Y%Lb`_S2~=ik(#%mgNf#m3moA#if%>MZ*DU5KqrSxK0|6LA#>Exn-?mCta957L7mx# z^K)FSP##C{28vyAx8Wxwg*4$`4i*rl{>^;+>n6ydPYIHhDyu$$?tYWmKOn_ylgJzV zP3DnRrA_J;>&ypDAtk;iJsVTDwnOqz>#D13{4wi2r?GxJ7Xrnub6gxsbgPp+?7lnj zCOE#UUrx4L_MAyDZ{Ti?So9bti8e%KNWR2XXL}kyO_Zy3V{)XPGqllP?@Se>B2_@` Y>gf8_who0V%@cUKuCJL_^N1jr&mpaJB|Jj`$3 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 diff --git a/GPU_version/vio/src/atan_camera.cpp b/GPU_version/vio/src/atan_camera.cpp index b2ed822..7be69e0 100644 --- a/GPU_version/vio/src/atan_camera.cpp +++ b/GPU_version/vio/src/atan_camera.cpp @@ -36,11 +36,14 @@ ATANCamera(double width, double height, tans_ = 0.0; distortion_ = false; } + param_ = (double *) malloc(5 * sizeof(double)); } ATANCamera:: ~ATANCamera() -{} +{ + delete param_; +} Vector3d ATANCamera:: cam2world(const double& x, const double& y) const diff --git a/GPU_version/vio/src/frame_handler_mono.cpp b/GPU_version/vio/src/frame_handler_mono.cpp index 9cb1471..eddcafc 100644 --- a/GPU_version/vio/src/frame_handler_mono.cpp +++ b/GPU_version/vio/src/frame_handler_mono.cpp @@ -54,20 +54,20 @@ FrameHandlerMono::FrameHandlerMono(vk::AbstractCamera* cam,Eigen::Matrixwrite_buf(1,4,300,f); cl_double2 px[300]={0}; gpu_fast_->write_buf(1,5,300,px); - int level=0; - gpu_fast_->write_buf(1,6,level); + int level[1]={0}; + gpu_fast_->write_buf(1,6,1,level); double c[5]={0}; gpu_fast_->write_buf(1,7,5,c); - float e[300]={0}; + double e[300]={0}; gpu_fast_->write_buf(1,8,300,e); - float H[6]={0}; - gpu_fast_->write_buf(1,9,6,H); - float J[3]={0}; + double H[9]={0}; + gpu_fast_->write_buf(1,9,9,H); + double J[3]={0}; gpu_fast_->write_buf(1,10,3,J); - double chi2=0.0; - gpu_fast_->write_buf(1,11,chi2); + double chi2[1]={0.0}; + gpu_fast_->write_buf(1,11,1,chi2); imageAlign_=new SparseImgAlignGpu(Config::kltMaxLevel(), Config::kltMinLevel(), - 30, SparseImgAlign::GaussNewton, false,gpu_fast_); + 30, SparseImgAlign::GaussNewton, true,gpu_fast_); klt_homography_init_=new initialization::KltHomographyInit(gpu_fast_); initialize(); } @@ -164,9 +164,10 @@ FrameHandlerBase::UpdateResult FrameHandlerMono::processFrame() new_frame_->T_f_w_=init_f.second; new_frame_->Cov_ = init_f.first; // sparse image align + /* SparseImgAlign img_align(Config::kltMaxLevel(), Config::kltMinLevel(), 30, SparseImgAlign::LevenbergMarquardt, false, false); - if(img_align.run(last_frame_, new_frame_)==0)return RESULT_FAILURE; + if(img_align.run(last_frame_, new_frame_)==0)return RESULT_FAILURE;*/ if(imageAlign_->run(last_frame_, new_frame_)==0)return RESULT_FAILURE; reprojector_.reprojectMap(new_frame_, overlap_kfs_); size_t sfba_n_edges_final=0; diff --git a/GPU_version/vio/src/sparse_img_align_gpu.cpp b/GPU_version/vio/src/sparse_img_align_gpu.cpp index a7891d2..b2eaf4f 100644 --- a/GPU_version/vio/src/sparse_img_align_gpu.cpp +++ b/GPU_version/vio/src/sparse_img_align_gpu.cpp @@ -35,7 +35,6 @@ SparseImgAlignGpu::SparseImgAlignGpu( size_t SparseImgAlignGpu::run(FramePtr ref_frame, FramePtr cur_frame) { reset(); - if(ref_frame->fts_.empty()) { return 0; @@ -46,15 +45,11 @@ size_t SparseImgAlignGpu::run(FramePtr ref_frame, FramePtr cur_frame) residual_->reload_buf(1,2,cur_pos); residual_->reload_buf(1,3,ref_pos); residual_->reload_buf(1,7,camera); - cl_double3* features; - cl_double2* featue_px; + cl_double3 features[ref_frame->fts_.size()]; + cl_double2 featue_px[ref_frame->fts_.size()]; feature_counter_ = 0; // is used to compute the index of the cached jacobian - std::vector::iterator visiblity_it = visible_fts_.begin(); - for(auto it=ref_frame->fts_.begin(); it!=ref_frame->fts_.end(); - ++it, ++visiblity_it){ - if(!*visiblity_it) - continue; - const Vector3d xyz_ref((*it)->f*((*it)->point->pos_ - Eigen::Vector3d(ref_pos[0],0.0,ref_pos[1])).norm()); + for(auto it=ref_frame->fts_.begin(); it!=ref_frame->fts_.end();++it){ + Vector3d xyz_ref=(*it)->f*((*it)->point->pos_ - Eigen::Vector3d(ref_pos[0],0.0,ref_pos[1])).norm(); features[feature_counter_].x=xyz_ref(0); features[feature_counter_].y=xyz_ref(1); features[feature_counter_].z=xyz_ref(2); @@ -84,8 +79,8 @@ double SparseImgAlignGpu::computeResiduals( bool linearize_system, bool compute_weight_scale) { - double chi2=0.0; - residual_->reload_buf(1,11,&chi2); + double chi2[1]={0}; + residual_->reload_buf(1,11,chi2); /// TODO GPU compute based on the feature residual_->run(1,feature_counter_); if(compute_weight_scale && iter_ == 0) { @@ -94,14 +89,16 @@ double SparseImgAlignGpu::computeResiduals( std::vector errors(error,error+feature_counter_); scale_ = scale_estimator_->compute(errors); } - residual_->read(1,11,&chi2); - return chi2; + + double out[1]={0.0}; + residual_->read(1,11,out); + return out[0]; } int SparseImgAlignGpu::solve() { - double* H; - double* J; + double H[9]={0}; + double J[3]={0}; residual_->read(1,9,H); residual_->read(1,10,J); x_ = Eigen::Matrix(H).ldlt().solve(Eigen::Matrix(J)); @@ -112,7 +109,7 @@ int SparseImgAlignGpu::solve() void SparseImgAlignGpu::update() { /// TODO the update situation may have a smarter solution - double* pos; + double pos[3]={0}; residual_->read(1,2,pos); SE2 update = SE2(pos[2],Eigen::Vector2d(pos[0],pos[1])) * SE2::exp(-0.25*x_); pos[0]=update.translation()(0); From e20e2c76e1e44cf8e84fb1a96dc39942e0d0032a Mon Sep 17 00:00:00 2001 From: gfuse Date: Thu, 5 Aug 2021 14:54:44 +0200 Subject: [PATCH 10/12] debug crashing --- GPU_version/vio/include/vio/cl_class.h | 18 ++++++++++++++---- .../vio/include/vio/frame_handler_mono.h | 1 - .../vio/include/vio/nlls_solver_impl.hpp | 1 - GPU_version/vio/kernel/compute-residual.cl | 1 - GPU_version/vio/kernel/fast-gray.cl | 2 +- GPU_version/vio/param/vo_fast.yaml | 2 +- GPU_version/vio/src/feature_detection.cpp | 2 +- GPU_version/vio/src/frame_handler_mono.cpp | 10 +++------- GPU_version/vio/src/sparse_img_align_gpu.cpp | 14 +++++++++----- 9 files changed, 29 insertions(+), 22 deletions(-) diff --git a/GPU_version/vio/include/vio/cl_class.h b/GPU_version/vio/include/vio/cl_class.h index 9ff34e5..2b30b3b 100644 --- a/GPU_version/vio/include/vio/cl_class.h +++ b/GPU_version/vio/include/vio/cl_class.h @@ -57,8 +57,14 @@ public: int32_t reload(size_t id,T* buf,cl::CommandQueue* queue){ try{ if(id>_buffers.size())return CL_MAP_FAILURE; - for(auto i:_buffers)if(i.second==id) - queue->enqueueWriteBuffer(i.first.first,CL_TRUE, 0, sizeof(T) * i.first.second, buf); + for(auto&& i:_buffers)if(i.second==id){ + cl_int err1=queue->enqueueWriteBuffer(i.first.first,CL_TRUE, 0, sizeof(T) * i.first.second, buf); + cl_int err2=_kernel->setArg(id,i.first.first); + if(err1!=0 || err2!=0){ + std::cerr<<"Error C:Kernel, F:write, L3:setArg\t"<(buf.data)); + cl_int err=_kernel->setArg(id,i.first); + if(err!=0){ + std::cerr<<"Error C:Kernel, F:write image, L:setArg ID:\t"<::optimizeGaussNewton() std::cout << "It. " << iter_ << "\t Success" << "\t new_chi2 = " << new_chi2 - << "\t n_meas = " << n_meas_ << "\t x_norm = " << vk::norm_max(x_)<<'\n'; } // stop when converged, i.e. update step too small diff --git a/GPU_version/vio/kernel/compute-residual.cl b/GPU_version/vio/kernel/compute-residual.cl index d02fd2b..6d11d83 100644 --- a/GPU_version/vio/kernel/compute-residual.cl +++ b/GPU_version/vio/kernel/compute-residual.cl @@ -94,7 +94,6 @@ __kernel void compute_residual( double v_ref = featue_px[f].y * scale; int u_ref_i = floor(u_ref); int v_ref_i = floor(v_ref); - if(u_ref_i - (PATCH_HALFSIZE + 1) < 0 || v_ref_i - (PATCH_HALFSIZE + 1) < 0 || u_ref_i + (PATCH_HALFSIZE + 1) >= get_image_dim(image_ref)[0] || v_ref_i + (PATCH_HALFSIZE + 1) >= get_image_dim(image_ref)[1]) return; diff --git a/GPU_version/vio/kernel/fast-gray.cl b/GPU_version/vio/kernel/fast-gray.cl index ce6a927..7622206 100644 --- a/GPU_version/vio/kernel/fast-gray.cl +++ b/GPU_version/vio/kernel/fast-gray.cl @@ -17,7 +17,7 @@ __kernel void fast_gray( // Use global work item as 2D image coordinates. int const x = get_global_id(0); int const y = get_global_id(1); - if(x>16 && x16){ + if(x>5 && x5){ int2 const xy = (int2)(x, y); // Read the candidate pixel. int const p00 = read_imageui(image, sampler, xy).x; diff --git a/GPU_version/vio/param/vo_fast.yaml b/GPU_version/vio/param/vo_fast.yaml index 1ecb630..b4e3359 100644 --- a/GPU_version/vio/param/vo_fast.yaml +++ b/GPU_version/vio/param/vo_fast.yaml @@ -3,7 +3,7 @@ svo: max_n_kfs: 20 #Limit the number of keyframes in the map. This makes nslam essentially. a Visual Odometry. Set to 0 if unlimited number of keyframes are allowed. Minimum number of keyframes is 3. loba_num_iter: 0 #Number of iterations in the local bundle adjustment. quality_min_fts: 10 #If the number of tracked features drops below this threshold. Tracking quality is bad. - quality_max_drop_fts: 60 #If within one frame, this amount of features are dropped. Tracking quality is bad. + quality_max_drop_fts: 90 #If within one frame, this amount of features are dropped. Tracking quality is bad. init_min_tracked: 100 init_min_disparity: 30 structureoptim_max_pts: 50 diff --git a/GPU_version/vio/src/feature_detection.cpp b/GPU_version/vio/src/feature_detection.cpp index d3eb264..d19b427 100644 --- a/GPU_version/vio/src/feature_detection.cpp +++ b/GPU_version/vio/src/feature_detection.cpp @@ -79,7 +79,7 @@ void FastDetector::detect( gpu_fast_->reload_buf(0,0,img); int icorner[1]={0}; gpu_fast_->reload_buf(0,2,icorner); - gpu_fast_->run(0,img_pyr[L].cols,img_pyr[L].rows); + gpu_fast_->run(0,img.cols,img.rows); cl_int2 fast_corners[350000]; gpu_fast_->read(0,1,fast_corners); int count[1]={0}; diff --git a/GPU_version/vio/src/frame_handler_mono.cpp b/GPU_version/vio/src/frame_handler_mono.cpp index eddcafc..f59dd72 100644 --- a/GPU_version/vio/src/frame_handler_mono.cpp +++ b/GPU_version/vio/src/frame_handler_mono.cpp @@ -66,8 +66,6 @@ FrameHandlerMono::FrameHandlerMono(vk::AbstractCamera* cam,Eigen::Matrixwrite_buf(1,10,3,J); double chi2[1]={0.0}; gpu_fast_->write_buf(1,11,1,chi2); - imageAlign_=new SparseImgAlignGpu(Config::kltMaxLevel(), Config::kltMinLevel(), - 30, SparseImgAlign::GaussNewton, true,gpu_fast_); klt_homography_init_=new initialization::KltHomographyInit(gpu_fast_); initialize(); } @@ -164,11 +162,9 @@ FrameHandlerBase::UpdateResult FrameHandlerMono::processFrame() new_frame_->T_f_w_=init_f.second; new_frame_->Cov_ = init_f.first; // sparse image align - /* - SparseImgAlign img_align(Config::kltMaxLevel(), Config::kltMinLevel(), - 30, SparseImgAlign::LevenbergMarquardt, false, false); - if(img_align.run(last_frame_, new_frame_)==0)return RESULT_FAILURE;*/ - if(imageAlign_->run(last_frame_, new_frame_)==0)return RESULT_FAILURE; + //SparseImgAlign img_align(Config::kltMaxLevel(), Config::kltMinLevel(),30, SparseImgAlign::LevenbergMarquardt, false, true); + SparseImgAlignGpu img_align(Config::kltMaxLevel(), Config::kltMinLevel(),30, SparseImgAlign::GaussNewton, false,gpu_fast_); + if(img_align.run(last_frame_, new_frame_)==0)return RESULT_FAILURE; reprojector_.reprojectMap(new_frame_, overlap_kfs_); size_t sfba_n_edges_final=0; double sfba_thresh, sfba_error_init, sfba_error_final; diff --git a/GPU_version/vio/src/sparse_img_align_gpu.cpp b/GPU_version/vio/src/sparse_img_align_gpu.cpp index b2eaf4f..617c690 100644 --- a/GPU_version/vio/src/sparse_img_align_gpu.cpp +++ b/GPU_version/vio/src/sparse_img_align_gpu.cpp @@ -49,6 +49,8 @@ size_t SparseImgAlignGpu::run(FramePtr ref_frame, FramePtr cur_frame) cl_double2 featue_px[ref_frame->fts_.size()]; feature_counter_ = 0; // is used to compute the index of the cached jacobian for(auto it=ref_frame->fts_.begin(); it!=ref_frame->fts_.end();++it){ + if(*it == nullptr)continue; + if((*it)->point == nullptr)continue; Vector3d xyz_ref=(*it)->f*((*it)->point->pos_ - Eigen::Vector3d(ref_pos[0],0.0,ref_pos[1])).norm(); features[feature_counter_].x=xyz_ref(0); features[feature_counter_].y=xyz_ref(1); @@ -62,17 +64,19 @@ size_t SparseImgAlignGpu::run(FramePtr ref_frame, FramePtr cur_frame) SE2 T_cur(cur_frame->T_f_w_.se2());///TODO temporary, we can remove it for(level_=max_level_; level_>=min_level_; --level_) { - cv::Mat& cur_img = cur_frame->img_pyr_.at(level_); - cv::Mat& ref_img = ref_frame->img_pyr_.at(level_); + cv::Mat cur_img = cur_frame->img_pyr_.at(level_); + cv::Mat ref_img = ref_frame->img_pyr_.at(level_); residual_->reload_buf(1,0,cur_img); residual_->reload_buf(1,1,ref_img); residual_->reload_buf(1,6,&level_); mu_ = 1.0; optimize(T_cur); } - cur_frame->T_f_w_ = SE2_5(T_cur); + double pos[3]={0}; + residual_->read(1,2,pos); + cur_frame->T_f_w_ = SE2_5(pos[0],pos[1],pos[2]); - return n_meas_/patch_area_; + return 1; } double SparseImgAlignGpu::computeResiduals( @@ -111,7 +115,7 @@ void SparseImgAlignGpu::update() /// TODO the update situation may have a smarter solution double pos[3]={0}; residual_->read(1,2,pos); - SE2 update = SE2(pos[2],Eigen::Vector2d(pos[0],pos[1])) * SE2::exp(-0.25*x_); + SE2 update = SE2(pos[2],Eigen::Vector2d(pos[0],pos[1])) * SE2::exp(-0.5*x_); pos[0]=update.translation()(0); pos[1]=update.translation()(1); pos[2]=atan(update.so2().unit_complex().imag()/update.so2().unit_complex().real()); From 819cc047c6ed9904c2412a8fdb607ab912174986 Mon Sep 17 00:00:00 2001 From: gfuse Date: Wed, 11 Aug 2021 16:29:45 +0200 Subject: [PATCH 11/12] add first version of kernel with out error --- GPU_version/vio/include/vio/cl_class.h | 95 ++++---- GPU_version/vio/include/vio/frame.h | 2 +- GPU_version/vio/include/vio/nlls_solver.h | 4 +- .../vio/include/vio/sparse_img_align_gpu.h | 1 + GPU_version/vio/kernel/compute-residual.cl | 223 +++++++----------- GPU_version/vio/src/cl_class.cpp | 30 +-- GPU_version/vio/src/frame_handler_mono.cpp | 30 +-- GPU_version/vio/src/sparse_img_align.cpp | 2 +- GPU_version/vio/src/sparse_img_align_gpu.cpp | 99 +++++--- 9 files changed, 230 insertions(+), 256 deletions(-) diff --git a/GPU_version/vio/include/vio/cl_class.h b/GPU_version/vio/include/vio/cl_class.h index 2b30b3b..99b6168 100644 --- a/GPU_version/vio/include/vio/cl_class.h +++ b/GPU_version/vio/include/vio/cl_class.h @@ -17,19 +17,17 @@ class kernel{ public: kernel(cl::Program* program,std::string name){_kernel = new cl::Kernel(*program,name.c_str());}; ~kernel(){ + for(auto&& i:_images)i.first.setDestructorCallback((void (*)(_cl_mem *, void *))notify, NULL); + for(auto&& i:_buffers)i.first.first.setDestructorCallback((void (*)(_cl_mem *, void *))notify, NULL); _buffers.clear(); _images.clear(); }; template int32_t write(size_t id/*buffer ID*/,T* buf,cl::CommandQueue* queue,cl::Context* context,size_t buf_size){ - _buffers.push_back(std::pair,size_t>(std::pair(cl::Buffer(*context, CL_MEM_READ_WRITE, sizeof(T) * buf_size), - buf_size),id)); - cl_int err=queue->enqueueWriteBuffer(_buffers.back().first.first,CL_TRUE, 0, sizeof(T) * buf_size, buf); - if(err!=0){ - std::cerr<<"Error C:Kernel, F:write, L:enqueueWriteBuffer\n"<setArg(id,_buffers.back().first.first); + _buffers.push_back(std::pair,size_t>(std::pair(cl::Buffer(*context, CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR + , sizeof(T) * buf_size,buf), + buf_size),id)); + cl_int err=_kernel->setArg(id,_buffers.back().first.first); if(err!=0){ std::cerr<<"Error C:Kernel, F:write, L3:setArg\t"<(cl::Image2D(*context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, - cl::ImageFormat(CL_R, CL_UNSIGNED_INT8), - buf.size().width, - buf.size().height, - 0, - reinterpret_cast(buf.data)),id)); + _images.push_back(std::pair(cl::Image2D(*context, CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, + cl::ImageFormat(CL_R, CL_UNSIGNED_INT8), + buf.size().width, + buf.size().height, + 0, + reinterpret_cast(buf.data)),id)); cl_int err=_kernel->setArg(id,_images.back().first); if(err!=0){ @@ -55,26 +53,18 @@ public: template int32_t reload(size_t id,T* buf,cl::CommandQueue* queue){ - try{ - if(id>_buffers.size())return CL_MAP_FAILURE; - for(auto&& i:_buffers)if(i.second==id){ - cl_int err1=queue->enqueueWriteBuffer(i.first.first,CL_TRUE, 0, sizeof(T) * i.first.second, buf); - cl_int err2=_kernel->setArg(id,i.first.first); - if(err1!=0 || err2!=0){ - std::cerr<<"Error C:Kernel, F:write, L3:setArg\t"<enqueueMapBuffer(i.first.first,CL_TRUE,CL_MAP_WRITE,0,sizeof(T) * i.first.second); + memcpy(Map_buf,buf,sizeof(T) * i.first.second); + if(queue->enqueueUnmapMemObject(i.first.first,Map_buf)!=CL_SUCCESS)std::cerr<<"Reload buffer on GPU failed"<<'\n'; } + return CL_SUCCESS; }; int32_t reload(size_t id,cv::Mat& buf,cl::Context* context){ try{ for(auto&& i:_images)if(i.second==id){ - i.first=cl::Image2D(*context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, + i.first.setDestructorCallback((void (*)(_cl_mem *, void *))notify, NULL); + i.first=cl::Image2D(*context, CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, cl::ImageFormat(CL_R, CL_UNSIGNED_INT8), buf.size().width, buf.size().height, @@ -85,7 +75,7 @@ public: std::cerr<<"Error C:Kernel, F:write image, L:setArg ID:\t"<,size_t>> _buffers; std::vector> _images; @@ -168,34 +161,40 @@ public: } int32_t run(size_t id1/*kernal ID*/,std::size_t x=1,std::size_t y=1,std::size_t z=1) { cl_int err=0; - if(z>1 && y>1){ - err=queue->enqueueNDRangeKernel(*_kernels.at(id1)._kernel, cl::NullRange/*offset*/, cl::NDRange(x,y,z)/*Global*/, cl::NullRange/*local*/); - }else if(z<2 && y>1){ - err=queue->enqueueNDRangeKernel(*_kernels.at(id1)._kernel, cl::NullRange/*offset*/, cl::NDRange(x,y)/*Global*/, cl::NullRange/*local*/); - }else{ - err=queue->enqueueNDRangeKernel(*_kernels.at(id1)._kernel, cl::NullRange/*offset*/, cl::NDRange(x)/*Global*/, cl::NullRange/*local*/); - }; - queue->finish(); - if(err!=0){ - std::cerr<<"kernel: "<<_kernels.at(id1)._kernel->getInfo(); - std::cerr<<" ,Args: "<<_kernels.at(id1)._kernel->getInfo()<<" ,Run out: "<getInfo();++i) + queue->flush(); + if(z>1 && y>1){ + err=queue->enqueueNDRangeKernel(*_kernels.at(id1)._kernel, cl::NullRange/*offset*/, cl::NDRange(x,y,z)/*Global*/, cl::NullRange/*local*/); + }else if(z<2 && y>1){ + err=queue->enqueueNDRangeKernel(*_kernels.at(id1)._kernel, cl::NullRange/*offset*/, cl::NDRange(x,y)/*Global*/, cl::NullRange/*local*/); + }else{ + err=queue->enqueueNDRangeKernel(*_kernels.at(id1)._kernel, cl::NullRange/*offset*/, cl::NDRange(x)/*Global*/, cl::NullRange/*local*/); + }; + if(err!=0){ + std::cerr<<"kernel: "<<_kernels.at(id1)._kernel->getInfo(); + std::cerr<<" ,Args: "<<_kernels.at(id1)._kernel->getInfo()<<" ,Run out: "<getInfo();++i) std::cerr<<"argument type "<getArgInfo(i)<<'\n'; - } - return err; + } + return queue->finish(); } template void read(size_t id1/*kernal ID*/,size_t id2/*buffer ID*/, T* out){ queue->enqueueReadBuffer(_kernels.at(id1).read(id2).first, CL_TRUE, 0, sizeof(T) * _kernels.at(id1).read(id2).second, out); } + template + void read(size_t id1/*kernal ID*/,size_t id2/*buffer ID*/,size_t size/*size*/, T* out){ + T* Map_buf=(T*)queue->enqueueMapBuffer(_kernels.at(id1).read(id2).first,CL_TRUE,CL_MAP_READ,0,sizeof(T) * size); + memcpy(out,Map_buf,sizeof(T) * size); + if(queue->enqueueUnmapMemObject(_kernels.at(id1).read(id2).first,Map_buf)!=CL_SUCCESS)std::cerr<<"Read buffer on GPU failed"<<'\n'; + } void clear_buf(); private: std::vector _kernels; - cl::Context* context = NULL; - cl::Device device; - cl::Program* program = NULL; - cl::CommandQueue* queue=NULL; + cl::Context* context = nullptr; + cl::Device* device = nullptr; + cl::Program* program = nullptr; + cl::CommandQueue* queue= nullptr; }; #endif //VIO_OPENCL_CL_CLASS_H diff --git a/GPU_version/vio/include/vio/frame.h b/GPU_version/vio/include/vio/frame.h index b8c10d7..7408805 100644 --- a/GPU_version/vio/include/vio/frame.h +++ b/GPU_version/vio/include/vio/frame.h @@ -148,7 +148,7 @@ public: J(0,0) = -z_inv; // -1/z J(0,1) = x*z_inv_2; // x/z^2 - J(0,2) = -(1.0 + pow(x,2)*z_inv_2); // -(1.0 + x^2/z^2) + J(0,2) = -(1.0 + pow(x,2)/z_inv_2); // -(1.0 + x^2/z^2) J(1,0) = 1e-19; // 0 J(1,1) = y*z_inv_2; // y/z^2 diff --git a/GPU_version/vio/include/vio/nlls_solver.h b/GPU_version/vio/include/vio/nlls_solver.h index 886556d..58ec2f1 100644 --- a/GPU_version/vio/include/vio/nlls_solver.h +++ b/GPU_version/vio/include/vio/nlls_solver.h @@ -110,7 +110,7 @@ public: // robust least squares bool use_weights_; - float scale_; + double scale_=2.0; robust_cost::ScaleEstimatorPtr scale_estimator_; robust_cost::WeightFunctionPtr weight_function_; @@ -131,7 +131,7 @@ public: eps_(0.0000000001), iter_(0), use_weights_(false), - scale_(0.0), + scale_(2.0), scale_estimator_(NULL), weight_function_(NULL) { } diff --git a/GPU_version/vio/include/vio/sparse_img_align_gpu.h b/GPU_version/vio/include/vio/sparse_img_align_gpu.h index 2655b22..27d7b53 100644 --- a/GPU_version/vio/include/vio/sparse_img_align_gpu.h +++ b/GPU_version/vio/include/vio/sparse_img_align_gpu.h @@ -54,6 +54,7 @@ public: FramePtr ref_frame, FramePtr cur_frame); + // FILE* data= nullptr; protected: int level_; //!< current pyramid level on which the optimization runs. diff --git a/GPU_version/vio/kernel/compute-residual.cl b/GPU_version/vio/kernel/compute-residual.cl index 6d11d83..baf62f5 100644 --- a/GPU_version/vio/kernel/compute-residual.cl +++ b/GPU_version/vio/kernel/compute-residual.cl @@ -4,45 +4,37 @@ // Enable OpenCL 32-bit integer atomic functions. #pragma OPENCL EXTENSION cl_khr_global_int32_base_atomics : enable -double2 world2cam(double f_x, double f_y, double c_x, double c_y, double s_, double x, double y, double z) +double2 world2cam(double3 feature) { - double r = sqrt(pow(x/z, 2) + pow(y/z, 2)); + double r = sqrt(pow(feature.x/feature.z, 2) + pow(feature.y/feature.z, 2)); double factor = 1.0; - if(s_ != 0 || r > 0.001) - factor = (atan(r * 2.0 * tan(0.5 * s_)) / (r * s_)); - return (double2)(c_x + f_x * factor * x/z, c_y + f_y * factor * y/z); + if(S != 0 || r > 0.001) + factor = (atan(r * 2.0 * tan(0.5 * S)) / (r * S)); + return (double2)(C_X + F_X * factor * feature.x/feature.z, C_Y + F_Y * factor * feature.y/feature.z); } -double3 xyz_cur(double cur_x, double cur_z, double cur_pitch, double ref_x, double ref_z, double ref_pitch, double3 ref_feature) +double3 xyz_cur(double3 cur, double3 ref, double3 ref_feature) { - if(ref_pitch < 0.0) - ref_pitch = 3.141592653589793238462643383279502884197169399375 - ref_pitch; + if(ref.z < 0.0) + ref.z = 3.141592653589793238462643383279502884197169399375 - ref.z; else - ref_pitch = ref_pitch - 3.1415926535897932384626433832795028841971693993; - double cc_ss = cos(cur_pitch) * cos(ref_pitch) - sin(cur_pitch) * sin(ref_pitch); - double sc_cs = cos(cur_pitch) * sin(ref_pitch) + cos(ref_pitch) * sin(cur_pitch); - return (double3)(cc_ss * ref_feature.x + sc_cs * ref_feature.z + cur_x - ref_x * cos(cur_pitch) - ref_z * sin(cur_pitch), + ref.z = ref.z - 3.1415926535897932384626433832795028841971693993; + double cc_ss = cos(cur.z) * cos(ref.z) - sin(cur.z) * sin(ref.z); + double sc_cs = cos(cur.z) * sin(ref.z) + cos(ref.z) * sin(cur.z); + return (double3)(cc_ss * ref_feature.x + sc_cs * ref_feature.z + cur.x - ref.x * cos(cur.z) - ref.z * sin(cur.z), ref_feature.y, - -1.0 * sc_cs * ref_feature.x + cc_ss * ref_feature.z + cur_z + ref_x * sin(cur_pitch) - ref_z * cos(cur_pitch)); -} - -double3 xyz_ref(double fts_pos_x, double fts_pos_y, double fts_pos_z, double ref_x, double ref_y, double ref_z) -{ - return (double3)(sqrt(pow((fts_pos_x - ref_x), 2)), - sqrt(pow((fts_pos_y - ref_y), 2)), - sqrt(pow((fts_pos_z - ref_z), 2))); + -1.0 * sc_cs * ref_feature.x + cc_ss * ref_feature.z + cur.z + ref.x * sin(cur.z) - ref.z * cos(cur.z)); } void jacobian_xyz2uv(double3 xyz_in_f, double* J) { *(J + 0) = -(1. / xyz_in_f[2]); // -1/z *(J + 1) = (xyz_in_f[0]) * ((1. / xyz_in_f[2]) * (1. / xyz_in_f[2])); // x/z^2 - *(J + 2) = -(1.0 + pow((xyz_in_f[0]),2) * ((1. / xyz_in_f[2]) * (1. / xyz_in_f[2]))); // -(1.0 + x^2/z^2) + *(J + 2) = -(1.0 + pow((xyz_in_f[0]),2) / ((1. / xyz_in_f[2]) * (1. / xyz_in_f[2]))); // -(1.0 + x^2/z^2) *(J + 3) = 1e-19; // 0 *(J + 4) = (xyz_in_f[1]) * ((1. / xyz_in_f[2]) * (1. / xyz_in_f[2])); // y/z^2 *(J + 5) = -(xyz_in_f[0]) * (xyz_in_f[1]) / ((1. / xyz_in_f[2]) * (1. / xyz_in_f[2])); // -x*y/z^2 } - void compute_hessain(double3 j, __global double* H, double w) { *(H + 0) += j[0] * j[0] * w; @@ -56,151 +48,106 @@ void compute_hessain(double3 j, __global double* H, double w) *(H + 8) += j[2] * j[2] * w; } -void compute_Jacobian(double3 j, __global double* Jacobian, double r, double w) -{ - *(Jacobian + 0) -= j[0] * r * w; - *(Jacobian + 1) -= j[1] * r * w; - *(Jacobian + 2) -= j[2] * r * w; -} - __kernel void compute_residual( __read_only image2d_t image_cur, // current frame __read_only image2d_t image_ref, // reference frame - __global double * cur_pose,//[reference frame pose{x,z,pitch}] - __global double * ref_pose,//[current frame pose{x,z,pitch}] + __global double3 * cur_pose,//[reference frame pose{x,z,pitch}] + __global double3 * ref_pose,//[current frame pose{x,z,pitch}] __global double3 * ref_feature, // feature on the reference frame, when we applied the distance calculation: xyz_ref((*it)->f*((*it)->point->pos_ - Eigen::Vector3d(ref_pos[0],0.0,ref_pos[1])).norm()); __global double2 * featue_px, - __global int * level, - __global double * camera_model, // camera model [f_x,f_y,c_x,c_y,s_] + int level, __global float * errors, __global double * Hessian, - __global double * Jacobian, - __global double * chi + __global double3 * Jacobian, + __global double * chi, + double scale_ ) { - const int PATCH_AREA_ = PATCH_SIZE * PATCH_SIZE; - int border = PATCH_HALFSIZE + 1; - int stride = get_image_dim(image_cur)[0]; //width, height - double scale = pow(2.0, -level[0]); - size_t n_meas_ = 0; + double scale = pow(2.0, -level); // Prepare a suitable OpenCL image sampler. sampler_t const sampler = CLK_ADDRESS_CLAMP | CLK_FILTER_NEAREST; - // Use global work feature. int f = get_global_id(0); - // check if reference with patch size is within image - double u_ref = featue_px[f].x * scale; - double v_ref = featue_px[f].y * scale; - int u_ref_i = floor(u_ref); - int v_ref_i = floor(v_ref); - if(u_ref_i - (PATCH_HALFSIZE + 1) < 0 || v_ref_i - (PATCH_HALFSIZE + 1) < 0 || - u_ref_i + (PATCH_HALFSIZE + 1) >= get_image_dim(image_ref)[0] || v_ref_i + (PATCH_HALFSIZE + 1) >= get_image_dim(image_ref)[1]) - return; - - double3 xyz_reference = xyz_ref(ref_feature[f][0], ref_feature[f][1], ref_feature[f][2], ref_pose[0], ref_pose[1], ref_pose[2]); - + double2 uv_ref = featue_px[f] * scale; + double2 uv_ref_i = floor(uv_ref); + if(uv_ref_i.x - (PATCH_HALFSIZE + 1) < 0 || uv_ref_i.y - (PATCH_HALFSIZE + 1) < 0 || uv_ref_i.x + (PATCH_HALFSIZE + 1) >= get_image_dim(image_ref)[0] || uv_ref_i.y + (PATCH_HALFSIZE + 1) >= get_image_dim(image_ref)[1])return; // evaluate projection jacobian - double frame_jac[6]; // 2X3 - jacobian_xyz2uv(xyz_reference, &frame_jac); + double frame_jac[6]={0.0}; // 2X3 + jacobian_xyz2uv(sqrt(pow(ref_feature[f] - ref_pose[0], 2.0)), &frame_jac); // compute bilateral interpolation weights for reference image - double subpix_u_ref = u_ref - u_ref_i; - double subpix_v_ref = v_ref - v_ref_i; - double w_ref_tl = (1.0 - subpix_u_ref) * (1.0 - subpix_v_ref); - double w_ref_tr = subpix_u_ref * (1.0 - subpix_v_ref); - double w_ref_bl = (1.0 - subpix_u_ref) * subpix_v_ref; - double w_ref_br = subpix_u_ref * subpix_v_ref; - size_t pixel_counter = 0; - - double3 xyz_current = xyz_cur(cur_pose[0], cur_pose[1], cur_pose[2], ref_pose[0] ,ref_pose[1] ,ref_pose[2], ref_feature[f]); - double2 uv_cur_pyr = world2cam(camera_model[0], camera_model[1], camera_model[2], camera_model[3], camera_model[4], - xyz_current[0], xyz_current[1], xyz_current[2]) * scale; - double u_cur = uv_cur_pyr[0]; - double v_cur = uv_cur_pyr[1]; - int u_cur_i = floor(u_cur); - int v_cur_i = floor(v_cur); - - // check if projection is within the image - if(u_cur_i < 0 || v_cur_i < 0 || u_cur_i - (PATCH_HALFSIZE + 1) < 0 || v_cur_i - (PATCH_HALFSIZE + 1) < 0 || - u_cur_i + (PATCH_HALFSIZE + 1) >= get_image_dim(image_cur)[0] || v_cur_i + (PATCH_HALFSIZE + 1) >= get_image_dim(image_cur)[1]) - return; + double2 subpix= uv_ref - uv_ref_i; + double w_ref_tl = (1.0 - subpix.x) * (1.0 - subpix.y); + double w_ref_tr = subpix.x * (1.0 - subpix.y); + double w_ref_bl = (1.0 - subpix.x) * subpix.y; + double w_ref_br = subpix.x * subpix.y; // compute bilateral interpolation weights for the current image - double subpix_u_cur = u_cur - u_cur_i; - double subpix_v_cur = v_cur - v_cur_i; - double w_cur_tl = (1.0 - subpix_u_cur) * (1.0 - subpix_v_cur); - double w_cur_tr = subpix_u_cur * (1.0 - subpix_v_cur); - double w_cur_bl = (1.0 - subpix_u_cur) * subpix_v_cur; - double w_cur_br = subpix_u_cur * subpix_v_cur; - + double2 uv_cur_pyr = world2cam(xyz_cur(cur_pose[0], ref_pose[0] ,ref_feature[f])) * scale; + double2 uv_cur_i = floor(uv_cur_pyr); + double2 subpix_uv_cur = uv_cur_pyr - uv_cur_i; + double w_cur_tl = (1.0 - subpix_uv_cur.x) * (1.0 - subpix_uv_cur.y); + double w_cur_tr = subpix_uv_cur.x * (1.0 - subpix_uv_cur.y); + double w_cur_bl = (1.0 - subpix_uv_cur.x) * subpix_uv_cur.y; + double w_cur_br = subpix_uv_cur.x * subpix_uv_cur.y; + float e = 0.0; + double chi_=0.0; for(int y = 0; y < PATCH_SIZE; ++y) { - int ref_element_addr = (v_ref_i + y - PATCH_HALFSIZE) * get_image_dim(image_ref)[0] + (u_ref_i - PATCH_HALFSIZE); - int cur_element_addr = (v_cur_i + y - PATCH_HALFSIZE) * get_image_dim(image_cur)[0] + (u_cur_i - PATCH_HALFSIZE); + int ref_element_addr = (int)(uv_ref_i.y + y - PATCH_HALFSIZE) * get_image_dim(image_ref)[0] + (uv_ref_i.x - PATCH_HALFSIZE); + int cur_element_addr = (int)(uv_cur_i.y + y - PATCH_HALFSIZE) * get_image_dim(image_cur)[0] + (uv_cur_i.x - PATCH_HALFSIZE); - for(int x = 0; x < PATCH_SIZE; ++x, ++pixel_counter, ++ref_element_addr, ++cur_element_addr) + for(int x = 0; x < PATCH_SIZE; ++x, ++ref_element_addr, ++cur_element_addr) { - // precompute interpolated reference patch color - int2 px_reftl = (int2)( ref_element_addr % get_image_dim(image_ref)[0], ref_element_addr / get_image_dim(image_ref)[0]); - int2 px_reftr = (int2)((ref_element_addr + 1) % get_image_dim(image_ref)[0], (ref_element_addr + 1) / get_image_dim(image_ref)[0]); - int2 px_refbl = (int2)((ref_element_addr + get_image_dim(image_ref)[0]) % get_image_dim(image_ref)[0], (ref_element_addr + get_image_dim(image_ref)[0]) / get_image_dim(image_ref)[0]); - int2 px_refbr = (int2)((ref_element_addr + get_image_dim(image_ref)[0] + 1) % get_image_dim(image_ref)[0], (ref_element_addr + get_image_dim(image_ref)[0] + 1) / get_image_dim(image_ref)[0]); - double value = w_ref_tl * read_imageui(image_ref, sampler, px_reftl).x + w_ref_tr * read_imageui(image_ref, sampler, px_reftr).x + - w_ref_bl * read_imageui(image_ref, sampler, px_refbl).x + w_ref_br * read_imageui(image_ref, sampler, px_refbr).x; + // precompute interpolated reference patch color + int2 px_reftl = (int2)( ref_element_addr % get_image_dim(image_ref)[0], ref_element_addr / get_image_dim(image_ref)[0]); + int2 px_reftr = (int2)((ref_element_addr + 1) % get_image_dim(image_ref)[0], (ref_element_addr + 1) / get_image_dim(image_ref)[0]); + int2 px_refbl = (int2)((ref_element_addr + get_image_dim(image_ref)[0]) % get_image_dim(image_ref)[0], (ref_element_addr + get_image_dim(image_ref)[0]) / get_image_dim(image_ref)[0]); + int2 px_refbr = (int2)((ref_element_addr + get_image_dim(image_ref)[0] + 1) % get_image_dim(image_ref)[0], (ref_element_addr + get_image_dim(image_ref)[0] + 1) / get_image_dim(image_ref)[0]); + double value = w_ref_tl * read_imageui(image_ref, sampler, px_reftl).x + w_ref_tr * read_imageui(image_ref, sampler, px_reftr).x + + w_ref_bl * read_imageui(image_ref, sampler, px_refbl).x + w_ref_br * read_imageui(image_ref, sampler, px_refbr).x; - double dx = 0.5f * ((w_ref_tl * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + 1) % get_image_dim(image_ref)[0], ((ref_element_addr + 1) / get_image_dim(image_ref)[0]))).x + - w_ref_tr * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + 2) % get_image_dim(image_ref)[0], ((ref_element_addr + 2) / get_image_dim(image_ref)[0]))).x + - w_ref_bl * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + (get_image_dim(image_ref)[0]) + 1) % get_image_dim(image_ref)[0], ((ref_element_addr + (get_image_dim(image_ref)[0]) + 1) / get_image_dim(image_ref)[0]))).x + - w_ref_br * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + (get_image_dim(image_ref)[0]) + 2) % get_image_dim(image_ref)[0], ((ref_element_addr + (get_image_dim(image_ref)[0]) + 2) / get_image_dim(image_ref)[0]))).x) - -(w_ref_tl * read_imageui(image_ref, sampler, (int2) ((ref_element_addr - 1) % get_image_dim(image_ref)[0], ((ref_element_addr - 1) / get_image_dim(image_ref)[0]))).x + - w_ref_tr * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + 0) % get_image_dim(image_ref)[0], ((ref_element_addr + 0) / get_image_dim(image_ref)[0]))).x + - w_ref_bl * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + (get_image_dim(image_ref)[0]) - 1) % get_image_dim(image_ref)[0], ((ref_element_addr + (get_image_dim(image_ref)[0]) - 1) / get_image_dim(image_ref)[0]))).x + - w_ref_br * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + (get_image_dim(image_ref)[0])) % get_image_dim(image_ref)[0], ((ref_element_addr + (get_image_dim(image_ref)[0])) / get_image_dim(image_ref)[0]))).x)); + double dx = 0.5f * ((w_ref_tl * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + 1) % get_image_dim(image_ref)[0], ((ref_element_addr + 1) / get_image_dim(image_ref)[0]))).x + + w_ref_tr * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + 2) % get_image_dim(image_ref)[0], ((ref_element_addr + 2) / get_image_dim(image_ref)[0]))).x + + w_ref_bl * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + (get_image_dim(image_ref)[0]) + 1) % get_image_dim(image_ref)[0], ((ref_element_addr + (get_image_dim(image_ref)[0]) + 1) / get_image_dim(image_ref)[0]))).x + + w_ref_br * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + (get_image_dim(image_ref)[0]) + 2) % get_image_dim(image_ref)[0], ((ref_element_addr + (get_image_dim(image_ref)[0]) + 2) / get_image_dim(image_ref)[0]))).x) + -(w_ref_tl * read_imageui(image_ref, sampler, (int2) ((ref_element_addr - 1) % get_image_dim(image_ref)[0], ((ref_element_addr - 1) / get_image_dim(image_ref)[0]))).x + + w_ref_tr * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + 0) % get_image_dim(image_ref)[0], ((ref_element_addr + 0) / get_image_dim(image_ref)[0]))).x + + w_ref_bl * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + (get_image_dim(image_ref)[0]) - 1) % get_image_dim(image_ref)[0], ((ref_element_addr + (get_image_dim(image_ref)[0]) - 1) / get_image_dim(image_ref)[0]))).x + + w_ref_br * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + (get_image_dim(image_ref)[0])) % get_image_dim(image_ref)[0], ((ref_element_addr + (get_image_dim(image_ref)[0])) / get_image_dim(image_ref)[0]))).x)); - double dy = 0.5f * ((w_ref_tl * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + (get_image_dim(image_ref)[0])) % get_image_dim(image_ref)[0], ((ref_element_addr + (get_image_dim(image_ref)[0])) / get_image_dim(image_ref)[0]))).x + - w_ref_tr * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + (get_image_dim(image_ref)[0]) + 1) % get_image_dim(image_ref)[0], ((ref_element_addr + (get_image_dim(image_ref)[0]) + 1) / get_image_dim(image_ref)[0]))).x + - w_ref_bl * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + (get_image_dim(image_ref)[0]) * 2) % get_image_dim(image_ref)[0], ((ref_element_addr + (get_image_dim(image_ref)[0]) * 2) / get_image_dim(image_ref)[0]))).x + - w_ref_br * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + (get_image_dim(image_ref)[0]) * 2 + 1) % get_image_dim(image_ref)[0], ((ref_element_addr + (get_image_dim(image_ref)[0]) * 2 + 1) / get_image_dim(image_ref)[0]))).x) - -(w_ref_tl * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + (-get_image_dim(image_ref)[0])) % get_image_dim(image_ref)[0], ((ref_element_addr + (-get_image_dim(image_ref)[0])) / get_image_dim(image_ref)[0]))).x + - w_ref_tr * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + (1 - get_image_dim(image_ref)[0])) % get_image_dim(image_ref)[0], ((ref_element_addr + (1 - get_image_dim(image_ref)[0])) / get_image_dim(image_ref)[0]))).x + - w_ref_bl * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + 0) % get_image_dim(image_ref)[0], ((ref_element_addr + 0) / get_image_dim(image_ref)[0]))).x + - w_ref_br * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + 1) % get_image_dim(image_ref)[0], ((ref_element_addr + 1) / get_image_dim(image_ref)[0]))).x)); + double dy = 0.5f * ((w_ref_tl * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + (get_image_dim(image_ref)[0])) % get_image_dim(image_ref)[0], ((ref_element_addr + (get_image_dim(image_ref)[0])) / get_image_dim(image_ref)[0]))).x + + w_ref_tr * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + (get_image_dim(image_ref)[0]) + 1) % get_image_dim(image_ref)[0], ((ref_element_addr + (get_image_dim(image_ref)[0]) + 1) / get_image_dim(image_ref)[0]))).x + + w_ref_bl * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + (get_image_dim(image_ref)[0]) * 2) % get_image_dim(image_ref)[0], ((ref_element_addr + (get_image_dim(image_ref)[0]) * 2) / get_image_dim(image_ref)[0]))).x + + w_ref_br * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + (get_image_dim(image_ref)[0]) * 2 + 1) % get_image_dim(image_ref)[0], ((ref_element_addr + (get_image_dim(image_ref)[0]) * 2 + 1) / get_image_dim(image_ref)[0]))).x) + -(w_ref_tl * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + (-get_image_dim(image_ref)[0])) % get_image_dim(image_ref)[0], ((ref_element_addr + (-get_image_dim(image_ref)[0])) / get_image_dim(image_ref)[0]))).x + + w_ref_tr * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + (1 - get_image_dim(image_ref)[0])) % get_image_dim(image_ref)[0], ((ref_element_addr + (1 - get_image_dim(image_ref)[0])) / get_image_dim(image_ref)[0]))).x + + w_ref_bl * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + 0) % get_image_dim(image_ref)[0], ((ref_element_addr + 0) / get_image_dim(image_ref)[0]))).x + + w_ref_br * read_imageui(image_ref, sampler, (int2) ((ref_element_addr + 1) % get_image_dim(image_ref)[0], ((ref_element_addr + 1) / get_image_dim(image_ref)[0]))).x)); - // compute residual - int2 px_curtl = ( cur_element_addr % get_image_dim(image_cur)[0], cur_element_addr / get_image_dim(image_cur)[0]); - int2 px_curtr = ((cur_element_addr + 1) % get_image_dim(image_cur)[0], (cur_element_addr + 1) / get_image_dim(image_cur)[0]); - int2 px_curbl = ((cur_element_addr + (get_image_dim(image_cur)[0])) % get_image_dim(image_cur)[0], (cur_element_addr + (get_image_dim(image_cur)[0])) / get_image_dim(image_cur)[0]); - int2 px_curbr = ((cur_element_addr + (get_image_dim(image_cur)[0]) + 1) % get_image_dim(image_cur)[0], (cur_element_addr + (get_image_dim(image_cur)[0]) + 1) / get_image_dim(image_cur)[0]); - double intensity_cur = w_cur_tl * read_imageui(image_cur, sampler, px_curtl).x + w_cur_tr * read_imageui(image_cur, sampler, px_curtr).x + - w_cur_bl * read_imageui(image_cur, sampler, px_curbl).x + w_cur_br * read_imageui(image_cur, sampler, px_curbr).x; + // compute residual + int2 px_curtl = (int2)( cur_element_addr % get_image_dim(image_cur)[0], cur_element_addr / get_image_dim(image_cur)[0]); + int2 px_curtr = (int2)((cur_element_addr + 1) % get_image_dim(image_cur)[0], (cur_element_addr + 1) / get_image_dim(image_cur)[0]); + int2 px_curbl = (int2)((cur_element_addr + (get_image_dim(image_cur)[0])) % get_image_dim(image_cur)[0], (cur_element_addr + (get_image_dim(image_cur)[0])) / get_image_dim(image_cur)[0]); + int2 px_curbr = (int2)((cur_element_addr + (get_image_dim(image_cur)[0]) + 1) % get_image_dim(image_cur)[0], (cur_element_addr + (get_image_dim(image_cur)[0]) + 1) / get_image_dim(image_cur)[0]); - double res = intensity_cur - value; + double res = value - w_cur_tl * read_imageui(image_cur, sampler, px_curtl).x + w_cur_tr * read_imageui(image_cur, sampler, px_curtr).x + + w_cur_bl * read_imageui(image_cur, sampler, px_curbl).x + w_cur_br * read_imageui(image_cur, sampler, px_curbr).x; + // used to compute scale for robust cost + e += fabs(res); + // robustification + double weight = res/scale_; //1.48f * vk::getMedian(errors) + chi_ += pow(res,2) * weight; + double3 j_row0 = (double3)((dx * frame_jac[0]), (dx * frame_jac[1]), (dx * frame_jac[2])); + double3 j_row1 = (double3)((dy * frame_jac[3]), (dy * frame_jac[4]), (dy * frame_jac[5])); + double3 J = (j_row0 + j_row1) * (F_X / scale); + compute_hessain(J, &Hessian[f*9], weight); + Jacobian[f] -= J * res * weight; - // used to compute scale for robust cost - // if(compute_weight_scale) - errors[(int)(f * pow((double)PATCH_SIZE, 2.0) + (y * PATCH_SIZE) + x)] = fabs(res); - - // robustification - double weight = 2.0; - // if(use_weights_) { // use_weights_ dafault value is false - // weight = weight_function_->value(res/scale_); - // } - - chi[0] += res * res * weight; - n_meas_++; - - // if(linearize_system) - // { - // compute Jacobian, weighted Hessian and weighted "steepest descend images" (times error) - double3 j_row0 = (double3)((dx * frame_jac[0]), (dx * frame_jac[1]), (dx * frame_jac[2])); - double3 j_row1 = (double3)((dy * frame_jac[3]), (dy * frame_jac[4]), (dy * frame_jac[5])); - double3 J = ((j_row0 + j_row1) * (camera_model[0] / scale)); - compute_hessain(J, Hessian, weight); // H_.noalias() += J * J.transpose() * weight; - compute_Jacobian(J, Jacobian, res, weight); // Jres_.noalias() -= J * res * weight; - // } } } - chi[0] = chi[0] / n_meas_; + errors[f] = e / pow(PATCH_SIZE,2.0); + chi[f]=chi_; } diff --git a/GPU_version/vio/src/cl_class.cpp b/GPU_version/vio/src/cl_class.cpp index 033ac11..c47c8be 100644 --- a/GPU_version/vio/src/cl_class.cpp +++ b/GPU_version/vio/src/cl_class.cpp @@ -1,7 +1,7 @@ // // Created by root on 4/27/21. // -#include "vio/cl_class.h" +#include opencl::opencl() { std::vector all_platforms; cl::Platform::get(&all_platforms); @@ -20,31 +20,33 @@ opencl::opencl() { std::cout << " No devices found. Check OpenCL installation!\n"; exit(1); } - device = all_devices[0]; - std::cout << "CL_DEVICE_NAME: " << device.getInfo() <<'\n' - << "CL_DEVICE_OPENCL_C_VERSION: " <()<<'\n' - << "CL_DEVICE_BUILT_IN_KERNELS: " <()<<'\n' - << "CL_DEVICE_COMPILER_AVAILABLE: " <()<<'\n' - << "CL_DEVICE_LOCAL_MEM_SIZE: " <()<<'\n' - << "CL_DEVICE_GLOBAL_MEM_SIZE: " <()<<'\n'; + device = new cl::Device(all_devices[0]); + std::cout << "CL_DEVICE_NAME: " << device->getInfo() <<'\n' + << "CL_DEVICE_OPENCL_C_VERSION: " <getInfo()<<'\n' + << "CL_DEVICE_BUILT_IN_KERNELS: " <getInfo()<<'\n' + << "CL_DEVICE_COMPILER_AVAILABLE: " <getInfo()<<'\n' + << "CL_DEVICE_LOCAL_MEM_SIZE: " <getInfo()<<'\n' + << "CL_DEVICE_GLOBAL_MEM_SIZE: " <getInfo()<<'\n'; - context=new cl::Context({ device }); + context=new cl::Context({ *device }); cl::Program::Sources sources; read_cl fast(std::string(KERNEL_DIR)+"/fast-gray.cl"); sources.push_back({ fast.src_str, fast.size }); read_cl compute_residual(std::string(KERNEL_DIR)+"/compute-residual.cl"); sources.push_back({ compute_residual.src_str, compute_residual.size }); program=new cl::Program(*context, sources); - if(program->build({ device },"-DFAST_THRESH=40 -DPATCH_SIZE=4 -DPATCH_HALFSIZE=2") !=0) - std::cout << " Error building: " << program->getBuildInfo(device)<<'\n' - <getBuildInfo(device) << '\n'; - queue=new cl::CommandQueue(*context,device,0,NULL); + if(program->build({ *device },"-DFAST_THRESH=40 -DPATCH_SIZE=2 -DPATCH_HALFSIZE=1 -DF_X=296.724480 -DF_Y=395.357280 -DC_X=317.877600 -DC_Y=238.752640 -DS=1.016870") !=0) + std::cout << " Error building: " << program->getBuildInfo(*device)<<'\n' + <getBuildInfo(*device) << '\n'; + queue=new cl::CommandQueue(*context,*device,CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE,NULL); } opencl::~opencl() { + delete context; + delete device; } void opencl::clear_buf() { queue->finish(); - queue->flush(); _kernels.clear(); + delete program; } diff --git a/GPU_version/vio/src/frame_handler_mono.cpp b/GPU_version/vio/src/frame_handler_mono.cpp index f59dd72..0b4950a 100644 --- a/GPU_version/vio/src/frame_handler_mono.cpp +++ b/GPU_version/vio/src/frame_handler_mono.cpp @@ -24,6 +24,7 @@ #include #include #include +#include namespace vio { @@ -47,25 +48,21 @@ FrameHandlerMono::FrameHandlerMono(vk::AbstractCamera* cam,Eigen::Matrixmake_kernel("compute_residual"); gpu_fast_->write_buf(1,0,img); gpu_fast_->write_buf(1,1,img); - double pose[3]={0}; + cl_double3 pose[1]={0.0}; gpu_fast_->write_buf(1,2,3,pose); gpu_fast_->write_buf(1,3,3,pose); cl_double3 f[300]={0}; gpu_fast_->write_buf(1,4,300,f); cl_double2 px[300]={0}; gpu_fast_->write_buf(1,5,300,px); - int level[1]={0}; - gpu_fast_->write_buf(1,6,1,level); - double c[5]={0}; - gpu_fast_->write_buf(1,7,5,c); double e[300]={0}; - gpu_fast_->write_buf(1,8,300,e); - double H[9]={0}; - gpu_fast_->write_buf(1,9,9,H); - double J[3]={0}; - gpu_fast_->write_buf(1,10,3,J); - double chi2[1]={0.0}; - gpu_fast_->write_buf(1,11,1,chi2); + gpu_fast_->write_buf(1,7,300,e); + double H[9*300]={0}; + gpu_fast_->write_buf(1,8,9*300,H); + cl_double3 J[300]; + gpu_fast_->write_buf(1,9,300,J); + double chi2[1]={0.01}; + gpu_fast_->write_buf(1,10,1,chi2); klt_homography_init_=new initialization::KltHomographyInit(gpu_fast_); initialize(); } @@ -162,10 +159,15 @@ FrameHandlerBase::UpdateResult FrameHandlerMono::processFrame() new_frame_->T_f_w_=init_f.second; new_frame_->Cov_ = init_f.first; // sparse image align - //SparseImgAlign img_align(Config::kltMaxLevel(), Config::kltMinLevel(),30, SparseImgAlign::LevenbergMarquardt, false, true); - SparseImgAlignGpu img_align(Config::kltMaxLevel(), Config::kltMinLevel(),30, SparseImgAlign::GaussNewton, false,gpu_fast_); + //SparseImgAlign img_align(Config::kltMaxLevel(), Config::kltMinLevel(),30, SparseImgAlign::LevenbergMarquardt, false, false); + SparseImgAlignGpu img_align(Config::kltMaxLevel(), Config::kltMinLevel(),30, SparseImgAlignGpu::GaussNewton, false,gpu_fast_); if(img_align.run(last_frame_, new_frame_)==0)return RESULT_FAILURE; + //assert (false); reprojector_.reprojectMap(new_frame_, overlap_kfs_); + std::cout<<"Reprojection Map nPoint: "<T_f_w_.se2().translation()-new_frame_->T_f_w_.se2().translation()).norm()<<'\n'; size_t sfba_n_edges_final=0; double sfba_thresh, sfba_error_init, sfba_error_final; pose_optimizer::optimizeGaussNewton( diff --git a/GPU_version/vio/src/sparse_img_align.cpp b/GPU_version/vio/src/sparse_img_align.cpp index e4aa55b..128be16 100644 --- a/GPU_version/vio/src/sparse_img_align.cpp +++ b/GPU_version/vio/src/sparse_img_align.cpp @@ -37,7 +37,7 @@ SparseImgAlign::SparseImgAlign( n_iter_init_ = n_iter_; method_ = method; verbose_ = verbose; - eps_ = 0.0001; + eps_ = 1e-5; } size_t SparseImgAlign::run(FramePtr ref_frame, FramePtr cur_frame) diff --git a/GPU_version/vio/src/sparse_img_align_gpu.cpp b/GPU_version/vio/src/sparse_img_align_gpu.cpp index 617c690..431e041 100644 --- a/GPU_version/vio/src/sparse_img_align_gpu.cpp +++ b/GPU_version/vio/src/sparse_img_align_gpu.cpp @@ -29,7 +29,8 @@ SparseImgAlignGpu::SparseImgAlignGpu( n_iter_init_ = n_iter_; method_ = method; verbose_ = verbose; - eps_ = 0.0001; + eps_ = 1e-10; +// data = fopen((std::string(getenv("HOME"))+"/Project/data.txt").c_str(), "w+"); } size_t SparseImgAlignGpu::run(FramePtr ref_frame, FramePtr cur_frame) @@ -39,24 +40,26 @@ size_t SparseImgAlignGpu::run(FramePtr ref_frame, FramePtr cur_frame) { return 0; } - double* camera=ref_frame->cam_->params(); - double ref_pos[3]={ref_frame->pos()(0),ref_frame->pos()(1),ref_frame->T_f_w_.pitch()}; - double cur_pos[3]={cur_frame->pos()(0),cur_frame->pos()(1),cur_frame->T_f_w_.pitch()}; + cl_double3 ref_pos[1]={ref_frame->pos()(0),ref_frame->pos()(1),ref_frame->T_f_w_.pitch()}; + cl_double3 cur_pos[1]={cur_frame->pos()(0),cur_frame->pos()(1),cur_frame->T_f_w_.pitch()}; residual_->reload_buf(1,2,cur_pos); residual_->reload_buf(1,3,ref_pos); - residual_->reload_buf(1,7,camera); cl_double3 features[ref_frame->fts_.size()]; cl_double2 featue_px[ref_frame->fts_.size()]; + // fprintf(data, "ref_frame:\n %f,%f,%f\n",ref_pos[0],ref_pos[1],ref_pos[2]); + // fprintf(data, "cur_frame:\n %f,%f,%f\n",cur_pos[0],cur_pos[1],cur_pos[2]); + // fprintf(data, "camera:\n %f,%f,%f,%f,%f\n features:\n",camera[0],camera[1],camera[2],camera[3],camera[4]); feature_counter_ = 0; // is used to compute the index of the cached jacobian for(auto it=ref_frame->fts_.begin(); it!=ref_frame->fts_.end();++it){ if(*it == nullptr)continue; if((*it)->point == nullptr)continue; - Vector3d xyz_ref=(*it)->f*((*it)->point->pos_ - Eigen::Vector3d(ref_pos[0],0.0,ref_pos[1])).norm(); + Vector3d xyz_ref=(*it)->f*((*it)->point->pos_ - Eigen::Vector3d(ref_pos[0].x,0.0,ref_pos[0].y)).norm(); features[feature_counter_].x=xyz_ref(0); features[feature_counter_].y=xyz_ref(1); features[feature_counter_].z=xyz_ref(2); featue_px[feature_counter_].x=(*it)->px(0); featue_px[feature_counter_].y=(*it)->px(1); + // fprintf(data, "%f,%f,%f,%f,%f\n",xyz_ref(0),xyz_ref(1),xyz_ref(2),(*it)->px(0),(*it)->px(1)); ++feature_counter_; } residual_->reload_buf(1,4,features); @@ -66,16 +69,17 @@ size_t SparseImgAlignGpu::run(FramePtr ref_frame, FramePtr cur_frame) { cv::Mat cur_img = cur_frame->img_pyr_.at(level_); cv::Mat ref_img = ref_frame->img_pyr_.at(level_); + // cv::imwrite(std::string(getenv("HOME"))+"/Project/cur"+to_string(level_)+".png",cur_img); + // cv::imwrite(std::string(getenv("HOME"))+"/Project/fer"+to_string(level_)+".png",ref_img); residual_->reload_buf(1,0,cur_img); residual_->reload_buf(1,1,ref_img); - residual_->reload_buf(1,6,&level_); + residual_->write_buf(1,6,level_); mu_ = 1.0; optimize(T_cur); } - double pos[3]={0}; - residual_->read(1,2,pos); - cur_frame->T_f_w_ = SE2_5(pos[0],pos[1],pos[2]); - + cl_double3 pos[1]={0}; + residual_->read(0,2,pos); + cur_frame->T_f_w_ = SE2_5(pos[0].x,pos[0].y,pos[0].z); return 1; } @@ -83,43 +87,62 @@ double SparseImgAlignGpu::computeResiduals( bool linearize_system, bool compute_weight_scale) { - double chi2[1]={0}; - residual_->reload_buf(1,11,chi2); - /// TODO GPU compute based on the feature - residual_->run(1,feature_counter_); - if(compute_weight_scale && iter_ == 0) { - float error[feature_counter_]; - residual_->read(1,8,error); - std::vector errors(error,error+feature_counter_); - scale_ = scale_estimator_->compute(errors); - } - - double out[1]={0.0}; - residual_->read(1,11,out); - return out[0]; + double H[9*300]={0}; + cl_double3 J[300]={0.0}; + double chi2_[300]={0.0}; + residual_->write_buf(1,11,scale_); + residual_->reload_buf(1,10,chi2_); + residual_->reload_buf(1,8,H); + residual_->reload_buf(1,9,J); + /// TODO GPU compute based on the feature + residual_->run(1,feature_counter_); + float error[300]={0.0}; + double chi[300]={0.0}; + residual_->read(1,10,feature_counter_,chi); + residual_->read(1,7,feature_counter_,error); + for(int i = 1; i < feature_counter_; ++i){ + error[0] += error[i]; + chi[0] += chi[i]; + } + scale_ = error[0]*(1.48f / feature_counter_); + return chi[0]/(feature_counter_*8); } int SparseImgAlignGpu::solve() { - double H[9]={0}; - double J[3]={0}; - residual_->read(1,9,H); - residual_->read(1,10,J); - x_ = Eigen::Matrix(H).ldlt().solve(Eigen::Matrix(J)); + double H[300*9]={0.0}; + cl_double3 J[300]={0.0}; + residual_->read(1,8,feature_counter_*9,H); + residual_->read(1,9,feature_counter_,J); + for(int i = 1; i < feature_counter_; ++i){ + H[0] += H[i*9]; + H[1] += H[i*9+1]; + H[2] += H[i*9+2]; + H[3] += H[i*9+3]; + H[4] += H[i*9+4]; + H[5] += H[i*9+5]; + H[6] += H[i*9+6]; + H[7] += H[i*9+7]; + H[8] += H[i*9+8]; + J[0].x -= J[i].x; + J[0].y -= J[i].y; + J[0].z -= J[i].z; + } + x_ = Eigen::Matrix(H).ldlt().solve(Eigen::Vector3d(J[0].x,J[0].y,J[0].z)); if((bool) std::isnan((double) x_[0])) - return 0; + return 0; return 1; } void SparseImgAlignGpu::update() { /// TODO the update situation may have a smarter solution - double pos[3]={0}; - residual_->read(1,2,pos); - SE2 update = SE2(pos[2],Eigen::Vector2d(pos[0],pos[1])) * SE2::exp(-0.5*x_); - pos[0]=update.translation()(0); - pos[1]=update.translation()(1); - pos[2]=atan(update.so2().unit_complex().imag()/update.so2().unit_complex().real()); - residual_->reload_buf(1,2,pos); + cl_double3 pos[1]={0.0,0.0,0.0}; + residual_->read(1,2,pos); + Sophus::SE2 update = Sophus::SE2(pos[0].z,Eigen::Vector2d(pos[0].x,pos[0].y)) * Sophus::SE2::exp(-0.5*x_); + pos[0].x=update.translation()(0); + pos[0].y=update.translation()(1); + pos[0].z=atan(update.so2().unit_complex().imag()/update.so2().unit_complex().real()); + residual_->reload_buf(1,2,pos); } void SparseImgAlignGpu::startIteration() From d0bac30af90a5a1c13bb1cfe1a76c82169a4eba2 Mon Sep 17 00:00:00 2001 From: gfuse Date: Wed, 11 Aug 2021 19:03:47 +0200 Subject: [PATCH 12/12] read camera parameters dynamicly --- GPU_version/vio/include/vio/cl_class.h | 4 +++- GPU_version/vio/src/cl_class.cpp | 11 ++++++++--- GPU_version/vio/src/frame_handler_mono.cpp | 2 +- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/GPU_version/vio/include/vio/cl_class.h b/GPU_version/vio/include/vio/cl_class.h index 99b6168..eb62562 100644 --- a/GPU_version/vio/include/vio/cl_class.h +++ b/GPU_version/vio/include/vio/cl_class.h @@ -12,6 +12,7 @@ #include #include #include +#include class kernel{ public: @@ -114,7 +115,7 @@ public: }; class opencl{ public: - opencl(); + opencl(vk::AbstractCamera* cam); ~opencl(); int32_t make_kernel(std::string name){_kernels.push_back(kernel(program,name));}; template @@ -195,6 +196,7 @@ private: cl::Device* device = nullptr; cl::Program* program = nullptr; cl::CommandQueue* queue= nullptr; + vk::AbstractCamera* cam= nullptr; }; #endif //VIO_OPENCL_CL_CLASS_H diff --git a/GPU_version/vio/src/cl_class.cpp b/GPU_version/vio/src/cl_class.cpp index c47c8be..46cb4bd 100644 --- a/GPU_version/vio/src/cl_class.cpp +++ b/GPU_version/vio/src/cl_class.cpp @@ -2,7 +2,7 @@ // Created by root on 4/27/21. // #include -opencl::opencl() { +opencl::opencl(vk::AbstractCamera* cam):cam(cam) { std::vector all_platforms; cl::Platform::get(&all_platforms); if (all_platforms.size() == 0){ @@ -27,7 +27,6 @@ opencl::opencl() { << "CL_DEVICE_COMPILER_AVAILABLE: " <getInfo()<<'\n' << "CL_DEVICE_LOCAL_MEM_SIZE: " <getInfo()<<'\n' << "CL_DEVICE_GLOBAL_MEM_SIZE: " <getInfo()<<'\n'; - context=new cl::Context({ *device }); cl::Program::Sources sources; read_cl fast(std::string(KERNEL_DIR)+"/fast-gray.cl"); @@ -35,7 +34,13 @@ opencl::opencl() { read_cl compute_residual(std::string(KERNEL_DIR)+"/compute-residual.cl"); sources.push_back({ compute_residual.src_str, compute_residual.size }); program=new cl::Program(*context, sources); - if(program->build({ *device },"-DFAST_THRESH=40 -DPATCH_SIZE=2 -DPATCH_HALFSIZE=1 -DF_X=296.724480 -DF_Y=395.357280 -DC_X=317.877600 -DC_Y=238.752640 -DS=1.016870") !=0) + double* camera=cam->params(); + std::string options="-DFAST_THRESH=40 -DPATCH_SIZE=2 -DPATCH_HALFSIZE=1 -DF_X="+ std::to_string(camera[0]) + + " -DF_Y="+std::to_string(camera[1])+ + " -DC_X="+std::to_string(camera[2])+ + " -DC_Y="+std::to_string(camera[3])+ + " -DS="+std::to_string(camera[4]); + if(program->build({ *device },options.c_str()) !=0) std::cout << " Error building: " << program->getBuildInfo(*device)<<'\n' <getBuildInfo(*device) << '\n'; queue=new cl::CommandQueue(*context,*device,CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE,NULL); diff --git a/GPU_version/vio/src/frame_handler_mono.cpp b/GPU_version/vio/src/frame_handler_mono.cpp index 0b4950a..84cb7b3 100644 --- a/GPU_version/vio/src/frame_handler_mono.cpp +++ b/GPU_version/vio/src/frame_handler_mono.cpp @@ -36,7 +36,7 @@ FrameHandlerMono::FrameHandlerMono(vk::AbstractCamera* cam,Eigen::Matrixmake_kernel("fast_gray"); cv::Mat img=cv::Mat(cv::Size(700, 500),CV_8UC1); gpu_fast_->write_buf(0,0,img);