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:
@@ -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,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
@@ -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) */
|
||||
|
||||
Reference in New Issue
Block a user