QA@IT

OpenCLのcl::copyが上手く動かない

1651 PV

 OpenCLの動作確認用に下記のCodeを作成しました。
下記のCodeのうち#if 0を書き換えて、enqueueReadBuffer()を使わず、
cl::copy()を使うようにすると正しくOpenCL側の処理結果を取得できません。
何故でしょうか?( 結果がおかしいだけで例外やErrorは発生していません )

 cl::copyの中では、clEnqueueMapBufferとclEnqueueUnmapMemObjectが
使われているのですが、これらの関数を正しく呼び出せる条件をわたしが
間違えているようにも思います。

 今回使用した環境ですが、下記になります。

OS:                 Fedora 17
OpenCL Platform:    AMD Accelerated Parallel Processing
CPU:                AMD A8-3850 APU with Radeon(tm) HD Graphics
主記憶容量:            15.1GB

どなたかご教示お願いいたします。

// Errorは全て例外処理で受け取る
#define __CL_ENABLE_EXCEPTIONS

#if defined( __APPLE__) || defined(__MACOSX )
#include <OpenCL/cl.hpp>
#else
#include <CL/cl.hpp>
#endif
#include <cstdio>
#include <cstdlib>
#include <iostream>

/**
 * Error codeから処理失敗時の通知を作成する
 */
inline const char *LookupErrorMessageWhere( cl_int code )
{
    //省略
}

#define QUOTE(string) #string
const std::string
    example_string =
    QUOTE
    ((
        /**
         * 単に入力した配列に-1を書き込むだけのOpenCL関数
         */
        __kernel void Example( __global float out[] )
        { 
            /* 広域の1次元目の識別子に従って配列を-1で埋める */
            out[get_global_id( 0 )] = -1;
        }
    ));

/**
 * OpenCLの動作を確認するためだけのProgram
 * 本来であれば、標準出力に下記の様な文字列を吐き出す
 *
 * -------------------------------------------------------
 * Quit Order
 * Result: -1 
 * Result: -1 
 * Result: -1 
 * Result: -1 
 *     ・
 *     ・
 *     ・
 * End
 * -------------------------------------------------------
 * OpenCLがGPUで処理するかCPUで処理しているかは、
 * 今回OpenCLの各Classが持つgetDefault()にまかせているため不定。
 */
signed main( signed, const char*[] )
try
{
    // OpenCL側にShader実行形式を作成する
    cl::Program
        program = cl::Program( std::string( example_string.begin() + 1, example_string.end() - 2 ) );

    program.build();


    // OpenCL側に結果を書き込む領域を作成する
    const size_t
        length = 0x10;
    cl::Buffer
        array( CL_MEM_READ_ONLY, length * sizeof( float ) );


    // OpenCL側のExample関数を作成する 
    cl::make_kernel<cl::Buffer>
        example( program, "Example" );

    // OpenCL側の広域並列数
    cl::EnqueueArgs
        enqueue_args = cl::NDRange( length );

    // Example関数を実行( 呼び出し指示を命令Queueへ追加 )
    for( signed i = 0; i < 0x10; ++i )
    {
        example( enqueue_args, array );
    }

    std::cerr << "Quit Order" << std::endl;

    // OpenCLの処理結果を受け取る領域を作り結果を書き込む
    std::vector<float>
        buffer;

    buffer.resize( length );
#if 0
    // こちらを使うとbufferの書き換えが一切おこらず上手く行かない
    cl::copy( array, buffer.begin(), buffer.end() );
#else
    // こちらを使うと想定通りbufferが-1で埋め尽くされる
    cl::enqueueReadBuffer
    (
     array,
     CL_TRUE,
     0,
     length * sizeof( float ),
     &buffer[0]
    );
#endif

    // 処理結果の確認
    for( size_t i = 0; i < length; ++i )
    {
        std::cerr << "Result: " << buffer[i] << std::endl;
    }

    std::cerr << "End" << std::endl;

    return EXIT_SUCCESS;
}
catch( const cl::Error &error )
{
    std::cerr 
        << "ERROR: "
        << error.what()
        << "("
        << LookupErrorMessageWhere( error.err() )
        << ")"
        << std::endl;

    return EXIT_FAILURE;
}
ウォッチ

この質問への回答やコメントをメールでお知らせします。