我正在Haskell和OpenCL中编写路径跟踪器,我遇到了将image2d_t传递给我的内核以将输出写入的问题。也就是说,在image2d_t上调用OpenCL中的任何get_image_*
函数会返回无意义的值(通常为0或2 ^ 24-1),write_imagef
不执行任何操作。这只发生在GPU上运行时 - CPU运行正常。在主机上调用clGetImageInfo
会返回正确的值。 OpenCL的Haskell绑定将错误代码转换为异常,因此不会忘记检查错误。 clinfo将我的版本报告为“OpenCL 1.2 AMD-APP(1084.2)”。我应该注意到我经历(并报告)多个错误导致OpenCL编译器发生段错误或链接失败,所以这可能是由于我的代码中的错误而不是错误。
我像这样初始化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
来显示get_image_*
函数的结果,但它们已经开始导致程序挂起。
答案 0 :(得分:1)
OpenCL规范有关于此的规则 - image2d_t
对象需要访问限定符。
有两个这样的限定符:
read_only
(或__read_only
)write_only
(或__write_only
)它们是互斥的,可能不能一起使用(所以你不能同时读取和写入纹理 - 如果你打算对你的图像进行积累工作,这很重要,我怀疑是这样的蒙特卡罗应用程序,如路径跟踪)。省略限定符是有效的,因为它只是默认为read_only
,但遗憾的是输出图像选择错误。
解决方案是使用write_only
限定图像参数,或者如果您需要从中读取它,请使用某种交换系统(或使用可以读取和写入的全局内存缓冲区)同时,但这使得CL / GL互操作变得更加困难,并且你失去了采样功能......)。
我认为它在CPU上工作的原因是因为在CPU上没有只读的“纹理存储器”,所以即使在技术上写入图像是非法的,也可以运行时运行它。另一方面,GPU确实有只读内存部分,无论您尝试多么努力(或者GPU设备的运行时间更严格),内核运行时都无法写入内存部分。
*当我说运行时,我的意思是支持OpenCL的设备,当然不是你的程序。
答案 1 :(得分:0)
我有类似的问题。重新排序内核参数后,所有image2d_t参数都是第一个参数,它起作用了。特别是调用get_image_dim会返回正确的结果。不知道,如果这是一个bug。我的GPU:ATI Radeon 7950。