## Presentation Device Driver Reference for OS/2

[prev][next][parent][TOC]

### GreGetScreenBits - Remarks

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.

The buffer size must be in the following range:

MIN_BUFFER_SIZE 2071 bytes; the length of a buffer containing only a compressed row at the maximum resolution, and when the input row only contains nonrepeating data

65536 bytes Limit due to PHUNK memory

Otherwise, the PMERR_INV_LENGTH_OR_COUNT error is logged and the call returns 0 (zero).

The flCmd field must be set with one or more valid flags.

Otherwise, the PMERR_INV_FORMAT_CONTROL error is logged and the call returns 0 (zero).

Presentation Manager must be in the foreground (fXGAdead is set to TRUE).

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.

If the internal format is 16bpp, a conversion table is not needed, whatever the target format may be.

If the requested format is 8bpp:

-if the hardware palette is the default, then no conversion is required.

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).

-Otherwise, a palette has been realized and the internal indices need to be converted into standard external format; that is, indices are converted into the default 256-color XGA (fudged) palette.

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 the requested format is 4bpp:

-A conversion table is always needed. It must correctly map the current hardware palette.

-In this case, the same scheme as for 8bpp is used.

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:

CreateConvertTable_8int_4ext creates a 256-entry table of bytes to convert 8bpp to 4bpp.

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).

CreateConvertTable_8int_8ext creates a 256-entry table of bytes to convert 8bpp internal indices to 8bpp external indices (XGA default palette).

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).

CreateConvertTable_4int_4ext creates a 256-entry table of bytes to convert 4bpp internal (fudged) format to 4bpp external (standard VGA) format.

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:

For each rectangle in the Spad.prclCurrent local buffer

    : 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

We can get out from the cycle above for two reasons:

-No more rectangles to process; reset the provided region or rectangle using GreSetRectRegion

-No more room in the output buffer; subtract the already processed rectangles from the region or the processed area from the provided rectangle.

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.