4

Haskell と OpenCL でパストレーサーを作成していますが、image2d_t をカーネルに渡して出力を書き込む際に問題が発生しています。つまり、get_image_*image2d_t で OpenCL の関数を呼び出すと、無意味な値 (通常は 0 または 2^24-1) が返され、何も行われwrite_imagefません。これは、GPU で実行している場合にのみ発生します。CPU は正常に実行されます。ホストで呼び出すclGetImageInfoと、正しい値が返されます。OpenCL の Haskell バインディングはエラー コードを例外に変換するため、エラーのチェックを忘れることはありません。clinfo は私のバージョンを「OpenCL 1.2 AMD-APP (1084.2)」と報告します。OpenCL コンパイラで segfault やリンクの失敗を引き起こす複数のバグを経験 (および報告) したことに注意してください。これは、私のコードのバグではなく、その結果である可能性があります。

OpenCL を次のように初期化します (Haskell を知らない人にも比較的わかりやすいはずです)。

(platform:_) <- clGetPlatformIDs
(device:_) <- clGetDeviceIDs platform CL_DEVICE_TYPE_GPU
glContext <- glXGetCurrentContext
glDisplay <- glXGetCurrentDisplay
context <- clCreateContext [CL_GL_CONTEXT_KHR glContext, CL_GLX_DISPLAY_KHR glDisplay] [device] putStrLn
queue <- clCreateCommandQueue context device []
source <- readFile "pt.cl"
program <- clCreateProgramWithSource context source
clBuildProgram program [device] "-cl-strict-aliasing"
        `catch` (λe -> case (e :: CLError) of
                            CL_BUILD_PROGRAM_FAILURE -> putStrLn "Building OpenCL program failed:"
                                                     >> clGetProgramBuildLog program device >>= putStrLn
                                                     >> throw e
                            _                        -> return ())
kernel <- clCreateKernel program "sample"
pCorners <- mallocArray 4
buffer <- clCreateBuffer context [CL_MEM_READ_ONLY, CL_MEM_USE_HOST_PTR] (4*sizeOf (undefined :: V.Vec4F), castPtr pCorners)
clSetKernelArgSto kernel 1 buffer
tex@(TextureObject texid) <- head <$> (genObjectNames 1)
activeTexture $= TextureUnit 0
textureBinding Texture2D $= Just tex
textureFilter Texture2D $= ((Nearest, Nothing), Nearest)
textureWrapMode Texture2D S $= (Repeated, Clamp)
textureWrapMode Texture2D T $= (Repeated, Clamp)
texImage2D Nothing NoProxy 0 RGBA′ (TextureSize2D initialWidth initialHeight) 0 (PixelData RGBA UnsignedByte nullPtr)
image <- clCreateFromGLTexture2D context [CL_MEM_READ_WRITE] gl_TEXTURE_2D 0 texid
clSetKernelArgSto kernel 2 image

そして、これを (少し簡略化して) 呼び出して、カーネルを実行し、結果をレンダリングします。

clSetKernelArgSto kernel 0 position
pokeArray pCorners orientedCorners -- update the pCorners array
finish -- This is glFinish()
clEnqueueAcquireGLObjects queue [image] []
clEnqueueNDRangeKernel queue kernel [width, height] [] []
clEnqueueReleaseGLObjects queue [image] []
clFinish queue
drawElements TriangleFan 4 UnsignedInt offset0
swapBuffers

最後に、テスト カーネル:

__kernel void sample(float3 position, __constant float3 corner[4], image2d_t output) {
        write_imagef(output, (int2)(get_global_id(0), get_global_id(1)), (float4)(0, 0.5f, 1, 1));
}

この出力は、GPU メモリのランダムな初期化されていない領域を表示するフルスクリーン クワッドです。フルスクリーンのシアンのクワッドにする必要があります。printf関数の結果を表示するためにいくつかの s がありget_image_*ましたが、それらが原因でプログラムがハングし始めました。

4

2 に答える 2

1

OpenCL 仕様には、これに関するルールimage2d_tがあります。オブジェクトにはアクセス修飾子が必要です。

このような修飾子は 2 つあります。

  • read_only(または__read_only)
  • write_only(または__write_only)

それらは相互に排他的であり、一緒に使用することはできません (したがって、テクスチャに対して同時に読み取りと書き込みを行うことはできません。これは、画像で蓄積作業を行う場合に重要です。モンテカルロの場合と思われます)パス トレーシングなどのアプリケーション)。修飾子は単にデフォルトで に設定されるため、省略してread_onlyも問題ありませんが、残念ながらこれは出力画像の選択としては間違っています。

解決策は、イメージ引数を で修飾するwrite_onlyか、それから読み取る必要がある場合は、ある種のスワップ システムを使用することです (または、同時に読み取りと書き込みが可能なグローバル メモリ バッファーを使用しますが、これにより、 CL/GL の相互運用は少し難しく、サンプリング機能が失われます...)。

CPUで動作する理由は、CPUには読み取り専用の「テクスチャメモリ」がないためだと思います。そのため、画像への書き込みが技術的に違法であっても、可能であり、ランタイムで実行できます。一方、GPU には読み取り専用のメモリ セクションがあり、どれだけ頑張ってもカーネルの実行中に書き込むことはできません (または、GPU デバイスのランタイムがより厳密である可能性があります)。

*ランタイムと言うときは、もちろん、プログラムではなく、OpenCL 対応デバイスを意味します。

于 2012-11-30T09:38:20.517 に答える
0

同様の問題がありました。カーネル引数を並べ替えた後、すべての image2d_t 引数が最初の引数になり、機能しました。特に get_image_dim を呼び出すと、正しい結果が返されました。これがバグかどうかはわかりません。私の GPU: ATI Radeon 7950。

于 2013-03-06T10:01:10.147 に答える