我正在使用Opencl.net,我正在尝试在GPU上进行一些图像处理。不幸的是,只有第一个像素([0; 0])具有正确的值,其余的是(0; 0; 0; 0)。 OpenCL内核应该为每个像素的所有颜色分量分配0.5。在我看来,内核只执行一次(或者读取函数可能只读取第一个像素)。我究竟做错了什么?我从代码中省略了不相关的部分:
...
int intPtrSize = 0;
intPtrSize = Marshal.SizeOf(typeof(IntPtr));
Cl.Mem srcImage2DBuffer;
Cl.ImageFormat imageFormat = new Cl.ImageFormat(Cl.ChannelOrder.ARGB, Cl.ChannelType.Float);
int imgWidth = 0, imgHeight = 0;
IntPtr srcFloatDataPtr;
int srcIMGBytesSize = 0;
GCHandle pinnedSrcFloatArray;
//Load image from file into OpenCL buffer
using (FileStream imageFileStream = new FileStream(inputImagePath, FileMode.Open) ) {
System.Drawing.Image inputImage = System.Drawing.Image.FromStream( imageFileStream );
imgWidth = inputImage.Width;
imgHeight = inputImage.Height;
System.Drawing.Bitmap bmpImage = new System.Drawing.Bitmap(inputImage);
BitmapData bitmapData = bmpImage.LockBits( new Rectangle(0, 0, bmpImage.Width, bmpImage.Height),
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
srcIMGBytesSize = bitmapData.Stride * bitmapData.Height;
//Convert image from byte to float array
byte[] inputByteArray = new byte[srcIMGBytesSize];
Marshal.Copy(bitmapData.Scan0, inputByteArray, 0, srcIMGBytesSize);
bmpImage.UnlockBits( bitmapData );
float[] inputFloatArray = new float[srcIMGBytesSize];
Array.Copy(inputByteArray, inputFloatArray, srcIMGBytesSize);
for (int i = 0; i < srcIMGBytesSize; i++) {
inputFloatArray[i] /= 255.0f;
}
pinnedSrcFloatArray = GCHandle.Alloc(inputFloatArray, GCHandleType.Pinned);
srcFloatDataPtr = pinnedSrcFloatArray.AddrOfPinnedObject();
srcImage2DBuffer = Cl.CreateImage2D(_context, Cl.MemFlags.CopyHostPtr | Cl.MemFlags.ReadOnly, imageFormat,
(IntPtr)bitmapData.Width, (IntPtr)bitmapData.Height,
(IntPtr)0, srcFloatDataPtr, out error);
}
float[] outputFloatArray = new float[srcIMGBytesSize];
//I'm not sure whether the pointer here is correct or not.
Cl.Mem resultImage2DBuffer = Cl.CreateImage2D(_context, Cl.MemFlags.CopyHostPtr | Cl.MemFlags.WriteOnly, imageFormat,
(IntPtr)imgWidth, (IntPtr)imgHeight, (IntPtr)0, outputFloatDataPtr, out error);
error = Cl.SetKernelArg(kernel, 0, (IntPtr)intPtrSize, srcImage2DBuffer);
error |= Cl.SetKernelArg(kernel, 1, (IntPtr)intPtrSize, resultImage2DBuffer);
...
IntPtr[] originPtr = new IntPtr[] { (IntPtr)0, (IntPtr)0, (IntPtr)0 };
IntPtr[] regionPtr = new IntPtr[] { (IntPtr)1, (IntPtr)1, (IntPtr)1 };
IntPtr[] workGroupSizePtr = new IntPtr[] { (IntPtr)imgWidth, (IntPtr)imgHeight, (IntPtr)1 };
error = Cl.EnqueueWriteImage(cmdQueue, srcImage2DBuffer, Cl.Bool.True, originPtr, regionPtr, (IntPtr)0, (IntPtr)0, srcFloatDataPtr, 0, null, out clevent);
pinnedSrcFloatArray.Free();
error = Cl.EnqueueNDRangeKernel(cmdQueue, kernel, 2, null, workGroupSizePtr, null, 0, null, out clevent);
error = Cl.EnqueueReadImage(cmdQueue, resultImage2DBuffer, Cl.Bool.True, originPtr, regionPtr,
(IntPtr)0, (IntPtr)0, outputFloatArray, 0, null, out clevent);
for (int i = 0; i < srcIMGBytesSize; i++) {
outputFloatArray[i] *= 255.0f;
}
//Right here I'm learning that all of the components are 0
for (int i = 0; i < srcIMGBytesSize; i+=4) {
Console.WriteLine("(" + outputFloatArray[i] + "; " + outputFloatArray[i+1] + "; "
+ outputFloatArray[i+2] + "; " + outputFloatArray[i+3] + ")");
}
谢谢!
答案 0 :(得分:2)
我已经找到了问题所在。 Cl.EnqueueWriteImage / Cl.EnqueueReadImage中的区域应该是(imageWidth,imageHeight,1)而不是(1,1,1):
IntPtr[] regionPtr = new IntPtr[] { (IntPtr)imgWidth, (IntPtr)imgHeight, (IntPtr)1 };