It is permissible to implement this function by returning 0 to indicate that the bits were not saved and, therefore, must be saved by the calling routine.
GreGetScreenBits calls EnterDriver and performs some initial error tests, checking the FunN field and the DC type. If the COM_PATH or the COM_AREA flags are set in FunN, the function logs PMERR_INV_IN_PATH or PMERR_INV_IN_AREA, respectively, and returns 0 (zero).
Next, the parameters are checked for validity.
MIN_BUFFER_SIZE
Otherwise, the PMERR_INV_FORMAT_CONTROL error is logged and the call returns 0 (zero).
Otherwise, PMERR_PEL_NOT_AVAILABLE error is logged and the call returns 0 (zero).
If all these checks are successful, the CompressScreenBits routine (in GETSCR.C) is called. CompressScreenBits checks whether the format is valid by creating a word containing the internal (screen) format and the external (requested) format. Then the aGSBValidDataFormats table is scanned for a match. This table is an array of valid source and destination format pairs, as defined in the VALID_DATA_FORMATS data structure. See VALID_DATA_FORMATS in Data Types for details on this data structure.
If a match is found, the format is valid. Otherwise, the format is invalid, the PMERR_INV_FORMAT_CONTROL error is logged and the call returns 0. Then, the pointer to the compression function for the required format combination is retrieved from the aGSBValidDataFormats structure and copied into the Spad global structure.
The following steps initialize the conversion cache by calling the InitializeCache routine in DCAFCNV.ASM (this is currently only required if source is 16bpp and destination is 8bpp or 4bpp). Then a check is done to determine whether a conversion table is needed for this combination of formats (actually, it is required for all the pairs, except for those with 16 bpp as a source. These latest pairs have a null pointer in the last two fields of their aGSBValidDataFormats structures.
This is checked by comparing two global variables, hForeGroundPal and DirectDeviceDefaultPalette. If there is an old conversion table, it will be freed by FreeConvertTable (in DCAFCNVT.C).
If a conversion table has been previously created, ensure that the mapping refers to the current palette (the internal palette may have changed since the conversion table was calculated). This is done via a global variable, Seamlessdata.ulLastPalUpdate, which is incremented when the hardware palette is changed. GreGetScreenBits takes a copy of this variable when the conversion table is created. Subsequent calls check whether the value has changed before using the table. If the value has changed, the old table is deleted and a new one is created.
If a conversion table is needed (according to the scheme above), the proper creation function (stored in the pfnCreateConvertTable field of the specific pair) is called and the pointer to the just created table is stored in the ppConvertTable field. The creation calls for the conversion table of valid format pairs; all of them are defined in DCAFCNVT.C:
To do this, after the memory allocation, the NearestRestrictedColourIndex (in CONVINT.C) is called, in order to map the RGB values in the HWPalette table to the nearest entry in the VGA standard default palette (see the appendix regarding default color palettes in the IBM OS/2 Display Device Driver Reference).
To do this, after the memory allocation, the NearestRestrictedColourIndex (in CONVINT.C) is called, in order to map the RGB values in the HWPalette table to the nearest entry in the FullSizeDeviceDefaultPalette palette (the 256-entry XGA default palette defined in EDDDATA.C).
Pels are converted a pair at a time, which is why the conversion table is 256 entries, rather than the expected 16. To do this, after the memory allocation, the NearestRestrictedColourIndex (in CONVINT.C) is called, in order to map the RGB values in the Reduced16DeviceDefaultPalette table (the 16-entry XGA default palette defined in EDDDATA.C) to the nearest entry in the VGA standard default palette (see the appendix regarding default color palettes in the IBM OS/2 Display Device Driver Reference).
The remaining values in the external table are obtained by combining pairs of conversion values, in the following way:
for (i = 0; i < 256; i++) { pConvertTable[i] = (abLocalConvertTable[i >> 4] << 4) | (abLocalConvertTable[i & 0x0F]) ; }
The next step is to calculate the bounding rectangle of the supplied area to be queried using GreGetRegionBox. If the query area is a region, the Graphics Engine is asked for the first 10 rectangles from the query area and puts their addresses in the Spad.prclCurrent pointer (our local buffer). If the query area is a rectangle, it is made EXCLUSIVE and its address is put in Spad.prclCurrent. A check is done to see if the bounding box (for the region) or the rectangle is a valid ordered rectangle. If it is not, a PMERR_INV_IMAGE_DIMENSION is logged and the call returns 0 (zero). The call also will return 0 if the rectangle is empty. If the bounding box or the rectangle exceeds the screen dimension, PMERR_INV_IMAGE_DIMENSION is logged and the call returns 0.
Next, the destination pointer is moved past the packet header. Then, the cursor is excluded from the bounding rectangle using eddm_excludeCursor in EDDMCCRS.C, after rounding the bounding rectangle up to 8 pel boundaries, because the rectangles may be rounded up to 2 or 8 pel boundaries below (depending upon bpp). The drawing mode is set to always use the real XGA hardware, calling the SetDrawModeHard macro (in EDDMACRO.H).
After setting some ShadowXGARegs fields, WaitForRealHWFunction in HWACCESS.ASM is called to ensure that the hardware is ready. Then, some of the registers that were just set up (calling TransferShadowRegisters(TSR_MAP_A | TSR_COLOUR_MIX) in HWACCESS.ASM) are transferred. Currently, only MAP_A and COLOR_MIX registers can be transferred. MAP_B, COORDINATES and PIXELOP registers will be transferred later (when all of the values are known), since they depend on the rectangle in processing.
At this point, the main loop starts:
: adjust the current rectangle coordinates if necessary. We alter the coordinates according to format and bits per pel so that we do not have to worry about the masking associated with compressing and decompressing partial bytes. 4bpp formats are rounded to 8 pel boundaries because the destination could be planar VGA. 8bpp formats are rounded to even pel boundaries because we transmit data in 16-bit fields i.e. two pels per data field. : call CompressRect in COMPRESS.ASM, getting as a return whether or not the output buffer is full : if the output buffer is full : : break : endif : if no more rectangles in the local buffer and a region was supplied and there are more rects in engine : : subtract the already compressed rectangles from the supplied region using GreCombineRectRegion (CRGN_DIFF) : : reload local buffer with more rects from engine : endif endfor
The number of bytes written is reported in the packet header and the cursor is renabled via reenable_cursor in EDDMCCRS.C. Then, ExitDriver is called and a return code indicating full (return code 1) or partial data returned (return code 2) is issued.
CompressRect (in COMPRESS.ASM)
if free bytes in output buffer < size of (RECTANGLE HEADER + WORST_CASE_ROW_LENGTH) : set a variable saying that there is no room in the output buffer : return else : write out rect header : for iRow = each row of rect : : // Check for duplicate scanlines : : if iRow > first row : : : if row[iRow] matches row[iRow-1] : : : : count subsequent matching rows : : : : write duplicate scanline code + count : : : endif : : endif : : // Check for duplicate scanline pairs : : if iRow > second row and iRow < last row : : : if row[iRow] matches row[iRow-2] and row[iRow+1] matches row[iRow-1] : : : : count subsequent matching row pairs : : : : write duplicate scanline pair code + count : : : endif : : endif : : // Compress the row : : call appropriate row compression function : : if free bytes in output buffer < WORST_CASE_ROW_LENGTH : : : set a variable saying that there is no room in the output buffer : : : update the passed rectangle to contain the area that was not compressed : : : return : : endif : endfor return endif
There is a separate compression function for each of the valid src/dst format combinations (in COMPRESS.ASM), as follows:
compress_row_16_16 (src 16bpp packed, dst 16bpp packed) calling only compression routine compress_row_16_8 (src 16bpp packed, dst 8bpp packed) calling: convert_row_16pk_8pk; compression routine compress_row_16_4 (src 16bpp packed, dst 4bpp packed) calling: convert_row_16pk_4pk; compression routine compress_row_16_4pl (src 16bpp packed, dst 4bpp planar) calling: convert_row_16pk_4pk; convert_row_4pk_4pl; compression routine compress_row_8_8 (src 8bpp packed, dst 8bpp packed) calling: convert_row_8pkint_8pkext; compression routine compress_row_8_4 (src 8bpp packed, dst 4bpp packed) calling: convert_row_8pk_4pk; compression routine compress_row_8_4pl (src 8bpp packed, dst 4bpp planar) calling: convert_row_8pk_4pk; convert_row_4pk_4pl; compression routine compress_row_4_4 (src 4bpp packed, dst 4bpp packed) calling: convert_row_4pkint_4pkext; compression routine compress_row_4_4pl (src 4bpp packed, dst 4bpp planar) calling: convert_row_4pkint_4pkext; convert_row_4pk_4pl; compression routine
Conversion between different data formats (for example, 8bpp and 4bpp) is done independently of the data compression. That is, if the source and destination formats differ, the source data is first converted to the destination format (in an intermediate buffer defined on the PHUNK), and then is compressed into the destination buffer. If the source and destination formats match, the data is compressed directly from the source to the destination. The data conversion routines use tables wherever possible to improve performance (see Converting Data in Code Modifications Required in Base Driver for DCAF for more information). The routines defined in COMPRESS.ASM are as follows:
convert_row_16pk_8pk (src 16bpp packed, dst 8bpp packed) using NearestRestrictedDeviceDefaultPalette to find, for every pixel, the nearest entry in the FullSizeDeviceDefaultPalette (the 256 entry default palette defined in EDDDATA.C). convert_row_16pk_4pk (src 16bpp packed, dst 4bpp packed) using NearestRestrictedDeviceDefaultPalette to find, for every pixel, the nearest entry in the StandardVGADefaultPalette convert_row_8pkint_8pkext (scr 8bpp packed, dst 8bpp packed) using ConvertTable_8int_8ext convert_row_8pk_4pk (src 8bpp packed, dst 4bpp packed) using ConvertTable_8int_4ext convert_row_4pk_4pl (src 4bpp packed, dst 4bpp planar) changes the packed to planar format convert_row_4pkint_4pkext (src 4bpp packed, dst 4bpp packed) using ConvertTable_4int_4ext
Additional work is done to make the required rows available for compression. Checks are performed to ensure that a row is available before accessing it. In the DCAF-enabled driver, VRAM is not directly accessible so the required rows have to be loaded into a locked buffer in system memory before they can be worked on. There already exists a 64K buffer in the Driver called the PHUNK (PHysical chUNK), which is ideal for this purpose. Rectangles can easily exceed 64K in size, so this buffer will often be reloaded multiple times during the processing of a single rectangle.