flat assembler
Message board for the users of flat assembler.

Index > Linux > [fasm2] Rendering a sine wave to a window with FPU

Author
Thread Post new topic Reply to topic
Jessé



Joined: 03 May 2025
Posts: 151
Location: Brazil
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!


Description: Source and binary, for the adventurous one. Needed: https://github.com/Jesse-6/fastcall
Download
Filename: sinewave.tar.gz
Filesize: 5.41 KB
Downloaded: 26 Time(s)


_________________
jesse6
Post 29 Aug 2026, 15:16
View user's profile Send private message Visit poster's website Reply with quote
Jessé



Joined: 03 May 2025
Posts: 151
Location: Brazil
Jessé 29 Aug 2026, 22:19
Much better now, with a thread animated, phase shifted sine wave!
Cool


Description: My first step on animated XCB windows!
Download
Filename: sinewave_animated.tar.gz
Filesize: 6.46 KB
Downloaded: 34 Time(s)


_________________
jesse6
Post 29 Aug 2026, 22:19
View user's profile Send private message Visit poster's website Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2026, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.