Я смотрю, это будет первая тема в данном разделе. Понадобилось мне тут найти приближённо границу множества Мандельброта для [math]z^4+c[/math]. Создал шейдер: Код (C): float2 Mult(float2 z1,float2 z2) { return (float2)(z1.x*z2.x-z1.y*z2.y, z1.y*z2.x+z1.x*z2.y); } float2 DoIter(float2 z,float2 c) { return Mult(Mult(Mult(Mult(z,z),z),z),z)+c; } __kernel void CalcMandel(float Border,float Threshold,uint NumOfIter,uint Size,__global uchar *Data/*,__global uint *NumOfPoints*/) { size_t _X=get_global_id(0); size_t _Y=get_global_id(1); if((_X<Size) && (_Y<Size)) { float2 c=(float2)(Border*2.0f*((float)_X/(float)(Size-1)-0.5f),Border*2.0f*((float)(Size-_Y-1)/(float)(Size-1)-0.5f)); float2 z=(float2)(0,0); for(uint i=0;(i<NumOfIter) && (length(z)<Threshold);i++) { z=DoIter(z,c); } uchar Val; if(length(z)<Threshold) { Val=1; } else { Val=0; } Data[_X+Size*_Y]=Val; barrier(CLK_GLOBAL_MEM_FENCE); if(Val==1) { if((Data[_X+Size*_Y-1]==1) && (Data[_X+Size*_Y+1]==1)) { if((Data[_X+Size*(_Y-1)-1]==1) && (Data[_X+Size*(_Y-1)]==1) && (Data[_X+Size*(_Y-1)+1]==1)) { if((Data[_X+Size*(_Y+1)-1]==1) && (Data[_X+Size*(_Y+1)]==1) && (Data[_X+Size*(_Y+1)+1]==1)) { Val=0; } } } } barrier(CLK_GLOBAL_MEM_FENCE); Data[_X+Size*_Y]=Val; } else { barrier(CLK_GLOBAL_MEM_FENCE); barrier(CLK_GLOBAL_MEM_FENCE); } } Передаю в kernel параметры: Border=1.5 Threshold=3.0 NumOfIter=500 Size=1000 Data - массив байт. Жду на выходе границу, а получаю: на этой картинке чёрные точки соответствуют значению 1, а белые - 0. Что я делаю не так?
_qwe8013 Хоть бы написал, что bmp сохраняется в C:\temp. У меня в системе например нет этой папки, пришлось создать. А вообще для сохранения в temp нужно использовать переменную среды %TEMP%.
Не совсем то но прикольно Код (C): float2 Mult(float2 z1,float2 z2) { return (float2)(z1.x*z2.x-z1.y*z2.y, z1.y*z2.x+z1.x*z2.y); } float2 DoIter(float2 z,float2 c) { return Mult(Mult(Mult(Mult(z,z),z),z),z)+c; } __kernel void CalcMandel(float Border,float Threshold,uint NumOfIter,uint Size,__global uchar *Data/*,__global uint *NumOfPoints*/) { size_t _X=get_global_id(0); size_t _Y=get_global_id(1); if((_X<Size) && (_Y<Size)) { float2 c=(float2)(Border*2.0f*((float)_X/(float)(Size-1)-0.5f),Border*2.0f*((float)(Size-_Y-1)/(float)(Size-1)-0.5f)); float2 z=(float2)(0,0); for(uint i=0;(i<NumOfIter) && (length(z)<Threshold);i++) { z=DoIter(z,c); } uchar Val; if(round(length(z)*0.2)==round(Threshold*0.2)) { Val=1; } else { Val=0; } Data[_X+Size*_Y]=Val; barrier(CLK_GLOBAL_MEM_FENCE); barrier(CLK_GLOBAL_MEM_FENCE); } else { barrier(CLK_GLOBAL_MEM_FENCE); barrier(CLK_GLOBAL_MEM_FENCE); } }
Мне кажется, что это условие нужно запускать после того, как массив Data будет заполнен и результат выводить в другой массив (например Data2) Код (C): barrier(CLK_GLOBAL_MEM_FENCE); if(Val==1) { if((Data[_X+Size*_Y-1]==1) && (Data[_X+Size*_Y+1]==1)) { if((Data[_X+Size*(_Y-1)-1]==1) && (Data[_X+Size*(_Y-1)]==1) && (Data[_X+Size*(_Y-1)+1]==1)) { if((Data[_X+Size*(_Y+1)-1]==1) && (Data[_X+Size*(_Y+1)]==1) && (Data[_X+Size*(_Y+1)+1]==1)) { Val=0; } } } } barrier(CLK_GLOBAL_MEM_FENCE); Data2[_X+Size*_Y]=Val; Не?
В #4 написано. Зачем Data2, если Data весь заполнен (для этого я и поставил barrier(CLK_GLOBAL_MEM_FENCE)).
Извиняюсь - прочитал немного про OpenCL теперь стало понятнее. Если втупую расчитывать каждую соседнюю точку - результат нормальный Код (C): float2 Mult(float2 z1,float2 z2) { return (float2)(z1.x*z2.x-z1.y*z2.y, z1.y*z2.x+z1.x*z2.y); } constant float Threshold; constant uint Size; constant float Border; constant uint NumOfIter; uchar Mandel(size_t _X, size_t _Y){ float2 c=(float2)(Border*2.0f*((float)_X/(float)(Size-1)-0.5f),Border*2.0f*((float)(Size-_Y-1)/(float)(Size-1)-0.5f)); float2 z=(float2)(0,0); for(uint i=0;(i<NumOfIter) && (length(z)<Threshold);i++) z=Mult(Mult(Mult(Mult(z,z),z),z),z)+c; if(length(z)<Threshold) return 1; else return 0; } __kernel void CalcMandel(float _Border,float _Threshold,uint _NumOfIter,uint _Size,__global uchar *Data/*,__global uint *NumOfPoints*/) { Threshold=_Threshold; Size =_Size; Border =_Border; NumOfIter=_NumOfIter; size_t _X=get_global_id(0); size_t _Y=get_global_id(1); Data[_X+_Size*_Y]=Mandel(_X,_Y); if((Mandel(_X-1,_Y)==1)&&(Mandel(_X+1,_Y)==1)) if((Mandel(_X-1,_Y-1)==1)&&(Mandel(_X,_Y-1)==1)&&(Mandel(_X+1,_Y-1)==1)) if((Mandel(_X-1,_Y+1)==1)&&(Mandel(_X,_Y+1)==1)&&(Mandel(_X+1,_Y+1)==1)) Data[_X+_Size*_Y]=0; } Я вот думаю val - это ведь private memory. И при синхронизации потоков в GPU просто не хватает памяти, чтобы сохранить значение переменной для каждого потока. Если сохранять промежуточные вычисления в __global массиве, то всё должно работать.