ホスト側のデータ生成 - 2023.2 日本語

Vitis 統合ソフトウェア プラットフォームの資料: アプリケーション アクセラレーション開発 (UG1393)

Document ID
UG1393
Release Date
2023-12-13
Version
2023.2 日本語

たたみ込みフィルターには、3 つの独立した CU が含まれ、それぞれがビデオ画像ストリームから 1 つのカラー チャネルを処理します。この例では、プロジェクトをシンプルに保って VSC に集中するため、実際のビデオ ストリームは使用しません。この例のホスト コードは、VSC 固有のコードを使用するソフトウェア関数に渡されるカラー チャネル 3 つを持つランダム イメージを生成するだけです。これにより、C スレッドがホストからデバイス、および compute() 呼び出しへのデータの送受信をするようになります。

この関数は、すべてのフィルター パラメーターとデータ ポインターをソースおよびデスティネーション イメージに渡します。次のコード部分は、この関数の定義を示しています。基本的なステップは、次のとおりです。

  • バッファー プール ハンドル (srcBufPool...) を作成して、ホストとデバイス間のデータの送受信をイネーブルにします。属性でバッファーが入力か出力かを示します。
  • ラムダ関数を使用して conv_acc::send_while() を呼び出します。ラムダ関数は、デバイス上でバッファーを割り当て、ホスト データをデバイス バッファーにコピーしてから、compute() 関数を呼び出します (これにより、ハードウェア アクセラレーションされた関数が実行されます)。send_while() は、true を戻し続ける限り、ラムダ関数を呼び出し続けます。
  • ラムダ関数を使用する conv_acc::receive_all_in_order() を呼び出し、処理されたバッファーを受信します。
  • join() 呼び出しを使用して、待機し、すべてを同期します。
ヒント: さまざまな関数の説明は、VPP_ACC クラスの API を参照してください。
#include "conv_filter_acc_wrapper.hpp"
 
int conv_filter_execute_fpga(
        const char           coeffs[FILTER_V_SIZE][FILTER_H_SIZE],
        float                factor,
        short                bias,
        unsigned short       width,
        unsigned short       height,
        unsigned int         numImages,
        YUVImage             srcImage,
        YUVImage             dstImage
                             )
{
    auto srcBufPool = conv_acc::create_bufpool(vpp::input);
    auto dstBufPool = conv_acc::create_bufpool(vpp::output);
    auto coeffsBufPool = conv_acc::create_bufpool(vpp::input);
 
    int run = 0;
    int dataSizePerChannel = width * height ;
    // sending input
    conv_acc::send_while([=]()->bool {
            conv_acc::set_handle(run);
            unsigned char *  srcBuf = (unsigned char *)conv_acc::alloc_buf(srcBufPool, 3*dataSizePerChannel);
            unsigned char *  dstBuf = (unsigned char *)conv_acc::alloc_buf(dstBufPool, 3*dataSizePerChannel);
            char *        coeffsBuf = (         char *)conv_acc::alloc_buf(coeffsBufPool, FILTER_V_SIZE*FILTER_H_SIZE);
 
            // initialize all input data before parallel computes
            unsigned char * srcChannel[3] = {srcImage.yChannel, srcImage.uChannel, srcImage.vChannel};
            for (int ch = 0; ch < 3; ch++){
                std::memcpy(srcBuf+ch*dataSizePerChannel, srcChannel[ch], dataSizePerChannel);
            }
            std::memcpy(coeffsBuf,coeffs,256);
            // execute conv_acc<NCU> parallel computes
            for (int ch = 0; ch < 3; ch++){
                conv_acc::compute(coeffsBuf,
                                  factor,
                                  bias,
                                  width,
                                  height,
                                  srcBuf + ch*dataSizePerChannel,
                                  dstBuf + ch*dataSizePerChannel);
            }
            return (++run < numImages);
        });
 
 
    // receive lambda function for receive thread
    conv_acc::receive_all_in_order([=]() {
            int run = conv_acc::get_handle();
            unsigned char * dstBuf = (unsigned char *)conv_acc::get_buf(dstBufPool);
            unsigned char * dstChannel[3] = {dstImage.yChannel, dstImage.uChannel, dstImage.vChannel};
            for (int ch = 0; ch < 3; ch++){
                std::memcpy(dstChannel[ch], dstBuf+ch*dataSizePerChannel, dataSizePerChannel);
            }
        });
    // wait for both loops to finish
    conv_acc::join();
 
    return 0;
}