aaaaaa123456789 icon

Render animation frames (renderframes.s)

aaaaaa123456789 | PRO | 11/09/22 07:38:53 PM UTC | 0 ⭐ | 14240 👁️ | Never ⏰ | []
ASM (NASM) |

0 B

|

None

|

0 👍

/

0 👎

%imacro function 0-1 end
    global %00:function (%00.%1 - %00)
%00:
%endmacro
 
%define ext(function) function wrt ..plt
 
struc plum_image
    .type:              resw 1
    .max_palette_index: resb 1
    .color_format:      resb 1
    .frames:            resd 1
    .height:            resd 1
    .width:             resd 1
    .allocator:         resq 1
    .metadata:          resq 1
    .palette:           resq 1
    .data:              resq 1
    .userdata:          resq 1
endstruc
 
struc plum_metadata
    .type: resd 1
    alignb 8
    .size: resq 1
    .data: resq 1
    .next: resq 1
endstruc
 
%assign PLUM_COLOR_64                 1
%assign PLUM_ERR_IMAGE_TOO_LARGE      7
%assign PLUM_IMAGE_PNG                3
%assign PLUM_METADATA_BACKGROUND      2
%assign PLUM_METADATA_FRAME_DISPOSAL  5
%assign PLUM_MODE_FILENAME           -1
 
extern plum_destroy_image:function
extern plum_find_metadata:function
extern plum_get_error_text:function
extern plum_load_image:function
extern plum_store_image:function
 
extern calloc:function
extern fprintf:function
extern free:function
extern stderr:data
 
section .text
 
main: function
    ; C calling convention! rdi = argc, rsi = argv, return status in rax
    push qword[rsi]
    cmp edi, 3
    je .continue
    mov rdx, [rsi]
    lea rsi, [rel .usage]
    mov rdi, [rel stderr]
    call ext(fprintf)
    add rsp, 8
    mov eax, 2
    ret
 
.error:
    mov edi, [rsp]
    call ext(plum_get_error_text)
    mov rcx, rax
.showerror:
    mov rdx, [rsp + 16]
    mov rsi, r13
    mov rdi, [rel stderr]
    call ext(fprintf)
    add rsp, 24
    mov eax, 1
    ret
 
.continue:
    push qword[rsi + 16]
    sub rsp, 8
    mov rdi, [rsi + 8]
    mov rsi, PLUM_MODE_FILENAME
    mov edx, PLUM_COLOR_64
    mov rcx, rsp
    call ext(plum_load_image)
    test rax, rax
    lea r13, [rel .loaderrmsg]
    jz .error
 
    ; image is loaded: check that height * frames doesn't overflow
    mov r12, rax
    mov esi, [rax + plum_image.height]
    mov ecx, [rax + plum_image.frames]
    imul rcx, rsi
    cmp rcx, 0x7fffffff
    mov ecx, PLUM_ERR_IMAGE_TOO_LARGE
    ja .showerror
    ; set to PNG, allocate a frame canvas, determine the background color and initialize
    mov word[rax + plum_image.type], PLUM_IMAGE_PNG
    mov edi, [rax + plum_image.width]
    imul rdi, rsi
    mov r13, rdi
    mov esi, 8
    call ext(calloc)
    ; don't care about calloc failure - this is assembly, so we can guarantee a segfault by accessing the buffer
    mov r14, rax
    mov esi, PLUM_METADATA_BACKGROUND
    mov rdi, r12
    call ext(plum_find_metadata)
    xor r15, r15
    test rax, rax
    jz .no_background
    mov r15, [rax + plum_metadata.data]
    mov r15, [r15]
    mov rdi, r14
    mov rcx, r13
    mov rax, r15
    rep stosq
.no_background:
    ; find the frame disposal information and initialize local variables (data buffer, metadata pointer, frame number)
    mov dword[rsp], 0
    mov esi, PLUM_METADATA_FRAME_DISPOSAL
    mov rdi, r12
    call ext(plum_find_metadata)
    test rax, rax
    jz .no_disposal_load
    mov rax, [rax + plum_metadata.data]
.no_disposal_load:
    push rax
    push qword[r12 + plum_image.data]
    ; preload some registers
    vpxor xmm0, xmm0, xmm0
    movq xmm8, r15
    vmovdqa xmm9, [rel .packmask]
    vmovdqa xmm10, [rel .roundmask]
    vmovdqa xmm11, [rel .flipmask]
    vmovdqa xmm12, [rel .shufflemask]
    vpunpcklwd xmm8, xmm8, xmm0
    xor eax, eax
 
.loop:
    ; process each frame
    mov rdx, [rsp + 8]
    test rdx, rdx
    jz .no_disposal
    movzx edx, byte[rdx + rax]
.no_disposal:
    mov r11, [rsp]
    lea rax, [rel .callback_offsets]
    add rax, [rax + rdx * 8]
    call rax
    lea rsi, [r11 + r13 * 8]
    mov [rsp], rsi
    inc dword[rsp + 16]
    mov eax, [rsp + 16]
    cmp eax, [r12 + plum_image.frames]
    jb .loop
    add rsp, 16
    mov rdi, r14
    call ext(free)
 
    ; update the image dimensions (one frame, height *= frames)
    mov eax, [r12 + plum_image.frames]
    mov dword[r12 + plum_image.frames], 1
    imul eax, [r12 + plum_image.height]
    mov [r12 + plum_image.height], eax
    ; store the image and finish
    mov rdi, r12
    mov rsi, [rsp + 8]
    mov rdx, PLUM_MODE_FILENAME
    mov rcx, rsp
    call ext(plum_store_image)
    mov rdi, r12
    call ext(plum_destroy_image)
    cmp dword[rsp], 0
    lea r13, [rel .storeerrmsg]
    jnz .error
    add rsp, 24
    xor eax, eax
    ret
.end:
 
.loaderrmsg: db `%s: load error: %s\n`, 0
.storeerrmsg: db `%s: store error: %s\n`, 0
.usage: db `usage: %s <image> <output.png>\n`, 0
 
    align 16, db 0
.packmask: db 2, 3, 6, 7, 10, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
.roundmask: dw 0x8000, 0, 0x8000, 0, 0x8000, 0, 0, 0
.flipmask: dw -1, 0, -1, 0, -1, 0, 0, 0
.shufflemask: db 12, 13, -1, -1, 12, 13, -1, -1, 12, 13, -1, -1, -1, -1, -1, -1
 
.callback_offsets:
    %rep 2
        dq render_frame - .callback_offsets
        dq render_frame_keep_background - .callback_offsets
        dq render_frame_no_preserve - .callback_offsets
    %endrep
 
render_frame: function
    endbr64
    xor eax, eax
.loop:
    movq xmm1, [r11 + rax * 8]
    movq xmm2, [r14 + rax * 8]
    vpunpcklwd xmm1, xmm1, xmm0
    vpunpcklwd xmm2, xmm2, xmm0
    vpshufb xmm3, xmm1, xmm12
    vpmulld xmm5, xmm2, xmm3
    vpxor xmm4, xmm3, xmm11
    vpaddd xmm5, xmm5, xmm10
    vpmulld xmm6, xmm1, xmm4
    vpaddd xmm3, xmm6, xmm5
    vpsrld xmm5, xmm3, 16
    vpaddd xmm3, xmm3, xmm5
    vpshufb xmm1, xmm3, xmm9
    movq [r11 + rax * 8], xmm1
    movq [r14 + rax * 8], xmm1
    inc rax
    cmp rax, r13
    jb .loop
    ret
.end:
 
render_frame_keep_background: function
    endbr64
    xor eax, eax
.loop:
    movq xmm1, [r11 + rax * 8]
    movq xmm2, [r14 + rax * 8]
    vpunpcklwd xmm1, xmm1, xmm0
    vpunpcklwd xmm2, xmm2, xmm0
    vpshufb xmm3, xmm1, xmm12
    vpmulld xmm5, xmm2, xmm3
    vpxor xmm4, xmm3, xmm11
    vpaddd xmm5, xmm5, xmm10
    vpmulld xmm6, xmm1, xmm4
    vpmulld xmm7, xmm8, xmm4
    vpaddd xmm3, xmm6, xmm5
    vpaddd xmm4, xmm7, xmm5
    vpsrld xmm5, xmm3, 16
    vpsrld xmm6, xmm4, 16
    vpaddd xmm3, xmm3, xmm5
    vpaddd xmm4, xmm4, xmm6
    vpshufb xmm1, xmm3, xmm9
    vpshufb xmm2, xmm4, xmm9
    movq [r11 + rax * 8], xmm1
    movq [r14 + rax * 8], xmm2
    inc rax
    cmp rax, r13
    jb .loop
    ret
.end:
 
render_frame_no_preserve: function
    endbr64
    xor eax, eax
.loop:
    movq xmm1, [r11 + rax * 8]
    movq xmm2, [r14 + rax * 8]
    vpunpcklwd xmm1, xmm1, xmm0
    vpunpcklwd xmm2, xmm2, xmm0
    vpshufb xmm3, xmm1, xmm12
    vpmulld xmm5, xmm2, xmm3
    vpxor xmm4, xmm3, xmm11
    vpaddd xmm5, xmm5, xmm10
    vpmulld xmm6, xmm1, xmm4
    vpaddd xmm3, xmm6, xmm5
    vpsrld xmm5, xmm3, 16
    vpaddd xmm3, xmm3, xmm5
    vpshufb xmm1, xmm3, xmm9
    movq [r11 + rax * 8], xmm1
    inc rax
    cmp rax, r13
    jb .loop
    ret
.end:

Comments

  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎

    
        
  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎