これは,GPU 上の(アラインメントが調整された)pitched memory をカプセル化した,シンプルな軽量クラスです.これは,nvcc でコンパイルされたコード,つまり,CUDA カーネルに渡すことを意図したものです.したがって,これは,OpenCV 内部やユーザが書いたデバイスコードで利用されます.そのメンバは,ホスト側とデバイス側の両方のコードから呼び出すことができます.
template <typename T> struct DevMem2D_
{
int cols;
int rows;
T* data;
size_t step;
DevMem2D_() : cols(0), rows(0), data(0), step(0){};
DevMem2D_(int rows_, int cols_, T *data_, size_t step_);
template <typename U>
explicit DevMem2D_(const DevMem2D_<U>& d);
typedef T elem_type;
enum { elem_size = sizeof(elem_type) };
__CV_GPU_HOST_DEVICE__ size_t elemSize() const;
/* 画像の指定行の先頭を指すポインタを返します. */
__CV_GPU_HOST_DEVICE__ T* ptr(int y = 0);
__CV_GPU_HOST_DEVICE__ const T* ptr(int y = 0) const;
};
これは DevMem2D _ と似た構造体ですが,内部にはポインタと行ステップ値のみが含まれています.パフォーマンス上の理由で,幅と高さのフィールドは除外されています.この構造体は,内部的利用や,デバイスコードを書くユーザのためのものです.
template<typename T> struct PtrStep_
{
T* data;
size_t step;
PtrStep_();
PtrStep_(const DevMem2D_<T>& mem);
typedef T elem_type;
enum { elem_size = sizeof(elem_type) };
__CV_GPU_HOST_DEVICE__ size_t elemSize() const;
__CV_GPU_HOST_DEVICE__ T* ptr(int y = 0);
__CV_GPU_HOST_DEVICE__ const T* ptr(int y = 0) const;
};
これは DevMem2D _ と似た構造体ですが,内部にはポインタと要素毎の行ステップ値のみが含まれています.パフォーマンス上の理由で,幅と高さのフィールドは除外されています.この構造体は, sizeof(T) が 256 の倍数である場合のみ,作成することができます.この構造体は,内部的利用や,デバイスコードを書くユーザのためのものです.
template<typename T> struct PtrElemStep_ : public PtrStep_<T>
{
PtrElemStep_(const DevMem2D_<T>& mem);
__CV_GPU_HOST_DEVICE__ T* ptr(int y = 0);
__CV_GPU_HOST_DEVICE__ const T* ptr(int y = 0) const;
};
参照カウンタを持つ,GPU メモリ用の基底ストレージクラス.このインタフェースは, Mat() インタフェースにいくつかの制限を加えたものとほぼ同様なので,使い方が問題になることはないでしょう.この制限とは,任意の次元がサポートされない(2次元のみ),データの参照を返す関数がない(GPU 上の参照は,CPUにとっては意味がないので),式テンプレートテクニックがサポートされない,という事です.最後の制限事項があるので,メモリの割り当てを引き起こす,行列の演算子オーバーロードには注意してください.GpuMat クラスは, cv::gpu::DevMem2D_ および cv::gpu::PtrStep_ に変換可能なので,カーネルに直接渡すことができます.
注意事項: Mat() とは対照的に,多くの場合 GpuMat::isContinuous() == false ,つまり,ハードウェア依存のサイズに行アラインメントが調整されます.また,1行の GpuMat は常に連続した行列になります.
class CV_EXPORTS GpuMat
{
public:
//! デフォルトコンストラクタ
GpuMat();
GpuMat(int rows, int cols, int type);
GpuMat(Size size, int type);
.....
//! Mat から GpuMat を作成.デバイスへのブロッキングアップロードを行います.
explicit GpuMat (const Mat& m);
//! nvcc でコンパイルされたコードに渡すための軽量な DevMem2D_ 構造体
// を返します.ここには,サイズ,データポインタ,ステップが含まれます.
template <class T> operator DevMem2D_<T>() const;
template <class T> operator PtrStep_<T>() const;
//! GpuMat へ,データをブロッキングアップロードします.
void upload(const cv::Mat& m);
void upload(const CudaMem& m, Stream& stream);
//! デバイスからホストメモリへデータをダウンロードします.ブロッキング呼び出しでs.
operator Mat() const;
void download(cv::Mat& m) const;
//! 非同期ダウンロードを行います.
void download(CudaMem& m, Stream& stream) const;
};
注意事項: static または global に割り当てられた GpuMat 変数をそのままに,つまりデストラクタ任せにするのは悪習です.何故なら,このような変数や CUDA コンテキストのデストラクトの順序は未定義であり,CUDAコンテキストが既に破壊されていた場合には,GPU メモリ解放関数がエラーを返すからです.
参考: Mat()
参照カウントを持つ,CUDAの特殊な種類のメモリ割り当て関数をラップしたクラス.このインタフェースも, Mat() と似ていますが,メモリ割り当ての種類を指定するパラメータが追加されています.
通常,この様な種類のメモリ割り当ては,サイズが制限される事に注意してください.詳細は, “CUDA 2.2 Pinned Memory APIs” ドキュメント,および “CUDA _ C Programming Guide” を参照してください.
class CV_EXPORTS CudaMem
{
public:
enum { ALLOC_PAGE_LOCKED = 1, ALLOC_ZEROCOPY = 2,
ALLOC_WRITE_COMBINED = 4 };
CudaMem(Size size, int type, int alloc_type = ALLOC_PAGE_LOCKED);
//! cv::Mat からデータをコピーして作成します.
explicit CudaMem(const Mat& m, int alloc_type = ALLOC_PAGE_LOCKED);
......
void create(Size size, int type, int alloc_type = ALLOC_PAGE_LOCKED);
//! CudaMem データへの参照カウンタを持たない行列ヘッダを返します.
Mat createMatHeader() const;
operator Mat() const;
//! ホストメモリをデバイスアドレス空間にマップします.
GpuMat createGpuMatHeader() const;
operator GpuMat() const;
// ホストメモリを GPU アドレス空間にマップできる否か.
static bool canMapHostMemory();
int alloc_type;
};
Mat()
CudaMem データ への参照カウンタを持たない ヘッダを作成します.
gpu::GpuMat() _
CPU メモリを GPU アドレス空間にマップし,参照カウンタを持たない ヘッダを作成します.これは, ALLOCZEROCOPYフラグを指定してメモリを割り当てが行われ,かつハードウェアがサポートしている場合のみ,実行できます(ノートPCでは,ビデオメモリとCPUメモリを共有する場合が多いので,アドレス空間のマップが可能で,余計なコピーが行われなくなります).
_
現在のハードウェアが,アドレス空間マッピング,および ALLOCZEROCOPYメモリ割り当てをサポートする場合に true を返します.
このクラスは,非同期呼び出しのキューがカプセル化されたクラスです.いくつかの関数は,オーバーロードで gpu::Stream() パラメータが追加されています.このオーバーロードは,初期化処理(出力バッファの割り当て,データのアップロード,など)を行い,GPUカーネルを開始し,結果が用意されるよりも前に retrun します.すべての処理が完了したかどうかのチェックは, gpu::Stream::queryIfComplete() でできます.非同期アップロード/ダウンロードは,ページロックバッファとの間で行われなければいけません.つまり, gpu::CudaMem() ,または gpu::CudaMem() 領域を指す Mat() ヘッダを利用する必要があります.
注意する制限事項: 現在のところ,1つの処理が異なるデータを伴って2度キューに入った場合,すべての処理が適切に動作する保障はありません.関数によっては,固定の GPU メモリを利用し,以前の処理が終わる前に,次の呼び出しでメモリ内容を更新してしまう可能性があるものが存在します.しかし,異なる処理はそれぞれの固有バッファを持つので,異なる処理の非同期呼び出しは安全です.また,ユーザが保持するバッファへの,メモリのコピー/アップロード/ダウンロード/セット処理も安全です.
class CV_EXPORTS Stream
{
public:
Stream();
~Stream();
Stream(const Stream&);
Stream& operator=(const Stream&);
bool queryIfComplete();
void waitForCompletion();
//! 非同期ダウンロード.
// 注意! cv::Mat は,必ずページロックメモリ
// (つまり,CudaMem データやその ROI )を指します.
void enqueueDownload(const GpuMat& src, CudaMem& dst);
void enqueueDownload(const GpuMat& src, Mat& dst);
//! 非同期アップロード.
// 注意! cv::Mat は,必ずページロックメモリ
// (つまり,CudaMem データやその ROI )を指します.
void enqueueUpload(const CudaMem& src, GpuMat& dst);
void enqueueUpload(const Mat& src, GpuMat& dst);
void enqueueCopy(const GpuMat& src, GpuMat& dst);
void enqueueMemSet(const GpuMat& src, Scalar val);
void enqueueMemSet(const GpuMat& src, Scalar val, const GpuMat& mask);
// 例えば, float から uchar のように,行列の型を type で指定されたものに変換します.
void enqueueConvert(const GpuMat& src, GpuMat& dst, int type,
double a = 1, double b = 0);
};
現在のストリームキューが完了した場合に true を返し,それ以外は false を返します.
このクラスは, gpu::Stream() から cudaStream_t を取得する手段を提供します. stream_accessor.hpp は,Cuda ランタイム API に依存する唯一の public なヘッダなので,このクラスはそこで宣言されています.これをインクルードすることで,ユーザのコードに依存関係が発生します.
struct StreamAccessor
{
CV_EXPORTS static cudaStream_t getStream(const Stream& stream);
};
GPUメモリ上に(データが連続した)行列を作成します.
パラメタ: |
|
---|
以下のラッパーも利用できます:
要素が途切れることなく格納されている行列,つまり,行間にギャップが存在しない行列を,連続している行列,と呼びます.
行列のサイズが十分に大きく,適切な型であることを保証します.この関数は,行列が既に適切な性質のものであれば,メモリの再割り当てを行いません
パラメタ: |
|
---|
以下のラッパーも利用できます: