flat assembler
Message board for the users of flat assembler.
Index
> Linux > [fasm2] Rendering a sine wave to a window with FPU |
| Author |
|
|
Jessé 29 Aug 2026, 15:16
Is incredible - as one can see at this excellent post - how knowing anything on math just multiplicates, or even scales what one can do with assembly - as well as any other programming languages.
This is something I neglect (must admit) quite often, since I don't go to school anymore, but with only one class of a simple concept (trigonometry, for the curious one), I made this work, with a formula that I created myself (probably, the main formula one will use to do it, anyways): Code: format ELF64 include 'fastcall.inc' include 'stdio.inc' include 'xcb.inc' include 'xcb-sync.inc' proto request_check, qword struct FLAGS init:? dd init virtual at . .0 db ? .1 db ? .2 db ? .3 db ? end virtual end struct define_offset s XCB_SCREEN_T define_offset ge XCB_GENERIC_EVENT_T define_offset cm XCB_CLIENT_MESSAGE_EVENT_T define_offset cn XCB_CONFIGURE_NOTIFY_EVENT_T define_offset ar XCB_INTERN_ATOM_REPLY_T define_offset p XCB_POINT_T define_offset re XCB_GENERIC_ERROR_T define_offset sir XCB_SYNC_INITIALIZE_REPLY_T define_offset qcr XCB_SYNC_QUERY_COUNTER_REPLY_T _bss cache: connection dq ? screen dq ? counter dq ? ; Counter to synchonize resize events (needed for Wayland) window dd ? gc dd ? sync dd ? ; Counter ID to help X sync redraws on resize with Xwayland _data width dw 720 height dw 480 flags FLAGS 0 _rdata align 64 align 4 window_p: .bgcolor dd 0FF_181833h .evmask dd XCB_EVENT_MASK_EXPOSURE or XCB_EVENT_MASK_STRUCTURE_NOTIFY gc_p: .fgcolor dd 0FF_095D0Ch .line dd 6 .join dd XCB_JOIN_STYLE_ROUND _code Start entry: prefetcht0 [cache] libc.StartMain(Main); request_check: push rbx mov rbx, rdi xcb_request_check(connection, eax); test rax, rax jz @f movzx ecx, [rax+re.error_code] fprintf(stderr, "%s. Error: %u"\n, rbx, ecx); pop rbx stc ret @@ pop rbx clc ret Main: enter 128, 0 prefetcht0 [rsp] prefetcht0 [rsp+32] prefetcht0 [rsp+64] prefetcht0 [rsp+96] xcb_connect(NULL, NULL); test rax, rax jnz @f fprintf(stderr, "Could not connect to X."\n); mov al, 1 leave ret @@ mov [connection], rax xcb_get_setup(rax); xcb_setup_roots_iterator(rax); mov [screen], rax xcb_sync_initialize(connection, 3, 0); xcb_sync_initialize_reply(connection, eax, rbp-8); test rax, rax jnz @f fprintf(stderr, "Could not initialize sync."\n); jmp @1f @@ movzx edx, [rax+sir.major_version] movzx ecx, [rax+sir.minor_version] fprintf(stderr, "Sync initialized successfully. V%u.%u"\n, edx, ecx); @1 xcb_intern_atom \ (connection, FALSE, lengthof("WM_PROTOCOLS"), "WM_PROTOCOLS"); mov [rbp-104], eax xcb_intern_atom \ (connection, FALSE, lengthof("WM_DELETE_WINDOW"), "WM_DELETE_WINDOW"); mov [rbp-12], eax xcb_intern_atom \ (connection, FALSE, lengthof("_NET_WM_SYNC_REQUEST"), "_NET_WM_SYNC_REQUEST"); mov [rbp-16], eax xcb_intern_atom(connection, FALSE, lengthof("_NET_WM_SYNC_REQUEST_COUNTER"), \ "_NET_WM_SYNC_REQUEST_COUNTER"); mov [rbp-100], eax xcb_generate_id(connection); mov [window], eax xcb_generate_id(connection); mov [gc], eax xcb_generate_id(connection); mov [sync], eax xcb_sync_create_counter_checked(connection, sync, 0); request_check("Couldn't create sync counter"); ; jc @f ; xcb_sync_set_counter(connection, sync, 800); ; xcb_sync_query_counter(connection, sync); ; xcb_sync_query_counter_reply(connection, eax, NULL); ; test rax, rax ; jz @f ; fprintf(stderr, "Sync counter starts at: %lu"\n, [rax+qcr.counter_value]); @@ mov r10, [screen] xcb_create_window(connection, XCB_COPY_FROM_PARENT, window, [r10+s.root], \ 0, 0, width, height, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, \ [r10+s.root_visual], XCB_CW_BACK_PIXEL or XCB_CW_EVENT_MASK, \ window_p); xcb_intern_atom_reply(connection, [rbp-104], NULL); mov [rbp-24], rax mov r11d, [rax+ar.atom] mov [rbp-104], r11d xcb_intern_atom_reply(connection, [rbp-12], NULL); mov [rbp-32], rax mov r10d, [rax+ar.atom] mov [rbp-12], r10d xcb_intern_atom_reply(connection, [rbp-16], NULL); mov [rbp-40], rax mov r9d, [rax+ar.atom] mov [rbp-16], r9d xcb_intern_atom_reply(connection, [rbp-100], NULL); mov [rbp-48], rax mov r8d, [rax+ar.atom] mov [rbp-100], r8d xcb_change_property(connection, XCB_PROP_MODE_REPLACE, window, XCB_ATOM_WM_NAME, \ XCB_ATOM_STRING, 8, lengthof("Sine wave"), "Sine wave"); xcb_change_property_checked(connection, XCB_PROP_MODE_REPLACE, window, [rbp-104], \ XCB_ATOM_ATOM, 32, 2, rbp-12); request_check("Couldn't set WM_PROTOCOLS atoms"); xcb_change_property_checked(connection, XCB_PROP_MODE_REPLACE, window, [rbp-100], \ XCB_ATOM_CARDINAL, 32, 1, &sync); request_check("Couldn't set sync counter atom"); free([rbp-24]); free([rbp-32]); free([rbp-40]); free([rbp-48]); xcb_create_gc(connection, gc, window, XCB_GC_FOREGROUND or XCB_GC_LINE_WIDTH or \ XCB_GC_JOIN_STYLE, gc_p); xcb_map_window(connection, window); xcb_flush(connection); .events: xcb_wait_for_event(connection); test rax, rax jnz @f fprintf(stderr, "Error processing XCB event."\n); xcb_disconnect(connection); jmp .end @@ mov [rbp-8], rbx mov dl, [rax+ge.response_type] and dl, 7Fh mov rbx, rax cmp dl, XCB_EXPOSE jne @f @9 push r14 push r15 movzx edi, [width] imul edi, edi, sizeof(p) mov [rbp-64], edi mov [rbp-60], dword 360 mov [rbp-68], dword 0 mov [rbp-72], dword 2 mov [rbp-76], dword 180 mov [rbp-80], dword 10 malloc(edi); wait mov r14, rax xor r15d, r15d fninit fild [height] fidiv dword [rbp-72] fstp dword [rbp-72] @1 fild dword [rbp-60] fild [width] fdivp fimul dword [rbp-68] fldpi fmulp fidiv dword [rbp-76] fsin fld dword [rbp-72] fisub dword [rbp-80] fmulp fsubr dword [rbp-72] imul eax, r15d, sizeof(p); wait fistp [r14+rax+p.y] mov [r14+rax+p.x], r15w inc r15d inc dword [rbp-68] cmp r15w, [width] jb @1b xcb_poly_line(connection, XCB_COORD_MODE_ORIGIN, window, gc, r15d, r14); free(r14); btr [flags], 0 jnc @1f xcb_sync_set_counter(connection, sync, counter); ; xcb_sync_query_counter(connection, sync); ; xcb_sync_query_counter_reply(connection, eax, NULL); ; fprintf(stderr, "%016lX", [rax+qcr.counter_value]); @1 xcb_flush(connection); pop r15 pop r14 jmp .default @@ cmp dl, XCB_CONFIGURE_NOTIFY jne @f movzx r10d, [rax+cn.width] movzx r11d, [rax+cn.height] mov [width], r10w mov [height], r11w jmp @9b ; redraw on resize @@ cmp dl, XCB_CLIENT_MESSAGE jne .default mov r10d, [rax+cm.window] cmp r10d, [window] jne .default mov r11d, [rbp-12] cmp [rax+cm.data32+0], r11d jne @1f mov rbx, [rbp-8] free(rax); xcb_free_gc(connection, gc); xcb_destroy_window(connection, window); xcb_sync_destroy_counter(connection, sync); xcb_flush(connection); xcb_disconnect(connection); ; test [flags.0], 2 ; jz .end ; fprintf(stderr, <10,0>); jmp .end @1 mov r10d, [rbp-16] cmp [rax+cm.data32+0*4], r10d jne .default mov rdx, qword [rax+cm.data32+2*4] ; Needed to swap dwords to match ror rdx, 32 ; xcb_sync_int64_t type mov [counter], rdx ; or [flags.0], 3 ; fprintf(stderr, <13,"Counter is: ",0>); jmp .default .default: free(rbx); mov rbx, [rbp-8] jmp .events .end: xor eax, eax leave ret This example uses XCB own (clever and efficient) way to draw that line, which avoid hundreds of recursive calls to a function that will happen otherwise, if I've used Cairo instead to do the same. I should also mention that, the sync technique provided by X on this example, isn't needed on XLibre, but it is mandatory on Wayland, otherwise resize will flicker, because XWayland does not necessarily sync with Wayland wl_surfaces, according to Gemini, which helped me with the main idea on the sync code at this example, explaining the "mechanics" behind how display server deals with this counter. The mentioned flickering happens only on resize, as well as this sync counter only works on resize event, too, as stated on my tests. Long live Assembly, and cheers!
|
|||||||||||
|
|
Jessé 29 Aug 2026, 22:19
Much better now, with a thread animated, phase shifted sine wave!
|
|||||||||||
|
< Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2026, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.