
#ifndef GFX_H_
#define GFX_H_

#include "def.h"
#include "type.h"
#include "sys.h"

#ifndef DISABLE_FBDEV
forcedinline void swap_buf(void* bb, void* real, size_t sz) {
    asm volatile("push %%edi\n"
                 "rep movsb\n"
                 "pop %%edi\n"
        ::"S" (bb), "D" (real), "c" (sz):);
}

forcedinline void sleep_60fps(void) {
    // this breaks on clang with sse2 enabled, and is incredibly large
    // regardless of flags
    /*struct timespec iv;
    iv.tv_sec ^= iv.tv_sec;
    iv.tv_nsec = 16666667;
    SYS_clock_nanosleep(CLOCK_REALTIME, 0, &iv, NULL);*/

#if defined(__x86_64__)
    asm volatile("push $16666667\n" // struct timespec on stack top
                 "push $0\n"
                 "push $230\n" // syscall number
                 "pop %%rax\n"
                 "movq %%rsp, %%rdx\n" // struct timespec* in rdx
                 "xorq %%r10, %%r10\n" // remain in r10 (NULL)
                 "xorq %%rsi, %%rsi\n" // flags in rsi (0)
                 "xorq %%rdi, %%rdi\n" // clock id in rdi (0: CLOCK_REALTIME)
                 "syscall\n"
                 "pop %%rax\n" // return stack to normal value
                 "pop %%rax\n"
        :::"rax", "r10", "rsi", "rdi", "rdx", "rcx", "r11");
#else
    asm volatile("push $16666667\n" // struct timespec on stack top
                 "push $0\n"
                 "push $267\n" // syscall number
                 "pop %%eax\n"
                 "mov %%esp, %%edx\n" // struct timespec* in esi
                 "xor %%esi, %%esi\n" // remain in edx (NULL)
                 "xor %%ecx, %%ecx\n" // flags in ecx (0)
                 "xor %%ebx, %%ebx\n" // clock id in ebx (0: CLOCK_REALTIME)
                 "int $0x80\n"
                 "pop %%eax\n" // return stack to normal value
                 "pop %%eax\n"
        :::"eax", "ebx", "ecx", "edx", "esi", "edi" /* if this one
            isn't included, 'mem' magically increases */);
#endif
}
#else
#define swap_buf(bb, real, sz) do{}while(0)
#define sleep_60fps() do{}while(0)
#endif

#endif

