blitter.inc
kolibrios-nextgen_kolibrios-kernel/kernel/video/blitter.inc
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;                                                              ;;
;; Copyright (C) KolibriOS team 2011-2022. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License    ;;
;;                                                              ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


struct  BLITTER_BLOCK
        xmin            dd ?
        ymin            dd ?
        xmax            dd ?
        ymax            dd ?
ends


struct  BLITTER
        dc              RECT
        sc              RECT
        dst_x           dd ?            ;  32
        dst_y           dd ?            ;  36
        src_x           dd ?            ;  40
        src_y           dd ?            ;  44
        w               dd ?            ;  48
        h               dd ?            ;  52

        bitmap          dd ?            ;  56
        stride          dd ?            ;  60
ends



align 4
block_clip:
;esi= clip RECT ptr
;edi= RECT ptr
;return code:
;CF= 0 - draw, 1 - don't draw

        push    ebx

        mov     eax, [edi + RECT.left]
        mov     ebx, [edi + RECT.right]
        mov     ecx, [esi + RECT.left]    ;clip.left
        mov     edx, [esi + RECT.right]   ;clip.right

        cmp     eax, edx                ;left >= clip.right
        jge     .fail

        cmp     ebx, ecx                ;right < clip.left
        jl      .fail

        cmp     eax, ecx                ;left >= clip.left
        jge     @F

        mov     [edi + RECT.left], ecx
@@:
        cmp     ebx, edx                ;right <= clip.right
        jle     @f

        mov     [edi + RECT.right], edx
@@:
        mov     eax, [edi + RECT.top]
        mov     ebx, [edi + RECT.bottom]
        mov     ecx, [esi + RECT.top]     ;clip.top
        mov     edx, [esi + RECT.bottom]  ;clip.bottom

        cmp     eax, edx                ;top >= clip.bottom
        jge     .fail

        cmp     ebx, ecx                ;bottom < clip.top
        jl      .fail

        cmp     eax, ecx                ;top >= clip.top
        jge     @F

        mov     [edi + RECT.top], ecx
@@:
        cmp     ebx, edx                ;bottom <= clip.bottom
        jle     @f

        mov     [edi + RECT.bottom], edx
@@:
        pop     ebx
        clc
        ret
.fail:
        pop     ebx
        stc
        ret


align 4
blit_clip:

;return code:
;CF= 0 - draw, 1 - don't draw

.sx0   = 8
.sy0   = 12
.sx1   = 16
.sy1   = 20

.dx0   = 24
.dy0   = 28
.dx1   = 32
.dy1   = 36


        push    edi
        push    esi
        push    ebx
        sub     esp, 40

        mov     ebx, ecx
        mov     edx, [ecx + BLITTER.src_x]
        mov     [esp+.sx0], edx
        mov     eax, [ecx + BLITTER.src_y]
        mov     [esp+.sy0], eax
        add     edx, [ecx + BLITTER.w]
        add     eax, [ecx + BLITTER.h]
        mov     [esp + .sx1], edx
        mov     [esp + .sy1], eax

        lea     edi, [esp + .sx0]
        lea     esi, [ebx + BLITTER.sc]

        call    block_clip
        jc      .done

        mov     edi, [esp + .sx0]
        mov     edx, [ebx + BLITTER.dst_x]
        add     edx, edi
        sub     edx, [ebx + BLITTER.src_x]
        mov     [esp + .dx0], edx

        mov     ecx, [esp+.sy0]
        mov     eax, [ebx + BLITTER.dst_y]
        add     eax, ecx
        sub     eax, [ebx + BLITTER.src_y]
        mov     [esp + .dy0], eax

        sub     edx, edi
        add     edx, [esp + .sx1]
        mov     [esp + .dx1], edx

        sub     eax, ecx
        add     eax, [esp + .sy1]
        mov     [esp + .dy1], eax

        lea     edi, [esp + .dx0]
        lea     esi, [ebx + BLITTER.dc]
        call    block_clip
        jc      .done

        mov     edx, [esp + .dx0]
        mov     eax, [esp + .dx1]
        sub     eax, edx
        mov     [ebx + BLITTER.w], eax

        mov     eax, [esp + .dy0]
        mov     ecx, [esp + .dy1]
        sub     ecx, eax
        mov     [ebx + BLITTER.h], ecx

        mov     ecx, [ebx + BLITTER.src_x]
        add     ecx, edx
        sub     ecx, [ebx + BLITTER.dst_x]
        mov     [ebx + BLITTER.src_x], ecx

        mov     ecx, [ebx + BLITTER.src_y]
        add     ecx, eax
        sub     ecx, [ebx + BLITTER.dst_y]
        mov     [ebx + BLITTER.src_y], ecx
        mov     [ebx + BLITTER.dst_x], edx
        mov     [ebx + BLITTER.dst_y], eax
        clc
.done:
        add     esp, 40
        pop     ebx
        pop     esi
        pop     edi


purge .sx0
purge .sy0
purge .sx1
purge .sy1

purge .dx0
purge .dy0
purge .dx1
purge .dy1

        ret

align 4
blit_32:
        push    ebp
        push    edi
        push    esi
        push    ebx
virtual at sizeof.BLITTER
.position       dd      ? ; (x shl 16) + y
; ???
.extra_var1     dd      ?
.flags          dd      ?
.local_vars_size = $
end virtual
        sub     esp, .local_vars_size
        
        mov     [esp + .flags], ebx

        mov     eax, [current_slot_idx]
        shl     eax, BSF sizeof.WDATA
        mov     ebx, [window_data + eax + WDATA.box.width]
        mov     edx, [window_data + eax + WDATA.box.height]
        inc     ebx
        inc     edx

        xor     eax, eax

        mov     [esp + BLITTER.dc.left], eax
        mov     [esp + BLITTER.dc.top], eax
        mov     [esp + BLITTER.dc.right], ebx
        mov     [esp + BLITTER.dc.bottom], edx

        mov     [esp + BLITTER.sc.left], eax
        mov     [esp + BLITTER.sc.top], eax
        mov     eax, [ecx+24]

        mov     [esp + BLITTER.sc.right], eax
        mov     eax, [ecx+28]

        mov     [esp + BLITTER.sc.bottom], eax

        mov     eax, [ecx]
        mov     [esp + BLITTER.dst_x], eax
        mov     eax, [ecx+4]
        mov     [esp + BLITTER.dst_y], eax

        mov     eax, [ecx+16]
        mov     [esp + BLITTER.src_x], eax
        mov     eax, [ecx+20]
        mov     [esp + BLITTER.src_y], eax
        mov     eax, [ecx+8]
        mov     [esp + BLITTER.w], eax
        mov     eax, [ecx+12]
        mov     [esp + BLITTER.h], eax


        mov     eax, [ecx+32]
        mov     [esp + BLITTER.bitmap], eax
        mov     eax, [ecx+36]
        mov     [esp + BLITTER.stride], eax

        mov     ecx, esp
        call    blit_clip
        jc      .L57

        mov     eax, [current_slot_idx]
        shl     eax, BSF sizeof.WDATA

        mov     ebx, [esp + BLITTER.dst_x]
        mov     ebp, [esp + BLITTER.dst_y]
        add     ebx, [window_data + eax + WDATA.box.left]
        add     ebp, [window_data + eax + WDATA.box.top]
        
        test    [esp + .flags], BLIT_CLIENT_RELATIVE
        jz      .no_client_relative        

        mov     eax, [current_slot]
        add     ebx, [eax + APPDATA.wnd_clientbox.left]
        add     ebp, [eax + APPDATA.wnd_clientbox.top]
.no_client_relative:

        mov     ecx, ebx
        add     ecx, [esp + BLITTER.w]
        shl     ecx, 16
        mov     cx, bp
        add     ecx, [esp + BLITTER.h]

        mov     eax, ebx
        shl     eax, 16
        mov     ax, bp
        mov     [esp + .position], eax

        mov     edi, ebp

;        imul    edi, [_display.pitch]
        mov     edi, [BPSLine_calc_area+edi*4]
;        imul    ebp, [_display.width]
        mov     ebp, [d_width_calc_area+ebp*4]

        add     ebp, ebx
        add     ebp, [_display.win_map]

        mov     eax, [esp + BLITTER.src_y]
        imul    eax, [esp + BLITTER.stride]
        mov     esi, [esp + BLITTER.src_x]
        lea     esi, [eax + esi*4]
        add     esi, [esp + BLITTER.bitmap]

        mov     eax, ecx
        mov     ecx, [esp + BLITTER.h]
        mov     edx, [esp + BLITTER.w]

        test    ecx, ecx    ;FIXME check clipping
        jz      .L57

        test    edx, edx
        jz      .L57

        cmp     [_display.bits_per_pixel], 32
        jne     .core_24

        lea     edi, [edi + ebx*4]

        mov     ebx, [current_slot_idx]
; check for hardware cursor
        cmp     [_display.select_cursor], select_cursor
        je      .core_32.software_cursor
        cmp     [_display.select_cursor], 0
        jne     .core_32.hardware_cursor
;--------------------------------------
.core_32.software_cursor:
align 4
.outer32:

align 4
.inner32:
        cmp     [ebp], bl
        jne     .skip
;--------------------------------------
        mov     eax, [esi]

        mov     ecx, [esp + .position]

; check mouse area for putpixel
        call    [_display.check_mouse]
;--------------------------------------
; store to real LFB
        mov     [LFB_BASE + edi], eax
;--------------------------------------
align 4
.skip:
        add     esi, 4
        add     edi, 4
        inc     ebp
        add     [esp + .position], 1 shl 16
        dec     edx
        jnz     .inner32

        add     esi, [esp + BLITTER.stride]
        add     edi, [_display.lfb_pitch]
        add     ebp, [_display.width]

        mov     edx, [esp + BLITTER.w]
        mov     eax, edx
        inc     [esp+.position]
        sub     ebp, edx
        shl     eax, 2
        sub     esi, eax
        sub     edi, eax
        shl     eax, 16-2
        sub     [esp + .position], eax
        dec     [esp + BLITTER.h]
        jnz     .outer32
        jmp     .done
.core_32.hardware_cursor:
align 4
.hw.outer32:
        xor     ecx, ecx

align 4
.hw.inner32:
        cmp     [ebp + ecx], bl
        jne     .hw.skip
        mov     eax, [esi + ecx*4]
        mov     [LFB_BASE + edi + ecx*4], eax

align 4
.hw.skip:
        inc     ecx
        dec     edx
        jnz     .hw.inner32

        add     esi, [esp + BLITTER.stride]
        add     edi, [_display.lfb_pitch]
        add     ebp, [_display.width]

        mov     edx, [esp + BLITTER.w]
        dec     [esp + BLITTER.h]
        jnz     .hw.outer32

.done:
;        call    [draw_pointer]
;        call    __sys_draw_pointer
.L57:
        add     esp, .local_vars_size
        pop     ebx
        pop     esi
        pop     edi
        pop     ebp
        ret

.core_24:
        cmp     [_display.bits_per_pixel], 24
        jne     .core_16

        lea     ebx, [ebx + ebx*2]
        lea     edi, [LFB_BASE + edi + ebx]
        mov     ebx, [current_slot_idx]

align 4
.outer24:
        mov     [esp + .extra_var1], edi
        xor     ecx, ecx

align 4
.inner24:
        cmp     [ebp + ecx], bl           ; Does the process own this pixel?
        jne     .skip_1
;--------------------------------------
        push    eax
        mov     eax, [esi + ecx*4]

        lea     edi, [edi + ecx*2]

; check for hardware cursor
        cmp     [_display.select_cursor], select_cursor
        je      @f
        cmp     [_display.select_cursor], 0
        jne     .no_mouseunder_1
;--------------------------------------
align 4
@@:
        push    ecx

        mov     ecx, [esp+4]
        ror     ecx, 16
        sub     ecx, edx
        rol     ecx, 16
        sub     ecx, [esp + BLITTER.h + 8]

; check mouse area for putpixel
        call    [_display.check_mouse]
        pop     ecx
;--------------------------------------
align 4
.no_mouseunder_1:
        mov     [edi + ecx], ax
        shr     eax, 16
        mov     [edi + ecx+2], al

        pop     eax
;--------------------------------------
align 4
.skip_1:
        mov     edi, [esp + .extra_var1]
        inc     ecx
        dec     edx
        jnz     .inner24

        add     esi, [esp + BLITTER.stride]
        add     edi, [_display.lfb_pitch]
        add     ebp, [_display.width]

        mov     edx, [esp + BLITTER.w]
        dec     [esp + BLITTER.h]
        jnz     .outer24

        jmp     .done


.core_16:
        lea     edi, [LFB_BASE + edi + ebx*2]
        mov     ebx, [current_slot_idx]

  .outer16:
        mov     [esp + .extra_var1], edi
        xor     ecx, ecx

  .inner16:
        cmp     [ebp + ecx], bl                   ; Does the process own this pixel?
        jne     .skip_2
;--------------------------------------
        push    eax
        mov     eax, [esi + ecx*4]

; check for hardware cursor
        cmp     [_display.select_cursor], select_cursor
        je      @f
        cmp     [_display.select_cursor], 0
        jne     .no_mouseunder_2
;--------------------------------------
  @@:
        push    ecx

        mov     ecx, [esp+4]
        ror     ecx, 16
        sub     ecx, edx
        rol     ecx, 16
        sub     ecx, [esp + BLITTER.h + 8]

; check mouse area for putpixel
        call    [_display.check_mouse]
        pop     ecx
;--------------------------------------
  .no_mouseunder_2:
; convert to 16 bpp and store to LFB
        and     eax, 00000000111110001111110011111000b
        shr     ah, 2
        shr     ax, 3
        ror     eax, 8
        add     al, ah
        rol     eax, 8
        mov     [edi + ecx*2], ax
        pop     eax
;--------------------------------------
  .skip_2:
        mov     edi, [esp + .extra_var1]
        inc     ecx
        dec     edx
        jnz     .inner16

        add     esi, [esp + BLITTER.stride]
        add     edi, [_display.lfb_pitch]
        add     ebp, [_display.width]

        mov     edx, [esp + BLITTER.w]
        dec     [esp + BLITTER.h]
        jnz     .outer16

        jmp     .done

