From d85a660f064e8130b27e11c7fd762221c754c315 Mon Sep 17 00:00:00 2001
From: Willem Jan Palenstijn <Willem.Jan.Palenstijn@cwi.nl>
Date: Thu, 26 Jan 2017 14:57:57 +0100
Subject: Start work on CFloat32Data3DGPU to allow persistent/external GPU
 memory

---
 astra_vc14.vcxproj                               |   6 +
 astra_vc14.vcxproj.filters                       |  18 ++
 build/linux/Makefile.in                          |   5 +-
 build/msvc/gen.py                                |   7 +-
 cuda/3d/mem3d.cu                                 |  24 +++
 cuda/3d/mem3d.h                                  |   5 +-
 include/astra/CompositeGeometryManager.h         |  43 ++--
 include/astra/CudaBackProjectionAlgorithm3D.h    |   8 +-
 include/astra/CudaFDKAlgorithm3D.h               |   8 +-
 include/astra/CudaForwardProjectionAlgorithm3D.h |   8 +-
 include/astra/Float32Data3D.h                    |   2 +
 include/astra/Float32Data3DGPU.h                 | 108 ++++++++++
 include/astra/Float32ProjectionData3DGPU.h       |  92 ++++++++
 include/astra/Float32VolumeData3DGPU.h           |  92 ++++++++
 python/astra/PyIncludes.pxd                      |  48 +++--
 python/astra/data3d.py                           |   8 +-
 python/astra/data3d_c.pyx                        |  53 +++--
 python/astra/experimental.pyx                    |  24 ++-
 python/astra/pythonutils.py                      |  18 ++
 src/CompositeGeometryManager.cpp                 | 260 +++++++++++++++++++----
 src/CudaBackProjectionAlgorithm3D.cpp            |  20 +-
 src/CudaFDKAlgorithm3D.cpp                       |  12 +-
 src/CudaForwardProjectionAlgorithm3D.cpp         |   8 +-
 src/Float32Data3D.cpp                            |   6 +-
 src/Float32Data3DGPU.cpp                         |  98 +++++++++
 src/Float32Data3DMemory.cpp                      |   2 +-
 src/Float32ProjectionData3DGPU.cpp               |  71 +++++++
 src/Float32ProjectionData3DMemory.cpp            |   2 +-
 src/Float32VolumeData3DGPU.cpp                   |  71 +++++++
 src/Float32VolumeData3DMemory.cpp                |   2 +-
 30 files changed, 990 insertions(+), 139 deletions(-)
 create mode 100644 include/astra/Float32Data3DGPU.h
 create mode 100644 include/astra/Float32ProjectionData3DGPU.h
 create mode 100644 include/astra/Float32VolumeData3DGPU.h
 create mode 100644 src/Float32Data3DGPU.cpp
 create mode 100644 src/Float32ProjectionData3DGPU.cpp
 create mode 100644 src/Float32VolumeData3DGPU.cpp

diff --git a/astra_vc14.vcxproj b/astra_vc14.vcxproj
index a28bbfa..36d37ec 100644
--- a/astra_vc14.vcxproj
+++ b/astra_vc14.vcxproj
@@ -512,12 +512,15 @@
     <ClCompile Include="src\Float32Data.cpp" />
     <ClCompile Include="src\Float32Data2D.cpp" />
     <ClCompile Include="src\Float32Data3D.cpp" />
+    <ClCompile Include="src\Float32Data3DGPU.cpp" />
     <ClCompile Include="src\Float32Data3DMemory.cpp" />
     <ClCompile Include="src\Float32ProjectionData2D.cpp" />
     <ClCompile Include="src\Float32ProjectionData3D.cpp" />
+    <ClCompile Include="src\Float32ProjectionData3DGPU.cpp" />
     <ClCompile Include="src\Float32ProjectionData3DMemory.cpp" />
     <ClCompile Include="src\Float32VolumeData2D.cpp" />
     <ClCompile Include="src\Float32VolumeData3D.cpp" />
+    <ClCompile Include="src\Float32VolumeData3DGPU.cpp" />
     <ClCompile Include="src\Float32VolumeData3DMemory.cpp" />
     <ClCompile Include="src\ForwardProjectionAlgorithm.cpp" />
     <ClCompile Include="src\Fourier.cpp" />
@@ -624,12 +627,15 @@
     <ClInclude Include="include\astra\Float32Data.h" />
     <ClInclude Include="include\astra\Float32Data2D.h" />
     <ClInclude Include="include\astra\Float32Data3D.h" />
+    <ClInclude Include="include\astra\Float32Data3DGPU.h" />
     <ClInclude Include="include\astra\Float32Data3DMemory.h" />
     <ClInclude Include="include\astra\Float32ProjectionData2D.h" />
     <ClInclude Include="include\astra\Float32ProjectionData3D.h" />
+    <ClInclude Include="include\astra\Float32ProjectionData3DGPU.h" />
     <ClInclude Include="include\astra\Float32ProjectionData3DMemory.h" />
     <ClInclude Include="include\astra\Float32VolumeData2D.h" />
     <ClInclude Include="include\astra\Float32VolumeData3D.h" />
+    <ClInclude Include="include\astra\Float32VolumeData3DGPU.h" />
     <ClInclude Include="include\astra\Float32VolumeData3DMemory.h" />
     <ClInclude Include="include\astra\ForwardProjectionAlgorithm.h" />
     <ClInclude Include="include\astra\Fourier.h" />
diff --git a/astra_vc14.vcxproj.filters b/astra_vc14.vcxproj.filters
index dd7f574..591a4c7 100644
--- a/astra_vc14.vcxproj.filters
+++ b/astra_vc14.vcxproj.filters
@@ -321,6 +321,15 @@
     <ClCompile Include="src\CudaSirtAlgorithm3D.cpp">
       <Filter>CUDA\astra source</Filter>
     </ClCompile>
+    <ClCompile Include="src\Float32Data3DGPU.cpp">
+      <Filter>CUDA\astra source</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Float32ProjectionData3DGPU.cpp">
+      <Filter>CUDA\astra source</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Float32VolumeData3DGPU.cpp">
+      <Filter>CUDA\astra source</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="include\astra\Algorithm.h">
@@ -581,6 +590,15 @@
     <ClInclude Include="include\astra\CudaSirtAlgorithm3D.h">
       <Filter>CUDA\astra headers</Filter>
     </ClInclude>
+    <ClInclude Include="include\astra\Float32Data3DGPU.h">
+      <Filter>CUDA\astra headers</Filter>
+    </ClInclude>
+    <ClInclude Include="include\astra\Float32ProjectionData3DGPU.h">
+      <Filter>CUDA\astra headers</Filter>
+    </ClInclude>
+    <ClInclude Include="include\astra\Float32VolumeData3DGPU.h">
+      <Filter>CUDA\astra headers</Filter>
+    </ClInclude>
     <ClInclude Include="cuda\2d\algo.h">
       <Filter>CUDA\cuda headers</Filter>
     </ClInclude>
diff --git a/build/linux/Makefile.in b/build/linux/Makefile.in
index 371b656..9066f0a 100644
--- a/build/linux/Makefile.in
+++ b/build/linux/Makefile.in
@@ -199,7 +199,10 @@ CUDA_CXX_OBJECTS=\
 	src/CudaFDKAlgorithm3D.lo \
 	src/CudaSirtAlgorithm3D.lo \
 	src/CudaBackProjectionAlgorithm3D.lo \
-	src/CudaForwardProjectionAlgorithm3D.lo
+	src/CudaForwardProjectionAlgorithm3D.lo \
+	src/Float32Data3DGPU.lo \
+	src/Float32ProjectionData3DGPU.lo \
+	src/Float32VolumeData3DGPU.lo
 
 CUDA_OBJECTS=\
 	cuda/2d/algo.lo \
diff --git a/build/msvc/gen.py b/build/msvc/gen.py
index 8a40c45..9c14ffe 100644
--- a/build/msvc/gen.py
+++ b/build/msvc/gen.py
@@ -274,6 +274,9 @@ P_astra["filters"]["CUDA\\astra source"] = [
 "src\\CudaSartAlgorithm.cpp",
 "src\\CudaSirtAlgorithm.cpp",
 "src\\CudaSirtAlgorithm3D.cpp",
+"src\\Float32Data3DGPU.cpp",
+"src\\Float32ProjectionData3DGPU.cpp",
+"src\\Float32VolumeData3DGPU.cpp",
 ]
 P_astra["filters"]["CUDA\\cuda headers"] = [
 "4e17872e-db7d-41bc-9760-fad1c253b583",
@@ -411,7 +414,9 @@ P_astra["filters"]["CUDA\\astra headers"] = [
 "include\\astra\\CudaSartAlgorithm.h",
 "include\\astra\\CudaSirtAlgorithm.h",
 "include\\astra\\CudaSirtAlgorithm3D.h",
-
+"include\\astra\\Float32Data3DGPU.h",
+"include\\astra\\Float32ProjectionData3DGPU.h",
+"include\\astra\\Float32VolumeData3DGPU.h",
 ]
 P_astra["filters"]["Projectors\\inline"] = [
 "0daffd63-ba49-4a5f-8d7a-5322e0e74f22",
diff --git a/cuda/3d/mem3d.cu b/cuda/3d/mem3d.cu
index 2b26fe1..97be8a4 100644
--- a/cuda/3d/mem3d.cu
+++ b/cuda/3d/mem3d.cu
@@ -118,6 +118,13 @@ MemHandle3D allocateGPUMemory(unsigned int x, unsigned int y, unsigned int z, Me
 	return ret;
 }
 
+bool zeroGPUMemory(MemHandle3D handle, unsigned int x, unsigned int y, unsigned int z)
+{
+	SMemHandle3D_internal& hnd = *handle.d.get();
+	cudaError_t err = cudaMemset3D(hnd.ptr, 0, make_cudaExtent(sizeof(float)*x, y, z));
+	return err == cudaSuccess;
+}
+
 bool freeGPUMemory(MemHandle3D handle)
 {
 	size_t free = availableGPUMemory();
@@ -307,6 +314,23 @@ bool FDK(const astra::CProjectionGeometry3D* pProjGeom, MemHandle3D projData, co
 
 }
 
+MemHandle3D wrapHandle(float *D_ptr, unsigned int x, unsigned int y, unsigned int z, unsigned int pitch)
+{
+	cudaPitchedPtr ptr;
+	ptr.ptr = D_ptr;
+	ptr.xsize = sizeof(float) * x;
+	ptr.pitch = sizeof(float) * pitch;
+	ptr.ysize = y;
+
+	SMemHandle3D_internal h;
+	h.ptr = ptr;
+
+	MemHandle3D hnd;
+	hnd.d = boost::shared_ptr<SMemHandle3D_internal>(new SMemHandle3D_internal);
+	*hnd.d = h;
+
+	return hnd;
+}
 
 
 
diff --git a/cuda/3d/mem3d.h b/cuda/3d/mem3d.h
index a0829e2..7a87ae6 100644
--- a/cuda/3d/mem3d.h
+++ b/cuda/3d/mem3d.h
@@ -80,6 +80,8 @@ enum Mem3DZeroMode {
 size_t availableGPUMemory();
 int maxBlockDimension();
 
+MemHandle3D wrapHandle(float *D_ptr, unsigned int x, unsigned int y, unsigned int z, unsigned int pitch);
+
 MemHandle3D allocateGPUMemory(unsigned int x, unsigned int y, unsigned int z, Mem3DZeroMode zero);
 
 bool copyToGPUMemory(const float *src, MemHandle3D dst, const SSubDimensions3D &pos);
@@ -88,6 +90,8 @@ bool copyFromGPUMemory(float *dst, MemHandle3D src, const SSubDimensions3D &pos)
 
 bool freeGPUMemory(MemHandle3D handle);
 
+bool zeroGPUMemory(MemHandle3D handle, unsigned int x, unsigned int y, unsigned int z);
+
 bool setGPUIndex(int index);
 
 
@@ -97,7 +101,6 @@ bool BP(const astra::CProjectionGeometry3D* pProjGeom, MemHandle3D projData, con
 
 bool FDK(const astra::CProjectionGeometry3D* pProjGeom, MemHandle3D projData, const astra::CVolumeGeometry3D* pVolGeom, MemHandle3D volData, bool bShortScan, const float *pfFilter = 0);
 
-
 }
 
 #endif
diff --git a/include/astra/CompositeGeometryManager.h b/include/astra/CompositeGeometryManager.h
index c0acf4f..08eb7af 100644
--- a/include/astra/CompositeGeometryManager.h
+++ b/include/astra/CompositeGeometryManager.h
@@ -42,9 +42,9 @@ namespace astra {
 
 class CCompositeVolume;
 class CCompositeProjections;
-class CFloat32Data3DMemory;
-class CFloat32ProjectionData3DMemory;
-class CFloat32VolumeData3DMemory;
+class CFloat32Data3D;
+class CFloat32ProjectionData3D;
+class CFloat32VolumeData3D;
 class CVolumeGeometry3D;
 class CProjectionGeometry3D;
 class CProjector3D;
@@ -77,7 +77,7 @@ public:
 			PART_VOL, PART_PROJ
 		} eType;
 
-		CFloat32Data3DMemory* pData;
+		CFloat32Data3D* pData;
 		unsigned int subX;
 		unsigned int subY;
 		unsigned int subZ;
@@ -88,8 +88,11 @@ public:
 		virtual void splitY(TPartList& out, size_t maxSize, size_t maxDim, int div) = 0;
 		virtual void splitZ(TPartList& out, size_t maxSize, size_t maxDim, int div) = 0;
 		virtual CPart* reduce(const CPart *other) = 0;
-		virtual void getDims(size_t &x, size_t &y, size_t &z) = 0;
-		size_t getSize();
+		virtual void getDims(size_t &x, size_t &y, size_t &z) const = 0;
+		size_t getSize() const;
+
+		bool canSplitAndReduce() const;
+		bool isFull() const;
 	};
 
 	class CVolumePart : public CPart {
@@ -104,7 +107,7 @@ public:
 		virtual void splitY(TPartList& out, size_t maxSize, size_t maxDim, int div);
 		virtual void splitZ(TPartList& out, size_t maxSize, size_t maxDim, int div);
 		virtual CPart* reduce(const CPart *other);
-		virtual void getDims(size_t &x, size_t &y, size_t &z);
+		virtual void getDims(size_t &x, size_t &y, size_t &z) const;
 
 		CVolumePart* clone() const;
 	};
@@ -120,7 +123,7 @@ public:
 		virtual void splitY(TPartList& out, size_t maxSize, size_t maxDim, int div);
 		virtual void splitZ(TPartList& out, size_t maxSize, size_t maxDim, int div);
 		virtual CPart* reduce(const CPart *other);
-		virtual void getDims(size_t &x, size_t &y, size_t &z);
+		virtual void getDims(size_t &x, size_t &y, size_t &z) const;
 
 		CProjectionPart* clone() const;
 	};
@@ -150,23 +153,23 @@ public:
 	bool doJobs(TJobList &jobs);
 
 	SJob createJobFP(CProjector3D *pProjector,
-                     CFloat32VolumeData3DMemory *pVolData,
-                     CFloat32ProjectionData3DMemory *pProjData);
+                     CFloat32VolumeData3D *pVolData,
+                     CFloat32ProjectionData3D *pProjData);
 	SJob createJobBP(CProjector3D *pProjector,
-                     CFloat32VolumeData3DMemory *pVolData,
-                     CFloat32ProjectionData3DMemory *pProjData);
+                     CFloat32VolumeData3D *pVolData,
+                     CFloat32ProjectionData3D *pProjData);
 
 	// Convenience functions for creating and running a single FP or BP job
-	bool doFP(CProjector3D *pProjector, CFloat32VolumeData3DMemory *pVolData,
-	          CFloat32ProjectionData3DMemory *pProjData);
-	bool doBP(CProjector3D *pProjector, CFloat32VolumeData3DMemory *pVolData,
-	          CFloat32ProjectionData3DMemory *pProjData);
-	bool doFDK(CProjector3D *pProjector, CFloat32VolumeData3DMemory *pVolData,
-	          CFloat32ProjectionData3DMemory *pProjData, bool bShortScan,
+	bool doFP(CProjector3D *pProjector, CFloat32VolumeData3D *pVolData,
+	          CFloat32ProjectionData3D *pProjData);
+	bool doBP(CProjector3D *pProjector, CFloat32VolumeData3D *pVolData,
+	          CFloat32ProjectionData3D *pProjData);
+	bool doFDK(CProjector3D *pProjector, CFloat32VolumeData3D *pVolData,
+	          CFloat32ProjectionData3D *pProjData, bool bShortScan,
 	          const float *pfFilter = 0);
 
-	bool doFP(CProjector3D *pProjector, const std::vector<CFloat32VolumeData3DMemory *>& volData, const std::vector<CFloat32ProjectionData3DMemory *>& projData);
-	bool doBP(CProjector3D *pProjector, const std::vector<CFloat32VolumeData3DMemory *>& volData, const std::vector<CFloat32ProjectionData3DMemory *>& projData);
+	bool doFP(CProjector3D *pProjector, const std::vector<CFloat32VolumeData3D *>& volData, const std::vector<CFloat32ProjectionData3D *>& projData);
+	bool doBP(CProjector3D *pProjector, const std::vector<CFloat32VolumeData3D *>& volData, const std::vector<CFloat32ProjectionData3D *>& projData);
 
 	void setGPUIndices(const std::vector<int>& GPUIndices);
 
diff --git a/include/astra/CudaBackProjectionAlgorithm3D.h b/include/astra/CudaBackProjectionAlgorithm3D.h
index 6738988..114d6f3 100644
--- a/include/astra/CudaBackProjectionAlgorithm3D.h
+++ b/include/astra/CudaBackProjectionAlgorithm3D.h
@@ -69,8 +69,8 @@ public:
 	 * @param _pReconstruction	VolumeData3D object for storing the reconstructed volume.
 	 */
 	CCudaBackProjectionAlgorithm3D(CProjector3D* _pProjector, 
-	                     CFloat32ProjectionData3DMemory* _pProjectionData, 
-	                     CFloat32VolumeData3DMemory* _pReconstruction);
+	                     CFloat32ProjectionData3D* _pProjectionData, 
+	                     CFloat32VolumeData3D* _pReconstruction);
 	
 	/** Copy constructor.
 	 */
@@ -99,8 +99,8 @@ public:
 	 * @return initialization successful?
 	 */
 	bool initialize(CProjector3D* _pProjector, 
-					CFloat32ProjectionData3DMemory* _pSinogram, 
-					CFloat32VolumeData3DMemory* _pReconstruction);
+					CFloat32ProjectionData3D* _pSinogram, 
+					CFloat32VolumeData3D* _pReconstruction);
 
 	/** Get all information parameters
 	 *
diff --git a/include/astra/CudaFDKAlgorithm3D.h b/include/astra/CudaFDKAlgorithm3D.h
index 386129e..1c4c622 100644
--- a/include/astra/CudaFDKAlgorithm3D.h
+++ b/include/astra/CudaFDKAlgorithm3D.h
@@ -81,8 +81,8 @@ public:
 	 * @param _pReconstruction	VolumeData3D object for storing the reconstructed volume.
 	 */
 	CCudaFDKAlgorithm3D(CProjector3D* _pProjector, 
-	                    CFloat32ProjectionData3DMemory* _pProjectionData, 
-	                    CFloat32VolumeData3DMemory* _pReconstruction);
+	                    CFloat32ProjectionData3D* _pProjectionData, 
+	                    CFloat32VolumeData3D* _pReconstruction);
 	
 	/** Copy constructor.
 	 */
@@ -111,8 +111,8 @@ public:
 	 * @return initialization successful?
 	 */
 	bool initialize(CProjector3D* _pProjector, 
-					CFloat32ProjectionData3DMemory* _pSinogram, 
-					CFloat32VolumeData3DMemory* _pReconstruction);
+					CFloat32ProjectionData3D* _pSinogram, 
+					CFloat32VolumeData3D* _pReconstruction);
 
 	/** Get all information parameters
 	 *
diff --git a/include/astra/CudaForwardProjectionAlgorithm3D.h b/include/astra/CudaForwardProjectionAlgorithm3D.h
index 95af73a..9dc889e 100644
--- a/include/astra/CudaForwardProjectionAlgorithm3D.h
+++ b/include/astra/CudaForwardProjectionAlgorithm3D.h
@@ -71,8 +71,8 @@ public:
 	 * @return initialization successful?
 	 */
 	bool initialize(CProjector3D* _pProjector, 
-					CFloat32ProjectionData3DMemory* _pSinogram, 
-					CFloat32VolumeData3DMemory* _pReconstruction,
+					CFloat32ProjectionData3D* _pSinogram, 
+					CFloat32VolumeData3D* _pReconstruction,
 					int _iGPUindex = -1, int _iDetectorSuperSampling = 1);
 
 
@@ -116,8 +116,8 @@ public:
 
 protected:
 	CProjector3D* m_pProjector;
-	CFloat32ProjectionData3DMemory* m_pProjections;
-	CFloat32VolumeData3DMemory* m_pVolume;
+	CFloat32ProjectionData3D* m_pProjections;
+	CFloat32VolumeData3D* m_pVolume;
 	int m_iGPUIndex;
 	int m_iDetectorSuperSampling;
 
diff --git a/include/astra/Float32Data3D.h b/include/astra/Float32Data3D.h
index 2b3b88e..aca82ab 100644
--- a/include/astra/Float32Data3D.h
+++ b/include/astra/Float32Data3D.h
@@ -32,6 +32,8 @@ along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
 #include "Float32Data.h"
 #include "Float32Data2D.h"
 
+#include "../../cuda/3d/mem3d.h"
+
 namespace astra {
 
 /**
diff --git a/include/astra/Float32Data3DGPU.h b/include/astra/Float32Data3DGPU.h
new file mode 100644
index 0000000..0802105
--- /dev/null
+++ b/include/astra/Float32Data3DGPU.h
@@ -0,0 +1,108 @@
+/*
+-----------------------------------------------------------------------
+Copyright: 2010-2015, iMinds-Vision Lab, University of Antwerp
+           2014-2015, CWI, Amsterdam
+
+Contact: astra@uantwerpen.be
+Website: http://sf.net/projects/astra-toolbox
+
+This file is part of the ASTRA Toolbox.
+
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_FLOAT32DATA3DGPU
+#define _INC_ASTRA_FLOAT32DATA3DGPU
+
+#ifdef ASTRA_CUDA
+
+#include "Globals.h"
+#include "Float32Data3D.h"
+
+#include "../../cuda/3d/mem3d.h"
+
+namespace astra {
+
+
+astraCUDA3d::MemHandle3D wrapHandle(float *D_ptr, unsigned int x, unsigned int y, unsigned int z, unsigned int pitch);
+
+
+/** 
+ * This class represents a three-dimensional block of float32ing point data.
+ * The data block is stored on a GPU, and owned by external code.
+ *
+ * TODO: Store/remember which GPU the data is stored on
+ */
+class _AstraExport CFloat32Data3DGPU : public virtual CFloat32Data3D {
+
+protected:
+	/** Handle for the memory block */
+	astraCUDA3d::MemHandle3D m_hnd;
+
+	/** Clear all member variables, setting all numeric variables to 0 and all pointers to NULL. 
+	 */
+	void _clear();
+
+	/** Un-initialize the object, bringing it back in the unitialized state.
+	 */
+	void _unInit();
+
+	/** Initialization. Initializes an instance of the CFloat32Data3DGPU class.
+	 * Can only be called by derived classes.
+	 *
+	 * This function does not set m_bInitialized to true if everything is ok.
+	 *
+	 * @param _iWidth width of the 2D data (x-axis), must be > 0
+	 * @param _iHeight height of the 2D data (y-axis), must be > 0 
+	 * @param _iDepth depth of the 2D data (z-axis), must be > 0 
+	 * @param _hnd the CUDA memory handle
+	 */
+
+	bool _initialize(int _iWidth, int _iHeight, int _iDepth, astraCUDA3d::MemHandle3D _hnd);
+
+public:
+
+	/** Default constructor. Sets all numeric member variables to 0 and all pointer member variables to NULL.
+	 *
+	 * If an object is constructed using this default constructor, it must always be followed by a call 
+	 * to one of the initialize() methods before the object can be used. Any use before calling init() is not allowed,
+	 * except calling the member function isInitialized().
+	 *
+	 */
+	CFloat32Data3DGPU();
+
+	/** Destructor.
+	 */
+	virtual ~CFloat32Data3DGPU();
+
+	/** which type is this class?
+	 *
+	 * @return DataType: ASTRA_DATATYPE_FLOAT32_PROJECTION or
+	 *					 ASTRA_DATATYPE_FLOAT32_VOLUME
+	 */
+	virtual EDataType getType() const { return BASE; }
+
+	astraCUDA3d::MemHandle3D getHandle() const { return m_hnd; }
+
+};
+
+} // end namespace astra
+
+#endif
+
+#endif // _INC_ASTRA_FLOAT32DATA3DGPU
diff --git a/include/astra/Float32ProjectionData3DGPU.h b/include/astra/Float32ProjectionData3DGPU.h
new file mode 100644
index 0000000..135c718
--- /dev/null
+++ b/include/astra/Float32ProjectionData3DGPU.h
@@ -0,0 +1,92 @@
+/*
+-----------------------------------------------------------------------
+Copyright: 2010-2015, iMinds-Vision Lab, University of Antwerp
+           2014-2015, CWI, Amsterdam
+
+Contact: astra@uantwerpen.be
+Website: http://sf.net/projects/astra-toolbox
+
+This file is part of the ASTRA Toolbox.
+
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_FLOAT32PROJECTIONDATA3DGPU
+#define _INC_ASTRA_FLOAT32PROJECTIONDATA3DGPU
+
+#include "Float32Data3DGPU.h"
+#include "ProjectionGeometry3D.h"
+#include "Float32ProjectionData3D.h"
+
+#ifdef ASTRA_CUDA
+
+namespace astra {
+
+/**
+ * This class represents three-dimensional Projection Data where the entire data block is stored in GPU memory.
+ */
+class _AstraExport CFloat32ProjectionData3DGPU : public CFloat32Data3DGPU, public CFloat32ProjectionData3D
+{
+public:
+
+	/** Default constructor. Sets all numeric member variables to 0 and all pointer member variables to NULL.
+	 *
+	 * If an object is constructed using this default constructor, it must always be followed by a call 
+	 * to one of the init() methods before the object can be used. Any use before calling init() is not allowed,
+	 * except calling the member function isInitialized().
+	 *
+	 */
+	CFloat32ProjectionData3DGPU();
+	
+	/** Construction.
+	 *
+	 * @param _pGeometry 3D volume geometry
+	 * @param _hnd the CUDA memory handle
+	 */
+
+	CFloat32ProjectionData3DGPU(CProjectionGeometry3D* _pGeometry, astraCUDA3d::MemHandle3D _hnd);
+
+	virtual ~CFloat32ProjectionData3DGPU();
+
+	/** Initialization.
+	 *
+	 * @param _pGeometry 3D volume geometry
+	 * @param _hnd the CUDA memory handle
+	 */
+
+	bool initialize(CProjectionGeometry3D* _pGeometry, astraCUDA3d::MemHandle3D _hnd);
+
+	/** Which type is this class?
+	 *
+	 * @return DataType: PROJECTION
+	 */
+	virtual CFloat32Data3D::EDataType getType() const { return PROJECTION; }
+
+	/** Get the volume geometry.
+	 *
+	 * @return pointer to volume geometry.
+	 */
+	CProjectionGeometry3D* getGeometry() const { ASTRA_ASSERT(m_bInitialized); return m_pGeometry; }
+
+};
+
+} // end namesProjection astra
+
+#endif
+
+#endif // _INC_ASTRA_FLOAT32PROJECTIONDATA3DGPU
diff --git a/include/astra/Float32VolumeData3DGPU.h b/include/astra/Float32VolumeData3DGPU.h
new file mode 100644
index 0000000..377ed75
--- /dev/null
+++ b/include/astra/Float32VolumeData3DGPU.h
@@ -0,0 +1,92 @@
+/*
+-----------------------------------------------------------------------
+Copyright: 2010-2015, iMinds-Vision Lab, University of Antwerp
+           2014-2015, CWI, Amsterdam
+
+Contact: astra@uantwerpen.be
+Website: http://sf.net/projects/astra-toolbox
+
+This file is part of the ASTRA Toolbox.
+
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_FLOAT32VOLUMEDATA3DGPU
+#define _INC_ASTRA_FLOAT32VOLUMEDATA3DGPU
+
+#include "Float32Data3DGPU.h"
+#include "VolumeGeometry3D.h"
+#include "Float32VolumeData3D.h"
+
+#ifdef ASTRA_CUDA
+
+namespace astra {
+
+/**
+ * This class represents three-dimensional Volume Data where the entire data block is stored in GPU memory.
+ */
+class _AstraExport CFloat32VolumeData3DGPU : public CFloat32Data3DGPU, public CFloat32VolumeData3D
+{
+public:
+
+	/** Default constructor. Sets all numeric member variables to 0 and all pointer member variables to NULL.
+	 *
+	 * If an object is constructed using this default constructor, it must always be followed by a call 
+	 * to one of the init() methods before the object can be used. Any use before calling init() is not allowed,
+	 * except calling the member function isInitialized().
+	 *
+	 */
+	CFloat32VolumeData3DGPU();
+	
+	/** Construction.
+	 *
+	 * @param _pGeometry 3D volume geometry
+	 * @param _hnd the CUDA memory handle
+	 */
+
+	CFloat32VolumeData3DGPU(CVolumeGeometry3D* _pGeometry, astraCUDA3d::MemHandle3D _hnd);
+
+	virtual ~CFloat32VolumeData3DGPU();
+
+	/** Initialization.
+	 *
+	 * @param _pGeometry 3D volume geometry
+	 * @param _hnd the CUDA memory handle
+	 */
+
+	bool initialize(CVolumeGeometry3D* _pGeometry, astraCUDA3d::MemHandle3D _hnd);
+
+	/** Which type is this class?
+	 *
+	 * @return DataType: VOLUME
+	 */
+	virtual CFloat32Data3D::EDataType getType() const { return VOLUME; }
+
+	/** Get the volume geometry.
+	 *
+	 * @return pointer to volume geometry.
+	 */
+	CVolumeGeometry3D* getGeometry() const { ASTRA_ASSERT(m_bInitialized); return m_pGeometry; }
+
+};
+
+} // end namespace astra
+
+#endif
+
+#endif // _INC_ASTRA_FLOAT32VOLUMEDATA3DGPU
diff --git a/python/astra/PyIncludes.pxd b/python/astra/PyIncludes.pxd
index 39f9039..d5da17c 100644
--- a/python/astra/PyIncludes.pxd
+++ b/python/astra/PyIncludes.pxd
@@ -172,6 +172,13 @@ IF HAVE_CUDA==True:
 	cdef extern from "astra/CudaProjector2D.h" namespace "astra":
 		cdef cppclass CCudaProjector2D
 
+	cdef extern from "astra/Float32Data3DGPU.h" namespace "astraCUDA3d":
+		cdef cppclass MemHandle3D:
+			pass
+
+	cdef extern from "astra/Float32Data3DGPU.h" namespace "astraCUDA3d":
+		cdef MemHandle3D wrapHandle(float *D_ptr, unsigned int x, unsigned int y, unsigned int z, unsigned int pitch)
+
 
 cdef extern from "astra/SparseMatrix.h" namespace "astra":
 	cdef cppclass CSparseMatrix:
@@ -184,14 +191,18 @@ cdef extern from "astra/SparseMatrix.h" namespace "astra":
 		unsigned int* m_piColIndices
 		unsigned long* m_plRowStarts
 
-cdef extern from "astra/Float32Data3DMemory.h" namespace "astra":
-	cdef cppclass CFloat32Data3DMemory:
-		CFloat32Data3DMemory()
+cdef extern from "astra/Float32Data3D.h" namespace "astra":
+	cdef cppclass CFloat32Data3D:
 		bool isInitialized()
 		int getSize()
 		int getWidth()
 		int getHeight()
 		int getDepth()
+
+
+cdef extern from "astra/Float32Data3DMemory.h" namespace "astra":
+	cdef cppclass CFloat32Data3DMemory(CFloat32Data3D):
+		CFloat32Data3DMemory()
 		void updateStatistics()
 		float32 *getData()
 		float32 ***getData3D()
@@ -228,8 +239,6 @@ cdef extern from "astra/Float32VolumeData3DMemory.h" namespace "astra":
 		int getSliceCount()
 		bool isInitialized()
 
-
-
 cdef extern from "astra/ParallelProjectionGeometry3D.h" namespace "astra":
 	cdef cppclass CParallelProjectionGeometry3D:
 		CParallelProjectionGeometry3D()
@@ -260,12 +269,23 @@ cdef extern from "astra/Float32ProjectionData3DMemory.h" namespace "astra":
 		int getAngleCount()
 		bool isInitialized()
 
-cdef extern from "astra/Float32Data3D.h" namespace "astra":
-	cdef cppclass CFloat32Data3D:
-		CFloat32Data3D()
-		bool isInitialized()
-		int getSize()
-		int getWidth()
-		int getHeight()
-		int getDepth()
-		void updateStatistics()
+IF HAVE_CUDA==True:
+	cdef extern from "astra/Float32VolumeData3DGPU.h" namespace "astra":
+		cdef cppclass CFloat32VolumeData3DGPU:
+			CFloat32VolumeData3DGPU(CVolumeGeometry3D*, MemHandle3D)
+			CVolumeGeometry3D* getGeometry()
+			void changeGeometry(CVolumeGeometry3D*)
+			int getRowCount()
+			int getColCount()
+			int getSliceCount()
+			bool isInitialized()
+
+	cdef extern from "astra/Float32ProjectionData3DGPU.h" namespace "astra":
+		cdef cppclass CFloat32ProjectionData3DGPU:
+			CFloat32ProjectionData3DGPU(CProjectionGeometry3D*, MemHandle3D)
+			CProjectionGeometry3D* getGeometry()
+			void changeGeometry(CProjectionGeometry3D*)
+			int getRowCount()
+			int getColCount()
+			int getSliceCount()
+			bool isInitialized()
diff --git a/python/astra/data3d.py b/python/astra/data3d.py
index 9c2bea4..a825700 100644
--- a/python/astra/data3d.py
+++ b/python/astra/data3d.py
@@ -26,6 +26,8 @@
 from . import data3d_c as d
 import numpy as np
 
+from .pythonutils import GPULink
+
 def create(datatype,geometry,data=None):
     """Create a 3D object.
 
@@ -52,11 +54,11 @@ def link(datatype, geometry, data):
     :returns: :class:`int` -- the ID of the constructed object.
     
     """
-    if not isinstance(data,np.ndarray):
+    if not isinstance(data,np.ndarray) and not isinstance(data,GPULink):
         raise ValueError("Input should be a numpy array")
-    if not data.dtype==np.float32:
+    if not isinstance(data,GPULink) and not data.dtype==np.float32:
         raise ValueError("Numpy array should be float32")
-    if not (data.flags['C_CONTIGUOUS'] and data.flags['ALIGNED']):
+    if not isinstance(data,GPULink) and not (data.flags['C_CONTIGUOUS'] and data.flags['ALIGNED']):
         raise ValueError("Numpy array should be C_CONTIGUOUS and ALIGNED")
     return d.create(datatype,geometry,data,True)
 
diff --git a/python/astra/data3d_c.pyx b/python/astra/data3d_c.pyx
index 3934f22..56247de 100644
--- a/python/astra/data3d_c.pyx
+++ b/python/astra/data3d_c.pyx
@@ -45,12 +45,17 @@ from .PyXMLDocument cimport XMLDocument
 cimport utils
 from .utils import wrap_from_bytes
 
-from .pythonutils import geom_size
+from .pythonutils import geom_size, GPULink
 
 import operator
 
 from six.moves import reduce
 
+include "config.pxi"
+
+cdef extern from "Python.h":
+    void* PyLong_AsVoidPtr(object)
+
 
 cdef CData3DManager * man3d = <CData3DManager * >PyData3DManager.getSingletonPtr()
 
@@ -65,12 +70,19 @@ def create(datatype,geometry,data=None, link=False):
     cdef Config *cfg
     cdef CVolumeGeometry3D * pGeometry
     cdef CProjectionGeometry3D * ppGeometry
-    cdef CFloat32Data3DMemory * pDataObject3D
+    cdef CFloat32Data3D * pDataObject3D
     cdef CConeProjectionGeometry3D* pppGeometry
-    cdef CFloat32CustomMemory * pCustom
-
-    if link and data.shape!=geom_size(geometry):
-        raise Exception("The dimensions of the data do not match those specified in the geometry.")
+    cdef CFloat32CustomMemory * pCustom = NULL
+    IF HAVE_CUDA==True:
+        cdef MemHandle3D hnd
+
+    if link:
+        if isinstance(data, GPULink):
+            s = geom_size(geometry)
+            if geom_size(geometry) != ( data.z, data.y, data.x ):
+                raise Exception("The dimensions of the data do not match those specified in the geometry.")
+        elif data.shape!=geom_size(geometry):
+            raise Exception("The dimensions of the data do not match those specified in the geometry.")
 
     if datatype == '-vol':
         cfg = utils.dictToConfig(six.b('VolumeGeometry'), geometry)
@@ -80,10 +92,18 @@ def create(datatype,geometry,data=None, link=False):
             del pGeometry
             raise Exception('Geometry class not initialized.')
         if link:
-            pCustom = <CFloat32CustomMemory*> new CFloat32CustomPython(data)
-            pDataObject3D = <CFloat32Data3DMemory * > new CFloat32VolumeData3DMemory(pGeometry, pCustom)
+            if isinstance(data, GPULink):
+                IF HAVE_CUDA==True:
+                    s = geom_size(geometry)
+                    hnd = wrapHandle(<float*>PyLong_AsVoidPtr(data.ptr), data.x, data.y, data.z, data.pitch/4)
+                    pDataObject3D = <CFloat32Data3D * > new CFloat32VolumeData3DGPU(pGeometry, hnd)
+                ELSE:
+                    raise NotImplementedError("CUDA support is not enabled in ASTRA")
+            else:
+                pCustom = <CFloat32CustomMemory*> new CFloat32CustomPython(data)
+                pDataObject3D = <CFloat32Data3D * > new CFloat32VolumeData3DMemory(pGeometry, pCustom)
         else:
-            pDataObject3D = <CFloat32Data3DMemory * > new CFloat32VolumeData3DMemory(pGeometry)
+            pDataObject3D = <CFloat32Data3D * > new CFloat32VolumeData3DMemory(pGeometry)
         del cfg
         del pGeometry
     elif datatype == '-sino' or datatype == '-proj3d' or datatype == '-sinocone':
@@ -105,8 +125,16 @@ def create(datatype,geometry,data=None, link=False):
             del ppGeometry
             raise Exception('Geometry class not initialized.')
         if link:
-            pCustom = <CFloat32CustomMemory*> new CFloat32CustomPython(data)
-            pDataObject3D = <CFloat32Data3DMemory * > new CFloat32ProjectionData3DMemory(ppGeometry, pCustom)
+            if isinstance(data, GPULink):
+                IF HAVE_CUDA==True:
+                    s = geom_size(geometry)
+                    hnd = wrapHandle(<float*>PyLong_AsVoidPtr(data.ptr), data.x, data.y, data.z, data.pitch/4)
+                    pDataObject3D = <CFloat32Data3D * > new CFloat32ProjectionData3DGPU(ppGeometry, hnd)
+                ELSE:
+                    raise NotImplementedError("CUDA support is not enabled in ASTRA")
+            else:
+                pCustom = <CFloat32CustomMemory*> new CFloat32CustomPython(data)
+                pDataObject3D = <CFloat32Data3D * > new CFloat32ProjectionData3DMemory(ppGeometry, pCustom)
         else:
             pDataObject3D = <CFloat32Data3DMemory * > new CFloat32ProjectionData3DMemory(ppGeometry)
         del ppGeometry
@@ -118,8 +146,7 @@ def create(datatype,geometry,data=None, link=False):
         del pDataObject3D
         raise Exception("Couldn't initialize data object.")
 
-    if not link: fillDataObject(pDataObject3D, data)
-
+    if not link: fillDataObject(dynamic_cast_mem(pDataObject3D), data)
 
     return man3d.store(<CFloat32Data3D*>pDataObject3D)
 
diff --git a/python/astra/experimental.pyx b/python/astra/experimental.pyx
index b6c7881..0af3118 100644
--- a/python/astra/experimental.pyx
+++ b/python/astra/experimental.pyx
@@ -36,12 +36,20 @@ IF HAVE_CUDA==True:
 
     cdef extern from "astra/CompositeGeometryManager.h" namespace "astra":
         cdef cppclass CCompositeGeometryManager:
-            bool doFP(CProjector3D *, vector[CFloat32VolumeData3DMemory *], vector[CFloat32ProjectionData3DMemory *])
-            bool doBP(CProjector3D *, vector[CFloat32VolumeData3DMemory *], vector[CFloat32ProjectionData3DMemory *])
+            bool doFP(CProjector3D *, vector[CFloat32VolumeData3D *], vector[CFloat32ProjectionData3D *])
+            bool doBP(CProjector3D *, vector[CFloat32VolumeData3D *], vector[CFloat32ProjectionData3D *])
 
     cdef extern from *:
-        CFloat32VolumeData3DMemory * dynamic_cast_vol_mem "dynamic_cast<astra::CFloat32VolumeData3DMemory*>" (CFloat32Data3D * ) except NULL
-        CFloat32ProjectionData3DMemory * dynamic_cast_proj_mem "dynamic_cast<astra::CFloat32ProjectionData3DMemory*>" (CFloat32Data3D * ) except NULL
+        CFloat32VolumeData3D * dynamic_cast_vol_mem "dynamic_cast<astra::CFloat32VolumeData3D*>" (CFloat32Data3D * ) except NULL
+        CFloat32ProjectionData3D * dynamic_cast_proj_mem "dynamic_cast<astra::CFloat32ProjectionData3D*>" (CFloat32Data3D * ) except NULL
+
+    cdef extern from "astra/Float32ProjectionData3D.h" namespace "astra":
+        cdef cppclass CFloat32ProjectionData3D:
+            bool isInitialized()
+    cdef extern from "astra/Float32VolumeData3D.h" namespace "astra":
+        cdef cppclass CFloat32VolumeData3D:
+            bool isInitialized()
+
 
     cimport PyProjector3DManager
     from .PyProjector3DManager cimport CProjector3DManager
@@ -52,9 +60,9 @@ IF HAVE_CUDA==True:
     cdef CData3DManager * man3d = <CData3DManager * >PyData3DManager.getSingletonPtr()
 
     def do_composite(projector_id, vol_ids, proj_ids, t):
-        cdef vector[CFloat32VolumeData3DMemory *] vol
-        cdef CFloat32VolumeData3DMemory * pVolObject
-        cdef CFloat32ProjectionData3DMemory * pProjObject
+        cdef vector[CFloat32VolumeData3D *] vol
+        cdef CFloat32VolumeData3D * pVolObject
+        cdef CFloat32ProjectionData3D * pProjObject
         for v in vol_ids:
             pVolObject = dynamic_cast_vol_mem(man3d.get(v))
             if pVolObject == NULL:
@@ -62,7 +70,7 @@ IF HAVE_CUDA==True:
             if not pVolObject.isInitialized():
                 raise Exception("Data object not initialized properly")
             vol.push_back(pVolObject)
-        cdef vector[CFloat32ProjectionData3DMemory *] proj
+        cdef vector[CFloat32ProjectionData3D *] proj
         for v in proj_ids:
             pProjObject = dynamic_cast_proj_mem(man3d.get(v))
             if pProjObject == NULL:
diff --git a/python/astra/pythonutils.py b/python/astra/pythonutils.py
index 3bd3321..27fa8fd 100644
--- a/python/astra/pythonutils.py
+++ b/python/astra/pythonutils.py
@@ -61,3 +61,21 @@ def geom_size(geom, dim=None):
         s = s[dim]
 
     return s
+
+class GPULink(object):
+    """Utility class for astra.data3d.link with a CUDA pointer
+
+    The CUDA pointer ptr must point to an array of floats.
+
+    x is the fastest-changing coordinate, z the slowest-changing.
+
+    pitch is the width in bytes of the memory block. For a contiguous
+    memory block, pitch is equal to sizeof(float) * x. For a memory block
+    allocated by cudaMalloc3D, pitch is the pitch as returned by cudaMalloc3D.
+    """
+    def __init__(self, ptr, x, y, z, pitch):
+        self.ptr = ptr
+        self.x = x
+        self.y = y
+        self.z = z
+        self.pitch = pitch
diff --git a/src/CompositeGeometryManager.cpp b/src/CompositeGeometryManager.cpp
index c3af228..74466db 100644
--- a/src/CompositeGeometryManager.cpp
+++ b/src/CompositeGeometryManager.cpp
@@ -39,6 +39,8 @@ along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
 #include "astra/CudaProjector3D.h"
 #include "astra/Float32ProjectionData3DMemory.h"
 #include "astra/Float32VolumeData3DMemory.h"
+#include "astra/Float32ProjectionData3DGPU.h"
+#include "astra/Float32VolumeData3DGPU.h"
 #include "astra/Logging.h"
 
 #include "../cuda/3d/mem3d.h"
@@ -97,6 +99,127 @@ CCompositeGeometryManager::CCompositeGeometryManager()
 //   (First approach: 0.5/0.5)
 
 
+
+
+
+class _AstraExport CFloat32CustomGPUMemory {
+public:
+    astraCUDA3d::MemHandle3D hnd; // Only required to be valid between allocate/free
+    virtual bool allocateGPUMemory(unsigned int x, unsigned int y, unsigned int z, astraCUDA3d::Mem3DZeroMode zero)=0;
+    virtual bool copyToGPUMemory(const astraCUDA3d::SSubDimensions3D &pos)=0;
+    virtual bool copyFromGPUMemory(const astraCUDA3d::SSubDimensions3D &pos)=0;
+    virtual bool freeGPUMemory()=0;
+	virtual ~CFloat32CustomGPUMemory() { }
+};
+
+class CFloat32ExistingGPUMemory : public astra::CFloat32CustomGPUMemory {
+public:
+    CFloat32ExistingGPUMemory(CFloat32Data3DGPU *d);
+    virtual bool allocateGPUMemory(unsigned int x, unsigned int y, unsigned int z, astraCUDA3d::Mem3DZeroMode zero);
+    virtual bool copyToGPUMemory(const astraCUDA3d::SSubDimensions3D &pos);
+    virtual bool copyFromGPUMemory(const astraCUDA3d::SSubDimensions3D &pos);
+    virtual bool freeGPUMemory();
+
+protected:
+    unsigned int x, y, z;
+};
+
+class CFloat32DefaultGPUMemory : public astra::CFloat32CustomGPUMemory {
+public:
+	CFloat32DefaultGPUMemory(CFloat32Data3DMemory* d) {
+		ptr = d->getData();
+	}
+	virtual bool allocateGPUMemory(unsigned int x, unsigned int y, unsigned int z, astraCUDA3d::Mem3DZeroMode zero) {
+		hnd = astraCUDA3d::allocateGPUMemory(x, y, z, zero);
+		return (bool)hnd;
+	}
+	virtual bool copyToGPUMemory(const astraCUDA3d::SSubDimensions3D &pos) {
+		return astraCUDA3d::copyToGPUMemory(ptr, hnd, pos);
+	}
+	virtual bool copyFromGPUMemory(const astraCUDA3d::SSubDimensions3D &pos) {
+		return astraCUDA3d::copyFromGPUMemory(ptr, hnd, pos);
+	}
+	virtual bool freeGPUMemory() {
+		return astraCUDA3d::freeGPUMemory(hnd);
+	}
+
+protected:
+	float *ptr;
+};
+
+
+
+CFloat32ExistingGPUMemory::CFloat32ExistingGPUMemory(CFloat32Data3DGPU *d)
+{
+	hnd = d->getHandle();
+	x = d->getWidth();
+	y = d->getHeight();
+	z = d->getDepth();
+}
+
+bool CFloat32ExistingGPUMemory::allocateGPUMemory(unsigned int x_, unsigned int y_, unsigned int z_, astraCUDA3d::Mem3DZeroMode zero) {
+    assert(x_ == x);
+    assert(y_ == y);
+    assert(z_ == z);
+
+    if (zero == astraCUDA3d::INIT_ZERO)
+        return astraCUDA3d::zeroGPUMemory(hnd, x, y, z);
+    else
+        return true;
+}
+bool CFloat32ExistingGPUMemory::copyToGPUMemory(const astraCUDA3d::SSubDimensions3D &pos) {
+    assert(pos.nx == x);
+    assert(pos.ny == y);
+    assert(pos.nz == z);
+    assert(pos.pitch == x);
+    assert(pos.subx == 0);
+    assert(pos.suby == 0);
+    assert(pos.subnx == x);
+    assert(pos.subny == y);
+
+    // These are less necessary than x/y, but allowing access to
+    // subvolumes needs an interface change
+    assert(pos.subz == 0);
+    assert(pos.subnz == z);
+
+    return true;
+}
+bool CFloat32ExistingGPUMemory::copyFromGPUMemory(const astraCUDA3d::SSubDimensions3D &pos) {
+    assert(pos.nx == x);
+    assert(pos.ny == y);
+    assert(pos.nz == z);
+    assert(pos.pitch == x);
+    assert(pos.subx == 0);
+    assert(pos.suby == 0);
+    assert(pos.subnx == x);
+    assert(pos.subny == y);
+
+    // These are less necessary than x/y, but allowing access to
+    // subvolumes needs an interface change
+    assert(pos.subz == 0);
+    assert(pos.subnz == z);
+
+    return true;
+}
+bool CFloat32ExistingGPUMemory::freeGPUMemory() {
+    return true;
+}
+
+
+CFloat32CustomGPUMemory * createGPUMemoryHandler(CFloat32Data3D *d) {
+	CFloat32Data3DMemory *dMem = dynamic_cast<CFloat32Data3DMemory*>(d);
+	CFloat32Data3DGPU *dGPU = dynamic_cast<CFloat32Data3DGPU*>(d);
+
+	if (dMem)
+		return new CFloat32DefaultGPUMemory(dMem);
+	else
+		return new CFloat32ExistingGPUMemory(dGPU);
+}
+
+
+
+
+
 bool CCompositeGeometryManager::splitJobs(TJobSet &jobs, size_t maxSize, int div, TJobSet &split)
 {
 	int maxBlockDim = astraCUDA3d::maxBlockDimension();
@@ -280,7 +403,7 @@ CCompositeGeometryManager::CVolumePart::~CVolumePart()
 	delete pGeom;
 }
 
-void CCompositeGeometryManager::CVolumePart::getDims(size_t &x, size_t &y, size_t &z)
+void CCompositeGeometryManager::CVolumePart::getDims(size_t &x, size_t &y, size_t &z) const
 {
 	if (!pGeom) {
 		x = y = z = 0;
@@ -292,13 +415,28 @@ void CCompositeGeometryManager::CVolumePart::getDims(size_t &x, size_t &y, size_
 	z = pGeom->getGridSliceCount();
 }
 
-size_t CCompositeGeometryManager::CPart::getSize()
+size_t CCompositeGeometryManager::CPart::getSize() const
 {
 	size_t x, y, z;
 	getDims(x, y, z);
 	return x * y * z;
 }
 
+bool CCompositeGeometryManager::CPart::isFull() const
+{
+	size_t x, y, z;
+	getDims(x, y, z);
+	return x == pData->getWidth() &&
+	       y == pData->getHeight() &&
+	       z == pData->getDepth();
+}
+
+bool CCompositeGeometryManager::CPart::canSplitAndReduce() const
+{
+	return dynamic_cast<CFloat32Data3DMemory *>(pData) != 0;
+}
+
+
 
 static bool testVolumeRange(const std::pair<double, double>& fullRange,
                             const CVolumeGeometry3D *pVolGeom,
@@ -334,6 +472,9 @@ static bool testVolumeRange(const std::pair<double, double>& fullRange,
 
 CCompositeGeometryManager::CPart* CCompositeGeometryManager::CVolumePart::reduce(const CPart *_other)
 {
+	if (!canSplitAndReduce())
+		return clone();
+
 	const CProjectionPart *other = dynamic_cast<const CProjectionPart *>(_other);
 	assert(other);
 
@@ -654,7 +795,7 @@ static CProjectionGeometry3D* getSubProjectionGeometryV(const CProjectionGeometr
 // - maybe all approximately the same size?
 void CCompositeGeometryManager::CVolumePart::splitX(CCompositeGeometryManager::TPartList& out, size_t maxSize, size_t maxDim, int div)
 {
-	if (true) {
+	if (canSplitAndReduce()) {
 		// Split in vertical direction only at first, until we figure out
 		// a model for splitting in other directions
 
@@ -698,12 +839,14 @@ void CCompositeGeometryManager::CVolumePart::splitX(CCompositeGeometryManager::T
 
 			out.push_back(boost::shared_ptr<CPart>(sub));
 		}
+	} else {
+		out.push_back(boost::shared_ptr<CPart>(clone()));
 	}
 }
 
 void CCompositeGeometryManager::CVolumePart::splitY(CCompositeGeometryManager::TPartList& out, size_t maxSize, size_t maxDim, int div)
 {
-	if (true) {
+	if (canSplitAndReduce()) {
 		// Split in vertical direction only at first, until we figure out
 		// a model for splitting in other directions
 
@@ -747,12 +890,14 @@ void CCompositeGeometryManager::CVolumePart::splitY(CCompositeGeometryManager::T
 
 			out.push_back(boost::shared_ptr<CPart>(sub));
 		}
+	} else {
+		out.push_back(boost::shared_ptr<CPart>(clone()));
 	}
 }
 
 void CCompositeGeometryManager::CVolumePart::splitZ(CCompositeGeometryManager::TPartList& out, size_t maxSize, size_t maxDim, int div)
 {
-	if (true) {
+	if (canSplitAndReduce()) {
 		// Split in vertical direction only at first, until we figure out
 		// a model for splitting in other directions
 
@@ -796,6 +941,8 @@ void CCompositeGeometryManager::CVolumePart::splitZ(CCompositeGeometryManager::T
 
 			out.push_back(boost::shared_ptr<CPart>(sub));
 		}
+	} else {
+		out.push_back(boost::shared_ptr<CPart>(clone()));
 	}
 }
 
@@ -815,7 +962,7 @@ CCompositeGeometryManager::CProjectionPart::~CProjectionPart()
 	delete pGeom;
 }
 
-void CCompositeGeometryManager::CProjectionPart::getDims(size_t &x, size_t &y, size_t &z)
+void CCompositeGeometryManager::CProjectionPart::getDims(size_t &x, size_t &y, size_t &z) const
 {
 	if (!pGeom) {
 		x = y = z = 0;
@@ -831,6 +978,9 @@ void CCompositeGeometryManager::CProjectionPart::getDims(size_t &x, size_t &y, s
 
 CCompositeGeometryManager::CPart* CCompositeGeometryManager::CProjectionPart::reduce(const CPart *_other)
 {
+	if (!canSplitAndReduce())
+		return clone();
+
 	const CVolumePart *other = dynamic_cast<const CVolumePart *>(_other);
 	assert(other);
 
@@ -868,7 +1018,7 @@ CCompositeGeometryManager::CPart* CCompositeGeometryManager::CProjectionPart::re
 
 void CCompositeGeometryManager::CProjectionPart::splitX(CCompositeGeometryManager::TPartList &out, size_t maxSize, size_t maxDim, int div)
 {
-	if (true) {
+	if (canSplitAndReduce()) {
 		// Split in vertical direction only at first, until we figure out
 		// a model for splitting in other directions
 
@@ -903,6 +1053,8 @@ void CCompositeGeometryManager::CProjectionPart::splitX(CCompositeGeometryManage
 
 			out.push_back(boost::shared_ptr<CPart>(sub));
 		}
+	} else {
+		out.push_back(boost::shared_ptr<CPart>(clone()));
 	}
 }
 
@@ -914,7 +1066,7 @@ void CCompositeGeometryManager::CProjectionPart::splitY(CCompositeGeometryManage
 
 void CCompositeGeometryManager::CProjectionPart::splitZ(CCompositeGeometryManager::TPartList &out, size_t maxSize, size_t maxDim, int div)
 {
-	if (true) {
+	if (canSplitAndReduce()) {
 		// Split in vertical direction only at first, until we figure out
 		// a model for splitting in other directions
 
@@ -949,6 +1101,8 @@ void CCompositeGeometryManager::CProjectionPart::splitZ(CCompositeGeometryManage
 
 			out.push_back(boost::shared_ptr<CPart>(sub));
 		}
+	} else {
+		out.push_back(boost::shared_ptr<CPart>(clone()));
 	}
 
 }
@@ -959,8 +1113,8 @@ CCompositeGeometryManager::CProjectionPart* CCompositeGeometryManager::CProjecti
 }
 
 CCompositeGeometryManager::SJob CCompositeGeometryManager::createJobFP(CProjector3D *pProjector,
-                                            CFloat32VolumeData3DMemory *pVolData,
-                                            CFloat32ProjectionData3DMemory *pProjData)
+                                            CFloat32VolumeData3D *pVolData,
+                                            CFloat32ProjectionData3D *pProjData)
 {
 	ASTRA_DEBUG("CCompositeGeometryManager::createJobFP");
 	// Create single job for FP
@@ -992,8 +1146,8 @@ CCompositeGeometryManager::SJob CCompositeGeometryManager::createJobFP(CProjecto
 }
 
 CCompositeGeometryManager::SJob CCompositeGeometryManager::createJobBP(CProjector3D *pProjector,
-                                            CFloat32VolumeData3DMemory *pVolData,
-                                            CFloat32ProjectionData3DMemory *pProjData)
+                                            CFloat32VolumeData3D *pVolData,
+                                            CFloat32ProjectionData3D *pProjData)
 {
 	ASTRA_DEBUG("CCompositeGeometryManager::createJobBP");
 	// Create single job for BP
@@ -1022,8 +1176,8 @@ CCompositeGeometryManager::SJob CCompositeGeometryManager::createJobBP(CProjecto
 	return BP;
 }
 
-bool CCompositeGeometryManager::doFP(CProjector3D *pProjector, CFloat32VolumeData3DMemory *pVolData,
-                                     CFloat32ProjectionData3DMemory *pProjData)
+bool CCompositeGeometryManager::doFP(CProjector3D *pProjector, CFloat32VolumeData3D *pVolData,
+                                     CFloat32ProjectionData3D *pProjData)
 {
 	TJobList L;
 	L.push_back(createJobFP(pProjector, pVolData, pProjData));
@@ -1031,8 +1185,8 @@ bool CCompositeGeometryManager::doFP(CProjector3D *pProjector, CFloat32VolumeDat
 	return doJobs(L);
 }
 
-bool CCompositeGeometryManager::doBP(CProjector3D *pProjector, CFloat32VolumeData3DMemory *pVolData,
-                                     CFloat32ProjectionData3DMemory *pProjData)
+bool CCompositeGeometryManager::doBP(CProjector3D *pProjector, CFloat32VolumeData3D *pVolData,
+                                     CFloat32ProjectionData3D *pProjData)
 {
 	TJobList L;
 	L.push_back(createJobBP(pProjector, pVolData, pProjData));
@@ -1041,8 +1195,8 @@ bool CCompositeGeometryManager::doBP(CProjector3D *pProjector, CFloat32VolumeDat
 }
 
 
-bool CCompositeGeometryManager::doFDK(CProjector3D *pProjector, CFloat32VolumeData3DMemory *pVolData,
-                                     CFloat32ProjectionData3DMemory *pProjData, bool bShortScan,
+bool CCompositeGeometryManager::doFDK(CProjector3D *pProjector, CFloat32VolumeData3D *pVolData,
+                                     CFloat32ProjectionData3D *pProjData, bool bShortScan,
                                      const float *pfFilter)
 {
 	if (!dynamic_cast<CConeProjectionGeometry3D*>(pProjData->getGeometry())) {
@@ -1061,11 +1215,11 @@ bool CCompositeGeometryManager::doFDK(CProjector3D *pProjector, CFloat32VolumeDa
 	return doJobs(L);
 }
 
-bool CCompositeGeometryManager::doFP(CProjector3D *pProjector, const std::vector<CFloat32VolumeData3DMemory *>& volData, const std::vector<CFloat32ProjectionData3DMemory *>& projData)
+bool CCompositeGeometryManager::doFP(CProjector3D *pProjector, const std::vector<CFloat32VolumeData3D *>& volData, const std::vector<CFloat32ProjectionData3D *>& projData)
 {
 	ASTRA_DEBUG("CCompositeGeometryManager::doFP, multi-volume");
 
-	std::vector<CFloat32VolumeData3DMemory *>::const_iterator i;
+	std::vector<CFloat32VolumeData3D *>::const_iterator i;
 	std::vector<boost::shared_ptr<CPart> > inputs;
 
 	for (i = volData.begin(); i != volData.end(); ++i) {
@@ -1079,7 +1233,7 @@ bool CCompositeGeometryManager::doFP(CProjector3D *pProjector, const std::vector
 		inputs.push_back(boost::shared_ptr<CPart>(input));
 	}
 
-	std::vector<CFloat32ProjectionData3DMemory *>::const_iterator j;
+	std::vector<CFloat32ProjectionData3D *>::const_iterator j;
 	std::vector<boost::shared_ptr<CPart> > outputs;
 
 	for (j = projData.begin(); j != projData.end(); ++j) {
@@ -1115,12 +1269,12 @@ bool CCompositeGeometryManager::doFP(CProjector3D *pProjector, const std::vector
 	return doJobs(L);
 }
 
-bool CCompositeGeometryManager::doBP(CProjector3D *pProjector, const std::vector<CFloat32VolumeData3DMemory *>& volData, const std::vector<CFloat32ProjectionData3DMemory *>& projData)
+bool CCompositeGeometryManager::doBP(CProjector3D *pProjector, const std::vector<CFloat32VolumeData3D *>& volData, const std::vector<CFloat32ProjectionData3D *>& projData)
 {
 	ASTRA_DEBUG("CCompositeGeometryManager::doBP, multi-volume");
 
 
-	std::vector<CFloat32VolumeData3DMemory *>::const_iterator i;
+	std::vector<CFloat32VolumeData3D *>::const_iterator i;
 	std::vector<boost::shared_ptr<CPart> > outputs;
 
 	for (i = volData.begin(); i != volData.end(); ++i) {
@@ -1134,7 +1288,7 @@ bool CCompositeGeometryManager::doBP(CProjector3D *pProjector, const std::vector
 		outputs.push_back(boost::shared_ptr<CPart>(output));
 	}
 
-	std::vector<CFloat32ProjectionData3DMemory *>::const_iterator j;
+	std::vector<CFloat32ProjectionData3D *>::const_iterator j;
 	std::vector<boost::shared_ptr<CPart> > inputs;
 
 	for (j = projData.begin(); j != projData.end(); ++j) {
@@ -1188,14 +1342,25 @@ static bool doJob(const CCompositeGeometryManager::TJobSet::const_iterator& iter
 	if (L.begin()->eType == CCompositeGeometryManager::SJob::JOB_NOP) {
 		// just zero output?
 		if (zero) {
-			for (size_t z = 0; z < outz; ++z) {
-				for (size_t y = 0; y < outy; ++y) {
-					float* ptr = output->pData->getData();
-					ptr += (z + output->subX) * (size_t)output->pData->getHeight() * (size_t)output->pData->getWidth();
-					ptr += (y + output->subY) * (size_t)output->pData->getWidth();
-					ptr += output->subX;
-					memset(ptr, 0, sizeof(float) * outx);
+			// TODO: This function shouldn't have to know about this difference
+			// between Memory/GPU
+			CFloat32Data3DMemory *hostMem = dynamic_cast<CFloat32Data3DMemory *>(output->pData);
+			if (hostMem) {
+				for (size_t z = 0; z < outz; ++z) {
+					for (size_t y = 0; y < outy; ++y) {
+						float* ptr = hostMem->getData();
+						ptr += (z + output->subX) * (size_t)output->pData->getHeight() * (size_t)output->pData->getWidth();
+						ptr += (y + output->subY) * (size_t)output->pData->getWidth();
+						ptr += output->subX;
+						memset(ptr, 0, sizeof(float) * outx);
+					}
 				}
+			} else {
+				CFloat32Data3DGPU *gpuMem = dynamic_cast<CFloat32Data3DGPU *>(output->pData);
+				assert(gpuMem);
+				assert(output->isFull()); // TODO: zero subset?
+
+				zeroGPUMemory(gpuMem->getHandle(), outx, outy, outz);
 			}
 		}
 		return true;
@@ -1214,10 +1379,11 @@ static bool doJob(const CCompositeGeometryManager::TJobSet::const_iterator& iter
 	dstdims.subx = output->subX;
 	dstdims.suby = output->subY;
 	dstdims.subz = output->subZ;
-	float *dst = output->pData->getData();
 
-	astraCUDA3d::MemHandle3D outputMem = astraCUDA3d::allocateGPUMemory(outx, outy, outz, zero ? astraCUDA3d::INIT_ZERO : astraCUDA3d::INIT_NO);
-	bool ok = outputMem;
+	CFloat32CustomGPUMemory *dstMem = createGPUMemoryHandler(output->pData);
+
+	bool ok = dstMem->allocateGPUMemory(outx, outy, outz, zero ? astraCUDA3d::INIT_ZERO : astraCUDA3d::INIT_NO);
+	if (!ok) ASTRA_ERROR("Error allocating GPU memory");
 
 	for (CCompositeGeometryManager::TJobList::const_iterator i = L.begin(); i != L.end(); ++i) {
 		const CCompositeGeometryManager::SJob &j = *i;
@@ -1238,7 +1404,8 @@ static bool doJob(const CCompositeGeometryManager::TJobSet::const_iterator& iter
 
 		size_t inx, iny, inz;
 		j.pInput->getDims(inx, iny, inz);
-		astraCUDA3d::MemHandle3D inputMem = astraCUDA3d::allocateGPUMemory(inx, iny, inz, astraCUDA3d::INIT_NO);
+
+		CFloat32CustomGPUMemory *srcMem = createGPUMemoryHandler(j.pInput->pData);
 
 		astraCUDA3d::SSubDimensions3D srcdims;
 		srcdims.nx = j.pInput->pData->getWidth();
@@ -1251,9 +1418,11 @@ static bool doJob(const CCompositeGeometryManager::TJobSet::const_iterator& iter
 		srcdims.subx = j.pInput->subX;
 		srcdims.suby = j.pInput->subY;
 		srcdims.subz = j.pInput->subZ;
-		const float *src = j.pInput->pData->getDataConst();
 
-		ok = astraCUDA3d::copyToGPUMemory(src, inputMem, srcdims);
+		ok = srcMem->allocateGPUMemory(inx, iny, inz, astraCUDA3d::INIT_NO);
+		if (!ok) ASTRA_ERROR("Error allocating GPU memory");
+
+		ok = srcMem->copyToGPUMemory(srcdims);
 		if (!ok) ASTRA_ERROR("Error copying input data to GPU");
 
 		switch (j.eType) {
@@ -1264,7 +1433,7 @@ static bool doJob(const CCompositeGeometryManager::TJobSet::const_iterator& iter
 
 			ASTRA_DEBUG("CCompositeGeometryManager::doJobs: doing FP");
 
-			ok = astraCUDA3d::FP(((CCompositeGeometryManager::CProjectionPart*)j.pOutput.get())->pGeom, outputMem, ((CCompositeGeometryManager::CVolumePart*)j.pInput.get())->pGeom, inputMem, detectorSuperSampling, projKernel);
+			ok = astraCUDA3d::FP(((CCompositeGeometryManager::CProjectionPart*)j.pOutput.get())->pGeom, dstMem->hnd, ((CCompositeGeometryManager::CVolumePart*)j.pInput.get())->pGeom, srcMem->hnd, detectorSuperSampling, projKernel);
 			if (!ok) ASTRA_ERROR("Error performing sub-FP");
 			ASTRA_DEBUG("CCompositeGeometryManager::doJobs: FP done");
 		}
@@ -1276,7 +1445,7 @@ static bool doJob(const CCompositeGeometryManager::TJobSet::const_iterator& iter
 
 			ASTRA_DEBUG("CCompositeGeometryManager::doJobs: doing BP");
 
-			ok = astraCUDA3d::BP(((CCompositeGeometryManager::CProjectionPart*)j.pInput.get())->pGeom, inputMem, ((CCompositeGeometryManager::CVolumePart*)j.pOutput.get())->pGeom, outputMem, voxelSuperSampling, densityWeighting);
+			ok = astraCUDA3d::BP(((CCompositeGeometryManager::CProjectionPart*)j.pInput.get())->pGeom, srcMem->hnd, ((CCompositeGeometryManager::CVolumePart*)j.pOutput.get())->pGeom, dstMem->hnd, voxelSuperSampling, densityWeighting);
 			if (!ok) ASTRA_ERROR("Error performing sub-BP");
 			ASTRA_DEBUG("CCompositeGeometryManager::doJobs: BP done");
 		}
@@ -1292,7 +1461,7 @@ static bool doJob(const CCompositeGeometryManager::TJobSet::const_iterator& iter
 			} else {
 				ASTRA_DEBUG("CCompositeGeometryManager::doJobs: doing FDK");
 
-				ok = astraCUDA3d::FDK(((CCompositeGeometryManager::CProjectionPart*)j.pInput.get())->pGeom, inputMem, ((CCompositeGeometryManager::CVolumePart*)j.pOutput.get())->pGeom, outputMem, j.FDKSettings.bShortScan, j.FDKSettings.pfFilter);
+				ok = astraCUDA3d::FDK(((CCompositeGeometryManager::CProjectionPart*)j.pInput.get())->pGeom, srcMem->hnd, ((CCompositeGeometryManager::CVolumePart*)j.pOutput.get())->pGeom, dstMem->hnd, j.FDKSettings.bShortScan, j.FDKSettings.pfFilter);
 				if (!ok) ASTRA_ERROR("Error performing sub-FDK");
 				ASTRA_DEBUG("CCompositeGeometryManager::doJobs: FDK done");
 			}
@@ -1302,17 +1471,20 @@ static bool doJob(const CCompositeGeometryManager::TJobSet::const_iterator& iter
 			assert(false);
 		}
 
-		ok = astraCUDA3d::freeGPUMemory(inputMem);
+		ok = srcMem->freeGPUMemory();
 		if (!ok) ASTRA_ERROR("Error freeing GPU memory");
 
+		delete srcMem;
 	}
 
-	ok = astraCUDA3d::copyFromGPUMemory(dst, outputMem, dstdims);
+	ok = dstMem->copyFromGPUMemory(dstdims);
 	if (!ok) ASTRA_ERROR("Error copying output data from GPU");
 	
-	ok = astraCUDA3d::freeGPUMemory(outputMem);
+	ok = dstMem->freeGPUMemory();
 	if (!ok) ASTRA_ERROR("Error freeing GPU memory");
 
+	delete dstMem;
+
 	return true;
 }
 
@@ -1455,6 +1627,8 @@ void CCompositeGeometryManager::setGPUIndices(const std::vector<int>& GPUIndices
 
 bool CCompositeGeometryManager::doJobs(TJobList &jobs)
 {
+	// TODO: Proper clean up if substeps fail (Or as proper as possible)
+
 	ASTRA_DEBUG("CCompositeGeometryManager::doJobs");
 
 	// Sort job list into job set by output part
diff --git a/src/CudaBackProjectionAlgorithm3D.cpp b/src/CudaBackProjectionAlgorithm3D.cpp
index 223a9a4..27bb968 100644
--- a/src/CudaBackProjectionAlgorithm3D.cpp
+++ b/src/CudaBackProjectionAlgorithm3D.cpp
@@ -60,8 +60,8 @@ CCudaBackProjectionAlgorithm3D::CCudaBackProjectionAlgorithm3D()
 //----------------------------------------------------------------------------------------
 // Constructor with initialization
 CCudaBackProjectionAlgorithm3D::CCudaBackProjectionAlgorithm3D(CProjector3D* _pProjector, 
-								   CFloat32ProjectionData3DMemory* _pProjectionData, 
-								   CFloat32VolumeData3DMemory* _pReconstruction)
+								   CFloat32ProjectionData3D* _pProjectionData, 
+								   CFloat32VolumeData3D* _pReconstruction)
 {
 	_clear();
 	initialize(_pProjector, _pProjectionData, _pReconstruction);
@@ -145,8 +145,8 @@ bool CCudaBackProjectionAlgorithm3D::initialize(const Config& _cfg)
 //----------------------------------------------------------------------------------------
 // Initialize - C++
 bool CCudaBackProjectionAlgorithm3D::initialize(CProjector3D* _pProjector, 
-								  CFloat32ProjectionData3DMemory* _pSinogram, 
-								  CFloat32VolumeData3DMemory* _pReconstruction)
+								  CFloat32ProjectionData3D* _pSinogram, 
+								  CFloat32VolumeData3D* _pReconstruction)
 {
 	// if already initialized, clear first
 	if (m_bIsInitialized) {
@@ -187,17 +187,21 @@ void CCudaBackProjectionAlgorithm3D::run(int _iNrIterations)
 	// check initialized
 	ASTRA_ASSERT(m_bIsInitialized);
 
-	CFloat32ProjectionData3DMemory* pSinoMem = dynamic_cast<CFloat32ProjectionData3DMemory*>(m_pSinogram);
+	CFloat32ProjectionData3D* pSinoMem = dynamic_cast<CFloat32ProjectionData3D*>(m_pSinogram);
 	ASTRA_ASSERT(pSinoMem);
-	CFloat32VolumeData3DMemory* pReconMem = dynamic_cast<CFloat32VolumeData3DMemory*>(m_pReconstruction);
+	CFloat32VolumeData3D* pReconMem = dynamic_cast<CFloat32VolumeData3D*>(m_pReconstruction);
 	ASTRA_ASSERT(pReconMem);
 
 	const CProjectionGeometry3D* projgeom = pSinoMem->getGeometry();
 	const CVolumeGeometry3D& volgeom = *pReconMem->getGeometry();
 
 	if (m_bSIRTWeighting) {
-		astraCudaBP_SIRTWeighted(pReconMem->getData(),
-		                         pSinoMem->getDataConst(),
+		CFloat32ProjectionData3DMemory* pSinoMemory = dynamic_cast<CFloat32ProjectionData3DMemory*>(m_pSinogram);
+		ASTRA_ASSERT(pSinoMemory);
+		CFloat32VolumeData3DMemory* pReconMemory = dynamic_cast<CFloat32VolumeData3DMemory*>(m_pReconstruction);
+		ASTRA_ASSERT(pReconMemory);
+		astraCudaBP_SIRTWeighted(pReconMemory->getData(),
+		                         pSinoMemory->getDataConst(),
 		                         &volgeom, projgeom,
 		                         m_iGPUIndex, m_iVoxelSuperSampling);
 	} else {
diff --git a/src/CudaFDKAlgorithm3D.cpp b/src/CudaFDKAlgorithm3D.cpp
index d02db6d..d503351 100644
--- a/src/CudaFDKAlgorithm3D.cpp
+++ b/src/CudaFDKAlgorithm3D.cpp
@@ -59,8 +59,8 @@ CCudaFDKAlgorithm3D::CCudaFDKAlgorithm3D()
 //----------------------------------------------------------------------------------------
 // Constructor with initialization
 CCudaFDKAlgorithm3D::CCudaFDKAlgorithm3D(CProjector3D* _pProjector, 
-								   CFloat32ProjectionData3DMemory* _pProjectionData, 
-								   CFloat32VolumeData3DMemory* _pReconstruction)
+								   CFloat32ProjectionData3D* _pProjectionData, 
+								   CFloat32VolumeData3D* _pReconstruction)
 {
 	_clear();
 	initialize(_pProjector, _pProjectionData, _pReconstruction);
@@ -179,8 +179,8 @@ bool CCudaFDKAlgorithm3D::initialize(const Config& _cfg)
 //----------------------------------------------------------------------------------------
 // Initialize - C++
 bool CCudaFDKAlgorithm3D::initialize(CProjector3D* _pProjector, 
-								  CFloat32ProjectionData3DMemory* _pSinogram, 
-								  CFloat32VolumeData3DMemory* _pReconstruction)
+								  CFloat32ProjectionData3D* _pSinogram, 
+								  CFloat32VolumeData3D* _pReconstruction)
 {
 	// if already initialized, clear first
 	if (m_bIsInitialized) {
@@ -225,9 +225,9 @@ void CCudaFDKAlgorithm3D::run(int _iNrIterations)
 
 	ASTRA_ASSERT(conegeom);
 
-	CFloat32ProjectionData3DMemory* pSinoMem = dynamic_cast<CFloat32ProjectionData3DMemory*>(m_pSinogram);
+	CFloat32ProjectionData3D* pSinoMem = dynamic_cast<CFloat32ProjectionData3D*>(m_pSinogram);
 	ASTRA_ASSERT(pSinoMem);
-	CFloat32VolumeData3DMemory* pReconMem = dynamic_cast<CFloat32VolumeData3DMemory*>(m_pReconstruction);
+	CFloat32VolumeData3D* pReconMem = dynamic_cast<CFloat32VolumeData3D*>(m_pReconstruction);
 	ASTRA_ASSERT(pReconMem);
 
 	const float *filter = NULL;
diff --git a/src/CudaForwardProjectionAlgorithm3D.cpp b/src/CudaForwardProjectionAlgorithm3D.cpp
index 6783093..ce808eb 100644
--- a/src/CudaForwardProjectionAlgorithm3D.cpp
+++ b/src/CudaForwardProjectionAlgorithm3D.cpp
@@ -101,14 +101,14 @@ bool CCudaForwardProjectionAlgorithm3D::initialize(const Config& _cfg)
 	node = _cfg.self.getSingleNode("ProjectionDataId");
 	ASTRA_CONFIG_CHECK(node, "CudaForwardProjection3D", "No ProjectionDataId tag specified.");
 	id = node.getContentInt();
-	m_pProjections = dynamic_cast<CFloat32ProjectionData3DMemory*>(CData3DManager::getSingleton().get(id));
+	m_pProjections = dynamic_cast<CFloat32ProjectionData3D*>(CData3DManager::getSingleton().get(id));
 	CC.markNodeParsed("ProjectionDataId");
 
 	// reconstruction data
 	node = _cfg.self.getSingleNode("VolumeDataId");
 	ASTRA_CONFIG_CHECK(node, "CudaForwardProjection3D", "No VolumeDataId tag specified.");
 	id = node.getContentInt();
-	m_pVolume = dynamic_cast<CFloat32VolumeData3DMemory*>(CData3DManager::getSingleton().get(id));
+	m_pVolume = dynamic_cast<CFloat32VolumeData3D*>(CData3DManager::getSingleton().get(id));
 	CC.markNodeParsed("VolumeDataId");
 
 	// optional: projector
@@ -140,8 +140,8 @@ bool CCudaForwardProjectionAlgorithm3D::initialize(const Config& _cfg)
 
 
 bool CCudaForwardProjectionAlgorithm3D::initialize(CProjector3D* _pProjector, 
-                                  CFloat32ProjectionData3DMemory* _pProjections, 
-                                  CFloat32VolumeData3DMemory* _pVolume,
+                                  CFloat32ProjectionData3D* _pProjections, 
+                                  CFloat32VolumeData3D* _pVolume,
                                   int _iGPUindex, int _iDetectorSuperSampling)
 {
 	m_pProjector = _pProjector;
diff --git a/src/Float32Data3D.cpp b/src/Float32Data3D.cpp
index cad1f18..cc824bd 100644
--- a/src/Float32Data3D.cpp
+++ b/src/Float32Data3D.cpp
@@ -28,6 +28,10 @@ along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
 #include "astra/Float32Data3D.h"
 #include <sstream>
 
+#ifdef ASTRA_CUDA
+#include "../../cuda/3d/mem3d.h"
+#endif
+
 using namespace std;
 
 namespace astra {
@@ -60,7 +64,5 @@ std::string CFloat32Data3D::description() const
 	if (getType() == CFloat32Data3D::VOLUME) res << " volume data \t";
 	return res.str();
 }
-//----------------------------------------------------------------------------------------
-
 
 } // end namespace astra
diff --git a/src/Float32Data3DGPU.cpp b/src/Float32Data3DGPU.cpp
new file mode 100644
index 0000000..cd9c4ad
--- /dev/null
+++ b/src/Float32Data3DGPU.cpp
@@ -0,0 +1,98 @@
+/*
+-----------------------------------------------------------------------
+Copyright: 2010-2015, iMinds-Vision Lab, University of Antwerp
+           2014-2015, CWI, Amsterdam
+
+Contact: astra@uantwerpen.be
+Website: http://sf.net/projects/astra-toolbox
+
+This file is part of the ASTRA Toolbox.
+
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/Float32Data3DGPU.h"
+
+namespace astra {
+
+//----------------------------------------------------------------------------------------
+// Default constructor.
+CFloat32Data3DGPU::CFloat32Data3DGPU()
+{
+	_clear();
+	m_bInitialized = false;
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor.
+CFloat32Data3DGPU::~CFloat32Data3DGPU() 
+{
+	if (m_bInitialized)
+	{
+		_unInit();
+	}
+}
+
+//----------------------------------------------------------------------------------------
+// Initializes an instance of the CFloat32Data3DGPU class with pre-allocated memory
+bool CFloat32Data3DGPU::_initialize(int _iWidth, int _iHeight, int _iDepth, astraCUDA3d::MemHandle3D _hnd)
+{
+	// basic checks
+	ASTRA_ASSERT(_iWidth > 0);
+	ASTRA_ASSERT(_iHeight > 0);
+	ASTRA_ASSERT(_iDepth > 0);
+	//ASTRA_ASSERT(_pCustomMemory != NULL);
+
+	if (m_bInitialized) {
+		_unInit();
+	}
+
+	// calculate size
+	m_iWidth = _iWidth;
+	m_iHeight = _iHeight;
+	m_iDepth = _iDepth;
+	m_iSize = (size_t)m_iWidth * m_iHeight * m_iDepth;
+
+	m_hnd = _hnd;
+
+	// initialization complete
+	return true;
+}
+//----------------------------------------------------------------------------------------
+// Clear all member variables, setting all numeric variables to 0 and all pointers to NULL. 
+void CFloat32Data3DGPU::_clear()
+{
+	m_iWidth = 0;
+	m_iHeight = 0;
+	m_iDepth = 0;
+	m_iSize = 0;
+
+	m_hnd.d.reset();
+}
+
+//----------------------------------------------------------------------------------------
+// Un-initialize the object, bringing it back in the unitialized state.
+void CFloat32Data3DGPU::_unInit()
+{
+	ASTRA_ASSERT(m_bInitialized);
+
+	_clear();
+	m_bInitialized = false;
+}
+
+} // end namespace astra
diff --git a/src/Float32Data3DMemory.cpp b/src/Float32Data3DMemory.cpp
index 7e60527..5c5c310 100644
--- a/src/Float32Data3DMemory.cpp
+++ b/src/Float32Data3DMemory.cpp
@@ -163,7 +163,7 @@ bool CFloat32Data3DMemory::_initialize(int _iWidth, int _iHeight, int _iDepth, C
 	ASTRA_ASSERT(_iWidth > 0);
 	ASTRA_ASSERT(_iHeight > 0);
 	ASTRA_ASSERT(_iDepth > 0);
-	ASTRA_ASSERT(_pCustomMemory != NULL);
+	//ASTRA_ASSERT(_pCustomMemory != NULL);
 
 	if (m_bInitialized) {
 		_unInit();
diff --git a/src/Float32ProjectionData3DGPU.cpp b/src/Float32ProjectionData3DGPU.cpp
new file mode 100644
index 0000000..0e063d6
--- /dev/null
+++ b/src/Float32ProjectionData3DGPU.cpp
@@ -0,0 +1,71 @@
+/*
+-----------------------------------------------------------------------
+Copyright: 2010-2015, iMinds-Vision Lab, University of Antwerp
+           2014-2015, CWI, Amsterdam
+
+Contact: astra@uantwerpen.be
+Website: http://sf.net/projects/astra-toolbox
+
+This file is part of the ASTRA Toolbox.
+
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/Float32ProjectionData3DGPU.h"
+
+using namespace std;
+
+namespace astra
+{
+
+//----------------------------------------------------------------------------------------
+// Default constructor
+CFloat32ProjectionData3DGPU::CFloat32ProjectionData3DGPU() :
+	CFloat32Data3DGPU() 
+{
+	m_pGeometry = NULL;
+	m_bInitialized = false;
+}
+
+//----------------------------------------------------------------------------------------
+// Create an instance of the CFloat32ProjectionData2D class with pre-allocated data
+CFloat32ProjectionData3DGPU::CFloat32ProjectionData3DGPU(CProjectionGeometry3D* _pGeometry, astraCUDA3d::MemHandle3D _hnd)
+{
+	m_bInitialized = false;
+	m_bInitialized = initialize(_pGeometry, _hnd);
+}
+
+
+//----------------------------------------------------------------------------------------
+// Destructor
+CFloat32ProjectionData3DGPU::~CFloat32ProjectionData3DGPU() 
+{
+	delete m_pGeometry;
+	m_pGeometry = 0;
+}
+
+//----------------------------------------------------------------------------------------
+// Initialization
+bool CFloat32ProjectionData3DGPU::initialize(CProjectionGeometry3D* _pGeometry, astraCUDA3d::MemHandle3D _hnd)
+{
+	m_pGeometry = _pGeometry->clone();
+	m_bInitialized = _initialize(m_pGeometry->getDetectorColCount(), m_pGeometry->getProjectionCount(), m_pGeometry->getDetectorRowCount(), _hnd);
+	return m_bInitialized;
+}
+
+} // end namespace astra
diff --git a/src/Float32ProjectionData3DMemory.cpp b/src/Float32ProjectionData3DMemory.cpp
index 81daf9e..69033d5 100644
--- a/src/Float32ProjectionData3DMemory.cpp
+++ b/src/Float32ProjectionData3DMemory.cpp
@@ -114,7 +114,7 @@ bool CFloat32ProjectionData3DMemory::initialize(CProjectionGeometry3D* _pGeometr
 
 //----------------------------------------------------------------------------------------
 // Initialization
-bool CFloat32ProjectionData3DMemory::initialize(CProjectionGeometry3D* _pGeometry, CFloat32CustomMemory* _pCustomMemory) 
+bool CFloat32ProjectionData3DMemory::initialize(CProjectionGeometry3D* _pGeometry, CFloat32CustomMemory* _pCustomMemory)
 {
 	m_pGeometry = _pGeometry->clone();
 	m_bInitialized = _initialize(m_pGeometry->getDetectorColCount(), m_pGeometry->getProjectionCount(), m_pGeometry->getDetectorRowCount(), _pCustomMemory);
diff --git a/src/Float32VolumeData3DGPU.cpp b/src/Float32VolumeData3DGPU.cpp
new file mode 100644
index 0000000..82a222f
--- /dev/null
+++ b/src/Float32VolumeData3DGPU.cpp
@@ -0,0 +1,71 @@
+/*
+-----------------------------------------------------------------------
+Copyright: 2010-2015, iMinds-Vision Lab, University of Antwerp
+           2014-2015, CWI, Amsterdam
+
+Contact: astra@uantwerpen.be
+Website: http://sf.net/projects/astra-toolbox
+
+This file is part of the ASTRA Toolbox.
+
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/Float32VolumeData3DGPU.h"
+
+using namespace std;
+
+namespace astra
+{
+
+//----------------------------------------------------------------------------------------
+// Default constructor
+CFloat32VolumeData3DGPU::CFloat32VolumeData3DGPU() :
+	CFloat32Data3DGPU() 
+{
+	m_pGeometry = NULL;
+	m_bInitialized = false;
+}
+
+//----------------------------------------------------------------------------------------
+// Create an instance of the CFloat32VolumeData2D class with pre-allocated data
+CFloat32VolumeData3DGPU::CFloat32VolumeData3DGPU(CVolumeGeometry3D* _pGeometry, astraCUDA3d::MemHandle3D _hnd)
+{
+	m_bInitialized = false;
+	m_bInitialized = initialize(_pGeometry, _hnd);
+}
+
+
+//----------------------------------------------------------------------------------------
+// Destructor
+CFloat32VolumeData3DGPU::~CFloat32VolumeData3DGPU() 
+{
+	delete m_pGeometry;
+	m_pGeometry = 0;
+}
+
+//----------------------------------------------------------------------------------------
+// Initialization
+bool CFloat32VolumeData3DGPU::initialize(CVolumeGeometry3D* _pGeometry, astraCUDA3d::MemHandle3D _hnd)
+{
+	m_pGeometry = _pGeometry->clone();
+	m_bInitialized = _initialize(m_pGeometry->getGridColCount(), m_pGeometry->getGridRowCount(), m_pGeometry->getGridSliceCount(), _hnd);
+	return m_bInitialized;
+}
+
+} // end namespace astra
diff --git a/src/Float32VolumeData3DMemory.cpp b/src/Float32VolumeData3DMemory.cpp
index 9f81c85..27ae87b 100644
--- a/src/Float32VolumeData3DMemory.cpp
+++ b/src/Float32VolumeData3DMemory.cpp
@@ -114,7 +114,7 @@ bool CFloat32VolumeData3DMemory::initialize(CVolumeGeometry3D* _pGeometry, float
 }
 //----------------------------------------------------------------------------------------
 // Initialization
-bool CFloat32VolumeData3DMemory::initialize(CVolumeGeometry3D* _pGeometry, CFloat32CustomMemory* _pCustomMemory) 
+bool CFloat32VolumeData3DMemory::initialize(CVolumeGeometry3D* _pGeometry, CFloat32CustomMemory* _pCustomMemory)
 {
 	m_pGeometry = _pGeometry->clone();
 	m_bInitialized = _initialize(m_pGeometry->getGridColCount(), m_pGeometry->getGridRowCount(), m_pGeometry->getGridSliceCount(), _pCustomMemory);
-- 
cgit v1.2.3