Сообщения на форуме пользователя Andrey (96 стр.)
SSE Перемножение матриц 4x3 не дает прироста. | 24 окт. 2008 | 23:37 | #39 |
---|
да ты прав.
SSE Перемножение матриц 4x3 не дает прироста. | 23 окт. 2008 | 22:08 | #32 |
---|
Спасибо буду знать такие нюансы.
SSE Перемножение матриц 4x3 не дает прироста. | 23 окт. 2008 | 20:49 | #27 |
---|
да я все понял. Написал другой тест. убрал 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 окт. 2008 | 9:46 | #21 |
---|
>Во первых, в твоем проекте даже перемножение на 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) }
да и __forceinline просто физически не может не ЗАИНЛАЙНИТЬ
SSE Перемножение матриц 4x3 не дает прироста. | 23 окт. 2008 | 0:37 | #20 |
---|
почему? скачай проект посмотри :)
SSE Перемножение матриц 4x3 не дает прироста. | 22 окт. 2008 | 21:26 | #17 |
---|
ага спасибо понял :)
SSE Перемножение матриц 4x3 не дает прироста. | 22 окт. 2008 | 21:21 | #15 |
---|
>>_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 окт. 2008 | 9:16 | #11 |
---|
Спасибо прирост на порядок. Попробую въехать почему получилось быстрее.
>Нельзя так писать на SSE.
Где подробнее почитать как правильно писать на SSE ?
Текстура из массива dx9 | 22 окт. 2008 | 0:10 | #2 |
---|
IDirect3DTexture9::LockRect;
IDirect3DTexture9::UnlockRect
потом загружай массив.
SSE Перемножение матриц 4x3 не дает прироста. | 21 окт. 2008 | 23:32 | #7 |
---|
Vector4D.h макрос SSE вверху.
SSE Перемножение матриц 4x3 не дает прироста. | 21 окт. 2008 | 23:04 | #4 |
---|
>Time(SSE) (Matrix4x3_SSE) : почемуто даёт разные результаты производительности в основном 62 - 77
>Time (Matrix4x3SSE ): тоже поразному 153 - 178.
>мож я чё не понял но помоему всё робит!
хм... т.е. ты хочешь сказать что SSE быстрей на твоем процессоре?
Как же тогда быть с разными процессорами.
all
Потестируйте пожалуйста. И укажите тип процессора.
SSE Перемножение матриц 4x3 не дает прироста. | 21 окт. 2008 | 23: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 окт. 2008 | 22:19 | #0 |
---|
матрица представлена так:
... 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
Использование Octree | 18 окт. 2008 | 12:52 | #20 |
---|
В общем проблема твоя понятна судя по рассуждениям в общем ты часто меняешь текстуры и часто рисуешь по несколько полигонов. Собирай список полигонов принадлежащих 1 материалу в листьях.
У тебя должно быть примерно так: http://www.filekeeper.org/download/shared/TestOctreeDemo.7z. Это я писал года 3 назад. Там есть ошибки с пропаданием поликов, но есть сортировка по материалам и прирост FPS.
Использование Octree | 18 окт. 2008 | 0:09 | #12 |
---|
>Каждый полигон рисовать начиная с 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 дерево" И бьет геометрию по кускам. Ты-же имеет ввиду дерево объектов(мешей) это несколько разные вещи.