1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-31 08:13:04 +04:00

refactored gpu::Stream (minor fixes)

This commit is contained in:
Vladislav Vinogradov
2013-04-16 17:43:49 +04:00
parent a52af84dcf
commit 76f4b02b06
16 changed files with 238 additions and 422 deletions
+40 -38
View File
@@ -51,8 +51,7 @@
#include "opencv2/core.hpp"
#include "opencv2/core/gpu_types.hpp"
namespace cv { namespace gpu
{
namespace cv { namespace gpu {
//////////////////////////////// GpuMat ///////////////////////////////
@@ -337,59 +336,56 @@ CV_EXPORTS void registerPageLocked(Mat& m);
//! unmaps the memory of matrix m, and makes it pageable again
CV_EXPORTS void unregisterPageLocked(Mat& m);
//////////////////////////////// CudaStream ////////////////////////////////
///////////////////////////////// Stream //////////////////////////////////
// Encapculates Cuda Stream. Provides interface for async coping.
// Passed to each function that supports async kernel execution.
// Reference counting is enabled
// Reference counting is enabled.
class CV_EXPORTS Stream
{
typedef void (Stream::*bool_type)() const;
void this_type_does_not_support_comparisons() const {}
public:
typedef void (*StreamCallback)(int status, void* userData);
//! creates a new asynchronous stream
Stream();
~Stream();
Stream(const Stream&);
Stream& operator =(const Stream&);
//! queries an asynchronous stream for completion status
bool queryIfComplete() const;
bool queryIfComplete();
//! waits for stream tasks to complete
void waitForCompletion();
//! downloads asynchronously
// Warning! cv::Mat must point to page locked memory (i.e. to CudaMem data or to its subMat)
void enqueueDownload(const GpuMat& src, CudaMem& dst);
void enqueueDownload(const GpuMat& src, Mat& dst);
//! uploads asynchronously
// Warning! cv::Mat must point to page locked memory (i.e. to CudaMem data or to its ROI)
void enqueueUpload(const CudaMem& src, GpuMat& dst);
void enqueueUpload(const Mat& src, GpuMat& dst);
//! copy asynchronously
void enqueueCopy(const GpuMat& src, GpuMat& dst);
//! memory set asynchronously
void enqueueMemSet(GpuMat& src, Scalar val);
void enqueueMemSet(GpuMat& src, Scalar val, const GpuMat& mask);
//! converts matrix type, ex from float to uchar depending on type
void enqueueConvert(const GpuMat& src, GpuMat& dst, int dtype, double a = 1, double b = 0);
//! adds a callback to be called on the host after all currently enqueued items in the stream have completed
typedef void (*StreamCallback)(Stream& stream, int status, void* userData);
void enqueueHostCallback(StreamCallback callback, void* userData);
//! return Stream object for default CUDA stream
static Stream& Null();
operator bool() const;
//! returns true if stream object is not default (!= 0)
operator bool_type() const;
// obsolete methods
void enqueueDownload(const GpuMat& src, OutputArray dst);
void enqueueUpload(InputArray src, GpuMat& dst);
void enqueueCopy(const GpuMat& src, OutputArray dst);
void enqueueMemSet(GpuMat& src, Scalar val);
void enqueueMemSet(GpuMat& src, Scalar val, InputArray mask);
void enqueueConvert(const GpuMat& src, OutputArray dst, int dtype, double alpha = 1.0, double beta = 0.0);
class Impl;
private:
struct Impl;
explicit Stream(Impl* impl);
void create();
void release();
Impl *impl;
Ptr<Impl> impl_;
Stream(const Ptr<Impl>& impl);
friend struct StreamAccessor;
};
@@ -498,7 +494,13 @@ CV_EXPORTS void printCudaDeviceInfo(int device);
CV_EXPORTS void printShortCudaDeviceInfo(int device);
}} // cv::gpu
}} // namespace cv { namespace gpu {
namespace cv {
template <> CV_EXPORTS void Ptr<cv::gpu::Stream::Impl>::delete_obj();
}
#include "opencv2/core/gpu.inl.hpp"
+46 -3
View File
@@ -46,8 +46,7 @@
#include "opencv2/core/gpu.hpp"
namespace cv { namespace gpu
{
namespace cv { namespace gpu {
//////////////////////////////// GpuMat ///////////////////////////////
@@ -524,7 +523,51 @@ void swap(CudaMem& a, CudaMem& b)
a.swap(b);
}
}} // namespace cv { namespace gpu
//////////////////////////////// Stream ///////////////////////////////
inline
void Stream::enqueueDownload(const GpuMat& src, OutputArray dst)
{
src.download(dst, *this);
}
inline
void Stream::enqueueUpload(InputArray src, GpuMat& dst)
{
dst.upload(src, *this);
}
inline
void Stream::enqueueCopy(const GpuMat& src, OutputArray dst)
{
src.copyTo(dst, *this);
}
inline
void Stream::enqueueMemSet(GpuMat& src, Scalar val)
{
src.setTo(val, *this);
}
inline
void Stream::enqueueMemSet(GpuMat& src, Scalar val, InputArray mask)
{
src.setTo(val, mask, *this);
}
inline
void Stream::enqueueConvert(const GpuMat& src, OutputArray dst, int dtype, double alpha, double beta)
{
src.convertTo(dst, dtype, alpha, beta, *this);
}
inline
Stream::Stream(const Ptr<Impl>& impl)
: impl_(impl)
{
}
}} // namespace cv { namespace gpu {
//////////////////////////////// Mat ////////////////////////////////
+82 -168
View File
@@ -45,170 +45,103 @@
using namespace cv;
using namespace cv::gpu;
#if !defined (HAVE_CUDA)
#ifndef HAVE_CUDA
cv::gpu::Stream::Stream() { throw_no_cuda(); }
cv::gpu::Stream::~Stream() {}
cv::gpu::Stream::Stream(const Stream&) { throw_no_cuda(); }
Stream& cv::gpu::Stream::operator=(const Stream&) { throw_no_cuda(); return *this; }
bool cv::gpu::Stream::queryIfComplete() { throw_no_cuda(); return false; }
void cv::gpu::Stream::waitForCompletion() { throw_no_cuda(); }
void cv::gpu::Stream::enqueueDownload(const GpuMat&, Mat&) { throw_no_cuda(); }
void cv::gpu::Stream::enqueueDownload(const GpuMat&, CudaMem&) { throw_no_cuda(); }
void cv::gpu::Stream::enqueueUpload(const CudaMem&, GpuMat&) { throw_no_cuda(); }
void cv::gpu::Stream::enqueueUpload(const Mat&, GpuMat&) { throw_no_cuda(); }
void cv::gpu::Stream::enqueueCopy(const GpuMat&, GpuMat&) { throw_no_cuda(); }
void cv::gpu::Stream::enqueueMemSet(GpuMat&, Scalar) { throw_no_cuda(); }
void cv::gpu::Stream::enqueueMemSet(GpuMat&, Scalar, const GpuMat&) { throw_no_cuda(); }
void cv::gpu::Stream::enqueueConvert(const GpuMat&, GpuMat&, int, double, double) { throw_no_cuda(); }
void cv::gpu::Stream::enqueueHostCallback(StreamCallback, void*) { throw_no_cuda(); }
Stream& cv::gpu::Stream::Null() { throw_no_cuda(); static Stream s; return s; }
cv::gpu::Stream::operator bool() const { throw_no_cuda(); return false; }
cv::gpu::Stream::Stream(Impl*) { throw_no_cuda(); }
void cv::gpu::Stream::create() { throw_no_cuda(); }
void cv::gpu::Stream::release() { throw_no_cuda(); }
#else /* !defined (HAVE_CUDA) */
struct Stream::Impl
class cv::gpu::Stream::Impl
{
static cudaStream_t getStream(const Impl* impl)
public:
Impl(void* ptr = 0)
{
return impl ? impl->stream : 0;
(void) ptr;
throw_no_cuda();
}
cudaStream_t stream;
int ref_counter;
};
#else
class cv::gpu::Stream::Impl
{
public:
cudaStream_t stream;
Impl();
Impl(cudaStream_t stream);
~Impl();
};
cv::gpu::Stream::Impl::Impl() : stream(0)
{
cudaSafeCall( cudaStreamCreate(&stream) );
}
cv::gpu::Stream::Impl::Impl(cudaStream_t stream_) : stream(stream_)
{
}
cv::gpu::Stream::Impl::~Impl()
{
if (stream)
cudaStreamDestroy(stream);
}
cudaStream_t cv::gpu::StreamAccessor::getStream(const Stream& stream)
{
return Stream::Impl::getStream(stream.impl);
return stream.impl_->stream;
}
cv::gpu::Stream::Stream() : impl(0)
#endif
cv::gpu::Stream::Stream()
{
create();
#ifndef HAVE_CUDA
throw_no_cuda();
#else
impl_ = new Impl;
#endif
}
cv::gpu::Stream::~Stream()
bool cv::gpu::Stream::queryIfComplete() const
{
release();
}
cv::gpu::Stream::Stream(const Stream& stream) : impl(stream.impl)
{
if (impl)
CV_XADD(&impl->ref_counter, 1);
}
Stream& cv::gpu::Stream::operator =(const Stream& stream)
{
if (this != &stream)
{
release();
impl = stream.impl;
if (impl)
CV_XADD(&impl->ref_counter, 1);
}
return *this;
}
bool cv::gpu::Stream::queryIfComplete()
{
cudaStream_t stream = Impl::getStream(impl);
cudaError_t err = cudaStreamQuery(stream);
#ifndef HAVE_CUDA
throw_no_cuda();
return false;
#else
cudaError_t err = cudaStreamQuery(impl_->stream);
if (err == cudaErrorNotReady || err == cudaSuccess)
return err == cudaSuccess;
cudaSafeCall(err);
return false;
#endif
}
void cv::gpu::Stream::waitForCompletion()
{
cudaStream_t stream = Impl::getStream(impl);
cudaSafeCall( cudaStreamSynchronize(stream) );
#ifndef HAVE_CUDA
throw_no_cuda();
#else
cudaSafeCall( cudaStreamSynchronize(impl_->stream) );
#endif
}
void cv::gpu::Stream::enqueueDownload(const GpuMat& src, Mat& dst)
{
// if not -> allocation will be done, but after that dst will not point to page locked memory
CV_Assert( src.size() == dst.size() && src.type() == dst.type() );
cudaStream_t stream = Impl::getStream(impl);
size_t bwidth = src.cols * src.elemSize();
cudaSafeCall( cudaMemcpy2DAsync(dst.data, dst.step, src.data, src.step, bwidth, src.rows, cudaMemcpyDeviceToHost, stream) );
}
void cv::gpu::Stream::enqueueDownload(const GpuMat& src, CudaMem& dst)
{
dst.create(src.size(), src.type());
cudaStream_t stream = Impl::getStream(impl);
size_t bwidth = src.cols * src.elemSize();
cudaSafeCall( cudaMemcpy2DAsync(dst.data, dst.step, src.data, src.step, bwidth, src.rows, cudaMemcpyDeviceToHost, stream) );
}
void cv::gpu::Stream::enqueueUpload(const CudaMem& src, GpuMat& dst)
{
dst.create(src.size(), src.type());
cudaStream_t stream = Impl::getStream(impl);
size_t bwidth = src.cols * src.elemSize();
cudaSafeCall( cudaMemcpy2DAsync(dst.data, dst.step, src.data, src.step, bwidth, src.rows, cudaMemcpyHostToDevice, stream) );
}
void cv::gpu::Stream::enqueueUpload(const Mat& src, GpuMat& dst)
{
dst.create(src.size(), src.type());
cudaStream_t stream = Impl::getStream(impl);
size_t bwidth = src.cols * src.elemSize();
cudaSafeCall( cudaMemcpy2DAsync(dst.data, dst.step, src.data, src.step, bwidth, src.rows, cudaMemcpyHostToDevice, stream) );
}
void cv::gpu::Stream::enqueueCopy(const GpuMat& src, GpuMat& dst)
{
dst.create(src.size(), src.type());
cudaStream_t stream = Impl::getStream(impl);
size_t bwidth = src.cols * src.elemSize();
cudaSafeCall( cudaMemcpy2DAsync(dst.data, dst.step, src.data, src.step, bwidth, src.rows, cudaMemcpyDeviceToDevice, stream) );
}
void cv::gpu::Stream::enqueueMemSet(GpuMat& src, Scalar val)
{
src.setTo(val, *this);
}
void cv::gpu::Stream::enqueueMemSet(GpuMat& src, Scalar val, const GpuMat& mask)
{
src.setTo(val, mask, *this);
}
void cv::gpu::Stream::enqueueConvert(const GpuMat& src, GpuMat& dst, int dtype, double alpha, double beta)
{
src.convertTo(dst, dtype, alpha, beta, *this);
}
#if CUDART_VERSION >= 5000
#if defined(HAVE_CUDA) && (CUDART_VERSION >= 5000)
namespace
{
struct CallbackData
{
cv::gpu::Stream::StreamCallback callback;
Stream::StreamCallback callback;
void* userData;
Stream stream;
CallbackData(Stream::StreamCallback callback_, void* userData_) : callback(callback_), userData(userData_) {}
};
void CUDART_CB cudaStreamCallback(cudaStream_t, cudaError_t status, void* userData)
{
CallbackData* data = reinterpret_cast<CallbackData*>(userData);
data->callback(data->stream, static_cast<int>(status), data->userData);
data->callback(static_cast<int>(status), data->userData);
delete data;
}
}
@@ -217,58 +150,39 @@ namespace
void cv::gpu::Stream::enqueueHostCallback(StreamCallback callback, void* userData)
{
#if CUDART_VERSION >= 5000
CallbackData* data = new CallbackData;
data->callback = callback;
data->userData = userData;
data->stream = *this;
cudaStream_t stream = Impl::getStream(impl);
cudaSafeCall( cudaStreamAddCallback(stream, cudaStreamCallback, data, 0) );
#else
#ifndef HAVE_CUDA
(void) callback;
(void) userData;
CV_Error(CV_StsNotImplemented, "This function requires CUDA 5.0");
throw_no_cuda();
#else
#if CUDART_VERSION < 5000
(void) callback;
(void) userData;
CV_Error(cv::Error::StsNotImplemented, "This function requires CUDA 5.0");
#else
CallbackData* data = new CallbackData(callback, userData);
cudaSafeCall( cudaStreamAddCallback(impl_->stream, cudaStreamCallback, data, 0) );
#endif
#endif
}
cv::gpu::Stream& cv::gpu::Stream::Null()
Stream& cv::gpu::Stream::Null()
{
static Stream s((Impl*) 0);
static Stream s(new Impl(0));
return s;
}
cv::gpu::Stream::operator bool() const
cv::gpu::Stream::operator bool_type() const
{
return impl && impl->stream;
#ifndef HAVE_CUDA
return 0;
#else
return (impl_->stream != 0) ? &Stream::this_type_does_not_support_comparisons : 0;
#endif
}
cv::gpu::Stream::Stream(Impl* impl_) : impl(impl_)
template <> void cv::Ptr<Stream::Impl>::delete_obj()
{
if (obj) delete obj;
}
void cv::gpu::Stream::create()
{
if (impl)
release();
cudaStream_t stream;
cudaSafeCall( cudaStreamCreate( &stream ) );
impl = (Stream::Impl*) fastMalloc(sizeof(Stream::Impl));
impl->stream = stream;
impl->ref_counter = 1;
}
void cv::gpu::Stream::release()
{
if (impl && CV_XADD(&impl->ref_counter, -1) == 1)
{
cudaSafeCall( cudaStreamDestroy(impl->stream) );
cv::fastFree(impl);
}
}
#endif /* !defined (HAVE_CUDA) */