;*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.;
;*****************************************************************************/
;/*****************************************************************************
;*
;* SOURCE FILE NAME = COMPRESS.ASM
;*
;* DESCRIPTIVE NAME = DCAF compression functions.
;*
;*
;* VERSION      V2.0
;*
;* DATE         06/01/92
;*
;* DESCRIPTION
;*
;*
;* FUNCTIONS   CompressScreenBits
;*             compress_rect
;*             compress_row_4pl_4pl
;*             compress_row_4pl_4
;*
;* NOTES
;*
;*    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 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!
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   06/01/92                     Created for DCAF 1.3
;*   08/01/92                     Converted to 32-bit for DCAF 2.0
;*
;*****************************************************************************/
                                        ;       requiring pmgre component
;/*
;** Include DCAF macros
;*/
;/*
;** The following table defines the formats that can be requested.
;** This depends upon the internal bits per pel and data format
;** (packed/planar).
;**
;** Each entry in the table consists of a pair of bytes. The first (low)
;** byte represents the internal (screen) data format. The second (high)
;** byte represents the external (requested) data format.
;**
;** When GetScreenBits is called, a word consisting of the internal and
;** external formats is formed and the formats_table is scanned for
;** a match.
;**
;** If no match is found then the requested format is invalid.
;** If a match is found then the requested format is valid, and the index
;** into the table tells us which conversion routine should be used.
;**
;** The order of this table MUST MATCH THE GSB_ROW_CONV_TABLE below.
;*/
;/*
;** The GSB_FORMAT_FLAGS must all fit in a byte for the following table
;** to be valid.
;*/
;/*
;**                Internal (screen) format         Requested format
;*/
;/*
;** gsb_row_conv_table contains the addresses of the routines to perform
;** the conversion/compression for each combination of internal formats.
;** The order of this table MUST MATCH THE GSB_FORMATS_TABLE above.
;*/
;/*
;** Check that the two tables have the same number of entries
;*/
;/*
;** Declare the control block used by DCAF.
;*/
;/*
;** Declare external procedures.
;*/
;/*************************************************************************
;** Function:
;** CompressScreenBits
;**
;** Overview:
;** Compresses the requested area of the screen (PRECTL or HRGN) into
;** the buffer supplied.
;**
;** Assumes device specific error checking / semaphore access etc has been
;** performed by calling routine.
;** Assumes buffer length is <= 64K
;**
;** Parameters:
;**
;**
;** Entry:
;**   None
;** Returns:
;**   EAX = 1  - buffer not full
;**         2  - buffer full
;**         3  - buffer empty (NULL region passed in)
;** Error Returns:
;**   EAX = FALSE (0)
;**   Error logged
;** Registers Preserved:
;**   32 bit  ESI,EDI,EBX,EBP,DS
;** Registers Destroyed:
;**   32 bit  EAX,ECX,EDX,FLAGS
;** History:
;**
;** Wed 14-May-1992       -by-    Andy Rogers
;** Wrote it.
;**
;**********************************************************************/
;/*
;** Check that the format is valid.
;** This is done by creating a word containing the internal
;** (screen) format and the external (requested) format.
;** The gsb_formats_table is then scanned for a match.
;** If matched, the format is valid. Otherwise it is invalid.
;*/
;/*
;** eax (actually al) contains the requested format flags.
;** Mask out the format flags (as opposed to option flags).
;** Move these to ah.
;*/
;/*
;** Now merge in the internal format
;*/
;/*
;** eax now contains the combined internal/external format word.
;** Save this code on the stack
;*/
;/*
;** Search for this word in the formats table.
;*/
;/*
;** We need edi->start of table
;*/
;/*
;** Load ecx with the table length in words
;*/
;/*
;** Get format code back
;*/
;/*
;** Search the table
;*/
;/*
;** Jump to error handler if format not found
;*/
;/*
;** Adjust ecx so that it contains the index of the found entry
;*/
;/*
;** Check that ecx is within range
;*/
;/*
;** Get a pointer to the compression function
;*/
;/*
;** Initialize variables.
;**
;** Initialize the output buffer full flag to FALSE.
;*/
;/*
;** Initialize our destination pointer to the start of the
;** supplied buffer.
;*/
;/*
;** Now branch according to whether we have been passed a rectangle
;** or a region.
;*/
;/*
;** Rectl: Copy the rectangle from the caller's data area into rclBound,
;** making exclusive while doing so.
;**
;** Load up destination pointer
;*/
;/*
;** Load up source pointer
;*/
;/*
;** Make the rectangle exclusive
;*/
;/*
;** Now copy the same rect into the rect buffer
;*/
;/*
;** Make the rectangle exclusive
;*/
;/*
;** Check that the rectangle is well-ordered
;** i.e. that (xLeft < xRight), (yBottom < yTop)
;** If rectangle is NULL then skip to exit.
;*/
;/*
;** Update the count of rectangles in our buffer
;*/
;/*
;** Clear flag to indicate no rects in engine
;*/
;/*
;** Initialise prclCurrentRect to the start of our rect buffer
;*/
;/*
;** Skip forwards over region code
;*/
;/*
;** Hrgn: Get the bounding box for the app's region into rclBound
;**
;** public csb_region_parm
;*/
;/*
;** Call back to the engine to get the region bounding box
;*/
;/*
;** Check whether an error occured (ax zero)
;*/
;/*
;** Prime our rect buffer with the first set of rectangles
;*/
;/*
;** rclBound contains the exclusive bounding box of the screen area to
;** be saved. Ensure it does not exceed device limits.
;*/
;/*
;** Put error handlers here for accessibility.
;*/
;/*
;** Return of the main code path!
;*/
;public  csb_write_format
;/*
;** Skip over the length of data word and write the format word.
;**
;** Check that there is room for the header!
;*/
;/*
;** Save destination pointer
;*/
;/*
;** Update the free bytes in the output buffer
;** This is the only update to ulBufferLen that uses DWORD rather than
;** WORD values. ulBufferLen <= 64k so after this subtraction the
;** length will always fit in a single word.
;*/
;/*
;** Exclude the pointer from the rectangle specified in rclBound
;*/
;/*
;** Start the main loop.
;*/
;/*
;** There are no more rectangles in our buffer.
;** If there are more in the engine then we will refresh it,
;** otherwise we are all done!
;*/
;/*
;** We need to remove the rectangles that have been compressed from
;** the region
;*/
;/*
;** Now fill the rect buffer with fresh rectangles
;*/
        ; Make [ebx] -> current rect
;/*
;** Adjust the current rectangle coordinates if necessary.
;**
;** if the source or destination format is planar
;** : adjust xLeft and xRight coords to be multiples of 8
;** else if the source or destination format is 4bpp or 8bpp
;** : adjust xLeft and xRight coords to be multiples of 2
;** endif
;**
;** This is so we do not have to worry about the masking associated
;** with compressing/decompressing partial bytes.
;** 8bpp is aligned on even boundaries because we transmit pels
;** in 16-bit data fields i.e. two pels per data field.
;*/
;/*
;** Src or dest is planar - adjust coords to be multiples of 8.
;*/
;/*
;** Src or dest is 4bpp or 8bpp - adjust coords to be multiples of 2.
;*/
;public coords_adjusted
        ; Check for null rectangles.
;/*
;** Compress the current rectangle!
;** Load up the destination pointer, buffer length and compression
;** function
;*/
;/*
;** Return code tells us whether the output buffer filled up.
;*/
;/*
;** Update other variables.
;*/
;/*
;** Update counters.
;*/
;/*
;** Check whether the output buffer is full.
;** If not, loop back to process next rect
;*/
;/*
;** If region supplied (rather than rectangle) then update it
;** to reflect the compressed area.
;*/
;/*
;** See if we terminated because the output buffer was full.
;*/
;/*
;** The output buffer is full. Remove the rects that we compressed
;** from the app region.
;*/
        ; Exit.
;/*
;** The output buffer is not full, which means that we must have
;** successfully returned all of the requested region. We therefore
;** just have to make the apps region NULL.
;*/
;/*
;** We need to update the supplied rectangle to reflect the
;** data compressed.
;** Only the rcl_yTop needs to be returned - all other edges will
;** have remained the same.
;** If the entire area was compressed we need to return a NULL
;** rectangle
;*/
;/*
;** Return a NULL rectangle - set yBottom = yTop + 1
;*/
;/*
;** The rectangle stored in arclBuffer has been updated to contain
;** the area compressed. (only yBottom will have changed)
;** We need to update the rectangle passed in to contain the
;** area NOT compressed
;*/
;/*
;** Now jump to the appropriate exit point.
;*/
;/*
;** A null region was passed in - nothing is in the buffer
;*/
;/*
;** Before we exit, write out the length of data stored in the buffer.
;** Calculate this by subtracting the buffer start from the current
;** pointer.
;*/
;/*
;** Write the total length into the first dword of the compressed
;** data.
;*/
;/*
;** Unexclude the pointer (without losing the return code in ax).
;*/
;/**********************************************************************
;**
;** Function:
;**   compress_rect
;**
;** Overview:
;**   Compresses the supplied rectangle into the destination buffer.
;**
;** Entry:
;**   edi      Pointer to next free byte in output buffer (dest)
;**   ecx      Count of bytes available in output buffer
;**
;** Exit:
;**   edi      Updated ptr to next free byte in output buffer (dest)
;**   ecx      Updated count of bytes available in output buffer
;**
;** Updated:
;**   *prclCurrentRect Updated to contain the rectangle area that was
;**                    compressed. In practice this will only be modified
;**                    if the output buffer fills up and a partial rectangle
;**                    is returned.
;**
;** 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
;**
;**********************************************************************/
;/*
;** Store the number of bytes available in the output buffer
;*/
;/*
;** 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.
;*/
;/*
;** Get pointer to the rectangle. The rectangle will always be on
;** the stack, which is why we only need a near pointer.
;*/
;/*
;** Calculate the width of a source row (in pels).
;**
;** Fetch the rectangle right-hand coordinate.
;*/
;/*
;** Subtract the rectangle left-hand coordinate to give us the
;** rectangle width in pels.
;*/
;/*
;** Convert the source row width from pels into bytes.
;**
;** Bpp is 4 - byte count is half the pel count.
;*/
;/*
;** Store the bytes per source row.
;*/
;/*
;** Calculate the bytes per src plane (rounding up)
;*/
;/*
;** Store the bytes per scan line.
;** Constant for device.
;*/
;/*
;** Calculate the worst-case bytes per destination row.
;*/
;/*
;** 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.
;*/
;/*
;** Compare the size calculated with the free bytes available
;** in the destination buffer (currently in cx).
;*/
;/*
;** We can't pass back a single row of this rect!
;** Set fOutputBufferFull to 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.
;*/
        ; Initialise fOutputBufferFull.
;/*
;** Calculate the start address of the rectangle on the screen
;**
;** Start Address = Screen Start + (YStartRow * BytesPerScan) + (LeftX / 8)
;*/
;/*
;** Save the current pointer to the destination buffer.
;** This is where we will fill in the rectangle header at the
;** end of the routine.
;*/
;/*
;** Move the destination pointer over the rectangle header.
;*/
;/*
;** Update the number of free bytes remaining in the dest buffer.
;*/
;/*
;** Load up the current start of line
;*/
;/*
;** 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
;**
;*/
;/*
;** Set first time counters to true
;*/
;/*
;** Check whether the remaining space in the destination
;** buffer is enough for a worst-case row.
;*/
;/*
;** Indicate that the output buffer is full and exit.
;*/
;/*
;** See if we are on the first line - if so we can't do duplicate
;** scanline (or scanline_pair) checking
;*/
;/*
;** Check for duplicate scanlines.
;** Compare the current row with the previous row to see if they match.
;*/
;/*
;** We need esi->current row
;** edi->current row-1
;*/
;/*
;** Save current positions
;*/
;/*
;** Copy the source to the destination
;*/
;/*
;** Now adjust edi to point to the previous row.
;*/
;/*
;** Set up the count
;*/
;/*
;** Do the compare
;*/
;/*
;** Restore the current positions (source segment will not have changed)
;*/
;/*
;** Jump forward if rows are different
;*/
;/*
;** 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.
;*/
;/*
;** Reset fFirstTime flag
;*/
;/*
;** Write out a duplicate scanline cell to the destination buffer.
;*/
;/*
;** Increment the count in the cell that we have already written.
;*/
;/*
;** Move to next source row. This will jump to the end of the loop
;** if the last row of the rectangle is passed.
;*/
;/*
;** Loop back to check for more duplicate scanlines.
;*/
;/*
;** 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.
;*/
;/*
;** Check that we are not on the last row of the rectangle.
;*/
;/*
;** We can now proceed and check for a matching pair.
;** First compare (row) with (row-2).
;**
;** Save current positions
;*/
;/*
;** Copy the source to the destination
;*/
;/*
;** We need to move edi back by 2 scanlines.
;*/
;/*
;** Set up the count
;*/
;/*
;** Compare the rows.
;*/
;/*
;** Restore the current positions
;** Restore the current positions (source segment will not have changed)
;*/
;/*
;** Jump forward if rows are different.
;*/
;/*
;** If we get here, (row) matches (row-2).
;** Now check whether (row+1) matched (row-1).
;*/
;/*
;** Copy the source to the destination
;*/
;/*
;** Adjust Source destination back one row, source forward one
;*/
;/*
;** Set up the count
;*/
;/*
;** Compare the rows.
;*/
;/*
;** Restore the current positions (source segment will not have changed)
;*/
;/*
;** Jump forward if rows are different.
;*/
;/*
;** 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.
;*/
;/*
;** Write out the cell.
;*/
;/*
;** Reset the first time flag.
;*/
;/*
;** Jump forward to update the current source position.
;*/
;/*
;** Increment the cell count.
;*/
;/*
;** Skip to the next unprocessed row (the row after next).
;** Note that this will automatically exit if we reach the end
;** of the rectangle.
;*/
;/*
;** Jump back to look for another matching pair.
;*/
;/*
;** If we reach this point we need to compress the whole source row.
;** We call the appropriate function using a table of function addresses.
;**
;** Save the current destination pointer as the start of the line
;*/
;/*
;** Load up the row width(in bytes) into cx.
;*/
;/*
;** Call the function to compress this row
;*/
;/*
;** Calculate the number of bytes stored
;*/
;/*
;** Update the free bytes remaining in the destination buffer.
;*/
;/*
;** Move the source pointer back to the beginning of this row
;*/
;/*
;** Move to the next source row.
;** This will automatically exit if we reach the end of the
;** rectangle.
;*/
;/*
;** Loop back to the start of the main loop.
;*/
;/*
;** Update the rectangle to the area compressed
;*/
;/*
;** The entire rectangle was not saved, adjust the yBottom
;** value to indicate how much of the rectangle was saved
;*/
;/*
;** Update the rectangle in the buffer
;**
;** Save the current destination pointer
;*/
;/*
;** Retrieve the position of the rectangle in the buffer
;*/
;/*
;** Copy the rectangle (RECTL -> RECTS)
;*/
;/*
;** Return whether the buffer is full or not
;** and how many bytes are remaining
;*/
;/**********************************************************************
;** Function: compress_row_4pl_4pl
;**
;** Input values:
;**   esi - Points to source row (data to be compressed)
;**   edi - Points to destination buffer (to receive compressed data)
;**   ecx     - Length of row in bytes (note: row NOT plane)
;**
;** On Exit:
;**   edi - Current place in destination buffer
;**********************************************************************/
;/*
;** Save the row start address and the calculate the plane length (rounding up)
;*/
;/*
;** Initialise the plane selection
;*/
;/*
;** Select the next plane
;*/
;/*
;** RESTORE pRowStartAddress and row length
;*/
;/*
;** Loop back for next plane
;*/
;/**********************************************************************
;** Function: compress_row_4pl_4
;**
;** Input values:
;**   esi - Points to source row (data to be compressed)
;**   ecx - Length of row in bytes
;**
;** On Exit:
;**   edi - Current place in destination buffer
;**********************************************************************/
;/*
;** First pack the data direct from the screen into the
;** temporary buffer
;*/
;/*
;** Now compress the packed data to the destination buffer
;*/
;/**********************************************************************
;** Function: compress_row_8_4pl
;**
;** Input values:
;**   esi - Points to source row (data to be compressed)
;**   edi - Points to destination buffer (to receive compressed data)
;**   ecx     - Length of row in bytes (note: row NOT plane)
;**
;** On Exit:
;**   edi - Current place in destination buffer
;**
;** History:
;**     22-Aug-1993       -by-    Hidemasa Muta
;** Wrote it.
;**********************************************************************/
;/**********************************************************************
;** Function: create_convert_table
;**
;** Input values:
;** None.
;**********************************************************************/

end
