2011-05-12 26 views
1

現在我正在編寫一些樣本以瞭解OpenCL以供將來使用。 在帶有問題的示例中,我加載了一些大的8位圖像並計算了像素平均值 。OpenCL - 加載特定數量的輸入數據時的空結果

結果[X,Y] =(IMAGE1 [X,Y] +圖像2 [X,Y] + ...)/ ImageCount

這非常適用於0到9的圖片。但是,當我加載10個或更多圖像時,結果只是一個黑色圖像(所有像素0)。

我認爲這可能是一個內存量的問題。但有10張照片,圖像數據只有100MB。顯卡是一款配備256MB RAM的8600GTS。

另外我檢查了所有的錯誤代碼返回,並沒有得到任何不同於CL_SUCCESS。

主持節目(德爾福,但我一點也C的訪客可以讀取它):

//Settings 
MaxImg := 4; //Images from 0..4 Count = 5 
SetLength(InImgs,MaxImg+1); //Array for images in Host memory 
SetLength(GPUInMems,MaxImg+1); //Array for images in GPU memory 

//Create Kernel 
CLKernel := clCreateKernel(CLProgram, PChar('MainKernel'), @LastError); 
//Create Queue 
CLQueue := clCreateCommandQueue(CLContext, CLDevices[0].DeviceID, 0, @LastError); 

//Load images 
for I := 0 to MaxImg do 
begin 
    InImgs[I] := TImageMem.Create; 
    InImgs[I].LoadFile('C:\Test\Img-' + IntToStr(I) + '.bmp'); 
    GPUInMems[I] := clCreateBuffer(CLContext, CL_MEM_READ_ONLY or CL_MEM_COPY_HOST_PTR, InImgs[I].MemSize, InImgs[I].Memory, @LastError); 
end; 

//Prepare Outputimage 
OutImg := TImageMem.Create; 
OutImg.LoadFile('C:\Test\CLTestOut.bmp');//Temporary solution to get right memory size and headers 
GPUOutMem := clCreateBuffer(CLContext, CL_MEM_WRITE_ONLY, OutImg.MemSize, nil, @LastError); 

//Set parameter for kernel call 
LastError := clSetKernelArg(CLKernel, 0, sizeof(cl_mem), @GPUOutMem); //Output image 
LastError := clSetKernelArg(CLKernel, 1, sizeof(integer), @OutImg.Width); 
LastError := clSetKernelArg(CLKernel, 2, sizeof(integer), @OutImg.Height); 

//Add pointer to memory from images as parameters 
for I := 0 to MaxImg do 
begin 
    LastError := clSetKernelArg(CLKernel, I+3, sizeof(cl_mem), @GPUInMems[I]); 
end; 

//Specify Group and Grid sizes 
GlobalWSize[0]:= (OutImg.Width div 512 + 1) * 512; //Calc groups needed for resolution 
LocalWSize[0] := 512; //Max WorkItems per group possible 

//Execute and transfer ouput to host memory 
LastError := clEnqueueNDRangeKernel(CLQueue, CLKernel, 1, nil, @GlobalWSize, @LocalWSize, 0, nil, nil); 
LastError := clEnqueueReadBuffer(CLQueue, GPUOutMem, CL_TRUE, 0, OutImg.MemSize, OutImg.Memory, 0, nil, nil); 

//Write output 
OutImg.SaveFile('C:\Test\CLTestOut.bmp'); 

內核:

__kernel void MainKernel(
    __global uchar* ret, 
    int xRes, 
    int yRes, 
    __global uchar* I0, 
    __global uchar* I1, 
    __global uchar* I2, 
    __global uchar* I3, 
    __global uchar* I4) 
    { 
      //Get line position 
      int y = get_global_id(0); 

      //Check inbound 
      if (y >= yRes) return; 

      //Set pointers to position 
      ret += xRes * y; 
      I0 += xRes * y; 
      I1 += xRes * y; 
      I2 += xRes * y; 
      I3 += xRes * y; 
      I4 += xRes * y; 

      //Set val for each pixel in line 
      for (int x = 0; x < xRes; ++x) 
      { 
       ret[x] = (I0[x] + I1[x] + I2[x] + I3[x] + I4[x])/5 ; 
      } 
    } 

這將是巨大的,如果有人能告訴我,爲什麼它是不與超過9個圖像一起工作,爲什麼我沒有得到錯誤代碼。

感謝您的任何幫助。

回答

1

內核參數應該是靜態的。 使用一個結構來加載所有圖像,或者可能以數組形式加載所有圖像,並向內核添加一些設置每個圖像長度的參數。爲了能夠在內核中分離每個圖像。

我見過很多使用10+ Kernel Args獲取錯誤的人。

也作爲「埃裏克Bainville」說。您應該將圖像添加爲矢量。既然你不做任何特殊的處理行或列。

1

在每次OpenCL調用後檢查錯誤代碼會很有用,因此您可以驗證所有緩衝區分配是否正常。

按列而不是行處理圖像可能會更快:在內核中,一起執行的線程將以xres間隔訪問內存,並且此模式下的內存訪問速度會很慢。運行二維數組的線程可能會更快。

編輯。使用的寄存器數量可能存在問題,限制了可能的工作組大小。檢查最大內核工作組大小,並嘗試減小工作組大小。

+0

如上所述,我在每次OpenCL調用後都檢查了錯誤代碼。我只是用調試器而不是'if'來檢查它們。全部爲0(CL_SUCCESS)。感謝列的提示,而不是行。我會試試這個。 – Marks 2011-05-12 13:43:06

+0

我之前檢查過CL_DEVICE_MAX_WORK_GROUP_SIZE。它的512,就像我使用它。還檢查了CL_DEVICE_MAX_WORK_ITEM_SIZES,它也是512.我也用小工作組沒有成功。 – Marks 2011-05-12 14:14:58

+0

我的意思是從'clGetKernelWorkGroupInfo'獲得的CL_KERNEL_WORK_GROUP_SIZE。 – 2011-05-12 15:30:04