2011-05-12 3 views
1

지금 당장 OpenCL을 이해하기 위해 몇 가지 샘플을 프로그래밍하고 있습니다. 문제가있는 샘플에서 큰 8 비트 이미지를로드하고 픽셀 단위 평균 값 을 계산합니다.OpenCL - 특정 양의 입력 데이터를로드 할 때 빈 결과가 발생합니다.

결과 [X, Y = (이미지 1 [X, Y] + 이미지 2 [X, Y] + ...)이 0-9 이미지 매우 잘 작동

/ImageCount. 하지만 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

커널 Args는 고정적이어야합니다 (SHOULD). 구조체를 사용하여 모든 이미지를로드하거나 모든 이미지를 배열 형식으로로드하고 Args를 모든 이미지의 길이를 설정하는 커널에 추가하십시오. 각 이미지를 커널 내부에서 분리 할 수 ​​있어야합니다.

많은 사람들이 10 개 이상의 커널 Arg를 사용하여 오류가 발생했습니다.

또한 "Eric Bainville"과 같이 말했습니다. 이미지를 벡터로 추가해야합니다. 행이나 열에 특별한 처리를하지 않기 때문입니다.

1

각 OpenCL 호출 후에 오류 코드를 확인하면 모든 버퍼 할당이 올바른지 확인할 수 있으므로 유용합니다.

행 대신 열로 이미지를 처리하는 것이 더 빠를 것입니다. 커널에서 함께 실행되는 스레드는 xRes 간격으로 메모리를 액세스하므로이 패턴으로 메모리 액세스가 느려집니다. 스레드의 2D 배열을 실행하는 것이 더 빠를 수도 있습니다.

EDIT. 작업 그룹 크기를 제한하여 사용되는 레지스터 수에 문제가있을 수 있습니다. 최대 커널 작업 그룹 크기를 확인하고 작업 그룹 크기를 줄이십시오.

+0

위에서 언급 한 것처럼 모든 OpenCL 호출 후에 오류 코드를 확인했습니다. 방금 'if'대신에 디버거로 검사했습니다. 모두 0 (CL_SUCCESS)이었습니다. 행 대신 열의 힌트를 주셔서 감사합니다. 나는 이것을 시도 할 것이다. – Marks

+0

이전에 CL_DEVICE_MAX_WORK_GROUP_SIZE을 (를) 확인했습니다. 그 512, 내가 그것을 사용하는 것처럼. 또한 CL_DEVICE_MAX_WORK_ITEM_SIZES도 512인지 확인했습니다. 작은 작업 그룹도 성공없이 사용했습니다. – Marks

+0

나는'clGetKernelWorkGroupInfo'에서 얻은 CL_KERNEL_WORK_GROUP_SIZE를 의미했습니다. –

관련 문제