repstosw 18 17 марта, 2019 Опубликовано 17 марта, 2019 · Жалоба Делаю расчёты в формате floating point. К примеру - делю одно на другое. В асм-листинге вижу такое: $C$RL64: ; CALL OCCURS {__c6xabi_divf} {0} ; [] |147| ;** --------------------------------------------------------------------------* CALLP .S2 __c6xabi_divf,B3 ; [B_Sb674] |147| Как это безобразие называется??? Аппаратная поддержка floating point? C6745 вообще поддерживает операции с плавающей точкой или нет? Я ожидал инлайнинга иструкций на ассемблере, а не вызов функций с черт-пойми каким содержимым. Как итог: программа тормозит, и скорее всего там идёт целочисленная эмуляция плавучки. Спецы, подскажите, как заставить генериться код с ассемблерными инструкциями плавучки? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 242 17 марта, 2019 Опубликовано 17 марта, 2019 · Жалоба 4 минуты назад, __inline__ сказал: Как это безобразие называется??? Это безобразие Вы сами и устроили. Везде, где можно обойтись без деления, нужно обходиться без него. 4 минуты назад, __inline__ сказал: C6745 вообще поддерживает операции с плавающей точкой или нет? Конечно. Но кто Вам сказал, что он имеет аппаратное деление? Да даже если бы и имел, то даже аппаратное деление не перестаёт быть делением. Вы вроде бы писали что раньше работали с другими DSP? Тогда странно не знать об этом. 4 минуты назад, __inline__ сказал: Как итог: программа тормозит, и скорее всего там идёт целочисленная эмуляция плавучки. Тормозит не из-за мнимой эмуляции, а из-за наличия инструкций вызова CALL. Их не может быть в быстрых аппаратных циклах. Я не зря вам свои функции приводил. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
repstosw 18 17 марта, 2019 Опубликовано 17 марта, 2019 · Жалоба 9 minutes ago, jcxz said: Тормозит не из-за мнимой эмуляции, а из-за наличия инструкций вызова CALL. Их не может быть в быстрых аппаратных циклах. Я не зря вам свои функции приводил. Это мне понятно. Непонятно, как заставить инлайниться во floating-point такой кусок кода: float A=0.4F; float B=0.223424F; float C; void main(void) { C=A/B; } Это простое деление, и оно должно инлайниться в инструкции , а не через CALL вызываться. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
repstosw 18 17 марта, 2019 Опубликовано 17 марта, 2019 · Жалоба Неужели это деление тоже через интринсики надо писать? Очень неудобно. В том же Keil + STM32 с их поддержкой VFPv4 плавучка инлайнится напрямую без применения интринсиков.. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 242 17 марта, 2019 Опубликовано 17 марта, 2019 · Жалоба 14 минут назад, __inline__ сказал: Это простое деление, и оно должно инлайниться в инструкции , а не через CALL вызываться. Ну так A и B - переменные же. Соответственно их деление компилятор не может заменить умножением. А команды деления (аппаратной) в этом ядре видимо нет (уже точно не помню, но скорей всего так). Поэтому вызывается библиотечная функция. 2 минуты назад, __inline__ сказал: Неужели это деление тоже через интринсики надо писать? Очень неудобно. В том же Keil + STM32 с их поддержкой VFPv4 плавучка инлайнится напрямую без применения интринсиков.. "В том же" есть аппаратная команда деления. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 242 17 марта, 2019 Опубликовано 17 марта, 2019 · Жалоба 1. Если делитель - константа, то замените деление умножением на обратное (хотя по идее компилятор сам должен это делать). 2. Если делитель - переменная, но деление делается в цикле с одним и тем же значением делителя, то вычислите однократно 1/B, а потом умножайте. Я даже для Cortex-ов так делаю, когда важна скорость. Также насколько помню - в этом DSP-ядре есть быстрая инструкция вычисления обратного значения от числа (1/x) - используйте её интринсинк для нахождения обратного. PS: При написании быстрого кода для этого ядра, нужно придерживаться правила чтобы в циклах нижнего уровня не было вызовов функций. Даже библиотечных. Иначе не будет использоваться SPLOOP. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
thermit 1 17 марта, 2019 Опубликовано 17 марта, 2019 (изменено) · Жалоба Да. Хочешь умножения - дели на константу, а не на переменную. А вообще-то аппаратное деление это довольно экзотическое явление. В цпос обычно реализована команда малоразрядного вычисления 1/y. Затем через ньютона-рафсона достигается требуемая точность и результат умножается на x. Использовать либские функции в масовом делении не надо. Надо написать собственную инлайн без глупостей типо проверок деления на 0 и пр наны. Вычисление квадратного корня реализовано примерно так же. Только примитив 1/sqrt(y). Изменено 17 марта, 2019 пользователем thermit Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
repstosw 18 17 марта, 2019 Опубликовано 17 марта, 2019 (изменено) · Жалоба Спасибо огромное! Да, заменил деление везде на умножение на интринсик _rcpsp() - тормоза исчезли, всё идёт очень лихо! Было 67 делений в программе. Часть из них сидели в цикле отрисовки линий. Попутно спрошу, есть ли возможность поменять местами значения переменных, а то приходится писать что-то вроде такого: if(p0y>p1y) { templ=p0y; p0y=p1y; p1y=templ; Весь код (начальный, без оптимизации) - привожу ниже. Рисуем текстуры.... На STM32H743 этот код просто летает. Spoiler #define MaxX H #define MaxY W #define P1 12 /* грань */ #define P2 32 /* длина */ #define D 3.0F /* дистанция */ #if TUNNEL_SIMPLE #define SPEED 0.5F #define TEXTURE_SPEED 5.0F #else #define SPEED 0.75F #define TEXTURE_SPEED 20.0F #endif #define PI 3.14159265358979323846F #define TRUNC(x) ((s32)(x)) float Angle=0.0F; struct TVertex { float X,Y,Z; }; struct TVertex Vertex[P1+1][P2]; u16 (*Texture)[MaxU][MaxV]=(u16 (*)[MaxU][MaxV])TUNNEL; s32 y; float x1,x2,z1,z2,u1,u2,v1,v2; float dz,du,dv; void ClearCQ(void) { for(register u32 y=((MaxX*(MaxY/4))+(MaxX/4))<<1;y<((MaxX*((3*MaxY)/4))+(MaxX/4))<<1;y+=(MaxX<<1))memset((void*)(SwitchBuffer[0]+y),0,MaxX); } inline void Line(void) { if(y<0)return; register s32 a,b,c; a=TRUNC(x1); b=TRUNC(x2); if((a<0)&&(b<0))return; if(((a>=MaxX))&&(b>=MaxX))return; if(a>b) { c=a; a=b; b=c; c=1; } else c=0; if(a<0)a=0; if(b>=MaxX)b=MaxX-1; if(a==b)return; register float z,u,v; register float xx1,xx2; if(c==0)if(a==0) { z=z1-x1*dz; u=u1-x1*du; v=v1-x1*dv; } else { xx1=x1-(float)a; z=z1-xx1*dz; u=u1-xx1*du; v=v1-xx1*dv; } else if(a==0) { z=z2-x2*dz; u=u2-x2*du; v=v2-x2*dv; } else { xx2=x2-(float)a; z=z2-xx2*dz; u=u2-xx2*du; v=v2-xx2*dv; } register u16 *vb=(u16*)(SwitchBuffer[0]+(((y*MaxX)+a)<<1)); b-=(a-1); while(b--) { *vb++=(*Texture)[TRUNC(v/z)&(MaxV-1)][TRUNC(u/z)&(MaxU-1)]; z=z+dz; u=u+du; v=v+dv; } } void Triangle(float k0x,float k0y,float k0z,float k0u,float k0v,float k1x,float k1y,float k1z,float k1u,float k1v,float k2x,float k2y,float k2z,float k2u, float k2v) { register float ddx,ddy; register float temps; register s32 templ; register s32 p0y,p1y,p2y; register float p0x,p1x,p2x; register float p0z,p1z,p2z; register float p0u,p1u,p2u; register float p0v,p1v,p2v; register float dx1,dz1,du1,dv1; register float dx2,dz2,du2,dv2; register float dx3,dz3,du3,dv3; p0z=D/k0z; p0x=(MaxX/2.0F)+k0x*p0z; p0y=TRUNC((MaxY/2.0F)-(k0y*p0z)); p0u=k0u*p0z; p0v=k0v*p0z; p1z=D/k1z; p1x=(MaxX/2.0F)+k1x*p1z; p1y=TRUNC((MaxY/2.0F)-(k1y*p1z)); p1u=k1u*p1z; p1v=k1v*p1z; p2z=D/k2z; p2x=(MaxX/2.0F)+k2x*p2z; p2y=TRUNC((MaxY/2.0F)-(k2y*p2z)); p2u=k2u*p2z; p2v=k2v*p2z; if(p0y>p1y) { templ=p0y; p0y=p1y; p1y=templ; temps=p0x; p0x=p1x; p1x=temps; temps=p0z; p0z=p1z; p1z=temps; temps=p0u; p0u=p1u; p1u=temps; temps=p0v; p0v=p1v; p1v=temps; }; if(p0y>p2y) { templ=p0y; p0y=p2y; p2y=templ; temps=p0x; p0x=p2x; p2x=temps; temps=p0z; p0z=p2z; p2z=temps; temps=p0u; p0u=p2u; p2u=temps; temps=p0v; p0v=p2v; p2v=temps; }; if(p1y>p2y) { templ=p1y; p1y=p2y; p2y=templ; temps=p1x; p1x=p2x; p2x=temps; temps=p1z; p1z=p2z; p2z=temps; temps=p1u; p1u=p2u; p2u=temps; temps=p1v; p1v=p2v; p2v=temps; }; if(p0y==p1y) { ddy=1.0F/(p2y-p0y); dx1=(p2x-p0x)*ddy; dz1=(p2z-p0z)*ddy; du1=(p2u-p0u)*ddy; dv1=(p2v-p0v)*ddy; dx2=p1x-p0x; ddy=1.0F/(p2y-p1y); dx3=(p2x-p1x)*ddy; dz3=(p2z-p1z)*ddy; du3=(p2u-p1u)*ddy; dv3=(p2v-p1v)*ddy; ddx=1.0F/(dx3-dx1); dz=(dz3-dz1)*ddx; du=(du3-du1)*ddx; dv=(dv3-dv1)*ddx; if(dx1>dx2) { x1=p1x; x2=p0x; z1=p1z; z2=p0z; u1=p1u; u2=p0u; v1=p1v; v2=p0v; for(y=p1y;y<=p2y;y++) { if(y>MaxY-1)return; Line(); x1=x1+dx3; x2=x2+dx1; z1=z1+dz3; z2=z2+dz1; u1=u1+du3; u2=u2+du1; v1=v1+dv3; v2=v2+dv1; }; } else { x1=p0x; x2=p1x; z1=p0z; z2=p1z; u1=p0u; u2=p1u; v1=p0v; v2=p1v; for(y=p1y;y<=p2y;y++) { if(y>MaxY-1)return; Line(); x1=x1+dx1; x2=x2+dx3; z1=z1+dz1; z2=z2+dz3; u1=u1+du1; u2=u2+du3; v1=v1+dv1; v2=v2+dv3; }; }; } else if(p1y==p2y) { ddy=1.0F/(p2y-p0y); dx1=(p2x-p0x)*ddy; dz1=(p2z-p0z)*ddy; du1=(p2u-p0u)*ddy; dv1=(p2v-p0v)*ddy; ddy=1.0F/(p1y-p0y); dx2=(p1x-p0x)*ddy; dz2=(p1z-p0z)*ddy; du2=(p1u-p0u)*ddy; dv2=(p1v-p0v)*ddy; ddx=1.0F/(dx2-dx1); dz=(dz2-dz1)*ddx; du=(du2-du1)*ddx; dv=(dv2-dv1)*ddx; x1=p0x; x2=p0x; z1=p0z; z2=p0z; u1=p0u; u2=p0u; v1=p0v; v2=p0v; if(dx1>dx2)for(y=p0y;y<=p1y;y++) { if(y>MaxY-1)return; Line(); x1=x1+dx2; x2=x2+dx1; z1=z1+dz2; z2=z2+dz1; u1=u1+du2; u2=u2+du1; v1=v1+dv2; v2=v2+dv1; } else for(y=p0y;y<=p1y;y++) { if(y>MaxY-1)return; Line(); x1=x1+dx1; x2=x2+dx2; z1=z1+dz1; z2=z2+dz2; u1=u1+du1; u2=u2+du2; v1=v1+dv1; v2=v2+dv2; }; } else { ddy=1.0F/(p2y-p0y); dx1=(p2x-p0x)*ddy; dz1=(p2z-p0z)*ddy; du1=(p2u-p0u)*ddy; dv1=(p2v-p0v)*ddy; ddy=1.0F/(p1y-p0y); dx2=(p1x-p0x)*ddy; dz2=(p1z-p0z)*ddy; du2=(p1u-p0u)*ddy; dv2=(p1v-p0v)*ddy; ddy=1.0F/(p2y-p1y); dx3=(p2x-p1x)*ddy; dz3=(p2z-p1z)*ddy; du3=(p2u-p1u)*ddy; dv3=(p2v-p1v)*ddy; ddx=1.0F/(dx2-dx1); dz=(dz2-dz1)*ddx; du=(du2-du1)*ddx; dv=(dv2-dv1)*ddx; x1=p0x; x2=p0x; z1=p0z; z2=p0z; u1=p0u; u2=p0u; v1=p0v; v2=p0v; if(dx1>dx2) { for(y=p0y;y<p1y;y++) { if(y>MaxY-1)return; Line(); x1=x1+dx2; x2=x2+dx1; z1=z1+dz2; z2=z2+dz1; u1=u1+du2; u2=u2+du1; v1=v1+dv2; v2=v2+dv1; }; for(y=p1y;y<=p2y;y++) { if(y>MaxY-1)return; Line(); x1=x1+dx3; x2=x2+dx1; z1=z1+dz3; z2=z2+dz1; u1=u1+du3; u2=u2+du1; v1=v1+dv3; v2=v2+dv1; }; } else { for(y=p0y;y<p1y;y++) { if(y>MaxY-1)return; Line(); x1=x1+dx1; x2=x2+dx2; z1=z1+dz1; z2=z2+dz2; u1=u1+du1; u2=u2+du2; v1=v1+dv1; v2=v2+dv2; }; for(y=p1y;y<=p2y;y++) { if(y>MaxY-1)return; Line(); x1=x1+dx1; x2=x2+dx3; z1=z1+dz1; z2=z2+dz3; u1=u1+du1; u2=u2+du3; v1=v1+dv1; v2=v2+dv3; }; }; }; }; void Tunnel(void) { s32 i,j; Angle+=SPEED; for(i=0;i<=P1;i++)for(j=0;j<P2;j++) { Vertex[i][j].X=(MaxX/2.0F)*((3.0F-(((float)j)/P1))*cosf(((2.0F*PI/P1)*((float)i)))+2.0F*sinf((Angle+(2.0F*((float)j)))/29.0F)+cosf((Angle+(2.0F*((float)j)))/13.0F)-2.0F*sinf(Angle/29.0F)-cosf(Angle/13.0F)); Vertex[i][j].Y=(MaxY/2.0F)*((3.0F-(((float)j)/P1))*sinf(((2.0F*PI/P1)*((float)i)))+2.0F*cosf((Angle+(2.0F*((float)j)))/33.0F)+sinf((Angle+(2.0F*((float)j)))/17.0F)-2.0F*cosf(Angle/33.0F)-sinf(Angle/17.0F)); Vertex[i][j].Z=((float)j)+1.0F; } for(j=P2-2;j>=0;j--) { float J1=MaxV-((MaxV*((float) j ))/P2)-(Angle*TEXTURE_SPEED); float J2=MaxV-((MaxV*((float)(j+1)))/P2)-(Angle*TEXTURE_SPEED); for(i=0;i<P1;i++) { float I1=MaxU-((MaxU*((float)(i-3+P1)))/P1); float I2=MaxU-((MaxU*((float)(i-2+P1)))/P1); Triangle( Vertex[i ][j ].X,Vertex[i ][j ].Y,Vertex[i ][j ].Z,I1,J1, //0 Vertex[i+1][j ].X,Vertex[i+1][j ].Y,Vertex[i+1][j ].Z,I2,J1, //1 Vertex[i+1][j+1].X,Vertex[i+1][j+1].Y,Vertex[i+1][j+1].Z,I2,J2 //2 ); Triangle( Vertex[i ][j ].X,Vertex[i ][j ].Y,Vertex[i ][j ].Z,I1,J1, //0 Vertex[i+1][j+1].X,Vertex[i+1][j+1].Y,Vertex[i+1][j+1].Z,I2,J2, //2 Vertex[i ][j+1].X,Vertex[i ][j+1].Y,Vertex[i ][j+1].Z,I1,J2 //3 ); } } } int main(void) { SCB_EnableICache(); SCB_EnableDCache(); HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_FMC_Init(); MX_DMA_Init(); LCD_Reset(); LCD_Init(); LCD_Position(0,0,W-1,H-1); Loop: LCD_Transfer(); ClearCQ(); Tunnel(); goto Loop; } Изменено 17 марта, 2019 пользователем repstosw Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 242 17 марта, 2019 Опубликовано 17 марта, 2019 · Жалоба 15 минут назад, __inline__ сказал: Попутно спрошу, есть ли возможность поменять местами значения переменных, а то приходится писать что-то вроде такого: А что не устраивает в таком коде? Если напрягает громоздкость текста - так оберните в макрос. А компилиться это будет оптимально: чем более простые конструкции используете - тем лучше работает оптимизатор. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
thermit 1 17 марта, 2019 Опубликовано 17 марта, 2019 · Жалоба 33 минуты назад, __inline__ сказал: Спасибо огромное! Да, заменил деление везде на умножение на интринсик _rcpsp() - тормоза исчезли, всё идёт очень лихо! Было 67 делений в программе. Часть из них сидели в цикле отрисовки линий. Попутно спрошу, есть ли возможность поменять местами значения переменных, а то приходится писать что-то вроде такого: if(p0y>p1y) { templ=p0y; p0y=p1y; p1y=templ; Весь код (начальный, без оптимизации) - привожу ниже. Рисуем текстуры.... На STM32H743 этот код просто летает. Показать контент #define MaxX H #define MaxY W #define P1 12 /* грань */ #define P2 32 /* длина */ #define D 3.0F /* дистанция */ #if TUNNEL_SIMPLE #define SPEED 0.5F #define TEXTURE_SPEED 5.0F #else #define SPEED 0.75F #define TEXTURE_SPEED 20.0F #endif #define PI 3.14159265358979323846F #define TRUNC(x) ((s32)(x)) float Angle=0.0F; struct TVertex { float X,Y,Z; }; struct TVertex Vertex[P1+1][P2]; u16 (*Texture)[MaxU][MaxV]=(u16 (*)[MaxU][MaxV])TUNNEL; s32 y; float x1,x2,z1,z2,u1,u2,v1,v2; float dz,du,dv; void ClearCQ(void) { for(register u32 y=((MaxX*(MaxY/4))+(MaxX/4))<<1;y<((MaxX*((3*MaxY)/4))+(MaxX/4))<<1;y+=(MaxX<<1))memset((void*)(SwitchBuffer[0]+y),0,MaxX); } inline void Line(void) { if(y<0)return; register s32 a,b,c; a=TRUNC(x1); b=TRUNC(x2); if((a<0)&&(b<0))return; if(((a>=MaxX))&&(b>=MaxX))return; if(a>b) { c=a; a=b; b=c; c=1; } else c=0; if(a<0)a=0; if(b>=MaxX)b=MaxX-1; if(a==b)return; register float z,u,v; register float xx1,xx2; if(c==0)if(a==0) { z=z1-x1*dz; u=u1-x1*du; v=v1-x1*dv; } else { xx1=x1-(float)a; z=z1-xx1*dz; u=u1-xx1*du; v=v1-xx1*dv; } else if(a==0) { z=z2-x2*dz; u=u2-x2*du; v=v2-x2*dv; } else { xx2=x2-(float)a; z=z2-xx2*dz; u=u2-xx2*du; v=v2-xx2*dv; } register u16 *vb=(u16*)(SwitchBuffer[0]+(((y*MaxX)+a)<<1)); b-=(a-1); while(b--) { *vb++=(*Texture)[TRUNC(v/z)&(MaxV-1)][TRUNC(u/z)&(MaxU-1)]; z=z+dz; u=u+du; v=v+dv; } } void Triangle(float k0x,float k0y,float k0z,float k0u,float k0v,float k1x,float k1y,float k1z,float k1u,float k1v,float k2x,float k2y,float k2z,float k2u, float k2v) { register float ddx,ddy; register float temps; register s32 templ; register s32 p0y,p1y,p2y; register float p0x,p1x,p2x; register float p0z,p1z,p2z; register float p0u,p1u,p2u; register float p0v,p1v,p2v; register float dx1,dz1,du1,dv1; register float dx2,dz2,du2,dv2; register float dx3,dz3,du3,dv3; p0z=D/k0z; p0x=(MaxX/2.0F)+k0x*p0z; p0y=TRUNC((MaxY/2.0F)-(k0y*p0z)); p0u=k0u*p0z; p0v=k0v*p0z; p1z=D/k1z; p1x=(MaxX/2.0F)+k1x*p1z; p1y=TRUNC((MaxY/2.0F)-(k1y*p1z)); p1u=k1u*p1z; p1v=k1v*p1z; p2z=D/k2z; p2x=(MaxX/2.0F)+k2x*p2z; p2y=TRUNC((MaxY/2.0F)-(k2y*p2z)); p2u=k2u*p2z; p2v=k2v*p2z; if(p0y>p1y) { templ=p0y; p0y=p1y; p1y=templ; temps=p0x; p0x=p1x; p1x=temps; temps=p0z; p0z=p1z; p1z=temps; temps=p0u; p0u=p1u; p1u=temps; temps=p0v; p0v=p1v; p1v=temps; }; if(p0y>p2y) { templ=p0y; p0y=p2y; p2y=templ; temps=p0x; p0x=p2x; p2x=temps; temps=p0z; p0z=p2z; p2z=temps; temps=p0u; p0u=p2u; p2u=temps; temps=p0v; p0v=p2v; p2v=temps; }; if(p1y>p2y) { templ=p1y; p1y=p2y; p2y=templ; temps=p1x; p1x=p2x; p2x=temps; temps=p1z; p1z=p2z; p2z=temps; temps=p1u; p1u=p2u; p2u=temps; temps=p1v; p1v=p2v; p2v=temps; }; if(p0y==p1y) { ddy=1.0F/(p2y-p0y); dx1=(p2x-p0x)*ddy; dz1=(p2z-p0z)*ddy; du1=(p2u-p0u)*ddy; dv1=(p2v-p0v)*ddy; dx2=p1x-p0x; ddy=1.0F/(p2y-p1y); dx3=(p2x-p1x)*ddy; dz3=(p2z-p1z)*ddy; du3=(p2u-p1u)*ddy; dv3=(p2v-p1v)*ddy; ddx=1.0F/(dx3-dx1); dz=(dz3-dz1)*ddx; du=(du3-du1)*ddx; dv=(dv3-dv1)*ddx; if(dx1>dx2) { x1=p1x; x2=p0x; z1=p1z; z2=p0z; u1=p1u; u2=p0u; v1=p1v; v2=p0v; for(y=p1y;y<=p2y;y++) { if(y>MaxY-1)return; Line(); x1=x1+dx3; x2=x2+dx1; z1=z1+dz3; z2=z2+dz1; u1=u1+du3; u2=u2+du1; v1=v1+dv3; v2=v2+dv1; }; } else { x1=p0x; x2=p1x; z1=p0z; z2=p1z; u1=p0u; u2=p1u; v1=p0v; v2=p1v; for(y=p1y;y<=p2y;y++) { if(y>MaxY-1)return; Line(); x1=x1+dx1; x2=x2+dx3; z1=z1+dz1; z2=z2+dz3; u1=u1+du1; u2=u2+du3; v1=v1+dv1; v2=v2+dv3; }; }; } else if(p1y==p2y) { ddy=1.0F/(p2y-p0y); dx1=(p2x-p0x)*ddy; dz1=(p2z-p0z)*ddy; du1=(p2u-p0u)*ddy; dv1=(p2v-p0v)*ddy; ddy=1.0F/(p1y-p0y); dx2=(p1x-p0x)*ddy; dz2=(p1z-p0z)*ddy; du2=(p1u-p0u)*ddy; dv2=(p1v-p0v)*ddy; ddx=1.0F/(dx2-dx1); dz=(dz2-dz1)*ddx; du=(du2-du1)*ddx; dv=(dv2-dv1)*ddx; x1=p0x; x2=p0x; z1=p0z; z2=p0z; u1=p0u; u2=p0u; v1=p0v; v2=p0v; if(dx1>dx2)for(y=p0y;y<=p1y;y++) { if(y>MaxY-1)return; Line(); x1=x1+dx2; x2=x2+dx1; z1=z1+dz2; z2=z2+dz1; u1=u1+du2; u2=u2+du1; v1=v1+dv2; v2=v2+dv1; } else for(y=p0y;y<=p1y;y++) { if(y>MaxY-1)return; Line(); x1=x1+dx1; x2=x2+dx2; z1=z1+dz1; z2=z2+dz2; u1=u1+du1; u2=u2+du2; v1=v1+dv1; v2=v2+dv2; }; } else { ddy=1.0F/(p2y-p0y); dx1=(p2x-p0x)*ddy; dz1=(p2z-p0z)*ddy; du1=(p2u-p0u)*ddy; dv1=(p2v-p0v)*ddy; ddy=1.0F/(p1y-p0y); dx2=(p1x-p0x)*ddy; dz2=(p1z-p0z)*ddy; du2=(p1u-p0u)*ddy; dv2=(p1v-p0v)*ddy; ddy=1.0F/(p2y-p1y); dx3=(p2x-p1x)*ddy; dz3=(p2z-p1z)*ddy; du3=(p2u-p1u)*ddy; dv3=(p2v-p1v)*ddy; ddx=1.0F/(dx2-dx1); dz=(dz2-dz1)*ddx; du=(du2-du1)*ddx; dv=(dv2-dv1)*ddx; x1=p0x; x2=p0x; z1=p0z; z2=p0z; u1=p0u; u2=p0u; v1=p0v; v2=p0v; if(dx1>dx2) { for(y=p0y;y<p1y;y++) { if(y>MaxY-1)return; Line(); x1=x1+dx2; x2=x2+dx1; z1=z1+dz2; z2=z2+dz1; u1=u1+du2; u2=u2+du1; v1=v1+dv2; v2=v2+dv1; }; for(y=p1y;y<=p2y;y++) { if(y>MaxY-1)return; Line(); x1=x1+dx3; x2=x2+dx1; z1=z1+dz3; z2=z2+dz1; u1=u1+du3; u2=u2+du1; v1=v1+dv3; v2=v2+dv1; }; } else { for(y=p0y;y<p1y;y++) { if(y>MaxY-1)return; Line(); x1=x1+dx1; x2=x2+dx2; z1=z1+dz1; z2=z2+dz2; u1=u1+du1; u2=u2+du2; v1=v1+dv1; v2=v2+dv2; }; for(y=p1y;y<=p2y;y++) { if(y>MaxY-1)return; Line(); x1=x1+dx1; x2=x2+dx3; z1=z1+dz1; z2=z2+dz3; u1=u1+du1; u2=u2+du3; v1=v1+dv1; v2=v2+dv3; }; }; }; }; void Tunnel(void) { s32 i,j; Angle+=SPEED; for(i=0;i<=P1;i++)for(j=0;j<P2;j++) { Vertex[i][j].X=(MaxX/2.0F)*((3.0F-(((float)j)/P1))*cosf(((2.0F*PI/P1)*((float)i)))+2.0F*sinf((Angle+(2.0F*((float)j)))/29.0F)+cosf((Angle+(2.0F*((float)j)))/13.0F)-2.0F*sinf(Angle/29.0F)-cosf(Angle/13.0F)); Vertex[i][j].Y=(MaxY/2.0F)*((3.0F-(((float)j)/P1))*sinf(((2.0F*PI/P1)*((float)i)))+2.0F*cosf((Angle+(2.0F*((float)j)))/33.0F)+sinf((Angle+(2.0F*((float)j)))/17.0F)-2.0F*cosf(Angle/33.0F)-sinf(Angle/17.0F)); Vertex[i][j].Z=((float)j)+1.0F; } for(j=P2-2;j>=0;j--) { float J1=MaxV-((MaxV*((float) j ))/P2)-(Angle*TEXTURE_SPEED); float J2=MaxV-((MaxV*((float)(j+1)))/P2)-(Angle*TEXTURE_SPEED); for(i=0;i<P1;i++) { float I1=MaxU-((MaxU*((float)(i-3+P1)))/P1); float I2=MaxU-((MaxU*((float)(i-2+P1)))/P1); Triangle( Vertex[i ][j ].X,Vertex[i ][j ].Y,Vertex[i ][j ].Z,I1,J1, //0 Vertex[i+1][j ].X,Vertex[i+1][j ].Y,Vertex[i+1][j ].Z,I2,J1, //1 Vertex[i+1][j+1].X,Vertex[i+1][j+1].Y,Vertex[i+1][j+1].Z,I2,J2 //2 ); Triangle( Vertex[i ][j ].X,Vertex[i ][j ].Y,Vertex[i ][j ].Z,I1,J1, //0 Vertex[i+1][j+1].X,Vertex[i+1][j+1].Y,Vertex[i+1][j+1].Z,I2,J2, //2 Vertex[i ][j+1].X,Vertex[i ][j+1].Y,Vertex[i ][j+1].Z,I1,J2 //3 ); } } } int main(void) { SCB_EnableICache(); SCB_EnableDCache(); HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_FMC_Init(); MX_DMA_Init(); LCD_Reset(); LCD_Init(); LCD_Position(0,0,W-1,H-1); Loop: LCD_Transfer(); ClearCQ(); Tunnel(); goto Loop; } 32-х битные нет. На ти ифы в цикле летают очень плохо. Впрочем, на ад тоже не особо. Конвейеры. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 242 17 марта, 2019 Опубликовано 17 марта, 2019 · Жалоба Глянул немного ваш код. Есть маленькое замечание - в Line(): if(y<0)return; if((a<0)&&(b<0))return; if(((a>=MaxX))&&(b>=MaxX))return; лучше, имхо, записать как: if ((a & b | y) < 0) return; if ((a - MaxX | b - MaxX) >= 0) return; а может даже: if ((~(a - MaxX | b - MaxX) | a & b | y) < 0) return; так как для DSP: чем меньше переходов в коде - тем быстрее. Хотя конечно вес этого фрагмента во времени выполнения функции Line() и очень невелик. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
repstosw 18 17 марта, 2019 Опубликовано 17 марта, 2019 · Жалоба OK, спасибо! Попутно новая проблема вылезла: В цикле отрисовки линии : while(b--) { FLOAT rz=_rcpsp(z); *vb++=(*Texture)[TRUNC(v*rz)&(MaxV-1)][TRUNC(u*rz)&(MaxU-1)]; z=z+dz; u=u+du; v=v+dv; } Со временем текстура деградирует - становится дырявой. В то время когда прежний код, который медлительный из-за делений: while(b--) { *vb++=(*Texture)[TRUNC(v/z)&(MaxV-1)][TRUNC(u/z)&(MaxU-1)]; z=z+dz; u=u+du; v=v+dv; } работает без деградации текстуры. Выходит что умножение на обратную величину приводит к потери точности, так как текстурные координаты постепенно "сползают" и картинка со временем становится дырявой. Что можно предпринять в этом случае? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
thermit 1 17 марта, 2019 Опубликовано 17 марта, 2019 · Жалоба 6 минут назад, __inline__ сказал: OK, спасибо! Попутно новая проблема вылезла: В цикле отрисовки линии : while(b--) { FLOAT rz=_rcpsp(z); *vb++=(*Texture)[TRUNC(v*rz)&(MaxV-1)][TRUNC(u*rz)&(MaxU-1)]; z=z+dz; u=u+du; v=v+dv; } Со временем текстура деградирует - становится дырявой. В то время когда прежний код, который медлительный из-за делений: while(b--) { *vb++=(*Texture)[TRUNC(v/z)&(MaxV-1)][TRUNC(u/z)&(MaxU-1)]; z=z+dz; u=u+du; v=v+dv; } работает без деградации текстуры. Выходит что умножение на обратную величину приводит к потери точности, так как текстурные координаты постепенно "сползают" и картинка со временем становится дырявой. Что можно предпринять в этом случае? Нет. rcpsp получает только 8 верных бит. Ошибка накапливается и давай до свидания. Нужно вычислять как минимум 16 бит. Или больше. Т е будет 2-3 итерации ньютона-рафсона. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 242 17 марта, 2019 Опубликовано 17 марта, 2019 · Жалоба 24 минуты назад, __inline__ сказал: Выходит что умножение на обратную величину приводит к потери точности, так как текстурные координаты постепенно "сползают" и картинка со временем становится дырявой. Как оно может "сползать" если и в том и в другом случае у Вас z=z+dz, а rz - временная, вычисляемая в каждой итерации из z. Т.е. - ошибки её вычисления нигде не накапливаются. Видимо проблема где-то в другом месте.... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
thermit 1 17 марта, 2019 Опубликовано 17 марта, 2019 · Жалоба 1 час назад, jcxz сказал: Как оно может "сползать" если и в том и в другом случае у Вас z=z+dz, а rz - временная, вычисляемая в каждой итерации из z. Т.е. - ошибки её вычисления нигде не накапливаются. Видимо проблема где-то в другом месте.... Не знаю. Разница только в точности результата деления. Ищите. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться