0

我正在使用 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] + ")");
}

谢谢!

4

1 回答 1

2

我已经弄清楚了问题所在。Cl.EnqueueWriteImage/Cl.EnqueueReadImage 中的区域应该是 (imageWidth, imageHeight, 1) 而不是 (1, 1, 1):

IntPtr[] regionPtr = new IntPtr[] { (IntPtr)imgWidth, (IntPtr)imgHeight, (IntPtr)1 };
于 2012-11-29T02:51:16.713 回答