;*DDK*************************************************************************/
;
; COPYRIGHT    Copyright (C) 1995 IBM Corporation
;
;    The following IBM OS/2 WARP source code is provided to you solely for
;    the purpose of assisting you in your development of OS/2 WARP device
;    drivers. You may use this code in accordance with the IBM License
;    Agreement provided in the IBM Device Driver Source Kit for OS/2. This
;    Copyright statement may not be removed.;
;*****************************************************************************/
;***********************************************************************
;
;   Module          = EDDHIMAG
;
;   Description     = Low level image data routine
;
;
;***********************************************************************

INCL_GPIBITMAPS EQU     1
include os2.inc
include eddinclt.inc

include eddhcone.inc
include eddhmacr.inc
include eddhtype.inc

include eddfcone.inc
include eddfmacr.inc
include eddftype.inc
include cmacros.inc

;***********************************************************************
; Cope with Microsoft compiler conventions
;***********************************************************************
ifndef   _8514
pXGARegs         equ <_pXGARegs>
else
include 8514.inc
p8514Regs        equ <_p8514Regs>
PURGE_PIPELINE   equ 1
ifdef   MEMMAPIO
pVRAM            equ <_pVRAM>
endif
endif
AIxfer           equ <_AIxfer>
pbHWPollRegister equ <_pbHWPollRegister>

;***********************************************************************
; External access for this module
;***********************************************************************
ifndef   _8514
extrn pXGARegs          :dword
else
extrn p8514Regs         :dword
extrn _DDT              :byte
ifdef   BPP24
extrn _Copy24MonoMixToVRAM :near           ;defect 74624
endif
ifdef   MEMMAPIO
extrn   pVRAM           :dword
endif
endif
extrn AIxfer            :dword
extrn pbHWPollRegister  :dword

;***********************************************************************
; handle the soft draw/hard draw differences
;***********************************************************************
IFDEF HARD_DRAW
bitmap_address  equ     phys_addr
ENDIF ; HARD_DRAW

IFDEF SOFT_DRAW
bitmap_address  equ     virt_addr
extrn _eddf_MESS        :proc
ENDIF ; SOFT_DRAW

_DATA           segment dword use32 public 'DATA'
_DATA           ends

_TEXT           segment dword use32 public 'CODE'
                assume  cs:FLAT, ds:FLAT, es:FLAT

IMAGE_DATA_PIXEL_OP equ 08012000h

; structure for parameter block

IMAGEDATAPB     struc
ptsStart        dd      ?
pPels           dd      ?
ulCount         dd      ?
pClipRects      dd      ?
pbmhDest        dd      ?
cClips          dw      ?
IMAGEDATAPB     ends


;***********************************************************************
;
; Function: _eddh_PMIMAGEDATA
;
; Called by: eddb_ImageData   in eddbimag.c
;
; This is the single bitmap case.  Code handles..
;       Clipping
;
; 386 only code
;***********************************************************************

        align   4
IFDEF HARD_DRAW
cProc   eddh_PMImageData,<PUBLIC>,<ebx,edi,esi>
ENDIF

IFDEF SOFT_DRAW
cProc   eddf_PMImageData,<PUBLIC>,<ebx,edi,esi>
ENDIF

        localD  ulPattXY
        localD  ulDestXY
        localD  ulDimensions
        localW  x_src
        localW  y_src
        localW  x_dst
        localW  y_dst
        localW  total_width
        localW  total_height
        localW  tempRows                ; working scan counter
        localW  CenterWords             ; # words in center of src blt
        localW  ncxExt                  ; cxExt adjust to src word boundaries
        localW  nxDst                   ; dest x origin adj to src word bdry's
        localB  PhaseShift              ; diff between src,dest nibble aligns
        localB  RorMask                 ; mask when phase shift is to right
        localW  BltFlags                ; local src to board blt flags
        localW  src_width               ; width of memory bitmap

cBegin

IFDEF TMP                                                   
        push    ebx
ENDIF 
ifndef _8514
        pushxga
endif

; get access to hardware registers
        ifndef  _8514
        movxga  pXGARegs
        else
        movxga  p8514Regs
        endif

; set up the destination bitmap (as pixel map A)
        mov     ebx, AIxfer.pbmhDest
        memregwrite     pi_map_index_A, SEL_PIX_MAP_A

; bitmap address
        mov     eax, [ebx].bitmap_address
        memregwrite     pi_map_base_ptr_A, eax

; width and height
        mov     eax, dword ptr [ebx].hw_width   ; get width and height !
        .erre   hw_height eq (hw_width + 2)
        memregwrite     pi_map_size_A, eax

; format
        mov     al, byte ptr [ebx].hw_format
        memregwrite     pi_map_format_A, al

; set up the source bitmap (as pixel map B)
        memregwrite     pi_map_index_B, SEL_PIX_MAP_B

; physical address
        mov     eax, AIxfer.pPels
        memregwrite     pi_map_base_ptr_B, eax

; width and height - height is always 1, which is h/w height of 0
; thus we just zero extend the count
        movzx   eax, word ptr AIxfer.ulCount
        dec     eax             ; convert count to h/w size
        memregwrite     pi_map_size_B, eax

; format
        memregwrite     pi_map_format_B, MOTOROLA+ONE_BPP

; now loop through all the clip rectangles
        movzx   ecx, AIxfer.cClips
        mov     ebx, AIxfer.pClipRects

clip_loop:

; clip the image data in software to each clip rectangle
; y first
        mov     ax, AIxfer.ptsStart.y
        cmp     ax, [ebx].clip_y0
        jb      no_intersect

        cmp     ax, [ebx].clip_y1
        ja      no_intersect

        mov     ax, AIxfer.ptsStart.x
        cmp     ax, [ebx].clip_x1
        jg      no_intersect            ; signed comparison since ptsStart.x
                                        ; can be negative

        add     ax, word ptr AIxfer.ulCount
        dec     ax
        cmp     ax, [ebx].clip_x0
        jl      no_intersect            ; signed comparison since ptsStart.x
                                        ; can be negative

; now adjust the x start and length
        mov     ax, AIxfer.ptsStart.x
        mov     dx, [ebx].clip_x0
        sorder  ax, dx
IFDEF _8514
        mov     x_dst,dx
        mov     ax,AIxfer.ptsStart.y
        mov     y_dst,ax
        mov     x_src,0
        mov     y_src,0
ENDIF
        swap    edx
        mov     ax, AIxfer.ptsStart.x
        add     ax, word ptr AIxfer.ulCount
        dec     ax
        mov     dx, [ebx].clip_x1
        sorder  dx, ax
        swap    edx             ; Hi Word is X end, Lo Word is X Start.

        mov     eax, AIxfer.ptsStart
        mov     ax, dx

; the start position (destination)
        mov     ulDestXY,eax

; the start position (pattern).  This is really just an X offset
; caused by clipping.
        sub     ax, AIxfer.ptsStart.x
        and     eax, 0000FFFFh
        mov     ulPattXY,eax

        mov     ax, dx
        mov     dx, 0
        swap    edx
        sub     dx, ax

; the operating dimensions adjusted for any clipping that may be
; required.
        mov     ulDimensions,edx
IFDEF _8514
        mov     total_width,dx
ENDIF

; now wait for the hardware
        waitshort

; now pop the parameters into the registers
        mov     eax,ulDimensions
        memregwrite     dimensions, eax
        mov     eax,ulPattXY
        memregwrite     patt_map, eax
        mov     eax,ulDestXY
        memregwrite     dest_map, eax

        mov     eax, IMAGE_DATA_PIXEL_OP
        memregwrite     pixel_op, eax

IFDEF HARD_DRAW

IFDEF _8514
        push    esi                     ; Save Shadow Regs
        push    ecx                     ; Save clip rect. counter
        push    ebx

        mov     ecx,ulDestXY
        and     ecx,3
        jnz     phase_reqd

ifdef   BPP24
        test    [_DDT],USE_24BPP
        jz      @f
        jmp     phase_reqd
@@:
endif

no_phase_reqd:
        WaitQIdle
        WaitQ   8
        mov     eax,ulDestXY
        outwQ   X0,ax
        outwQ   X1,ax
        swap    eax
        outwQ   Y0,ax
        outwQ   Y1,ax

        mov     eax,ulDimensions
        outwQ   LX,ax
        outwQ   LY,0

        outwQ   MODE,(MODE_2DECODE+MD_PS_VAR+MD_UP_FALSE)
        outwQ   CMD_FLAGS,CMDIMAGE

        mov     ecx,ulDimensions
IFDEF _8514
        mov     total_width,cx
ENDIF
        inc     ecx                     ; One-base width.
        add     ecx,7                   ; Round up and
        ;shr     ecx,3                   ;  determine # of bytes.
        shr     ecx,4                   ; convert to word count
        inc     ecx                     ; for single byte or odd count
        mov     dx,COLOR_0_WAIT
        mov     esi,AIxfer.pPels

image_loop:

        ifdef   MEMMAPIO
        ; @DMS can we go over  64k here
        mov     edi,pVRAM
        endif
        twistbits16                     ; Massage into planar format and send it

        loop    image_loop
        jmp     drawing_complete

phase_reqd:

;***************************************************************************
; Drawing monochrome data to a VRAM X-address that is not nibble aligned
; requires special processing.  Here it goes....
;***************************************************************************

; Because the 8514/A aligns along nibble boundaries for mono
; sources the source must be shifted left or right to align it with the
; screen destination. Calculate the nibble phase difference between
; the destination and the source.

        mov     al,Byte Ptr x_src       ; source origin in x
        and     al,3                    ; bit # in source word, zero hi byte
        sub     cl,al                   ; phase difference between them
        and     cl,3                    ; make left phasing look like right
        mov     PhaseShift,cl           ; save rotate count

; Given the phase difference we can also precalculate the mask needed
; for preserving bits to be pipelined to the next operation.

        mov     dl,0ffh                 ; precalculate masks also
        shr     dl,cl                   ; 0s to high end,this is the ror mask
        mov     RorMask,dl              ; save for inner loop

; The bottom-level operations conduct their operations as a left-edge
; fetch/store, all center words fetch/store, right-edge fetch/store
; series of operations. Depending on the situation, all, some, or just 1
; of these operations may actually be executed.

        mov     dx,total_width          ; width of blt in pixels
        inc     dx
        sub     ch,ch                   ; zext'ed phase difference

; Calculate # whole words to fetch for mono src. We adjust the starting
; destination origin left and destination extent upwards so that we may
; always fetch src pixels as words (ie: 16 pixels at a time) and write
; 2 nibbles with one output to the board. Pixels written to the destination
; on the board which are to the left of the specified left of the destination
; rectangle are not actually written since the hw clip rectangle is set
; for the originally specified rectangle. The situation is similar for
; pixels written beyond the original right edge of the destination.

; Calculate the new destination left x origin. The amount of the adjustment
; is determined by the number of pixels needed to bring the src left x origin
; left to a word boundary. This amount must be calculated after the adjustment
; for aligning to the destination nibble boundary is added in.

        mov     ax,x_src                ; src left edge x
        mov     bx,ax                   ; need it later also
        and     bx,15                   ; bit position in src word
        add     ax,cx                   ; adjust for right phase shift
        neg     ax                      ; # pixels to adjust dest x by
        add     ax,x_dst                ; dest adj. for src word fetches
        and     ax,XY_SIGNIFICANT       ; mask to just hw bits
        mov     nxDst,ax                ; save new left x for bottom level

; Calculate the # of whole src words which must be fetched for the extended
; scanline. This is determined by rounding the left side down to a word
; boundary and the right side up to the next word boundary. The # of pixels
; in between divided by 16 is the number of whole src words to be fetched.

        mov     ax,bx                   ; src left edge x
        add     ax,dx                   ; point to right edge x + 1
        and     bx,NOT 15               ; src left rounded down to word bdry
        sub     ax,bx                   ; # pixels in extended scan
        mov     di,ax                   ; need this later
        add     ax,15                   ; round up to word boundary
        shr     ax,4                    ; now # whole src words to fetch
        mov     CenterWords,ax          ; save for bottom level

; Calculate the new extent of the scanline which is actually output to the
; board. It will always be the number of pixels determined from the number
; of whole src words to be fetched (this quantity times 16) plus the
; pixels in any extra word which must be output because of overflow of
; pipelined pixels into a next word.

        mov     ax,di                   ; # pixels in extended scan
        add     ax,cx                   ; adjust extent by phase shift
        add     ax,15                   ; round up to word boundary
        and     ax,NOT 15               ; now # pixels in adj extent
        dec     ax                      ; 0-based for hw
        mov     ncxExt,ax               ; save for bottom level

; Determine whether or not a final output of 4 nibbles must be done. This will
; occur if pipelined pixels overflow into a next word not accounted for by
; src word fetches. An extra src fetch must be avoided because of the
; possibility of GP faults if we access beyond the end of the src bitmap
; memory.

        inc     ax                      ; back to 1-based new x extent
        shr     ax,4                    ; # words in extent
        mov     BltFlags,0
        cmp     ax,CenterWords          ; equal to src word fetches ?
        jbe     short @F                ; yes, no pipelined pixels...
        or      BltFlags,PURGE_PIPELINE ; have to write pipelined pixels
@@:

ifdef   BPP24
        test    [_DDT],USE_24BPP
        jz      @f

        mov     ax,di                   ; # pixels in extended scan
        add     ax,cx                   ; adjust extent by phase shift
        add     ax,7                    ; round up to byte boundary
        and     ax,Not 7                ; now # pixels in adj extent
        dec     ax                      ; 0-based for hw
        mov     ncxExt,ax               ; save for bottom level

        mov     esi,AIxfer.pPels
        mov     edi,AIxfer.ulCount       ; scansize in pels
        add     edi,7                   ; round up to byte boundry
        shr     edi,3                   ; get byte count
        movzx   eax,y_src               ; src y origin
        mul     edi                     ; offset to scan of interest
        add     esi,eax                 ; add offset into bitmap
        movzx   eax,x_src               ; pixels into scanline
       ;add     eax,7                   ; round up to byte boundry
        shr     eax,3                   ; get byte count
        add     esi,eax                 ; -> byte containing pixel

        mov     eax,0                   ; zero based mono height
        push    ax                      ; start bits
        push    ONE_BPP
        push    eax                     ; zero based mono height
        movzx   eax,ncxExt              ; get zero based mono height
        push    eax
        movzx   edx,total_width         ; get blt width in pels
        push    edx

;        mov     ax,nxDst
        mov     ax,x_dst                ; Defect 73542
        ror     eax,16
        mov     ax,y_dst
        push    eax
        push    esi
        call    _Copy24MonoMixToVRAM
        add     esp,26

        jmp     id_done
@@:
endif

; H/W initializations common to all mono to board cases.
        WaitQIdle
        WaitQ   2                       ; need room in the queue
        mov     bx,x_dst                ; set up scissor rectangle
        dec     bx
        mov     ax,bx
        or      ax,XMIN_2DECODE
        outwQ   XMIN,ax

        mov     ax,total_width          ; width of the cursor
        inc     ax
        add     ax,bx                   ; Calculate the right edge of the scissor rect.
        or      ax,XMAX_2DECODE
        outwQ   XMAX,ax

        WaitQ   8
        outwQ   MODE,(MODE_2DECODE+MD_PS_VAR+MD_UP_FALSE); variable pattern
        outwQ   LX,ncxExt               ; 0-based width of blt
        outwQ   LY,0
        mov     tempRows,1              ; working counter storage
        outwQ   Y0,y_dst                ; destination y origin
        outwQ   Y1,ax                   ; destination y origin

;------------------------------------------------------------------------------
; Mono src, src must shift right to align with destination nibble alignment.
;------------------------------------------------------------------------------
        outwQ   X0,nxDst                ; destination x origin
        outwQ   X1,ax                   ; destination x origin
        outwQ   CMD_FLAGS,CMDIMAGE      ; 1 bpp blt from memory

        ; get pointer to bitmap in esi
        mov     esi,AIxfer.pPels
        mov     edi,AIxfer.ulCount      ; scansize in pels
        add     edi,7                   ; round up to byte boundry
        and     edi,NOT 7
        shr     edi,3                   ; get byte count
        movzx   eax,y_src               ; src y origin
        mul     edi                     ; offset to scan of interest
        add     esi,eax                 ; add offset into bitmap
        movzx   eax,x_src               ; pixels into scanline
        mov     cx,(1 Shl  8) + 4       ; shift count for xyaddr
        shr     ax,cl
        xchg    ch,cl                   ; round to specified boundary
        shl     ax,cl                   ; now make byte offset
        add     esi,eax                 ; -> byte containing pixel
        neg     eax                     ; negative of offset into each scan
        add     eax,edi                 ; now # bytes to end of scan
        mov     src_width,ax            ; save the width

        mov     dx,COLOR_0_WAIT         ; variable data port
        mov     cl,PhaseShift           ; nibble phase diff between src,dest
        or      cl,cl                   ; phases equal ?
        jz      id_mono_equal_align     ; yes, utilize special-cased code...
        mov     ch,RorMask              ; mask for pipelined pixels

id_mono_rScan_lp:
        push    esi                     ; save scan start offset
        sub     bh,bh                   ; 0 previous pipelined pixels
        mov     di,CenterWords          ; # src words to be fetched
        shr     di,1                    ; Preserve the odd word count
        jz      short id_mono_no_dword

@@:     lodsd                           ; fetch P2|P3|P0|P1:P2|P3|P0|P1
        xchg    ah,al                   ; now   P0|P1|P2|P3
        ror     ax,cl                   ; align to destination

        mov     bl,ah                   ; cache new unused pixels
        not     ch                      ; form left mask
        and     bl,ch                   ; isolate new unused pixels
        not     ch                      ; restore right mask
        and     ah,ch                   ; make room for old unused pixels
        or      ah,bh                   ; add in old unused pixels
        mov     bh,bl                   ; save new unused pixels

                                        ; currently P0|P1|P2|P3
IFNDEF S3
        rol     al,4                    ; now       P0|P1|P3|P2
        rol     ax,4                    ; now       P1|P3|P2|P0
        rol     ah,4                    ; now       P3|P1|P2|P0
        rol     ax,1                    ; P0,P1 into hw position
        out     dx,ax                   ; output P0,P1
        ror     ax,4                    ; P2,P3 into hw position
ELSE
        xchg    ah,al
ENDIF
        out     dx,ax                   ; output P2,P3

        ror     eax,16                  ; move the hi-word down to low-word
        xchg    ah,al                   ; now   P0|P1|P2|P3

        ror     ax,cl                   ; align to destination

        mov     bl,ah                   ; cache new unused pixels
        not     ch                      ; form left mask
        and     bl,ch                   ; isolate new unused pixels
        not     ch                      ; restore right mask
        and     ah,ch                   ; make room for old unused pixels
        or      ah,bh                   ; add in old unused pixels
        mov     bh,bl                   ; save new unused pixels
                                        ; currently P0|P1|P2|P3
IFNDEF S3
        rol     al,4                    ; now       P0|P1|P3|P2
        rol     ax,4                    ; now       P1|P3|P2|P0
        rol     ah,4                    ; now       P3|P1|P2|P0
        rol     ax,1                    ; P0,P1 into hw position
        out     dx,ax                   ; output P0,P1
        ror     ax,4                    ; P2,P3 into hw position
ELSE
        xchg    ah,al
ENDIF
        out     dx,ax                   ; output P2,P3

        dec     di                      ; drop word count
        jnz     @B                      ; for all whole src words to output...

id_mono_no_dword:
        mov     di,CenterWords          ; # src words to be fetched
        and     di,1                    ; The fetch for the odd word if any
        jz      short @F
        lodsw
        xchg    ah,al                   ; now   P0|P1|P2|P3

        ror     ax,cl                   ; align to destination

        mov     bl,ah                   ; cache new unused pixels
        not     ch                      ; form left mask
        and     bl,ch                   ; isolate new unused pixels
        not     ch                      ; restore right mask
        and     ah,ch                   ; make room for old unused pixels
        or      ah,bh                   ; add in old unused pixels
        mov     bh,bl                   ; save new unused pixels

                                        ; currently P0|P1|P2|P3
IFNDEF S3
        rol     al,4                    ; now       P0|P1|P3|P2
        rol     ax,4                    ; now       P1|P3|P2|P0
        rol     ah,4                    ; now       P3|P1|P2|P0
        rol     ax,1                    ; P0,P1 into hw position
        out     dx,ax                   ; output P0,P1
        ror     ax,4                    ; P2,P3 into hw position
ELSE
        xchg    ah,al
ENDIF
        out     dx,ax                   ; output P2,P3
@@:
        test    BltFlags,PURGE_PIPELINE ; have to write final pipelined pixels?
        jz      short @F                ; no...

        mov     al,Bh                   ; get pipelined pixels
        ror     al,3                    ; into hw position
        out     dx,Ax                   ; output pipelined nibble, ignore others
IFNDEF  S3
        out     dx,Ax                   ; just to satisfy the hw
ENDIF
@@:
        pop     esi                     ; recover original src offset
        movzx   eax,src_width           ; get total number of bytes
        add     esi,eax                 ; go to next source scan

id_mono_rReenter:

        dec     tempRows                ; 1 less row to blt
        jnz     id_mono_rScan_lp        ; else for all rows to blt...
        jmp     short id_done           ; get out if no more...

;------------------------------------------------------------------------------
; Mono src, src and destination nibble alignments are equal.
;------------------------------------------------------------------------------

id_mono_equal_align:

        mov     bx,tempRows

id_mono_eqScan_lp:

        ifndef  MEMMAPIO
        mov     edi,esi                 ; save scan offset
        else
        mov     edx,esi                 ; wont be using dx in twistbits
        ; @DMS can we go over  64k here
        mov     edi,pVRAM
        endif
        movzx   ecx,CenterWords         ; # whole src words to fetch
        shr     cx,1
        jz      short id_mono_eqno_dword


@@:
        ; @DMS can do this faster with a dword load instead of two word loads
        twistbits16
        twistbits16

        loop    @B                      ; for all whole src words to output...

id_mono_eqno_dword:
        movzx   ecx,CenterWords
        and     cx,1                    ; the last fetch for the odd word
        jz      short @F

        twistbits16
@@:

        ifndef  MEMMAPIO
        mov     esi,edi                 ; recover original src offset
        else
        mov     esi,edx                 ; recover original src offset
        endif
        movzx   eax,src_width           ; get total number of bytes
        add     esi,eax                 ; go to next source scan

id_mono_eqReenter:

        dec     Bx                      ; 1 less row to blt
        jnz     Short id_mono_eqScan_lp ; else for all rows to blt...

id_done:

        WaitQ   2
        outwQ   XMIN,(XMIN_2DECODE+0)   ;; set scissor to full screen
        ifdef   S3
        mov     ax,SCR_S3_WIDTH-1
        else
        mov     ax,SCR_8514_WIDTH
        endif
        or      ax,XMAX_2DECODE
        outwQ   XMAX,ax                 ; set max scissor x extent



drawing_complete:

        pop     ebx
        pop     ecx                     ; Restore clip rect. counter.
        pop     esi                     ; Restore Shadow Regs

ENDIF ; _8514

ELSE ; SOFT_DRAW
        saveregs
        call    _eddf_MESS
        restoreregs
ENDIF ; SOFT_DRAW

no_intersect:
        add     ebx, size clip_rect

; unfortunately we are out of range for a loop instruction
        dec     ecx
        jnz     clip_loop

; all done

ifndef _8514
        popxga
endif
IFDEF TMP                                                   
        pop     ebx
ENDIF 

cEnd ;PMImageData

_TEXT           ends

END
