Eliminate upload/download for OpenCV cuda::GpuMat using shared memory?

I don’t know for sure, but my understanding or feeling so far is that you would have to allocate with a special allocator for sharing memory, so it should be done before.
I don’t know any way to test if a buffer has been allocated in unified memory. It may exist ways I don’t know, though, but I think the probabilty that you face an unexpected unified memory buffer from your code is very low, so is it worth a try?

I’d also suggest the following structure for your example:

//
//  SimpleTestGPU.cpp
//  Loads an image, calls a GPU enabled function that uses opencv GPUMat.
//  Eliminates copying from GPU device to CPU host using download for the result, but
//  still requires copying from a pre-existing image 
//

#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>
#include <stdio.h> 

// cuda stuff
#include <opencv2/cudaarithm.hpp>
// Nvidia cuda api
#include <cuda_runtime.h>

using namespace std;

void OpencvCudaProcess(const cv::cuda::GpuMat& d_original, cv::cuda::GpuMat& d_result) {
	// perform a GPU operation of some sort.  Using threshold for simple placeholder
	cv::cuda::threshold(d_original, d_result, 128.0, 255.0, cv::THRESH_BINARY);
}

int main(int argc, char *argv[]) {

	cv::namedWindow("original image", cv::WINDOW_AUTOSIZE);
	cv::namedWindow("modified image", cv::WINDOW_AUTOSIZE );
	cv::String filename = "/usr/share/visionworks/sources/data/lena.jpg";

	// Max size buffer. Be aware of your max number of channels and format size (UC, F32, F64) for computing max byte size 
	const unsigned int maxImageByteSize = 1920*1080*3;

	void *image_in, *image_out;
    	// allocate unified memory space for INPUT image 
    	if (cudaSuccess != cudaMallocManaged(&image_in, maxImageByteSize))
		return (-1);
     	// allocate unified memory space for OUTPUT image 
   	if (cudaSuccess != cudaMallocManaged(&image_out, maxImageByteSize))
		return (-2);

        /* Process image, this block may be in a loop */
	{
		cv::Mat read_img = cv::imread(filename);
		if (read_img.empty()) {
		    cout << "could not open or find the image" << endl;
		    return (-3);
		}

		/* Prepare appropriate Mats (headers for size and format, specifying our unified memory buffers */
 		cv::Mat image(read_img.rows, read_img.cols, read_img.type(), image_in);
		cv::Mat newimage(read_img.rows, read_img.cols, read_img.type(), image_out);

		/* Prepare appropriate GpuMats (headers for size and format, specifying our unified memory buffers */ 
		cv::cuda::GpuMat d_image(read_img.rows, read_img.cols, read_img.type(), image_in);
		cv::cuda::GpuMat d_newimage(read_img.rows, read_img.cols, read_img.type(), image_out);

// Both options should work, you would check timings for your case
//#define COPY_TO_CPU
#ifdef COPY_TO_CPU
		read_img.copyTo(image);
		if (image.data != image_in) {
			std::cerr << "Error: image data buffer changed from initial unified memory" << std::endl;
			return (-4);
		}
#else /* COPY_TO_GPU */
		d_image.upload(read_img);
		if (d_image.data != image_in) {
			std::cerr << "Error: d_image data buffer changed from initial unified memory" << std::endl;
			return (-5);
		}	
#endif

		/* Process image on GPU */
		OpencvCudaProcess(d_image, d_newimage);

		cv::imshow("original image", image);

		/* Display result from CPU Mat without copy */
		cv::imshow("modified image", newimage);

		/* Wait for key press */
		cv::waitKey(-1);
	}

	cudaFree(image_in);
	cudaFree(image_out);
	cv::destroyAllWindows();

	return 0;
}