1

私が達成しようとしていること:
OpenCL でいくつかのものをレンダリングし、それを OpenGL フレームバッファーに書き込もうとしています (Renderbuffers などを介して取得できる唯一のフレームバッファーであるため、使用できる他のものを喜んで受け入れます-あなたglsl シェーダーを使用するように指示しても役に立ちません)

問題:
タイトルにあるように、OpenCL 関数clBuildProgramがエラー -11 (CL_ BUILD_ PROGRAM_ FAILURE) で失敗します。これは問題にはなりませんが、CL コンパイラからのログは空です。ログ コードを再確認しましたが、問題ないはずです。あなたが自分自身を見ることができるように、私はそれを下に投稿しました.

私が修正しようとしたこと:

  • もちろん、グーグル
  • Khronos Groups のドキュメントを読む
  • デバイスが「cl_khr_gl_sharing」拡張機能をサポートしているかどうかを確認しています (これは から返された文字列に含まれていますclGetDeviceInfo(device_id, CL_DEVICE_EXTENSIONS, retSize, extensions, &retSize);)
  • シェーダー/カーネルの変更:
  • ロギングコードが実際に機能するかどうかを確認するために、いくつかの意図的なエラーを作成しました(機能しています)
  • そして、シェーダー/カーネルを縮小して、シェーダー内のいくつかのものが正常に機能しないかどうかを確認します (私が読んだように、いくつかの欠落が cl のコンパイラーをクラッシュさせる可能性があることを読んだ)

私が見つけたもの:
私が試した最後のポイントから、私は気づいた、write_imageuiread_imageuiopencl 関数は、コンパイラが私のコードをコンパイルするのに失敗します (これが、「cl_khr_gl_sharing」拡張子をチェックした理由です)

さらに:
私のオペレーティングシステムはWindows 10で、使用しているCコンパイラはGCCです(ホストプログラムは正常にコンパイルされるため、それがどのように役立つかわかりませんが、それでもなおです)

いくつかのコード:
シェーダー/カーネル (問題を再現するために可能な限り縮小されています。あなたにもお願いします。呼び出しの最後の 2 行は、opencl コンパイラーが機能しない原因だと思います。他のものはそこにあります。これは、実際に何かを処理できるシェーダーです。

#define ScreenWidth 1000
#define ScreenHight 1000
const sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_NONE | CLK_FILTER_NEAREST;
__kernel void rainbow(__read_write image2d_t asd) {
    int i = get_global_id(0);
    unsigned int x = i%ScreenWidth;
    unsigned int y = i/ScreenHight;
    uint4 pixel;
    pixel = read_imageui(asd, sampler, (int2)(x, y));
    write_imageui(asd, (int2)(x, y), pixel);
}

必要なすべての初期化処理を実行する縮小された呼び出しコード (C) (注: ログ バッファは動的に変更可能です):

cl_program program = clCreateProgramWithSource(contextZ, 1, (const char **)&source_str, (const size_t *)&source_size, &ret);

size_t retSize = 0;
clGetDeviceInfo(device_id, CL_DEVICE_EXTENSIONS, 0, NULL, &retSize);

char extensions[retSize];
clGetDeviceInfo(device_id, CL_DEVICE_EXTENSIONS, retSize, extensions, &retSize);
printf("%s\n", extensions);

// Build the program
ret = clBuildProgram(program, 1, &device_id, NULL, NULL, NULL);
if (ret == CL_BUILD_PROGRAM_FAILURE) {
    l_logError("Could not build Kernel!");
    // Determine the size of the log
    size_t log_size;
    printf(" reta: %i\n", clGetProgramBuildInfo(program, device_id, CL_PROGRAM_BUILD_LOG, 0, NULL, &log_size));

    // Allocate memory for the log
    char *log = (char *) malloc(log_size);

    // Get the log
    printf(" retb: %i\n", clGetProgramBuildInfo(program, device_id, CL_PROGRAM_BUILD_LOG, log_size, log, NULL));

    // Print the log
    printf(" ret-val: %i\n", ret);
    printf("%s\n", log);
}

出力に興味があるかもしれません (最後の 2 行はカーネルがビルドされていないことが原因です。ただし、プログラムはソースから作成できます - コードを見てください):

E: Could not build Kernel!
 reta: 0
 retb: 0
 ret-val: -11

E: Could not create Kernel!
 kernel error: -45

他の誰かが同様の問題を抱えていましたか?私はそれについて何をすべきですか?cl Kernel/Shader のヘッダーが含まれている可能性がありますが、これを含める必要がありますか? 私の clBuildProgram 呼び出しが間違っている可能性がありますか? (誰かがデバイスを渡さなかったと読んだので、コードに何か他のものが欠けている可能性があります)

詳細が必要な場合は、お知らせください。提供できるようにします (他に必要なものは今のところ思いつきません)。

お時間をいただきありがとうございます。

編集:
仕様によると、デバイスはCL_ DEVICE_ IMAGE_ SUPPORT拡張機能をサポートする必要があります。

これを使用して確認しました:

cl_bool image_support = CL_FALSE;
clGetDeviceInfo(device_id, CL_DEVICE_IMAGE_SUPPORT, sizeof(cl_bool), &image_support, NULL);
printf("image_support: %i\n", image_support);

どの出力:

image_support: 1

別名。CL_TRUE

編集 2:
カーネルで OpenCL 拡張機能を有効にする必要があることが判明しました: https://www.khronos.org/registry/OpenCL/sdk/2.2/docs/man/html/EXTENSION.htmlの最初の行に
追加#pragma OPENCL EXTENSION all : enableカーネル/シェーダーは同じ問題を引き起こします

編集 3:
カーネル イメージ パラメーターから __read_write フラグを削除するか、それを別のもの (__read_only など) に置き換えると、clBuildProgram が返されない (または非常に長い時間のように返される) ため、OpenCL コンパイラがクラッシュするか無限にループします。

4

1 に答える 1

2

ここ数日でわかったことは、少し間違っていたかもしれません。私の編集 3 (元の投稿/質問から) は、__read_write を __read_only に置き換えると、コンパイラが完全にクラッシュすることを示しています。これは正しくありません。コンパイル呼び出しの後にデバッグ出力コードを追加しなかったことを確認できるようになりました。clBuildProgram 呼び出しの後にデバッグ行を追加すると、実際に機能することが示されます。

これにより OpenCL コンパイラがエラーとして文字通り何も出力しない理由がわかりません。ドライバーのベンダーは、これを修正するか、何かを出力する必要があります (コメントのデバイス情報)。(警告だけでも役に立ちます)

同様の問題について議論しているこのスタックオーバーフローの投稿を見つけました: OpenCL - カーネルから読み取りと書き込みの両方を取得するために image2d_t を 2 回渡す? . これは、これが壊滅的な問題を引き起こす可能性があることを私が理解した方法でもあります.
公平を期すために、公式ドキュメントにはこれが記載されていますが、__read_write (read_only | write_only == __read_write) に組み合わせることができるように理解しました。

次の表の aQual は、アクセス修飾子の 1 つを指します。書き込み関数の場合、これは write_only または read_write になります。

カーネルを write_image 呼び出し (write_imageui) のみに置き換え、image2d_t を __write_only に設定して、デバッグの可能性を最小限に抑えました。これにより、シェーダー/カーネルは正常にコンパイルされましたが、画面はまだ空のままです。しかし、後者は別の問題です。

于 2021-12-09T11:13:03.950 に答える