diff --git a/CMakeLists.txt b/CMakeLists.txt
index 65b3fb9c01a1db2aaf46f59ae9fdfd67024fcfce..a4d3075786da3ac7b8cc95f74bd80933fc8ef49a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -175,7 +175,7 @@ check_include_file_cxx("opencv2/cudastereo.hpp" HAVE_OPENCVCUDA)
 find_program(CPPCHECK_FOUND cppcheck)
 if (CPPCHECK_FOUND)
 	message(STATUS "Found cppcheck: will perform source checks")
-	set(CMAKE_CXX_CPPCHECK "cppcheck" "-D__align__(A)" "-DCUDARTAPI" "--enable=warning,performance,portability,style" "--inline-suppr" "--std=c++11" "--suppress=*:*catch.hpp" "--suppress=*:*elas*" "--suppress=*:*nanogui*" "--suppress=*:*json.hpp" "--quiet")
+	set(CMAKE_CXX_CPPCHECK "cppcheck" "-D__align__(A)" "-DCUDARTAPI" "--enable=warning,performance,style" "--inline-suppr" "--std=c++11" "--suppress=*:*catch.hpp" "--suppress=*:*elas*" "--suppress=*:*nanogui*" "--suppress=*:*json.hpp" "--quiet")
 endif()
 
 # include_directories(${PROJECT_SOURCE_DIR}/common/cpp/include)
diff --git a/components/common/cpp/CMakeLists.txt b/components/common/cpp/CMakeLists.txt
index 8759e81039afede246d4f7e783531da98a1bc473..de0f7707c504447a16967625c2f01ab76e1218bb 100644
--- a/components/common/cpp/CMakeLists.txt
+++ b/components/common/cpp/CMakeLists.txt
@@ -21,7 +21,7 @@ target_include_directories(ftlcommon PUBLIC
 	$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
 	$<INSTALL_INTERFACE:include>
 	PRIVATE src)
-target_link_libraries(ftlcommon Threads::Threads ${OS_LIBS} ${OpenCV_LIBS} ${PCL_LIBRARIES} ${URIPARSER_LIBRARIES})
+target_link_libraries(ftlcommon Threads::Threads ${OS_LIBS} ${OpenCV_LIBS} ${PCL_LIBRARIES} ${URIPARSER_LIBRARIES} ${CUDA_LIBRARIES})
 
 add_subdirectory(test)
 
diff --git a/components/common/cpp/include/ftl/cuda_common.hpp b/components/common/cpp/include/ftl/cuda_common.hpp
index 09a1dd062ad62bd3e8c0c7384a201a8565573517..70a6a4ad6d4dc0def715979f9eaf348e621d103e 100644
--- a/components/common/cpp/include/ftl/cuda_common.hpp
+++ b/components/common/cpp/include/ftl/cuda_common.hpp
@@ -22,6 +22,12 @@
 namespace ftl {
 namespace cuda {
 
+bool initialise();
+
+bool hasCompute(int major, int minor);
+
+int deviceCount();
+
 /**
  * Represent a CUDA texture object. Instances of this class can be used on both
  * host and device. A texture object base cannot be constructed directly, it
@@ -142,6 +148,7 @@ TextureObject<T>::TextureObject(const cv::cuda::GpuMat &d) {
 	resDesc.res.pitch2D.height = d.rows;
 
 	cudaTextureDesc texDesc;
+	// cppcheck-suppress memsetClassFloat
 	memset(&texDesc, 0, sizeof(texDesc));
 	texDesc.readMode = cudaReadModeElementType;
 
@@ -175,6 +182,7 @@ TextureObject<T>::TextureObject(const cv::cuda::PtrStepSz<T> &d) {
 	resDesc.res.pitch2D.height = d.rows;
 
 	cudaTextureDesc texDesc;
+	// cppcheck-suppress memsetClassFloat
 	memset(&texDesc, 0, sizeof(texDesc));
 	texDesc.readMode = cudaReadModeElementType;
 
@@ -207,6 +215,7 @@ TextureObject<T>::TextureObject(T *ptr, int pitch, int width, int height) {
 	resDesc.res.pitch2D.height = height;
 
 	cudaTextureDesc texDesc;
+	// cppcheck-suppress memsetClassFloat
 	memset(&texDesc, 0, sizeof(texDesc));
 	texDesc.readMode = cudaReadModeElementType;
 
@@ -240,6 +249,7 @@ TextureObject<T>::TextureObject(size_t width, size_t height) {
 		resDesc.res.pitch2D.height = height;
 
 		cudaTextureDesc texDesc;
+		// cppcheck-suppress memsetClassFloat
 		memset(&texDesc, 0, sizeof(texDesc));
 		texDesc.readMode = cudaReadModeElementType;
 		cudaCreateTextureObject(&tex, &resDesc, &texDesc, NULL);
diff --git a/components/common/cpp/src/configuration.cpp b/components/common/cpp/src/configuration.cpp
index ef33ab93a1c93dc5c74ef6787cb47bceab49f71e..476b09cabb72a4b82e4832721c21fd552b2a562b 100644
--- a/components/common/cpp/src/configuration.cpp
+++ b/components/common/cpp/src/configuration.cpp
@@ -20,6 +20,7 @@
 #include <ftl/uri.hpp>
 #include <ftl/threads.hpp>
 #include <ftl/timer.hpp>
+#include <ftl/cuda_common.hpp>
 
 #include <fstream>
 #include <string>
@@ -519,6 +520,9 @@ Configurable *ftl::config::configure(int argc, char **argv, const std::string &r
 	// Some global settings
 	ftl::timer::setInterval(1000 / rootcfg->value("fps",20));
 
+	// Check CUDA
+	ftl::cuda::initialise();
+
 	int pool_size = rootcfg->value("thread_pool_factor", 2.0f)*std::thread::hardware_concurrency();
 	if (pool_size != ftl::pool.size()) ftl::pool.resize(pool_size);
 
diff --git a/components/common/cpp/src/cuda_common.cpp b/components/common/cpp/src/cuda_common.cpp
index 15fa9c94963bb073647f609176f3f022a084d4a0..b29c1df08ba14d61a17d8b7afce290b353c25ce6 100644
--- a/components/common/cpp/src/cuda_common.cpp
+++ b/components/common/cpp/src/cuda_common.cpp
@@ -2,6 +2,40 @@
 
 using ftl::cuda::TextureObjectBase;
 
+static int dev_count = 0;
+static std::vector<cudaDeviceProp> properties;
+
+bool ftl::cuda::initialise() {
+	// Do an initial CUDA check
+	cudaSafeCall(cudaGetDeviceCount(&dev_count));
+	CHECK_GE(dev_count, 1) << "No CUDA devices found";
+
+	LOG(INFO) << "CUDA Devices (" << dev_count << "):";
+
+	properties.resize(dev_count);
+	for (int i=0; i<dev_count; i++) {
+		cudaSafeCall(cudaGetDeviceProperties(&properties[i], i));
+		LOG(INFO) << " - " << properties[i].name;
+	}
+
+	return true;
+}
+
+bool ftl::cuda::hasCompute(int major, int minor) {
+	int dev = -1;
+	cudaSafeCall(cudaGetDevice(&dev));
+
+	if (dev > 0) {
+		return properties[dev].major > major ||
+			(properties[dev].major == major && properties[dev].minor >= minor);
+	}
+	return false;
+}
+
+int ftl::cuda::deviceCount() {
+	return dev_count;
+}
+
 TextureObjectBase::~TextureObjectBase() {
 	free();
 }
diff --git a/components/common/cpp/test/CMakeLists.txt b/components/common/cpp/test/CMakeLists.txt
index 2ef8e4338ae4e5bb3b39f4eaf8c88ec343fb1b95..f9c1773b92718fc79eb1e26c1d63c7668f12fa53 100644
--- a/components/common/cpp/test/CMakeLists.txt
+++ b/components/common/cpp/test/CMakeLists.txt
@@ -7,12 +7,13 @@ add_executable(configurable_unit
 	../src/configuration.cpp
 	../src/loguru.cpp
 	../src/ctpl_stl.cpp
+	../src/cuda_common.cpp
 	./configurable_unit.cpp
 )
 target_include_directories(configurable_unit PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../include")
 target_link_libraries(configurable_unit
 	${URIPARSER_LIBRARIES}
-	Threads::Threads ${OS_LIBS})
+	Threads::Threads ${OS_LIBS} ${OpenCV_LIBS} ${CUDA_LIBRARIES})
 
 ### URI ########################################################################
 add_executable(uri_unit