;*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.;
;*****************************************************************************/
        page    ,132
;---------------------------Module-Header-------------------------------;
; Module Name: COMPRESS.ASM
;
; Provides screen pixel access functions as required for DCAF.
;
;
; Data is passed between the drivers in run-length encoded form.
;
; The algorithm is a modification of Golomb run-length encoding
; (Golomb, "SW Run-length encoding", IEEE Transactions on
; Information Theory, IT-12 1966, pp 399-401).
;
;
; The format of the compressed data is:
;
;   PACKET HEADER
;
;     RECTANGLE 1 HEADER
;     RECTANGLE 1 DATA
;
;     RECTANGLE 2 HEADER
;     RECTANGLE 2 DATA
;     .    .       .
;     .    .       .
;     RECTANGLE n HEADER
;     RECTANGLE n DATA
;
;
;   Definitions of the data structures are:
;
;   1) PACKET HEADER
;
;   dd   total_data_packet_length (including header)
;   dw   data_format
;
;
;   2) RECTANGLE HEADER
;
;   dw   xLeft
;   dw   yBottom
;   dw   xRight
;   dw   yTop
;
;   3) RECTANGLE DATA
;
;   The rectangle data is split into individual rows.
;   Each row is split into run-length encoded blocks("cells"), each of
;   which comprises a length field followed by one or more data fields.
;
;   If the length field contains a "positive" value (msb not set) then
;   the following single data field is repeated (length) times.
;
;   If the length field contains a "negative" value (most significant
;   bit set) then (length - m.s. bit) fields of non-repeating data follow.
;
;   If the length field is zero and the following field is non-zero, the
;   non-zero field is a count of the number of times that the single
;   previous row is repeated. This will only appear as the first cell in
;   a row, and only after there has been at least one row of data.
;
;   If the length field is zero and the following field is zero,
;   the next (i.e. third) field is a count of the number of times that
;   the previous pair of rows are repeated. This will only appear as the
;   first cell in a row, and only after there have been at least two
;   rows of data.
;
;
;   The size of both the length and data fields varies according to
;   the format of the data being transmitted (as specified by the
;   data_format field in the packet header):
;
;       - 4bpp:        field size is one byte  (8 bits)
;       - 8bpp, 16bpp: field size is two bytes (16 bits)
;
;
;   A picture paints a thousand words but takes a thousand times longer
;   to write!
;-----------------------------------------------------------------------;


        .xlist
?DF     equ     1       ; don't define _TEXT segment
        include cmacros.inc

REGION_TYPE             equ     0200h   ;@GPL - define it here to save
                                        ;       requiring pmgre component
INCL_ERRORS             equ     1
INCL_DDICOMFLAGS        equ     1
INCL_GPIREGIONS         equ     1
INCL_GRE_CLIP           equ     1
INCL_GRE_DCAF           equ     1
INCL_GRE_REGIONS        equ     1
INCL_GRE_SCREEN         equ     1
INCL_GPIBITMAPS         equ     1

        include os2.inc
        include eddinclt.inc
        include hwaccess.inc
        include eddhmacr.inc
        include eddhtype.inc

;----------------------------------------------------------------------;
; Include DCAF macros
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
        include dcaf.inc
        include dcafmac.inc
        include compmac.inc
ifdef S3
        include 8514.inc
endif

;-----------------------------------------------------------------------
; Cope with C naming convention
;-----------------------------------------------------------------------
ifdef S3
    p8514Regs             equ <_p8514Regs>
else
    pXGARegs              equ <_pXGARegs>
endif
Spad                      equ <_Spad>
pbHWPollRegister          equ <_pbHWPollRegister>

ifdef S3
convert_row_24pk_16pk     equ <_convert_row_24pk_16pk>
convert_row_24pk_8pk      equ <_convert_row_24pk_8pk>
convert_row_24pk_4pk      equ <_convert_row_24pk_4pk>
endif
convert_row_16pk_8pk      equ <_convert_row_16pk_8pk>
convert_row_16pk_4pk      equ <_convert_row_16pk_4pk>
convert_row_8pkint_8pkext equ <_convert_row_8pkint_8pkext>
convert_row_8pk_4pk       equ <_convert_row_8pk_4pk>
convert_row_4pk_4pl       equ <_convert_row_4pk_4pl>
convert_row_4pkint_4pkext equ <_convert_row_4pkint_4pkext>

;-----------------------------------------------------------------------
; External access for this module
;-----------------------------------------------------------------------

ifdef S3
    extrn p8514Regs     :dword
else
    extrn pXGARegs      :dword
endif
extrn Spad              :dword
extrn pbHWPollRegister  :dword
extrn _pConvertTable_8int_8ext :dword

ifdef S3
extrn convert_row_24pk_16pk      :proc
extrn convert_row_24pk_8pk       :proc
extrn convert_row_24pk_4pk       :proc
endif
extrn convert_row_16pk_8pk       :proc
extrn convert_row_16pk_4pk       :proc
extrn convert_row_8pkint_8pkext  :proc
extrn convert_row_8pk_4pk        :proc
extrn convert_row_4pk_4pl        :proc
extrn convert_row_4pkint_4pkext  :proc

ifdef S3
extrn _CopyVRAMToMemory          :proc
endif


        .list

.386p

_DATA           segment dword use32 public 'DATA'

_DATA           ends


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


;----------------------------------------------------------------------;
;
; Function:
;       compress_rect
;
; Overview:
;       Compresses the supplied rectangle into the destination buffer.
;
; Entry:
;       Spad.gsb_prclCurrent
;          Pointer to RECTL to compress
;       Spad.gsb_pfnCompressRow
;          Pointer to row compression function
;       Spad.gsb_pNextFreeDestByte
;          Pointer to next free byte in output buffer
;       Spad.gsb_cbFreeBytesInDestBuffer
;          Count of free bytes in output buffer
;
; Exit:
;       Spad.gsb_pNextFreeDestByte
;          Updated ptr to next free byte in output buffer
;       Spad.gsb_cbFreeBytesInDestBuffer
;          Updated count of free bytes in output buffer
;
; Updated:
;       Spad.gsb_prclCurrent
;          If the output buffer fills up and a partial rectangle is
;          returned, the RECTL is updated to contain the area that was
;          compressed.
;
; Returns:
;       eax = 0 indicates output buffer not filled i.e. whole rect
;       returned
;
;       eax = 1 indicates output buffer full i.e. only partial rect
;       returned
;
;----------------------------------------------------------------------;
ALIGN   4
cProc   CompressRect,<PUBLIC>,<esi,edi>


        localD  cbBytesPerSrcRow
        localD  cbWorstCaseBytesPerDstRow
        localD  pRectHeader
        localD  yCurrentRow
        localD  yStartRow
        localD  yEndRow
        localD  yLastBufferedRow
        localD  cbBytesPerScanline
        localD  fFirstTime
        localD  fFirstTimePair
        localD  pCurrentSrcPos
        localD  pNextFreeDstPos
        localD  pDestAtStartOfLine
        localD  fOutputBufferFull
        localD  cxRectWidth
        localD  cyRectHeight
        localD  cyMaxRowsInTransferBuffer
        localD  ulBitsPerPel

cBegin
        ; Save the segment register that we will use for XGA
        pushxga

        ; Get the number of bytes available in the output buffer
        mov     ecx,Spad.gsb_cbFreeBytesInDestBuffer

        ; Load up the destination pointer
        mov     edi,Spad.gsb_pNextFreeDestByte

        ;---------------------------------------------------------------
        ; Initialise yCurrentRow to yTop of the supplied rectangle.
        ; Note that the rectangle is exclusive, so this value will be
        ; one greater than the first row  we want to compress.
        ;---------------------------------------------------------------

        ; Calculate the flipped yCurrentRow (i.e. relative to top
        ; of screen) and the flipped yStartRow and yEndRow.
        ; Note that the top is exclusive, but the flipping operation
        ; will give us the number of rows from the top of the screen.
        mov     eax,Spad.gsb_cyScreenHeight
        mov     edx,eax

        ; Get the pointer to the current rectangle.
        mov     ebx,Spad.gsb_prclCurrent

        ; yEndRow = (ScreenHeight-1) - yBottom (inclusive)
        dec     eax
        sub     eax,[ebx].rcl_yBottom
        mov     yEndRow,eax

        ; yStartRow = ScreenHeight - yTop (exclusive)
        mov     eax,edx
        sub     eax,[ebx].rcl_yTop
        mov     yStartRow,eax
        mov     yCurrentRow,eax

        ;---------------------------------------------------------------
        ; Calculate the width of a source row (in pels).
        ;---------------------------------------------------------------
        ; Fetch the rectangle right-hand coordinate.
        mov     eax,[ebx].rcl_xRight

        ; Subtract the rectangle left-hand coordinate to give us the
        ; rectangle width in pels.
        sub     eax,[ebx].rcl_xLeft

        ; Store width
        mov     cxRectWidth, eax

        ;---------------------------------------------------------------
        ; Convert the source row width from pels into bytes.
        ;---------------------------------------------------------------
        mov     ebx,Spad.gsb_cScreenBitsPerPel
        mov     ulBitsPerPel, ebx

        ; ebx now contains screen bits/pel.
        ; If bpp is 8 then pel count is same as byte count.
        cmp     ebx,8
        je      short got_byte_count

        cmp     ebx,4
        jne     short @F

        ; Bpp is 4 - byte count is half the pel count.
        shr     eax,1
        jmp     short   got_byte_count

@@:
        cmp     ebx,16
        jne     @F

        ; Bpp is 16 - byte count is double the pel count.
        shl     eax,1

ifdef S3
        jmp     short   got_byte_count

@@:
        ; Bpp must be 24 - byte count is triple the pel count.
        mov     edx,eax
        shl     eax,1
        add     eax,edx
endif ;S3

public got_byte_count
got_byte_count:

        ; Store the bytes per source row.
        mov     cbBytesPerSrcRow,eax

        ; Store the bytes per scan line
        ; Constant for device unless on XGA.
        ; If XGA then the bytes per source row is equal to the bytes
        ; per scanline when the data is read into the transfer buffer.
        mov     cbBytesPerScanline,eax

        ; Calculate the worst-case bytes per destination row.
        ; eax already contains the the bytes per src row.
        add     eax,WORST_CASE_ROW_EXPANSION
        mov     cbWorstCaseBytesPerDstRow,eax

        ;---------------------------------------------------------------
        ; Do an initial check to see whether it is worth starting to
        ; compress the rectangle.
        ;---------------------------------------------------------------

        ; Calculate the size needed for the rect header, plus a single
        ; row. ax already contains the worst case row length.
        add     eax,size RECTS

        ; Compare the size calculated with the free bytes available
        ; in the destination buffer (currently in ecx).
        cmp     eax,ecx
        jbe     short buffer_size_ok

        ; We can't pass back a single row of this rect!
        ; Set fOutputBufferFull to TRUE.
        mov     fOutputBufferFull,TRUE

        ; Update the supplied rectangle to NULL and exit.
        ; This is a special case exit as the rectangle is not in the
        ; buffer and can't be updated.
        mov     ebx,Spad.gsb_prclCurrent
        mov     eax,[ebx].rcl_yTop
        mov     [ebx].rcl_yBottom, eax

        jmp     compress_rect_no_rects_exit

public buffer_size_ok
buffer_size_ok:
        ; Initialise fOutputBufferFull.
        mov     fOutputBufferFull,FALSE

        ; Initialise yLastBufferedRow to zero.
        ; This will force loading of the Transfer Buffer on the first pass
        ; of the loop.
        mov     yLastBufferedRow, 0

        ; Calculate the maximum number of rows we can store in the PHUNK.
        mov     eax, Spad.gsb_cbTransferBufferSize
        xor     edx, edx
        mov     ecx, cbBytesPerScanline
        div     ecx
        mov     cyMaxRowsInTransferBuffer, eax

        ;---------------------------------------------------------------
        ; We now have all the information we need to set up
        ; Pixmap B (the destination pixmap).
        ; The dimensions of the pixblt are set up later, when we
        ; actually transfer the data into the Transfer Buffer (PHUNK).
        ;---------------------------------------------------------------

        ; Get the base address of the hardware registers (into gs:esi).
ifndef S3
        movxga  pXGARegs

        ; Set up the destination pixmap height
        memregwrite     pi_map_index_B, SEL_PIX_MAP_B
        dec     eax
        memregwrite     pi_map_height_B, ax

        ; Set up the destination pixmap width
        mov     eax, cxRectWidth
        dec     eax
        memregwrite     pi_map_width_B, ax

        ; Set up the destination pixmap base address
        mov     eax, Spad.gsb_pTransferBufferPhys
        memregwrite     pi_map_base_ptr_B, eax

        ; Set up the destination pixmap format
        mov     eax, Spad.gsb_ulPixMapFormatB
        memregwrite     pi_map_format_B, al
endif

        ; Save the current pointer to the destination buffer.
        ; This is where we will fill in the rectangle header at the
        ; end of the routine.
        mov     pRectHeader,edi

        ; Move the destination pointer over the rectangle header.
        add     edi,size RECTS

        ; Update the number of free bytes remaining in the dest buffer.
        sub     Spad.gsb_cbFreeBytesInDestBuffer, size RECTS

        ; Load up the address of first source row into esi.
        mov     esi,Spad.gsb_pTransferBufferVirt

        ;---------------------------------------------------------------
        ; Begin the main loop that processes each row of the rectangle.
        ; 
        ; Here: esi is the current source position
        ;       edi is the next free destination position
        ; 
        ;---------------------------------------------------------------
public main_row_loop
main_row_loop:
        ; Set first time counters to true
        mov     eax,TRUE
        mov     fFirstTime,eax
        mov     fFirstTimePair,eax

        ; Store the current row pointer.
        mov     pCurrentSrcPos,esi

        ; Check that we have the required rows in the PHUNK
        ensure_rows_are_buffered

        ; Check whether the remaining space in the destination
        ; buffer is enough for a worst-case row.
        mov     ecx,Spad.gsb_cbFreeBytesInDestBuffer
        cmp     ecx,cbWorstCaseBytesPerDstRow
        ja      short row_will_fit

        ; Indicate that the output buffer is full and exit.
        mov     fOutputBufferFull,TRUE
        jmp     compress_rect_exit

public row_will_fit
row_will_fit:
        ;---------------------------------------------------------------
        ; See if we are on the first line - if so we can't do duplicate
        ; scanline (or scanline_pair) checking
        ;---------------------------------------------------------------
        mov     eax,yCurrentRow
        cmp     eax,yStartRow
        je      no_scanline_pair

        ;---------------------------------------------------------------
        ; Check for duplicate scanlines.
        ; Compare the current row with the previous row to see if they
        ; match.
        ;---------------------------------------------------------------
public dup_scanline_loop
dup_scanline_loop:
        ; We need esi->current row
        ;         edi->current row-1

        ; Save current positions
        mov     pCurrentSrcPos, esi
        mov     pNextFreeDstPos, edi

        ; Copy the source pointer to edi
        mov     edi,esi

        ; Now adjust edi to point to the previous row.
        sub     edi,cbBytesPerScanline

        ; Set up the count
        mov     ecx,cbBytesPerSrcRow

        ; Do the compare
        compare_rows

        ; Restore the current positions
        mov     esi, pCurrentSrcPos
        mov     edi, pNextFreeDstPos

        ; Jump forward if rows are different
        jne     adjacent_scanlines_differ

        ;---------------------------------------------------------------
        ; We have a duplicate scanline!
        ;---------------------------------------------------------------
        ; If this is the first time through then write a new cell
        ; to the destination, else increment the count in the cell
        ; that has previously been written.
;       cmp     fFirstTime,TRUE ; !Assembler has problems with this!
;       jne     inc_scanline_count
        mov     eax, fFirstTime
        or      eax, eax
        je      short inc_scanline_count

        ; Reset fFirstTime flag
        mov     fFirstTime,FALSE

        ; Write out a duplicate scanline cell to the destination buffer.
        write_dup_scanline_cell

        jmp     short processed_dup_scanline

public inc_scanline_count
inc_scanline_count:
        ; Increment the count in the cell that we have already written.
        inc_cell_count dup_scan

public processed_dup_scanline
processed_dup_scanline:
        ; Move to next source row. This will jump to the end of the loop
        ; if the last row of the rectangle is passed.
        inc_source_row compress_rect_exit

        ; Check that we have the required rows in the PHUNK
        ensure_rows_are_buffered

        ; Loop back to check for more duplicate scanlines.
        jmp     dup_scanline_loop


public adjacent_scanlines_differ
adjacent_scanlines_differ:
        ;---------------------------------------------------------------
        ; Check for duplicate scanline pairs.
        ; 
        ;                  (row-2)    ababababababa
        ;                  (row-1)    cdcdcdcdcdcdc
        ; current row ---->(row)      ababababababa
        ;                  (row+1)    cdcdcdcdcdcdc
        ; 
        ; (row) must match (row-2), and (row+1) must match (row-1).
        ; 
        ; As we are testing 2 rows behind and 1 row ahead of the
        ; current row, we will only compare the rows if we are:
        ;       - at least 2 rows into the rectangle
        ;       - at least 1 row from the end of the rectangle.
        ;---------------------------------------------------------------

        ; Check that we are at least 2 rows into the rectangle.
        mov     eax,yCurrentRow
        sub     eax,yStartRow
        cmp     eax,2
        jl      no_scanline_pair

public dup_scanline_pair_loop
dup_scanline_pair_loop:
        ; Check that there is at least 1 more row after this one.
        ; If not, then we cannot have a scanline pair.
        mov     eax, yEndRow
        sub     eax, yCurrentRow
        cmp     eax, 1
        jle     no_scanline_pair

not_last_row:
        ;---------------------------------------------------------------
        ; We can now proceed and check for a matching pair.
        ; First compare (row) with (row-2).
        ;---------------------------------------------------------------
        ; Save current positions
        mov     pCurrentSrcPos, esi
        mov     pNextFreeDstPos, edi

        ; Copy the source to the destination
        mov     edi,esi

        ; We need to move edi back by 2 scanlines.
        mov     ebx,cbBytesPerScanline
        shl     ebx,1
        sub     edi,ebx

        ; set up the count
        mov     ecx,cbBytesPerSrcRow

        ; Compare the rows.
        compare_rows

        ; Restore the current positions
        mov    esi, pCurrentSrcPos
        mov    edi, pNextFreeDstPos

        ; Jump forward if rows are different.
        jne    no_scanline_pair

        ;---------------------------------------------------------------
        ; If we get here, (row) matches (row-2).
        ; Now check whether (row+1) matched (row-1).
        ;---------------------------------------------------------------

        ; Copy the source to the destination
        mov     edi,esi

        ; Adjust Source destination back one row, source forward one
        mov     ebx,cbBytesPerScanline
        sub     edi,ebx
        add     esi,ebx

        ; Set up the count
        mov     ecx,cbBytesPerSrcRow

        ; Compare the rows.
        compare_rows

        ; Restore the current positions
        mov    esi, pCurrentSrcPos
        mov    edi, pNextFreeDstPos

        ; Jump forward if rows are different.
        jne    no_scanline_pair

        ;---------------------------------------------------------------
        ; We have a duplicate scanline pair!
        ;---------------------------------------------------------------
        ; If this is the first time through then write a new cell
        ; to the destination, else increment the count in the cell
        ; that has previously been written.
;       cmp     fFirstTimePair, TRUE    ; !Assembler has problems with this!
;       jne     inc_pair_count
        mov     eax, fFirstTimePair
        or      eax,eax
        jz      short inc_pair_count

        ; Write out the cell.
        write_dup_scanline_pair_cell

        ; Reset the first time flag.
        mov     fFirstTimePair, FALSE

        ; Jump forward to update the current source position.
        jmp     short processed_dup_pair

public inc_pair_count
inc_pair_count:
        ; Increment the cell count.
        inc_cell_count dup_scan_pair

public processed_dup_pair
processed_dup_pair:
        ; Skip to the next unprocessed row (the row after next).
        ; Note that this will automatically exit if we reach the end
        ; of the rectangle.
        inc_source_row_twice compress_rect_exit

        ; Check that we have the required rows in the PHUNK
        ensure_rows_are_buffered

        ; Jump back to look for another matching pair.
        jmp     dup_scanline_pair_loop

public no_scanline_pair
no_scanline_pair:
        ;---------------------------------------------------------------
        ; If we reach this point we need to compress the whole source
        ; row. We call the appropriate function using a function
        ; address that has been stored in the Spad.
        ;---------------------------------------------------------------
        ; Save the current destination pointer as the start of the line
        mov     pDestAtStartOfLine,edi

        ; Load up the row width(in pels) into ecx.
        mov     ecx,cxRectWidth

        ; Call the function to compress this row
        mov     ebx, Spad.gsb_pfnCompressRow
        call    ebx

        ; Calculate the number of bytes stored
        mov     eax, edi
        sub     eax, pDestAtStartOfLine

        ; Update the free bytes remaining in the destination buffer.
IFDEF   FIREWALLS
        cmp     eax,Spad.gsb_cbFreeBytesInDestBuffer
        jle     short @F
        int     3
@@:
ENDIF  ;FIREWALLS
        sub     Spad.gsb_cbFreeBytesInDestBuffer,eax

        ; Move the source pointer back to the beginning of this row
        mov     esi, pCurrentSrcPos

        ; Move to the next source row.
        ; This will automatically exit if we reach the end of the
        ; rectangle.

        inc_source_row compress_rect_exit

        ; Loop back to the start of the main loop.
        jmp     main_row_loop


public compress_rect_exit
compress_rect_exit:
        ;---------------------------------------------------------------
        ; Update the rectangle to the area compressed
        ;---------------------------------------------------------------
        mov     eax, fOutputBufferFull
        or      eax, eax
        jz      short rectangle_ok

        ; The entire rectangle was not saved, adjust the yBottom
        ; value to indicate how much of the rectangle was saved
        mov     ebx,Spad.gsb_prclCurrent

        ; Calculate the number of rows we did not save.
        ; yCurrentRow is the row after the last one compressed.
        mov     eax,yEndRow
        sub     eax,yCurrentRow
        inc     eax

        ; Now nudge up the bottom of the stored rectangle by the
        ; number of rows not done.
        add     [ebx].rcl_yBottom, eax
rectangle_ok:

        ;---------------------------------------------------------------
        ; Update the rectangle in the buffer
        ;---------------------------------------------------------------
        ; Save the current destination pointer.
        mov     Spad.gsb_pNextFreeDestByte,edi

        ; Retrieve the position of the rectangle in the buffer.
        mov     edi, pRectHeader

        ; Copy the rectangle (RECTL -> RECTS).
        mov     ebx,Spad.gsb_prclCurrent

        mov     eax,[ebx].rcl_xLeft
        stosw
        mov     eax,[ebx].rcl_yBottom
        stosw
        mov     eax,[ebx].rcl_xRight
        stosw
        mov     eax,[ebx].rcl_yTop
        stosw


compress_rect_no_rects_exit:
        ; Return whether the buffer is full
        mov     eax, fOutputBufferFull

        ; Restore the XGA seg register
        popxga
cEnd


;----------------------------------------------------------------------;
; compress_row_16bit_fields
;
; Compresses the specified data using 16-bit data fields.
; This is used for compressing 16bpp and 8bpp data.
;
; Input values:
;   esi - Points to source row (data to be compressed)
;   edi - Points to destination buffer (to receive compressed data)
;   ecx - Number of data fields to compress
;
; On Exit:
;   edi - Current place in destination buffer
;
;----------------------------------------------------------------------;
cProc   compress_row_16bit_fields,<PUBLIC>

        localD  cbBytesToCompress
cBegin
        compress_row    16
cEnd

;----------------------------------------------------------------------;
; compress_row_8bit_fields
;
; Compresses the specified data using 8-bit data fields.
; This is used for compressing 4bpp data.
;
; Input values:
;   esi - Points to source row (data to be compressed)
;   edi - Points to destination buffer (to receive compressed data)
;   ecx - Number of data fields to compress
;
; On Exit:
;   edi - Current place in destination buffer
;
;----------------------------------------------------------------------;
cProc   compress_row_8bit_fields,<PUBLIC>

        localD  cbBytesToCompress
cBegin
        compress_row    8
cEnd


;----------------------------------------------------------------------;
; compress_row_16_16
;
; Compresses a row of 16bpp data.
;
; Input values:
;   esi - Points to source row (data to be compressed)
;   edi - Points to destination buffer (to receive compressed data)
;   ecx - Number of pels to compress
;
; On Exit:
;   edi - Current place in destination buffer
;
;----------------------------------------------------------------------;
cProc   compress_row_16_16,<PUBLIC>
cBegin
        ; No conversion is required, and the registers are loaded with
        ; the correct values, so just call on to compress the data in
        ; 16-bit data fields.
        call    compress_row_16bit_fields
cEnd


;----------------------------------------------------------------------;
; compress_row_16_8
;
; Converts a row of 16bpp data to 8bpp and then compresses it.
;
; Input values:
;   esi - Points to source row (data to be compressed)
;   edi - Points to destination buffer (to receive compressed data)
;   ecx - Number of pels to compress
;
;   Spad.gsb_pConvertBuffer1 - Points to a conversion buffer
;
; On Exit:
;   edi - Current place in destination buffer
;
;----------------------------------------------------------------------;
cProc   compress_row_16_8,<PUBLIC>
localD  cPelsPerSrcRow
localD  pDest
cBegin
        ; Save input values.
        mov     pDest,edi
        mov     cPelsPerSrcRow,ecx

        ; Convert the data from 16bpp to 8bpp
        mov     edi,Spad.gsb_pConvertBuffer1
        cCall   convert_row_16pk_8pk

        ; Recover original input values.
        mov     ecx,cPelsPerSrcRow
        mov     edi,pDest

        ; Compress the 8bpp data
        shr     ecx,1           ; Convert pel count into field count
        mov     esi,Spad.gsb_pConvertBuffer1
        call    compress_row_16bit_fields
cEnd

;----------------------------------------------------------------------;
; compress_row_16_4
;
; Converts a row of 16bpp data to 4bpp and then compresses it.
;
; Input values:
;   esi - Points to source row (data to be compressed)
;   edi - Points to destination buffer (to receive compressed data)
;   ecx - Number of pels to compress
;
;   Spad.gsb_pConvertBuffer1 - Points to a conversion buffer
;
; On Exit:
;   edi - Current place in destination buffer
;
;----------------------------------------------------------------------;
cProc   compress_row_16_4,<PUBLIC>
localD  cPelsPerSrcRow
localD  pDest
cBegin
        ; Save input values.
        mov     cPelsPerSrcRow,ecx
        mov     pDest,edi

        ; Convert the data from 16bpp to 4bpp
        mov     edi,Spad.gsb_pConvertBuffer1
        cCall   convert_row_16pk_4pk

        ; We have converted from 16bpp to 4bpp.
        ; Compress the 4bpp data
        mov     ecx,cPelsPerSrcRow
        shr     ecx,1           ; Convert pel count into field count
        mov     edi,pDest
        mov     esi,Spad.gsb_pConvertBuffer1
        call    compress_row_8bit_fields
cEnd

;----------------------------------------------------------------------;
; compress_row_16_4pl
;
; Converts a row of 16bpp data to 4bpp planar and then compresses it.
;
; Input values:
;   esi - Points to source row (data to be compressed)
;   edi - Points to destination buffer (to receive compressed data)
;   ecx - Number of pels to compress
;
;   Spad.gsb_pConvertBuffer1 - Points to a conversion buffer
;   Spad.gsb_pConvertBuffer2 - Points to a conversion buffer
;
; On Exit:
;   edi - Current place in destination buffer
;
;----------------------------------------------------------------------;
cProc   compress_row_16_4pl,<PUBLIC>

localD  cPelsPerSrcRow
localD  pDest
localD  cDataFieldsPerPlane

cBegin
        ; Save input values.
        mov     pDest,edi
        mov     cPelsPerSrcRow,ecx

        ; Convert the data from 16bpp to 4bpp packed
        mov     edi,Spad.gsb_pConvertBuffer1
        cCall   convert_row_16pk_4pk

        ; We have converted from 16bpp to 4bpp.

        ; Convert the data from 4bpp packed to 4bpp planar
        mov     esi,Spad.gsb_pConvertBuffer1
        mov     edi,Spad.gsb_pConvertBuffer2
        mov     ecx,cPelsPerSrcRow

        ; ebx must contain the offset in bytes between consecutive planes.
        ; The distance between consecutive planes is
        ;   = length of row in bytes / 4
        ;   = length of row in pels / 8
        mov     ebx,ecx         ; Length of row in pels
        shr     ebx,3

        cCall   convert_row_4pk_4pl

        ; Compress the 4bpp planar data
        ; Load ecx with the number of data fields (bytes) per plane
        mov     ecx,cPelsPerSrcRow
        shr     ecx,3
        mov     cDataFieldsPerPlane,ecx

        ; Compress the first plane.
        mov     edi,pDest
        mov     esi,Spad.gsb_pConvertBuffer2
        call    compress_row_8bit_fields

        ; Compress the second plane.
        mov     ecx,cDataFieldsPerPlane
        call    compress_row_8bit_fields

        ; Compress the third plane.
        mov     ecx,cDataFieldsPerPlane
        call    compress_row_8bit_fields

        ; Compress the fourth plane.
        mov     ecx,cDataFieldsPerPlane
        call    compress_row_8bit_fields
cEnd

;----------------------------------------------------------------------;
; compress_row_8_8
;
; Compresses a row of 8bpp data.
;
; Input values:
;   esi - Points to source row (data to be compressed)
;   edi - Points to destination buffer (to receive compressed data)
;   ecx - Number of pels to compress
;
; On Exit:
;   edi - Current place in destination buffer
;
;----------------------------------------------------------------------;
cProc   compress_row_8_8,<PUBLIC>
localD  cPelsPerSrcRow
localD  pDest
cBegin
        ; If there is a conversion table then we have to use it.
        ; If there is no conversion table then we can go right ahead
        ; and compress the data immediately.
        cmp     _pConvertTable_8int_8ext,0
        je      short compress_8_8

        ; We need to convert the data before compression.
        ; Save input values.
        mov     cPelsPerSrcRow,ecx
        mov     pDest,edi

        ; Convert the data from 8bpp internal to 8bpp external format.
        mov     edi,Spad.gsb_pConvertBuffer1
        cCall   convert_row_8pkint_8pkext

        ; Reload the registers for the compression
        mov     esi,Spad.gsb_pConvertBuffer1
        mov     edi,pDest
        mov     ecx,cPelsPerSrcRow

compress_8_8:
        ; ecx contains the number of pels in the row.
        ; We need the number of 16-bit data fields, so divide by two.
        shr     ecx,1
        call    compress_row_16bit_fields
cEnd

;----------------------------------------------------------------------;
; compress_row_8_4
;
; Converts a row of 8bpp data to 4bpp packed and then compresses it.
;
; Input values:
;   esi - Points to source row (data to be compressed)
;   edi - Points to destination buffer (to receive compressed data)
;   ecx - Number of pels to compress
;
;   Spad.gsb_pConvertBuffer1 - Points to a conversion buffer
;
; On Exit:
;   edi - Current place in destination buffer
;
;----------------------------------------------------------------------;
cProc   compress_row_8_4,<PUBLIC>
localD  cPelsPerSrcRow
localD  pDest
cBegin
        ; Save input values.
        mov     cPelsPerSrcRow,ecx
        mov     pDest,edi

        ; Convert the data from 8bpp to 4bpp
        mov     edi,Spad.gsb_pConvertBuffer1
        cCall   convert_row_8pk_4pk

        ; We have converted from 8bpp to 4bpp.

        ; Compress the 4bpp data
        mov     ecx,cPelsPerSrcRow
        shr     ecx,1           ; Convert pel count into field count
        mov     edi,pDest
        mov     esi,Spad.gsb_pConvertBuffer1
        call    compress_row_8bit_fields
cEnd

;----------------------------------------------------------------------;
; compress_row_8_4pl
;
; Converts a row of 8bpp data to 4bpp planar and then compresses it.
;
; Input values:
;   esi - Points to source row (data to be compressed)
;   edi - Points to destination buffer (to receive compressed data)
;   ecx - Number of pels to compress
;
;   Spad.gsb_pConvertBuffer1 - Points to a conversion buffer
;   Spad.gsb_pConvertBuffer2 - Points to a conversion buffer
;
; On Exit:
;   edi - Current place in destination buffer
;
;----------------------------------------------------------------------;
cProc   compress_row_8_4pl,<PUBLIC>
localD  cPelsPerSrcRow
localD  pDest
localD  cDataFieldsPerPlane

cBegin
        ; Save input values.
        mov     pDest,edi
        mov     cPelsPerSrcRow,ecx

        ; Convert the data from 8bpp to 4bpp packed
        mov     edi,Spad.gsb_pConvertBuffer1
        cCall   convert_row_8pk_4pk

        ; We have converted from 8bpp to 4bpp.

        ; Convert the data from 4bpp packed to 4bpp planar
        mov     esi,Spad.gsb_pConvertBuffer1
        mov     edi,Spad.gsb_pConvertBuffer2
        mov     ecx,cPelsPerSrcRow

        ; ebx must contain the offset in bytes between consecutive planes.
        ; The distance between consecutive planes is
        ;   = length of row in bytes / 4
        ;   = length of row in pels / 8
        mov     ebx,ecx         ; Length of row in pels
        shr     ebx,3

        cCall   convert_row_4pk_4pl

        ; Compress the 4bpp planar data
        ; Load ecx with the number of data fields (bytes) per plane
        mov     ecx,cPelsPerSrcRow
        shr     ecx,3
        mov     cDataFieldsPerPlane,ecx

        ; Compress the first plane.
        mov     edi,pDest
        mov     esi,Spad.gsb_pConvertBuffer2
        call    compress_row_8bit_fields

        ; Compress the second plane.
        mov     ecx,cDataFieldsPerPlane
        call    compress_row_8bit_fields

        ; Compress the third plane.
        mov     ecx,cDataFieldsPerPlane
        call    compress_row_8bit_fields

        ; Compress the fourth plane.
        mov     ecx,cDataFieldsPerPlane
        call    compress_row_8bit_fields
cEnd

;----------------------------------------------------------------------;
; compress_row_4_4
;
; Converts a row of 4bpp packed internal data to 4bpp packed external
; format and then compresses it.
;
; Input values:
;   esi - Points to source row (data to be compressed)
;   edi - Points to destination buffer (to receive compressed data)
;   ecx - Number of pels to compress
;
;   Spad.gsb_pConvertBuffer1 - Points to a conversion buffer
;
; On Exit:
;   edi - Current place in destination buffer
;
;----------------------------------------------------------------------;
cProc   compress_row_4_4,<PUBLIC>
localD  cPelsPerSrcRow
localD  pDest

cBegin
        ; Save input values.
        mov     cPelsPerSrcRow,ecx
        mov     pDest,edi

        ; Convert the data from 4bpp internal to 4bpp external (VGA)
        mov     edi,Spad.gsb_pConvertBuffer1
        cCall   convert_row_4pkint_4pkext

        ; We have converted from 4bpp internal to 4bpp external.

        ; Compress the 4bpp data
        mov     ecx,cPelsPerSrcRow
        shr     ecx,1           ; Convert pel count into field count
        mov     edi,pDest
        mov     esi,Spad.gsb_pConvertBuffer1
        call    compress_row_8bit_fields
cEnd

;----------------------------------------------------------------------;
; compress_row_4_4pl
;
; Converts a row of 4bpp packed internal data to 4bpp planar external
; format and then compresses it.
;
; Input values:
;   esi - Points to source row (data to be compressed)
;   edi - Points to destination buffer (to receive compressed data)
;   ecx - Number of pels to compress
;
;   Spad.gsb_pConvertBuffer1 - Points to a conversion buffer
;   Spad.gsb_pConvertBuffer2 - Points to a conversion buffer
;
; On Exit:
;   edi - Current place in destination buffer
;
;----------------------------------------------------------------------;
cProc   compress_row_4_4pl,<PUBLIC>
localD  cPelsPerSrcRow
localD  pDest
localD  cDataFieldsPerPlane

cBegin
        ; Save input values.
        mov     pDest,edi
        mov     cPelsPerSrcRow,ecx

        ; Convert the data from 4bpp internal to 4bpp external
        mov     edi,Spad.gsb_pConvertBuffer1
        cCall   convert_row_4pkint_4pkext

        ; We have converted from 4bpp internal to external.

        ; Convert the data from 4bpp packed to 4bpp planar
        mov     esi,Spad.gsb_pConvertBuffer1
        mov     edi,Spad.gsb_pConvertBuffer2
        mov     ecx,cPelsPerSrcRow

        ; ebx must contain the offset in bytes between consecutive planes.
        ; The distance between consecutive planes is
        ;   = length of row in bytes / 4
        ;   = length of row in pels / 8
        mov     ebx,ecx         ; Length of row in pels
        shr     ebx,3
        cCall   convert_row_4pk_4pl

        ; Compress the 4bpp planar data
        ; Load ecx with the number of data fields (bytes) per plane
        mov     ecx,cPelsPerSrcRow
        shr     ecx,3
        mov     cDataFieldsPerPlane,ecx

        ; Compress the first plane.
        mov     edi,pDest
        mov     esi,Spad.gsb_pConvertBuffer2
        call    compress_row_8bit_fields

        ; Compress the second plane.
        mov     ecx,cDataFieldsPerPlane
        call    compress_row_8bit_fields

        ; Compress the third plane.
        mov     ecx,cDataFieldsPerPlane
        call    compress_row_8bit_fields

        ; Compress the fourth plane.
        mov     ecx,cDataFieldsPerPlane
        call    compress_row_8bit_fields

cEnd



IFDEF S3


;**********************************************************************
; ONLY NEEDED FOR 24BPP DRIVERS!
;**********************************************************************


;----------------------------------------------------------------------;
; compress_row_24_16
;
; Converts a row of 24bpp data to 16bpp and then compresses it.
;
; Input values:
;   esi - Points to source row (data to be compressed)
;   edi - Points to destination buffer (to receive compressed data)
;   ecx - Number of pels to compress
;
;   Spad.gsb_pConvertBuffer1 - Points to a conversion buffer
;
; On Exit:
;   edi - Current place in destination buffer
;
;----------------------------------------------------------------------;
cProc   compress_row_24_16,<PUBLIC>
localD  cPelsPerSrcRow
localD  pDest
cBegin
        ; Save input values.
        mov     pDest,edi
        mov     cPelsPerSrcRow,ecx

        ; Convert the data from 24bpp to 16bpp
        mov     edi,Spad.gsb_pConvertBuffer1
        cCall   convert_row_24pk_16pk

        ; Recover original input values.
        mov     ecx,cPelsPerSrcRow
        mov     edi,pDest

        ; Compress the 16bpp data
        mov     esi,Spad.gsb_pConvertBuffer1
        call    compress_row_16bit_fields
cEnd

;----------------------------------------------------------------------;
; compress_row_24_8
;
; Converts a row of 24bpp data to 8bpp and then compresses it.
;
; Input values:
;   esi - Points to source row (data to be compressed)
;   edi - Points to destination buffer (to receive compressed data)
;   ecx - Number of pels to compress
;
;   Spad.gsb_pConvertBuffer1 - Points to a conversion buffer
;
; On Exit:
;   edi - Current place in destination buffer
;
;----------------------------------------------------------------------;
cProc   compress_row_24_8,<PUBLIC>
localD  cPelsPerSrcRow
localD  pDest
cBegin
        ; Save input values.
        mov     pDest,edi
        mov     cPelsPerSrcRow,ecx

        ; Convert the data from 24bpp to 8bpp
        mov     edi,Spad.gsb_pConvertBuffer1
        cCall   convert_row_24pk_8pk

        ; Recover original input values.
        mov     ecx,cPelsPerSrcRow
        mov     edi,pDest

        ; Compress the 8bpp data
        shr     ecx,1           ; Convert pel count into field count
        mov     esi,Spad.gsb_pConvertBuffer1
        call    compress_row_16bit_fields
cEnd

;----------------------------------------------------------------------;
; compress_row_24_4
;
; Converts a row of 24bpp data to 4bpp and then compresses it.
;
; Input values:
;   esi - Points to source row (data to be compressed)
;   edi - Points to destination buffer (to receive compressed data)
;   ecx - Number of pels to compress
;
;   Spad.gsb_pConvertBuffer1 - Points to a conversion buffer
;
; On Exit:
;   edi - Current place in destination buffer
;
;----------------------------------------------------------------------;
cProc   compress_row_24_4,<PUBLIC>
localD  cPelsPerSrcRow
localD  pDest
cBegin
        ; Save input values.
        mov     cPelsPerSrcRow,ecx
        mov     pDest,edi

        ; Convert the data from 24bpp to 4bpp
        mov     edi,Spad.gsb_pConvertBuffer1
        cCall   convert_row_24pk_4pk

        ; We have converted from 24bpp to 4bpp.
        ; Compress the 4bpp data
        mov     ecx,cPelsPerSrcRow
        shr     ecx,1           ; Convert pel count into field count
        mov     edi,pDest
        mov     esi,Spad.gsb_pConvertBuffer1
        call    compress_row_8bit_fields
cEnd

;----------------------------------------------------------------------;
; compress_row_24_4pl
;
; Converts a row of 24bpp data to 4bpp planar and then compresses it.
;
; Input values:
;   esi - Points to source row (data to be compressed)
;   edi - Points to destination buffer (to receive compressed data)
;   ecx - Number of pels to compress
;
;   Spad.gsb_pConvertBuffer1 - Points to a conversion buffer
;   Spad.gsb_pConvertBuffer2 - Points to a conversion buffer
;
; On Exit:
;   edi - Current place in destination buffer
;
;----------------------------------------------------------------------;
cProc   compress_row_24_4pl,<PUBLIC>

localD  cPelsPerSrcRow
localD  pDest
localD  cDataFieldsPerPlane

cBegin
        ; Save input values.
        mov     pDest,edi
        mov     cPelsPerSrcRow,ecx

        ; Convert the data from 24bpp to 4bpp packed
        mov     edi,Spad.gsb_pConvertBuffer1
        cCall   convert_row_24pk_4pk

        ; We have converted from 24bpp to 4bpp.

        ; Convert the data from 4bpp packed to 4bpp planar
        mov     esi,Spad.gsb_pConvertBuffer1
        mov     edi,Spad.gsb_pConvertBuffer2
        mov     ecx,cPelsPerSrcRow

        ; ebx must contain the offset in bytes between consecutive planes.
        ; The distance between consecutive planes is
        ;   = length of row in bytes / 4
        ;   = length of row in pels / 8
        mov     ebx,ecx         ; Length of row in pels
        shr     ebx,3

        cCall   convert_row_4pk_4pl

        ; Compress the 4bpp planar data
        ; Load ecx with the number of data fields (bytes) per plane
        mov     ecx,cPelsPerSrcRow
        shr     ecx,3
        mov     cDataFieldsPerPlane,ecx

        ; Compress the first plane.
        mov     edi,pDest
        mov     esi,Spad.gsb_pConvertBuffer2
        call    compress_row_8bit_fields

        ; Compress the second plane.
        mov     ecx,cDataFieldsPerPlane
        call    compress_row_8bit_fields

        ; Compress the third plane.
        mov     ecx,cDataFieldsPerPlane
        call    compress_row_8bit_fields

        ; Compress the fourth plane.
        mov     ecx,cDataFieldsPerPlane
        call    compress_row_8bit_fields
cEnd


endif   ;S3


_TEXT   ends

end
