diff --git a/wayland/include/figure.h b/wayland/include/figure.h index e23c168..8eef67c 100644 --- a/wayland/include/figure.h +++ b/wayland/include/figure.h @@ -13,24 +13,13 @@ enum figure_type struct figure_animation_info { enum figure_type type; struct vec2 position; - /* Direction vector; its components are not in pixels. Anim code converts - * them to pixel-space and normalizes them so that `speed` is applied as - * pixels/sec uniformly in both axes (aspect ratio is accounted for). */ struct vec2 velocity; float angle; float angular_velocity; - /* Speed in pixels per second. This value is applied uniformly to both - * axes (X and Y); the animation code converts this pixel speed to - * normalized increments for position updates taking window aspect ratio - * into account. */ + float speed; - /* Radius of the figure in pixels (float) - * This field is used by animation code to check collisions - * with the left/right/top/bottom borders. The animation code - * will convert this pixel radius to normalized coordinates for - * collision checks against normalized positions. */ float radius; }; diff --git a/wayland/src/figure-animate.asm b/wayland/src/figure-animate.asm index d77c064..08b766c 100644 --- a/wayland/src/figure-animate.asm +++ b/wayland/src/figure-animate.asm @@ -1,203 +1,191 @@ +; Макрос для локальных переменных +%macro local 2 + %assign __local_offset __local_offset - %2 + %define %1 (__local_offset) +%endmacro + ; Подключаем автоматически сгенерированные offsets из C структур %include "offsets.inc" +section .rodata +PI: dd 3.1415926 +TWO_PI: dd 6.2831852 +NEG_ONE_CONST: dd -1.0 +ONE_CONST: dd 1.0 +ZERO_CONST: dd 0.0 + section .text -; void animation_step(struct window_draw_info* draw_info); +; void figure_animation_step(struct window_draw_info* draw_info); ; Параметры: ; rdi - указатель на struct window_draw_info +%assign __local_offset 0 global figure_animation_step figure_animation_step: ; Создаём локальную область на стеке и будем туда копировать поля структуры - enter 0, 0 - ; rdi - pointer to struct window_draw_info - ; figure is embedded at offset WDI_FIGURE - mov rax, rdi - add rax, WDI_FIGURE - - ; --- compute movement increments so that `speed` means pixels/second - ; Convert velocity to pixel-space (vx = vel.x * width, vy = vel.y * height), - ; normalize that vector and apply `speed*dt` so movement in pixel units equals speed. - ; using SSE for float math - movss xmm0, dword [rax + FIG_SPEED] ; xmm0 = speed (pixels/sec) - movss xmm9, [rel DT] ; xmm9 = dt - mulss xmm0, xmm9 ; xmm0 = speed * dt (pixels) - - ; load width/height - mov ebx, dword [rdi + WDI_WIDTH] - cvtsi2ss xmm10, ebx ; xmm10 = width - mov ebx, dword [rdi + WDI_HEIGHT] - cvtsi2ss xmm11, ebx ; xmm11 = height - - ; vx_pixels = vel.x * width - movss xmm1, dword [rax + FIG_VELOCITY] ; vel.x - mulss xmm1, xmm10 ; xmm1 = vx_pixels - - ; vy_pixels = vel.y * height - movss xmm2, dword [rax + FIG_VELOCITY + 4] - mulss xmm2, xmm11 ; xmm2 = vy_pixels - - ; length = sqrt(vx^2 + vy^2) - movss xmm3, xmm1 - mulss xmm3, xmm1 ; xmm3 = vx^2 - movss xmm4, xmm2 - mulss xmm4, xmm4 ; xmm4 = vy^2 - addss xmm3, xmm4 ; xmm3 = vx^2 + vy^2 - sqrtss xmm3, xmm3 ; xmm3 = length (pixels) - - ; if length == 0 -> skip movement - ucomiss xmm3, [rel ZERO_CONST] - je .skip_move - - ; scalar = (speed * dt) / length - movss xmm4, xmm0 ; xmm4 = speed*dt - divss xmm4, xmm3 ; xmm4 = scalar - - ; dx = vel.x * scalar - movss xmm1, dword [rax + FIG_VELOCITY] - mulss xmm1, xmm4 - movss xmm2, dword [rax + FIG_POSITION] ; position.x - addss xmm2, xmm1 - movss dword [rax + FIG_POSITION], xmm2 - - ; dy = vel.y * scalar - movss xmm1, dword [rax + FIG_VELOCITY + 4] - mulss xmm1, xmm4 - movss xmm2, dword [rax + FIG_POSITION + 4] - addss xmm2, xmm1 - movss dword [rax + FIG_POSITION + 4], xmm2 - -.skip_move: - - ; rotate: angle += angular_velocity * dt - movss xmm3, dword [rax + FIG_ANG_VEL] - mulss xmm3, [rel DT] - movss xmm4, dword [rax + FIG_ANGLE] - addss xmm4, xmm3 - movss dword [rax + FIG_ANGLE], xmm4 - - ; If circle -> call collision check helper - mov ecx, dword [rax + FIG_TYPE] - cmp ecx, 0 - jne .no_collision_check - ; pass pointer to window_draw_info (original rdi) in rdi - ; rdi already has draw_info pointer - call figure_check_collision_circle - -.no_collision_check: + enter 48, 0 + ; Отработка коллизий + call figure_handle_collision; + + ; Сохранить регистры + + ; Сдвиги переменных + ; Аргументы + local width, 4 + local height, 4 + local fig_type, 4 + local pos_x, 4 + local pos_y, 4 + local vel_x, 4 + local vel_y, 4 + local angle, 4 + local angular_vel, 4 + local speed, 4 + local radius, 4 + + ; Чтение аргументов + mov eax, dword [rdi + WDI_WIDTH] + mov [rbp - width], eax + + mov eax, dword [rdi + WDI_HEIGHT] + mov [rbp - height], eax + + mov eax, dword [rdi + WDI_FIGURE + FIG_TYPE] + mov [rbp - fig_type], eax + + mov eax, dword [rdi + WDI_FIGURE + FIG_POSITION] + mov [rbp - pos_x], eax + + mov eax, dword [rdi + WDI_FIGURE + FIG_POSITION + 4] + mov [rbp - pos_x], eax + + mov eax, dword [rdi + WDI_FIGURE + FIG_VELOCITY] + mov [rbp - vel_x], eax + + mov eax, dword [rdi + WDI_FIGURE + FIG_VELOCITY + 4] + mov [rbp - vel_y], eax + + mov eax, dword [rdi + WDI_FIGURE + FIG_ANGLE] + mov [rbp - angle], eax + + mov eax, dword [rdi + WDI_FIGURE + FIG_ANG_VEL] + mov [rbp - angular_vel], eax + + mov eax, dword [rdi + WDI_FIGURE + FIG_SPEED] + mov [rbp - speed], eax + + mov eax, dword [rdi + WDI_FIGURE + FIG_RADIUS] + mov [rbp - radius], eax + + + + + ; Восстановить регистры + + leave + ret + +; Функция для обработки коллизии, изменяет velocity при обнаружении коллизии с границами +; Параметры: +; rdi - указатель на struct window_draw_info +%assign __local_offset 0 +figure_handle_collision: + enter 128,0 + + local point_buffer, 128 + + + ; Вызов place_points_on_circle + movss xmm0, [rdi + WDI_FIGURE + FIG_POSITION] + movss xmm1, [rdi + WDI_FIGURE + FIG_POSITION + 4] + mov rsi, 4 + mov rdx, 0 + push rdi + mov rdi, rbp + add rdi, point_buffer + call place_points_on_circle + pop rdi + leave ret -; helper: check collision for circle and reflect velocity & angular velocity -; rdi - pointer to struct window_draw_info -global figure_check_collision_circle -figure_check_collision_circle: - push rbx - ; rdi -> window_draw_info - ; rax -> figure_animation_info - mov rax, rdi - add rax, WDI_FIGURE +; Функция для расположения точек на окружности +; Вход: +; xmm0 - pos_x +; xmm1 - pos_y +; xmm2 - смещение точек на окружности в радианах +; xmm3 - радиус +; rdi - адрес буфера для точек +; rsi - количество точек +; Уничтожает: rax, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7 +global place_points_on_circle +place_points_on_circle: + enter 0, 0 - movss xmm0, dword [rax + FIG_POSITION] ; pos.x - movss xmm1, dword [rax + FIG_POSITION + 4] ; pos.y + ; Сохранить координаты центра + movss xmm6, xmm0 + movss xmm7, xmm1 - movss xmm2, dword [rax + FIG_VELOCITY] ; vel.x - movss xmm3, dword [rax + FIG_VELOCITY + 4] ; vel.y + ; Рассчитать TWO_PI / rsi и сохранить в xmm4 + movss xmm4, [rel TWO_PI] + cvtsi2ss xmm5, rsi + divss xmm4, xmm5 - movss xmm4, dword [rax + FIG_ANG_VEL] ; angvel + movss xmm5, [rel ZERO_CONST] ; счётчик + mov rcx, rsi +.cycle: + movss xmm0, xmm5 - ; radius is stored in figure as pixel count (float) - ; we keep positions normalized (0..1) so convert radius to normalized - ; coordinates for x and y: r_x = radius / width, r_y = radius / height - movss xmm5, dword [rax + FIG_RADIUS] ; xmm5 = radius_pixels + mulss xmm0, xmm4 ; Счётчик*шаг + addss xmm0, xmm2 ; Прибавить смещение + call sincos_f32_rbp ; Посчитать sincos + mulss xmm0, xmm3 ; sin *= radius + mulss xmm1, xmm3 ; cos *= radius - ; load width/height from window_draw_info - mov ebx, dword [rdi + WDI_WIDTH] - cvtsi2ss xmm10, ebx ; xmm10 = width - mov ebx, dword [rdi + WDI_HEIGHT] - cvtsi2ss xmm11, ebx ; xmm11 = height + addss xmm1, xmm6 ; x = center_x + cos*radius + addss xmm0, xmm7 ; y = center_y + sin*radius - ; compute r_x = radius / width - movss xmm12, xmm5 - divss xmm12, xmm10 ; xmm12 = r_x + movss [rdi], xmm1 + movss [rdi + 4], xmm0 + add rdi, 8 - ; compute r_y = radius / height - movss xmm13, xmm5 - divss xmm13, xmm11 ; xmm13 = r_y - ; left edge: pos.x < r_x ? - ucomiss xmm0, xmm12 - jae .check_right - ; pos.x = radius - movss dword [rax + FIG_POSITION], xmm12 - ; vel.x = -vel.x - movss xmm6, xmm2 - mulss xmm6, [rel NEG_ONE] - movss dword [rax + FIG_VELOCITY], xmm6 - ; invert angular velocity - movss xmm7, xmm4 - mulss xmm7, [rel NEG_ONE] - movss dword [rax + FIG_ANG_VEL], xmm7 - jmp .done_x + addss xmm5, [rel ONE_CONST] + loop .cycle -.check_right: - ; pos.x + radius > 1 ? - movss xmm8, [rel ONE_CONST] - addss xmm8, xmm12 ; xmm8 = 1 + r_x - ; Actually want pos.x + radius > 1 <=> pos.x > 1 - radius - ; compute bound = 1 - r_x - movss xmm9, [rel ONE_CONST] - subss xmm9, xmm12 - ucomiss xmm0, xmm9 - jbe .done_x - ; pos.x = 1 - radius - movss dword [rax + FIG_POSITION], xmm9 - ; vel.x = -vel.x - movss xmm6, xmm2 - mulss xmm6, [rel NEG_ONE] - movss dword [rax + FIG_VELOCITY], xmm6 - ; invert angular velocity - movss xmm7, xmm4 - mulss xmm7, [rel NEG_ONE] - movss dword [rax + FIG_ANG_VEL], xmm7 - -.done_x: - ; check bottom / top boundaries for y - ; bottom: pos.y < r_y - ucomiss xmm1, xmm13 - jae .check_top2 - movss dword [rax + FIG_POSITION + 4], xmm13 - movss xmm6, xmm3 - mulss xmm6, [rel NEG_ONE] - movss dword [rax + FIG_VELOCITY + 4], xmm6 - ; invert angular - movss xmm7, xmm4 - mulss xmm7, [rel NEG_ONE] - movss dword [rax + FIG_ANG_VEL], xmm7 - jmp .done_y - -.check_top2: - ; top: pos.y > 1 - r_y - movss xmm9, [rel ONE_CONST] - subss xmm9, xmm13 - ucomiss xmm1, xmm9 - jbe .done_y - movss dword [rax + FIG_POSITION + 4], xmm9 - movss xmm6, xmm3 - mulss xmm6, [rel NEG_ONE] - movss dword [rax + FIG_VELOCITY + 4], xmm6 - movss xmm7, xmm4 - mulss xmm7, [rel NEG_ONE] - movss dword [rax + FIG_ANG_VEL], xmm7 - -.done_y: - pop rbx + leave ret -section .rodata -DT: dd 0.1 -NEG_ONE: dd -1.0 -ONE_CONST: dd 1.0 -ZERO_CONST: dd 0.0 + +; Функция для рассчёта sin и cos +; Вход: +; xmm0 - угол в радианах (float) +; Выход: +; xmm0 - sin(angle) +; xmm1 - cos(angle) +; Уничтожает: rax, flags +sincos_f32_rbp: + enter 24, 0 ; 24 байта локального места: + ; [rbp-8] — временно угол (для fld) + ; [rbp-16] — sin + ; [rbp-24] — cos + ; (выравнивание по 16 будет соблюдено за счёт enter) + + ; Сохраняем входной угол как float32 в стек для загрузки в x87 + movss [rbp-8], xmm0 + fld dword [rbp-8] ; ST(0) = angle (в extended precision) + + fsincos ; ST(0) = cos, ST(1) = sin + + ; Сохраняем результаты обратно в память как float32 + fstp dword [rbp-24] ; pop cos → [rbp-24] + fstp dword [rbp-16] ; pop sin → [rbp-16] + + ; Загружаем результаты в xmm0 и xmm1 + movss xmm0, [rbp-16] ; xmm0 = sin + movss xmm1, [rbp-24] ; xmm1 = cos + + leave ; эквивалент: mov rsp, rbp / pop rbp + ret \ No newline at end of file diff --git a/wayland/src/wayland-runtime.c b/wayland/src/wayland-runtime.c index 1c1cd93..b3365f6 100644 --- a/wayland/src/wayland-runtime.c +++ b/wayland/src/wayland-runtime.c @@ -41,6 +41,26 @@ static void signal_thread_exit(struct window_thread_slot *slot) pthread_mutex_unlock(&g_thread_lock); } +#include +#include +#include +#include + +// Прототип ASM-функции +void place_points_on_circle( + float pos_x, + float pos_y, + float offset_rad, + float radius, + float *points, + size_t count); + +struct Point +{ + float x; + float y; +}; + static void *window_aux_loop(void *arg) { struct window_thread_slot *slot = arg; @@ -49,7 +69,36 @@ static void *window_aux_loop(void *arg) { /* На время обновления позиции фигуры локаем мутекс */ pthread_mutex_lock(&draw_info->figure_mutex); - figure_animation_step(draw_info); + // figure_animation_step(draw_info); + + const size_t n = 8; + struct vec2 *pts = malloc(sizeof(struct vec2) * n); + if (!pts) + { + printf("malloc failed\n"); + } + + float center_x = 0.0f; + float center_y = 0.0f; + float offset = 0.78f; + float radius = 1.0f; + + // Вызов ASM-функции + place_points_on_circle( + center_x, + center_y, + offset, + radius, + (float *)pts, // адрес выходного массива + n); + + // Вывод для проверки (и удобной точки останова) + for (size_t i = 0; i < n; i++) + { + printf("%zu: x = %f, y = %f\n", i, pts[i].x, pts[i].y); + } + + free(pts); pthread_mutex_unlock(&draw_info->figure_mutex); usleep(30 * 1000);