/*         ______   ___    ___
 *        /\  _  \ /\_ \  /\_ \
 *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___ 
 *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
 *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
 *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
 *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
 *                                           /\____/
 *                                           \_/__/
 *
 *      Asm functions for Windows bitmap locking.
 *
 *      By Isaac Cruz.
 *
 *      Improved dirty rectangles mechanism by Eric Botcazou.
 *
 *      See readme.txt for copyright information.
 */


#include "src/i386/asmdefs.inc"


.text


/* gfx_directx_write_bank:
 *  edx = bitmap
 *  eax = line
 */
FUNC (gfx_directx_write_bank)

      /* check whether bitmap is already locked */
      testl $BMP_ID_LOCKED, BMP_ID(%edx)
      jnz Locked

      /* lock the surface */
      pushl %ecx
      pushl %eax
      pushl %edx
      pushl %edx  /* argument */
      call *GLOBL(ptr_gfx_directx_autolock)
      popl %edx
      popl %edx
      popl %eax
      popl %ecx

   Locked:
      /* get pointer to the video memory */
      movl BMP_LINE(%edx,%eax,4), %eax

      ret




/* gfx_directx_unwrite_bank:
 *  edx = bmp
 */
FUNC (gfx_directx_unwrite_bank)

      /* only unlock bitmaps that were autolocked */
      testl $BMP_ID_AUTOLOCK, BMP_ID(%edx)
      jz No_unlock

      /* unlock surface */
      pushl %ecx
      pushl %eax
      pushl %edx
      pushl %edx  /* argument */
      call *GLOBL(ptr_gfx_directx_unlock)
      popl %edx
      popl %edx
      popl %eax
      popl %ecx

      /* clear the autolock flag */
      andl $~BMP_ID_AUTOLOCK, BMP_ID(%edx)

   No_unlock:
      ret




/* gfx_directx_write_bank_win:
 *  edx = bitmap
 *  eax = line
 */
FUNC (gfx_directx_write_bank_win)
      pushl %ecx

      /* clobber the line */
      movl GLOBL(wd_dirty_lines), %ecx
      addl BMP_YOFFSET(%edx), %ecx
      movb $1, (%ecx,%eax)   /* wd_dirty_lines[line] = 1; (line has changed) */

      /* check whether bitmap is already locked */
      testl $BMP_ID_LOCKED, BMP_ID(%edx)
      jnz Locked_win

      /* lock the surface */
      pushl %eax
      pushl %edx
      pushl %edx  /* argument */
      call *GLOBL(ptr_gfx_directx_autolock)
      popl %edx
      popl %edx
      popl %eax

   Locked_win:
      popl %ecx

      /* get pointer to the video memory */
      movl BMP_LINE(%edx,%eax,4), %eax

      ret



/* gfx_directx_unwrite_bank_win:
 *  edx = bmp
 */
FUNC (gfx_directx_unwrite_bank_win)

      /* only unlock bitmaps that were autolocked */
      testl $BMP_ID_AUTOLOCK, BMP_ID(%edx)
      jz No_unlock_win

      pushl %ecx
      pushl %eax

      /* unlock surface */
      pushl %edx
      pushl %edx  /* argument */
      call *GLOBL(ptr_gfx_directx_unlock)
      popl %edx
      popl %edx

      /* clear the autolock flag */
      andl $~BMP_ID_AUTOLOCK, BMP_ID(%edx)

      /* update dirty lines: this is safe because autolocking
       * is guaranteed to be the only level of locking.
       */
      movl GLOBL(gfx_directx_forefront_bitmap), %edx
      call update_dirty_lines

      popl %eax
      popl %ecx

   No_unlock_win:
      ret


/* gfx_directx_unlock_win:
 *  arg1 = bmp
 */
FUNC(gfx_directx_unlock_win)

      /* unlock surface */
      movl 4(%esp), %edx
      pushl %edx 
      pushl %edx  /* argument */
      call *GLOBL(ptr_gfx_directx_unlock)
      popl %edx
      popl %edx

      /* forefront_bitmap may still be locked in case of nested locking */
      movl GLOBL(gfx_directx_forefront_bitmap), %edx
      testl $BMP_ID_LOCKED, BMP_ID(%edx)
      jnz No_update_win

      /* ok, we can safely update */
      call update_dirty_lines

   No_update_win:
      ret



/* update_dirty_lines
 *  edx = dd_frontbuffer
 *  clobbers: %eax, %ecx
 */

#define RECT_LEFT   (%esp)
#define RECT_TOP    4(%esp)
#define RECT_RIGHT  8(%esp)
#define RECT_BOTTOM 12(%esp)

update_dirty_lines:
      pushl %ebx
      pushl %esi
      pushl %edi
      subl $16, %esp  /* allocate a RECT structure */

      movl $0, RECT_LEFT
      movl BMP_W(%edx), %ecx           /* ecx = dd_frontbuffer->w */
      movl %ecx, RECT_RIGHT
      movl GLOBL(wd_dirty_lines), %ebx /* ebx = wd_dirty_lines   */
      movl BMP_H(%edx), %esi           /* esi = dd_frontbuffer->h */
      movl $0, %edi  

   _align_
   next_line:
      movb (%ebx,%edi), %al  /* al = wd_dirty_lines[edi] */
      testb %al, %al         /* is dirty? */
      jz test_end            /* no ! */

      movl %edi, RECT_TOP
   _align_
   loop_dirty_lines:
      movb $0, (%ebx,%edi)   /* wd_dirty_lines[edi] = 0  */
      incl %edi
      movb (%ebx,%edi), %al  /* al = wd_dirty_lines[edi] */
      testb %al, %al         /* is still dirty? */
      jnz loop_dirty_lines   /* yes ! */

      movl %edi, RECT_BOTTOM
      leal RECT_LEFT, %eax
      pushl %eax
      call *GLOBL(update_window) 
      popl %eax

   _align_
   test_end:   
      incl %edi
      cmpl %edi, %esi  /* last line? */
      jge next_line    /* no ! */

      addl $16, %esp
      popl %edi
      popl %esi
      popl %ebx
      ret



/* gfx_gdi_write_bank:
 *  edx = bitmap
 *  eax = line
 */
FUNC (gfx_gdi_write_bank)
      pushl %ecx

      /* clobber the line */
      movl GLOBL(gdi_dirty_lines), %ecx
      addl BMP_YOFFSET(%edx), %ecx
      movb $1, (%ecx,%eax)   /* gdi_dirty_lines[line] = 1; (line has changed) */

      /* check whether bitmap is already locked */
      testl $BMP_ID_LOCKED, BMP_ID(%edx)
      jnz Locked_gdi

      /* lock the surface */
      pushl %eax
      pushl %edx
      pushl %edx  /* argument */
      call *GLOBL(ptr_gfx_gdi_autolock) 
      popl %edx
      popl %edx
      popl %eax

   Locked_gdi:
      popl %ecx

      /* get pointer to the video memory */
      movl BMP_LINE(%edx,%eax,4), %eax

      ret



/* gfx_gdi_unwrite_bank:
 *  edx = bmp
 */
FUNC (gfx_gdi_unwrite_bank)

      /* only unlock bitmaps that were autolocked */
      testl $BMP_ID_AUTOLOCK, BMP_ID(%edx)
      jz No_unlock_gdi

      /* unlock surface */
      pushl %ecx
      pushl %eax
      pushl %edx
      pushl %edx  /* argument */
      call *GLOBL(ptr_gfx_gdi_unlock) 
      popl %edx
      popl %edx
      popl %eax
      popl %ecx

      /* clear the autolock flag */
      andl $~BMP_ID_AUTOLOCK, BMP_ID(%edx)

   No_unlock_gdi:
      ret
