GameDev.ru
/ GameDev.ru / Пользователи / Andrey / Сообщения на форуме пользователя Andrey (96 стр.)

Сообщения на форуме пользователя Andrey (96 стр.)

SSE Перемножение матриц 4x3 не дает прироста.23 окт. 200822:08#32
IronPeter
Спасибо буду знать такие нюансы.
SSE Перемножение матриц 4x3 не дает прироста.23 окт. 200820:49#27
Ghost2
да я все понял. Написал  другой тест. убрал enhanced instruction set. SSE опережает действительно на 20%
код теста более адекватный:
  enum {
    numMat = 500000,
  };
  Matrix4x3* Mat = new Matrix4x3[numMat];
  Matrix4x3* Mat1 = new Matrix4x3[numMat];
  Matrix4x3* Mat2 = new Matrix4x3[numMat];
  for(int i = 0; i < numMat; ++i) {
    Mat1[i].LoadIdentity();
    Mat2[i].LoadIdentity();
    Mat2[i].RotateY(30.0f);
    Mat1[i].Translate(2.0f, 5.0f, 4.0f);
  }
  clock_t t = clock();
  for(int i = 0; i < numMat; ++i) {
    Mat[i] = Mat1[i] * Mat2[i];
    Mat[i] = Mat[i] * Mat2[i];
    Mat[i] = Mat[i] * Mat1[i];

    Mat[i] = Mat2[i] * Mat[i];
    Mat[i] = Mat1[i] * Mat[i];
    Mat[i] = Mat1[i] * Mat[i];
    Mat[i] = Mat2[i] * Mat[i];
  }
  t = clock() - t;
вот новый проект
http://www.gamedev.ru/download/?id=7956
прошу потестировать что вышло.

Правка: 23 окт. 2008 20:51

SSE Перемножение матриц 4x3 не дает прироста.23 окт. 20089:46#21
Ghost2
>Во первых, в твоем проекте даже перемножение на FPU не заинлайнилось.
странно может я что-то не понимаю но все инлайнится:
for(int i = 0; i < num; ++i) {
0040122B  sub         eax,1 
    Mat = Mat1 * Mat2;
0040122E  movss       xmm7,dword ptr [esp+8] 
00401234  movss       dword ptr [esp+64h],xmm7 
0040123A  movss       xmm7,dword ptr [esp+10h] 
00401240  movss       dword ptr [esp+74h],xmm7 
00401246  movss       xmm7,dword ptr [esp+14h] 
0040124C  movss       dword ptr [esp+58h],xmm7 
00401252  movss       xmm7,dword ptr [esp+18h] 
00401258  movss       dword ptr [esp+68h],xmm7 
0040125E  movss       xmm7,dword ptr [esp+1Ch] 
00401264  movss       dword ptr [esp+78h],xmm7 
0040126A  movss       dword ptr [esp+50h],xmm3 
00401270  movss       dword ptr [esp+54h],xmm6 
00401276  movss       dword ptr [esp+5Ch],xmm1 
0040127C  movdqa      xmm7,xmmword ptr [esp+50h] 
00401282  movdqa      xmmword ptr [esp+20h],xmm7 
00401288  movss       dword ptr [esp+60h],xmm4 
0040128E  movss       dword ptr [esp+6Ch],xmm2 
00401294  movdqa      xmm7,xmmword ptr [esp+60h] 
0040129A  movss       dword ptr [esp+70h],xmm5 
004012A0  movss       dword ptr [esp+7Ch],xmm0 
004012A6  movdqa      xmmword ptr [esp+30h],xmm7 
004012AC  movdqa      xmm7,xmmword ptr [esp+70h] 
004012B2  movdqa      xmmword ptr [esp+40h],xmm7 
004012B8  jne         main+22Bh (40122Bh) 
  }
где ты там увидел call инструкцию?
да и __forceinline просто физически не может не ЗАИНЛАЙНИТЬ
SSE Перемножение матриц 4x3 не дает прироста.23 окт. 20080:37#20
Ghost2
почему? скачай проект посмотри :)
SSE Перемножение матриц 4x3 не дает прироста.22 окт. 200821:26#17
Zeux
ага спасибо понял :)
SSE Перемножение матриц 4x3 не дает прироста.22 окт. 200821:21#15
cppguru
>>_mm_load1_ps(&A[0]), B.m0
>По-моему это только матрицы вращения умеет умножать.
что-то я не понял что тут ты хотел сказать :)
Zeux
>Надо пытаться оставаться в регистрах, чем меньше load* операций - тем лучше. Для этого есть shuffle и битовые операции.
да это я уже понял просто решил сам попробовать написать решил задачу в лоб. load действительно тормоз.
я теперь подробней разберусь с интристиками shuffle_ps, ну а макрос _MM_SHUFFLE довольно упростит понимание.
>где row3 - виртуальный ряд 0 0 0 1.
а что это такое виртуальный ряд?
flaber
>Выкладывай новые дэмы! Очень интересно потестить.
Zeux
>Кстати а какие у тебя в итоге-то результаты?
ну в общем clock действительно довольно грубый для этого и сделал цикл. Ну в любом случае прирост на порядок!
Теперь скелетка будет шустро считаться Code Analyst как раз в перемножение матриц показывал.
вот последние результаты
Time:(SSE) 15
Time: 197
вот для теста проект
http://www.gamedev.ru/download/?id=7953
Всем спасибо! отдельное спасибо Zeux за исправленный код и за науку, и cppguru за советы.
SSE Перемножение матриц 4x3 не дает прироста.22 окт. 20089:16#11
Zeux
Спасибо прирост на порядок. Попробую въехать почему получилось быстрее.
>Нельзя так писать на SSE.
Где подробнее почитать как правильно писать на SSE ?
Текстура из массива dx922 окт. 20080:10#2
flaber
IDirect3DTexture9::LockRect;
IDirect3DTexture9::UnlockRect
потом загружай массив.
SSE Перемножение матриц 4x3 не дает прироста.21 окт. 200823:32#7
flaber
Vector4D.h макрос SSE вверху.
SSE Перемножение матриц 4x3 не дает прироста.21 окт. 200823:04#4
flaber
>Time(SSE) (Matrix4x3_SSE) : почемуто даёт разные результаты производительности в основном 62 - 77
>Time (Matrix4x3SSE ): тоже поразному 153 - 178.
>мож я чё не понял но помоему всё робит!
хм... т.е. ты хочешь сказать что SSE быстрей на твоем процессоре?
Как же тогда быть с разными процессорами.
all
Потестируйте пожалуйста. И укажите тип процессора.
SSE Перемножение матриц 4x3 не дает прироста.21 окт. 200823:01#3
Семен
>Посмотри во что компилируется часть

> C[3] += A[3];
> C[7] += A[7];
> C[11] += A[11];
код компилится в SSE,
>Если не в SSE, то лучше писать add_ss и store_ps.
так по этому поводу додумался только до этого:

float temp[4];
_mm_store_ss(temp, _mm_add_ss(_mm_load1_ps(&C[3]), _mm_load1_ps(&A[3])));
C[3] = temp[0];
_mm_store_ss(temp, _mm_add_ss(_mm_load1_ps(&C[7]), _mm_load1_ps(&A[7])));
C[7] = temp[0];
_mm_store_ss(temp, _mm_add_ss(_mm_load1_ps(&C[11]), _mm_load1_ps(&A[11])));
C[11] = temp[0];
использовал то что ты сказал но получилось длиней и медленней :(.

SSE Перемножение матриц 4x3 не дает прироста.21 окт. 200822:19#0
Привет! всем сделал перемножение матриц на SSE интристиках, чтобы ускорить расчет иерархии костей на CPU.
матрица представлена так:
...
union ALIGN16 {
      struct {
        __m128 m0;
        __m128 m1;
        __m128 m2;
      };
      struct {
        float _11, _12, _13;
        float _21, _22, _23;
        float _31, _32, _33;
        float _41, _42, _43;
      };
      struct {
        float matrix[4][3];
      };
      struct {
        float Matrix[12];
      };
...
хранится матрицы так
0 4 8
1 5 9
2 6 10
3 7 11
вот код умножения на FPU/SSE:
    // Перемножение матриц
    INLINE friend Matrix4x3 operator * (const Matrix4x3& A, const Matrix4x3& B)
    {
      register Matrix4x3 C;
#ifdef SSE
      //__m128 t0 = _mm_load1_ps(&A[0]);
      //__m128 t1 = _mm_load1_ps(&A[1]);
      //__m128 t2 = _mm_load1_ps(&A[2]);
      //t0 = _mm_mul_ps(t0, B.m0);
      //t1 = _mm_mul_ps(t1, B.m1);
      //t2 = _mm_mul_ps(t2, B.m2);
      //C.m0 = _mm_add_ps(t0,_mm_add_ps(t1, t2));

      //__m128 t0 = _mm_mul_ps(_mm_load1_ps(&A[0]), B.m0);
      //__m128 t1 = _mm_mul_ps(_mm_load1_ps(&A[1]), B.m1);
      //__m128 t2 = _mm_mul_ps(_mm_load1_ps(&A[2]), B.m2);
      //C.m0 = _mm_add_ps(t0,_mm_add_ps(t1, t2));

      C.m0 = _mm_add_ps(_mm_mul_ps(_mm_load1_ps(&A[0]), B.m0), _mm_add_ps(_mm_mul_ps(_mm_load1_ps(&A[1]), B.m1), 
_mm_mul_ps(_mm_load1_ps(&A[2]), B.m2)));



      //t0 = _mm_load1_ps(&A[4]);
      //t1 = _mm_load1_ps(&A[5]);
      //t2 = _mm_load1_ps(&A[6]);
      //t0 = _mm_mul_ps(t0, B.m0);
      //t1 = _mm_mul_ps(t1, B.m1);
      //t2 = _mm_mul_ps(t2, B.m2);
      //C.m1 = _mm_add_ps(t0,_mm_add_ps(t1, t2));

      //t0 = _mm_mul_ps(_mm_load1_ps(&A[4]), B.m0);
      //t1 = _mm_mul_ps(_mm_load1_ps(&A[5]), B.m1);
      //t2 = _mm_mul_ps(_mm_load1_ps(&A[6]), B.m2);
      //C.m1 = _mm_add_ps(t0,_mm_add_ps(t1, t2));
      C.m1 = _mm_add_ps(_mm_mul_ps(_mm_load1_ps(&A[4]), B.m0), _mm_add_ps(_mm_mul_ps(_mm_load1_ps(&A[5]), B.m1),
 _mm_mul_ps(_mm_load1_ps(&A[6]), B.m2)));


      //t0 = _mm_load1_ps(&A[8]);
      //t1 = _mm_load1_ps(&A[9]);
      //t2 = _mm_load1_ps(&A[10]);
      //t0 = _mm_mul_ps(t0, B.m0);
      //t1 = _mm_mul_ps(t1, B.m1);
      //t2 = _mm_mul_ps(t2, B.m2);
      //C.m2 = _mm_add_ps(t0,_mm_add_ps(t1, t2));

      //t0 = _mm_mul_ps(_mm_load1_ps(&A[8]), B.m0);
      //t1 = _mm_mul_ps(_mm_load1_ps(&A[9]), B.m1);
      //t2 = _mm_mul_ps(_mm_load1_ps(&A[10]), B.m2);
      //C.m2 = _mm_add_ps(t0,_mm_add_ps(t1, t2));
      C.m2 = _mm_add_ps(_mm_mul_ps(_mm_load1_ps(&A[8]), B.m0), _mm_add_ps(_mm_mul_ps(_mm_load1_ps(&A[9]), B.m1),
 _mm_mul_ps(_mm_load1_ps(&A[10]), B.m2)));

      C[3] += A[3];
      C[7] += A[7];
      C[11] += A[11];
      //__m128 t = _mm_add_ps(_mm_load_ps(Vector4D(C[3], C[7], C[11], 1.0f)), _mm_load_ps(Vector4D(A[3], A[7], A[11], 1.0f)));
      //C[3] = reinterpret_cast<const float *>(&t)[3];
      //C[7] = reinterpret_cast<const float *>(&t)[2];
      //C[11] = reinterpret_cast<const float *>(&t)[1];


#else
      C[0] = A[0] * B[0] + A[1] * B[4] + A[2] * B[8];
      C[4] = A[4] * B[0] + A[5] * B[4] + A[6] * B[8];
      C[8] = A[8] * B[0] + A[9] * B[4] + A[10] * B[8];

      C[1] = A[0] * B[1] + A[1] * B[5] + A[2] * B[9];
      C[5] = A[4] * B[1] + A[5] * B[5] + A[6] * B[9];
      C[9] = A[8] * B[1] + A[9] * B[5] + A[10] * B[9];

      C[2] = A[0] * B[2] + A[1] * B[6] + A[2] * B[10];
      C[6] = A[4] * B[2] + A[5] * B[6] + A[6] * B[10];
      C[10] = A[8] * B[2] + A[9] * B[6] + A[10] * B[10];

      C[3] = A[0] * B[3] + A[1] * B[7] + A[2] * B[11] + A[3];
      C[7] = A[4] * B[3] + A[5] * B[7] + A[6] * B[11] + A[7];
      C[11] = A[8] * B[3] + A[9] * B[7] + A[10] * B[11] + A[11];
#endif
      return C;
    }
тестировал на таком коде:
Matrix4x3 Mat;
  Matrix4x3 Mat1;
  Matrix4x3 Mat2;
  Mat1.LoadIdentity();
  Mat2.LoadIdentity();
  Mat2.RotateY(30.0f);
  Mat1.Translate(2.0f, 5.0f, 4.0f);
  enum {
    num = 5000000
  };
  clock_t t = clock();
  for(int i = 0; i < num; ++i) {
    Mat = Mat1 * Mat2;
  }
  t = clock() - t;
  for(int i= 0; i < 4; ++i) {
    fprintf(stderr, "%f%s%f%s%f%s", Mat[i], " ", Mat[4 + i], " ", Mat[i + 8], "\n");
  }
получил такие результаты:
D:\Work\C & C++\Graphics Pro
0.154251 -0.988032 0.000000
0.000000 1.000000 0.000000
0.988032 0.000000 0.154251
2.000000 5.000000 4.000000
Time: 203


D:\Work\C & C++\Graphics Pro
0.154251 -0.988032 0.000000
0.000000 1.000000 0.000000
0.988032 0.000000 0.154251
2.000000 5.000000 4.000000
Time:(SSE) 296
Что я делаю не так? Как можно оптимизировать, если возможно для этого случая.
Подобную проблему встречал на форуме
http://forum.ixbt.com/topic.cgi?id=26:37520
Настройки компилятора для обоих и тестов
/O2 /GL /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /MT /GS- /arch:SSE2 /fp:fast
/GR- /Fo"Release\\" /Fd"Release\vc80.pdb" /W3 /nologo /c /Wp64 /Zi /TP /errorReport:prompt
Компилировал и запускал на Visual C++ 2005 SP1,  CPU Amd Athlon, 64 3000+
проект и скомпиленные тесты:http://www.gamedev.ru/download/?id=7946
Спасибо всем заранее С Уважением Андрей.

cppguru: разбил длинные строчки

Правка: 22 окт. 2008 10:35

Использование Octree18 окт. 200812:52#20
DEN 3D
В общем проблема твоя понятна судя по рассуждениям в общем ты часто меняешь текстуры и часто рисуешь по несколько полигонов. Собирай список полигонов принадлежащих 1 материалу в листьях.
У тебя должно быть примерно так:  http://www.filekeeper.org/download/shared/TestOctreeDemo.7z. Это я писал года 3 назад. Там есть ошибки с пропаданием поликов, но есть сортировка по материалам и прирост FPS.

Использование Octree18 окт. 20080:09#12
Andru
>Каждый полигон рисовать начиная с glBegin? О_о Может все-таки попробуешь отсортировать сцену по текстурам, и рисовать через glDrawElements(для начала без >использования VBO)?
ну без Octree то у него тоже через glBegin но медленней. проблема не в этом.
DEN 3D
я когда-то делал первую реализацию Octree тоже было медленно. В общем посмотрел исходники. В принципе все правильно за исключением правильного программирования которое не имеет отношения пока  к проблеме.
Скажи чем равно значение максимального числа полигонов в листе? В строка 222 твоего кода:
PolygonsCount<=MaxPolysInLeaf тут ты принимаешь решение остановить выполнение функции и решить что текущий узел - лист. Это число нужно оптимально подобрать.
и еще... Если сцена маленькая и ты к примеру не в середине то смысл Octree отпадает, т.к. увеличивается число проверок узлов + частота вызовов glBegin/glEnd в этом случае на видеокарту более мелкими частями отправляется геометрия.
Какая глубина разбиений получилась? Сколько узлов? сколько листьев? и сколько пустых узлов? Пустые узлы помечай, не заходи в них и не проверяй на видимость.
тогда уменьшится число циклов по дочерним узлам, не всегда бывает 8 дочерних узлов.
как со всем этим разберешься передавай параметры по ссылке, вместо значений, используй итераторы в std::vector, а не std::vector::size()
выноси glBegin/glEnd за цыклы а в будущем используй VBO как подсказали выше.
Aldaron
локов там нету :) он не использует VBO в OpenGL
ChASeR
он проверяет боксы. Дело в том что он строит "Геометрическое Octree дерево" И бьет геометрию по кускам. Ты-же имеет ввиду дерево объектов(мешей) это несколько разные вещи.

Следующие темы >>

2001—2012 © GameDev.ru — Разработка игр