DirectX - страница 3

 
Rorschach:

Большое спасибо!

У вас расчеты в double идут? Тогда результат особенно впечатляющий.

Дельное замечание. Действительно, в одном месте был float вместо double:

D = fast_length(p);

Чтобы был double, нужно исправить на

D = length(p);

Кроме того, можно избавиться от последней строки (аналог макроса XRGB), если применить uchar4 вместо uint для аргумента *buf. Попробуйте так:

__kernel void Func(int N, __global double *XP, __global double *YP, __global uchar *h, __global uchar4 *buf)
{
   size_t X = get_global_id(0);
   size_t Width = get_global_size(0);
   size_t Y = get_global_id(1);
   
   float2 p;
   double D=0,S1=0,S2=0;
   
   for(int w=0;w<N;w++){ 
      p.x = XP[w]-X;
      p.y = YP[w]-Y;
      D = length(p);
      S2+=D;
      if(w<N/2)
         S1+=D;
   }   
   //
   double d=S1/S2;
   buf[Y*Width+X] = (uchar4)(0xFF,h[(int)(d*11520)],h[(int)(d*17920)],h[(int)(d*6400)]);
}
 
Serhii Shevchuk:

Это действительно впечатляет! Fps в 1.5 раза выше, чем на шейдерах.

Спасибо, код работает, производительность не упала, только в последней строке альфа канал перенес в конец:

buf[Y*Width+X] = (uchar4)(h[(int)(d*11520)],h[(int)(d*17920)],h[(int)(d*6400)],0xFF);
 
Rorschach:

Это действительно впечатляет! Fps в 1.5 раза выше, чем на шейдерах.

Спасибо, код работает, производительность не упала, только в последней строке альфа канал перенес в конец:

В данной реализации производительность сильно зависит от количества центров (N). По-хорошему, надо бы избавиться от цикла в кернеле, но тогда S1 и S2 придётся делать целочисленными. Нужно посмотреть, насколько велик разброс их значений, может получится на что-то умножить без особого греха. И тогда можно перевести цикл в третье измерение, что теоретически даст прирост производительности при больших значениях N.

У меня на HD 7950 на full-hd мониторе получается 80-90 fps при N=128.

 
Serhii Shevchuk:

В данной реализации производительность сильно зависит от количества центров (N). По-хорошему, надо бы избавиться от цикла в кернеле, но тогда S1 и S2 придётся делать целочисленными. Нужно посмотреть, насколько велик разброс их значений, может получится на что-то умножить без особого греха. И тогда можно перевести цикл в третье измерение, что теоретически даст прирост производительности при больших значениях N.

У меня на HD 7950 на full-hd мониторе получается 80-90 fps при N=128.

На моей 750ti 11 fps. Я спеки для карточек нашел: 

GPU 
FP32 GFLOPS
 FP64 GFLOPS  Ratio
Radeon HD 7950 2867 717 FP64 = 1/4 FP32
GeForce GTX 750 Ti 1388 43 FP64 = 1/32 FP32

По логике, переход на float может поднять fps сразу в 4 раза на amd и в 32 на nvidia.

 

Сделал копию OCL версии. Я в шоке от результата. При 1600 центрах не смог загрузить видяху больше 85%.

Оптимизация с предрасчетом h не влияет, но оставил с ней. Все расчеты в float, не вижу смысла использовать double, т.к. все функции все равно возвращают float.

Файлы:
pixel.zip  1 kb
 

Некоторые выводы.

1) Предрасчет h не повлиял.

2) При избавлении от if разницы не заметил

S1+=D*(i<0.5f*N);
//if(i<N*0.5f) S1+=D;

3) Так медленнее,

for(int i=0;i<N;i++)
  {XP[i]= (1.f-sin(j/iArr[2*i  ].w))*wh.x*0.5f;
   YP[i]= (1.f-cos(j/iArr[2*i+1].w))*wh.y*0.5f;
  }
float S1=0.f,S2=0.f;
for(int i=0;i<N;i++)
  {float2 p;
   p.x=XP[i]-Pos.x;
   p.y=YP[i]-Pos.y;
   ...
  }

чем так

float S1=0.f,S2=0.f;
for(int i=0;i<N;i++)
  {float2 p;
   p.x=(1.f-sin(j/iArr[2*i  ].w))*wh.x*0.5f-Pos.x;
   p.y=(1.f-cos(j/iArr[2*i+1].w))*wh.y*0.5f-Pos.y;
   ...
  }

казалось бы...

4) Не удается разгрузить проц, то есть про скальперские стаканы и т.п. можно забыть.

 
Rorschach:

Некоторые выводы.

1) Предрасчет h не повлиял.

2) При избавлении от if разницы не заметил

3) Так медленнее,

чем так

казалось бы...

4) Не удается разгрузить проц, то есть про скальперские стаканы и т.п. можно забыть.

На МТ5, скальперские стаканы запросто в одном потоке могут работать, без OCL и не перегружать процессор. Конечно, это не значит, что он не нужен. Просто к сведению.

Если использовать класс CCanvas при построении стакана, то, нагрузка при работе будет соразмерна площади стакана. Т.е. - чем больше окно стакана, тем выше нагрузка, ведь перерисовывается ВЕСЬ канвас, а не отдельные, изменившиеся части. Однако, превратив ячейки стакана в самостоятельные элементы, их можно обновлять независимо от остальной площади канваса, в разы снизив время перерисовки и вызываемую ею нагрузку на процессор. 

 
Реter Konow:

На МТ5, скальперские стаканы запросто в одном потоке могут работать, без OCL и не перегружать процессор. Конечно, это не значит, что он не нужен. Просто к сведению.

Если использовать класс CCanvas при построении стакана, то, нагрузка при работе будет соразмерна площади стакана. Т.е. - чем больше окно стакана, тем выше нагрузка, ведь перерисовывается ВЕСЬ канвас, а не отдельные, изменившиеся части. Однако, превратив ячейки стакана в самостоятельные элементы, их можно обновлять независимо от остальной площади канваса, в разы снизив время перерисовки и вызываемую ею нагрузку на процессор. 

4 пункт под вопросом. В примере Remnant3D проц почти не грузится.

 
Rorschach:

4 пункт под вопросом. В примере Remnant3D проц почти не грузится.

Это проверено. Проц на МТ5 при обычной динамики стакана почти не грузится, если перерисовывать отдельные ячейки в которых изменилось значение.

Напротив, если на событии каждого приходящего значения рисовать ВСЮ площадь канваса - процессор будет сильно напрягаться.

Разница в количестве переинициализируемых значений в массиве пикселей. Нужно выборочное обновление отдельных областей и проблем с нагрузкой не будет.

 
Реter Konow:

Это проверено. Проц на МТ5 при обычной динамики стакана почти не грузится, если перерисовывать отдельные ячейки в которых изменилось значение.

Напротив, если на событии каждого приходящего значения рисовать ВСЮ площадь канваса - процессор будет сильно напрягаться.

Разница в количестве переинициализируемых значений в массиве пикселей. Нужно выборочное обновление отдельных областей и проблем с нагрузкой не будет.

В том и прикол, что в Remnant3D канвас на весь экран и проц не грузит.