Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3927 lines
134 KiB

/******************************Module*Header**********************************\
*
* *******************
* * GDI SAMPLE CODE *
* *******************
*
* Module Name: bitblt.c
*
* Note: Since we've implemented device-bitmaps, any surface that GDI passes
* to us can have 3 values for its 'iType': STYPE_BITMAP, STYPE_DEVICE
* or STYPE_DEVBITMAP. We filter device-bitmaps that we've stored
* as DIBs fairly high in the code, so after we adjust its 'pptlSrc',
* we can treat STYPE_DEVBITMAP surfaces the same as STYPE_DEVICE
* surfaces (e.g., a blt from an off-screen device bitmap to the screen
* gets treated as a normal screen-to-screen blt). So throughout
* this code, we will compare a surface's 'iType' to STYPE_BITMAP:
* if it's equal, we've got a true DIB, and if it's unequal, we have
* a screen-to-screen operation.
*
* Copyright (c) 1994-1999 3Dlabs Inc. Ltd. All rights reserved.
* Copyright (c) 1995-2003 Microsoft Corporation. All rights reserved.
\*****************************************************************************/
#include "precomp.h"
#include "glint.h"
/************************************************************************\
*
* decompose all rops into GLINT logic ops if the dest is the screen.
* Sometimes we do this in a few stages. The following defines mimic
* the definitions found in the ROP3 table in the books. The idea
* is to minimize errors in constructing the ropTable array below by
* allowing me to copy the reverse Polish notation more or less in
* tact.
*
\**************************************************************************/
#define unset __GLINT_LOGICOP_CLEAR
#define P __GLINT_LOGICOP_COPY
#define S P
#define DPna __GLINT_LOGICOP_AND_INVERTED
#define DSna DPna
#define DPa __GLINT_LOGICOP_AND
#define DSa DPa
#define PDa DPa
#define SDa DPa
#define PDna __GLINT_LOGICOP_AND_REVERSE
#define SDna PDna
#define DPno __GLINT_LOGICOP_OR_INVERT
#define DSno DPno
#define DPo __GLINT_LOGICOP_OR
#define DSo DPo
#define PDo DPo
#define SDo DPo
#define PDno __GLINT_LOGICOP_OR_REVERSE
#define SDno PDno
#define D __GLINT_LOGICOP_NOOP
#define Dn __GLINT_LOGICOP_INVERT
#define Pn __GLINT_LOGICOP_COPY_INVERT
#define Sn Pn
#define DPan __GLINT_LOGICOP_NAND
#define DSan DPan
#define PDan DPan
#define SDan DPan
#define DPon __GLINT_LOGICOP_NOR
#define DSon DPon
#define PDon DPon
#define SDon DPon
#define DPxn __GLINT_LOGICOP_EQUIV
#define DSxn DPxn
#define PDxn DPxn
#define SDxn DPxn
#define DPx __GLINT_LOGICOP_XOR
#define DSx DPx
#define PDx DPx
#define SDx DPx
#define set __GLINT_LOGICOP_SET
/************************************************************************\
*
* if we have to first combine the source and pattern before downloading
* to GLINT we use the engine to do it using EngBitBlt. So these are the
* chosen rop3s which combine the source with the pattern. We blt into
* a temporary bitmap and use this to download.
*
\**************************************************************************/
#define SPa 0x30
#define PSa SPa
#define SPan 0x3F
#define PSan SPan
#define SPna 0x0C
#define PSna 0x30
#define SPo 0xFC
#define PSo SPo
#define SPon 0x03
#define PSon SPon
#define SPno 0xCF
#define PSno 0xF3
#define SPx 0x3C
#define PSx SPx
#define SPxn 0xC3
#define PSxn SPxn
#define SPnx SPxn
#define PSnx SPxn
/************************************************************************\
*
* we set up a junp table for the different rop3's. Each entry contains
* a category and a set of 1, 2 or 3 GLINT logic ops. In the main blt
* routine we switch on the category to figure out what routine to call.
* We pass the GLINT logic op straight in without having to do any further
* conversion. By keeping each entry in the table down to 4 bytes it
* takes up 1K of data. That's not too much. The benefit is that in each
* routine we call we don't have to do any checking to see whether the
* rop really needs pattern or source. I've done some pre-processing on
* some of the rops to decompose them into forms which allow us to use
* the hardware in a series of steps. e.g. pattern fill followed by
* source download. If anything doesn't fit into a defined category then
* we go back to the engine.
*
\**************************************************************************/
// categories
#define SOLID_FILL_1_BLT 0 // must be 0
#define PAT_FILL_1_BLT 1 // must be 1
#define SRC_FILL_1_BLT 2 // must be 2
#define PAT_SRC_2_BLT 3 // PatSrcPatBlt
#define PAT_SRC_PAT_3_BLT 4 // PatSrcPatBlt
#define SRC_PAT_2_BLT 5 // SrcPatSrcBlt
#define SRC_PAT_SRC_3_BLT 6 // SrcPatSrcBlt
#define ENG_DOWNLOAD_2_BLT 7 // EngBitBlt for now
#define ENGINE_BITBLT 8 // EngBitBlt always
// adding new entries here may double the table size.
typedef struct _rop_table {
UCHAR func_index;
UCHAR logicop[3];
} RopTableRec, *RopTablePtr;
RopTableRec ropTable[] = {
/* 00 */ { SOLID_FILL_1_BLT, unset },
/* 01 */ { SRC_PAT_2_BLT, SDo, DPon, },
/* 02 */ { SRC_PAT_2_BLT, DSna, DPna },
/* 03 */ { SRC_PAT_2_BLT, S, PDon, },
/* 04 */ { SRC_PAT_2_BLT, SDna, DPna, },
/* 05 */ { PAT_FILL_1_BLT, DPon, },
/* 06 */ { SRC_PAT_2_BLT, DSxn, PDon, },
/* 07 */ { SRC_PAT_2_BLT, DSa, PDon, },
/* 08 */ { SRC_PAT_2_BLT, DSa, DPna, },
/* 09 */ { SRC_PAT_2_BLT, DSx, PDon, },
/* 0A */ { PAT_FILL_1_BLT, DPna, },
/* 0B */ { SRC_PAT_2_BLT, SDna, PDon, },
/* 0C */ { SRC_PAT_2_BLT, S, DPna, },
/* 0D */ { SRC_PAT_2_BLT, DSna, PDon, },
/* 0E */ { SRC_PAT_2_BLT, DSon, PDon, },
/* 0F */ { PAT_FILL_1_BLT, Pn, },
/* 10 */ { SRC_PAT_2_BLT, DSon, PDa, },
/* 11 */ { SRC_FILL_1_BLT, DSon, },
/* 12 */ { PAT_SRC_2_BLT, DPxn, SDon, },
/* 13 */ { PAT_SRC_2_BLT, DPa, SDon, },
/* 14 */ { ENG_DOWNLOAD_2_BLT, PSx, SDno, },
/* 15 */ { ENG_DOWNLOAD_2_BLT, PSa, DSon, },
/* 16 */ { ENGINE_BITBLT, },
/* 17 */ { ENGINE_BITBLT, },
/* 18 */ { ENGINE_BITBLT, },
/* 19 */ { ENGINE_BITBLT, },
/* 1A */ { ENGINE_BITBLT, },
/* 1B */ { ENGINE_BITBLT, },
/* 1C */ { PAT_SRC_PAT_3_BLT, DPa, SDo, PDx, },
/* 1D */ { ENGINE_BITBLT, },
/* 1E */ { SRC_PAT_2_BLT, DSo, PDx, },
/* 1F */ { SRC_PAT_2_BLT, DSo, PDan, },
/* 20 */ { SRC_PAT_2_BLT, DSna, PDa, },
/* 21 */ { PAT_SRC_2_BLT, DPx, SDon, },
/* 22 */ { SRC_FILL_1_BLT, DSna, },
/* 23 */ { PAT_SRC_2_BLT, PDna, SDon, },
/* 24 */ { ENGINE_BITBLT, },
/* 25 */ { ENGINE_BITBLT, },
/* 26 */ { ENGINE_BITBLT, },
/* 27 */ { ENGINE_BITBLT, },
/* 28 */ { ENG_DOWNLOAD_2_BLT, PSx, DSa, },
/* 29 */ { ENGINE_BITBLT, },
/* 2A */ { ENG_DOWNLOAD_2_BLT, PSa, DSna, },
/* 2B */ { ENGINE_BITBLT, },
/* 2C */ { SRC_PAT_SRC_3_BLT, DSo, PDa, SDx, },
/* 2D */ { SRC_PAT_2_BLT, SDno, PDx, },
/* 2E */ { PAT_SRC_PAT_3_BLT, DPx, SDo, PDx, },
/* 2F */ { SRC_PAT_2_BLT, SDno, PDan, },
/* 30 */ { SRC_PAT_2_BLT, S, PDna, },
/* 31 */ { PAT_SRC_2_BLT, DPna, SDon, },
/* 32 */ { SRC_PAT_SRC_3_BLT, SDo, PDo, SDx },
/* 33 */ { SRC_FILL_1_BLT, Sn, },
/* 34 */ { SRC_PAT_SRC_3_BLT, DSa, PDo, SDx, },
/* 35 */ { SRC_PAT_SRC_3_BLT, DSxn, PDo, SDx, },
/* 36 */ { PAT_SRC_2_BLT, DPo, SDx, },
/* 37 */ { PAT_SRC_2_BLT, DPo, SDan, },
/* 38 */ { PAT_SRC_PAT_3_BLT, DPo, SDa, PDx, },
/* 39 */ { PAT_SRC_2_BLT, PDno, SDx, },
/* 3A */ { SRC_PAT_SRC_3_BLT, DSx, PDo, SDx, },
/* 3B */ { PAT_SRC_2_BLT, PDno, SDan, },
/* 3C */ { SRC_PAT_2_BLT, S, PDx, },
/* 3D */ { SRC_PAT_SRC_3_BLT, DSon, PDo, SDx, },
/* 3E */ { SRC_PAT_SRC_3_BLT, DSna, PDo, SDx, },
/* 3F */ { SRC_PAT_2_BLT, S, PDan, },
/* 40 */ { SRC_PAT_2_BLT, SDna, PDa, },
/* 41 */ { ENG_DOWNLOAD_2_BLT, PSx, DSon, },
/* 42 */ { ENGINE_BITBLT, },
/* 43 */ { SRC_PAT_SRC_3_BLT, DSan, PDa, SDxn, },
/* 44 */ { SRC_FILL_1_BLT, SDna, },
/* 45 */ { ENG_DOWNLOAD_2_BLT, PSna, DSon, },
/* 46 */ { ENGINE_BITBLT, },
/* 47 */ { PAT_SRC_PAT_3_BLT, DPx, SDa, PDxn, },
/* 48 */ { PAT_SRC_2_BLT, DPx, SDa, },
/* 49 */ { ENGINE_BITBLT, },
/* 4A */ { ENGINE_BITBLT, },
/* 4B */ { SRC_PAT_2_BLT, DSno, PDx, },
/* 4C */ { PAT_SRC_2_BLT, DPan, SDa, },
/* 4D */ { ENGINE_BITBLT, },
/* 4E */ { ENGINE_BITBLT, },
/* 4F */ { SRC_PAT_2_BLT, DSno, PDan, },
/* 50 */ { PAT_FILL_1_BLT, PDna, },
/* 51 */ { ENG_DOWNLOAD_2_BLT, SPna, DSon, },
/* 52 */ { ENGINE_BITBLT, },
/* 53 */ { SRC_PAT_SRC_3_BLT, DSx, PDa, SDxn, },
/* 54 */ { ENG_DOWNLOAD_2_BLT, PSo, SDna, },
/* 55 */ { SOLID_FILL_1_BLT, Dn, },
/* 56 */ { ENG_DOWNLOAD_2_BLT, PSo, DSx, },
/* 57 */ { ENG_DOWNLOAD_2_BLT, PSo, DSan, },
/* 58 */ { ENGINE_BITBLT, },
/* 59 */ { ENG_DOWNLOAD_2_BLT, PSno, DSx, },
/* 5A */ { PAT_FILL_1_BLT, DPx, },
/* 5B */ { ENGINE_BITBLT, },
/* 5C */ { ENGINE_BITBLT, },
/* 5D */ { ENG_DOWNLOAD_2_BLT, PSno, DSan, },
/* 5E */ { ENGINE_BITBLT, },
/* 5F */ { PAT_FILL_1_BLT, DPan, },
/* 60 */ { SRC_PAT_2_BLT, DSx, PDa, },
/* 61 */ { ENGINE_BITBLT, },
/* 62 */ { ENGINE_BITBLT, },
/* 63 */ { PAT_SRC_2_BLT, DPno, SDx, },
/* 64 */ { ENGINE_BITBLT, },
/* 65 */ { ENG_DOWNLOAD_2_BLT, SPno, DSx, },
/* 66 */ { SRC_FILL_1_BLT, DSx, },
/* 67 */ { ENGINE_BITBLT, },
/* 68 */ { ENGINE_BITBLT, },
/* 69 */ { SRC_PAT_2_BLT, DSx, PDxn, },
/* 6A */ { ENG_DOWNLOAD_2_BLT, PSa, DSx, },
/* 6B */ { ENGINE_BITBLT, },
/* 6C */ { PAT_SRC_2_BLT, DPa, SDx, },
/* 6D */ { ENGINE_BITBLT, },
/* 6E */ { ENGINE_BITBLT, },
/* 6F */ { SRC_PAT_2_BLT, DSxn, PDan, },
/* 70 */ { SRC_PAT_2_BLT, DSan, PDa, },
/* 71 */ { ENGINE_BITBLT, },
/* 72 */ { ENGINE_BITBLT, },
/* 73 */ { PAT_SRC_2_BLT, DPno, SDan, },
/* 74 */ { ENGINE_BITBLT, },
/* 75 */ { ENG_DOWNLOAD_2_BLT, SPno, DSan, },
/* 76 */ { ENGINE_BITBLT, },
/* 77 */ { SRC_FILL_1_BLT, DSan, },
/* 78 */ { SRC_PAT_2_BLT, DSa, PDx, },
/* 79 */ { ENGINE_BITBLT, },
/* 7A */ { ENGINE_BITBLT, },
/* 7B */ { PAT_SRC_2_BLT, DPxn, SDan, },
/* 7C */ { SRC_PAT_SRC_3_BLT, DSno, PDa, SDx, },
/* 7D */ { ENG_DOWNLOAD_2_BLT, PSxn, DSan, },
/* 7E */ { ENGINE_BITBLT, },
/* 7F */ { ENG_DOWNLOAD_2_BLT, PSa, DSan, },
/* 80 */ { ENG_DOWNLOAD_2_BLT, PSa, DSa, },
/* 81 */ { ENGINE_BITBLT, },
/* 82 */ { ENG_DOWNLOAD_2_BLT, PSx, DSna, },
/* 83 */ { SRC_PAT_SRC_3_BLT, DSno, PDa, SDxn, },
/* 84 */ { PAT_SRC_2_BLT, DPxn, SDa, },
/* 85 */ { ENGINE_BITBLT, },
/* 86 */ { ENGINE_BITBLT, },
/* 87 */ { SRC_PAT_2_BLT, DSa, PDxn, },
/* 88 */ { SRC_FILL_1_BLT, DSa, },
/* 89 */ { ENGINE_BITBLT, },
/* 8A */ { ENG_DOWNLOAD_2_BLT, SPno, DSa, },
/* 8B */ { ENGINE_BITBLT, },
/* 8C */ { PAT_SRC_2_BLT, DPno, SDa, },
/* 8D */ { ENGINE_BITBLT, },
/* 8E */ { ENGINE_BITBLT, },
/* 8F */ { SRC_PAT_2_BLT, DSan, PDan, },
/* 90 */ { SRC_PAT_2_BLT, DSxn, PDa, },
/* 91 */ { ENGINE_BITBLT, },
/* 92 */ { ENGINE_BITBLT, },
/* 93 */ { PAT_SRC_2_BLT, PDa, SDxn, },
/* 94 */ { ENGINE_BITBLT, },
/* 95 */ { ENG_DOWNLOAD_2_BLT, PSa, DSxn, },
/* 96 */ { SRC_PAT_2_BLT, DSx, PDx, }, /* DPSxx == PDSxx */
/* 97 */ { ENGINE_BITBLT, },
/* 98 */ { ENGINE_BITBLT, },
/* 99 */ { SRC_FILL_1_BLT, DSxn, },
/* 9A */ { ENG_DOWNLOAD_2_BLT, PSna, DSx, },
/* 9B */ { ENGINE_BITBLT, },
/* 9C */ { PAT_SRC_2_BLT, PDna, SDx, },
/* 9D */ { ENGINE_BITBLT, },
/* 9E */ { ENGINE_BITBLT, },
/* 9F */ { SRC_PAT_2_BLT, DSx, PDan, },
/* A0 */ { PAT_FILL_1_BLT, DPa, },
/* A1 */ { ENGINE_BITBLT, },
/* A2 */ { ENG_DOWNLOAD_2_BLT, PSno, DSa, },
/* A3 */ { ENGINE_BITBLT, },
/* A4 */ { ENGINE_BITBLT, },
/* A5 */ { PAT_FILL_1_BLT, PDxn, },
/* A6 */ { ENG_DOWNLOAD_2_BLT, SPna, DSx, },
/* A7 */ { ENGINE_BITBLT, },
/* A8 */ { ENG_DOWNLOAD_2_BLT, PSo, DSa, },
/* A9 */ { ENG_DOWNLOAD_2_BLT, PSo, DSxn, },
/* AA */ { SOLID_FILL_1_BLT, D },
/* AB */ { ENG_DOWNLOAD_2_BLT, PSo, DSno, },
/* AC */ { SRC_PAT_SRC_3_BLT, DSx, PDa, SDx, },
/* AD */ { ENGINE_BITBLT, },
/* AE */ { ENG_DOWNLOAD_2_BLT, SPna, DSo, },
/* AF */ { PAT_FILL_1_BLT, DPno, },
/* B0 */ { SRC_PAT_2_BLT, DSno, PDa, },
/* B1 */ { ENGINE_BITBLT, },
/* B2 */ { ENGINE_BITBLT, },
/* B3 */ { PAT_SRC_2_BLT, DPan, SDan, },
/* B4 */ { SRC_PAT_2_BLT, SDna, PDx, },
/* B5 */ { ENGINE_BITBLT, },
/* B6 */ { ENGINE_BITBLT, },
/* B7 */ { PAT_SRC_2_BLT, DPx, SDan, },
/* B8 */ { PAT_SRC_PAT_3_BLT, DPx, SDa, PDx, },
/* B9 */ { ENGINE_BITBLT, },
/* BA */ { ENG_DOWNLOAD_2_BLT, PSna, DSo, },
/* BB */ { SRC_FILL_1_BLT, DSno, },
/* BC */ { SRC_PAT_SRC_3_BLT, DSan, PDa, SDx, },
/* BD */ { ENGINE_BITBLT, },
/* BE */ { ENG_DOWNLOAD_2_BLT, PSx, DSo, },
/* BF */ { ENG_DOWNLOAD_2_BLT, PSa, DSno, },
/* C0 */ { SRC_PAT_2_BLT, S, PDa, },
/* C1 */ { ENGINE_BITBLT, },
/* C2 */ { ENGINE_BITBLT, },
/* C3 */ { SRC_PAT_2_BLT, S, PDxn, },
/* C4 */ { PAT_SRC_2_BLT, PDno, SDa, },
/* C5 */ { SRC_PAT_SRC_3_BLT, DSx, PDo, SDxn, },
/* C6 */ { PAT_SRC_2_BLT, DPna, SDx, },
/* C7 */ { PAT_SRC_PAT_3_BLT, DPo, SDa, PDxn, },
/* C8 */ { PAT_SRC_2_BLT, DPo, SDa, },
/* C9 */ { PAT_SRC_2_BLT, PDo, SDxn, },
/* CA */ { ENGINE_BITBLT, },
/* CB */ { SRC_PAT_SRC_3_BLT, DSa, PDo, SDxn, },
/* CC */ { SRC_FILL_1_BLT, S, },
/* CD */ { PAT_SRC_2_BLT, DPon, SDo, },
/* CE */ { PAT_SRC_2_BLT, DPna, SDo, },
/* CF */ { SRC_PAT_2_BLT, S, DPno, },
/* D0 */ { SRC_PAT_2_BLT, SDno, PDa, },
/* D1 */ { PAT_SRC_PAT_3_BLT, DPx, SDo, PDxn, },
/* D2 */ { SRC_PAT_2_BLT, DSna, PDx, },
/* D3 */ { SRC_PAT_SRC_3_BLT, DSo, PDa, SDxn, },
/* D4 */ { ENGINE_BITBLT, },
/* D5 */ { ENG_DOWNLOAD_2_BLT, PSan, DSan, },
/* D6 */ { ENGINE_BITBLT, },
/* D7 */ { ENG_DOWNLOAD_2_BLT, PSx, DSan, },
/* D8 */ { ENGINE_BITBLT, },
/* D9 */ { ENGINE_BITBLT, },
/* DA */ { ENGINE_BITBLT, },
/* DB */ { ENGINE_BITBLT, },
/* DC */ { PAT_SRC_2_BLT, PDna, SDo, },
/* DD */ { SRC_FILL_1_BLT, SDno, },
/* DE */ { PAT_SRC_2_BLT, DPx, SDo, },
/* DF */ { ENG_DOWNLOAD_2_BLT, DPan, SDo, },
/* E0 */ { SRC_PAT_2_BLT, DSo, PDa, },
/* E1 */ { SRC_PAT_2_BLT, DSo, PDxn, },
/* E2 */ { ENGINE_BITBLT, }, /* DSPDxax : XXX S3 special cases this */
/* E3 */ { PAT_SRC_PAT_3_BLT, DPa, SDo, PDxn, },
/* E4 */ { ENGINE_BITBLT, },
/* E5 */ { ENGINE_BITBLT, },
/* E6 */ { ENGINE_BITBLT, },
/* E7 */ { ENGINE_BITBLT, },
/* E8 */ { ENGINE_BITBLT, },
/* E9 */ { ENGINE_BITBLT, },
/* EA */ { ENG_DOWNLOAD_2_BLT, PSa, DSo, },
/* EB */ { ENG_DOWNLOAD_2_BLT, PSx, DSno, },
/* EC */ { PAT_SRC_2_BLT, DPa, SDo, },
/* ED */ { PAT_SRC_2_BLT, DPxn, SDo, },
/* EE */ { SRC_FILL_1_BLT, DSo, },
/* EF */ { SRC_PAT_2_BLT, SDo, DPno },
/* F0 */ { PAT_FILL_1_BLT, P, },
/* F1 */ { SRC_PAT_2_BLT, DSon, PDo, },
/* F2 */ { SRC_PAT_2_BLT, DSna, PDo, },
/* F3 */ { SRC_PAT_2_BLT, S, PDno, },
/* F4 */ { SRC_PAT_2_BLT, SDna, PDo, },
/* F5 */ { PAT_FILL_1_BLT, PDno, },
/* F6 */ { SRC_PAT_2_BLT, DSx, PDo, },
/* F7 */ { SRC_PAT_2_BLT, DSan, PDo, },
/* F8 */ { SRC_PAT_2_BLT, DSa, PDo, },
/* F9 */ { SRC_PAT_2_BLT, DSxn, PDo, },
/* FA */ { PAT_FILL_1_BLT, DPo, },
/* FB */ { SRC_PAT_2_BLT, DSno, PDo, },
/* FC */ { SRC_PAT_2_BLT, S, PDo, },
/* FD */ { SRC_PAT_2_BLT, SDno, PDo, },
/* FE */ { ENG_DOWNLOAD_2_BLT, PSo, DSo, },
/* FF */ { SOLID_FILL_1_BLT, set, },
};
// table to determine which logicops need read dest turned on in FBReadMode
DWORD LogicopReadDest[] = {
0, /* 00 */
__FB_READ_DESTINATION, /* 01 */
__FB_READ_DESTINATION, /* 02 */
0, /* 03 */
__FB_READ_DESTINATION, /* 04 */
__FB_READ_DESTINATION, /* 05 */
__FB_READ_DESTINATION, /* 06 */
__FB_READ_DESTINATION, /* 07 */
__FB_READ_DESTINATION, /* 08 */
__FB_READ_DESTINATION, /* 09 */
__FB_READ_DESTINATION, /* 10 */
__FB_READ_DESTINATION, /* 11 */
0, /* 12 */
__FB_READ_DESTINATION, /* 13 */
__FB_READ_DESTINATION, /* 14 */
0, /* 15 */
};
// translate a ROP2 into a GLINT logicop. Note, ROP2's start at 1 so
// entry 0 is not used.
DWORD GlintLogicOpsFromR2[] = {
0, /* rop2's start at 1 */
__GLINT_LOGICOP_CLEAR, /* 0 1 */
__GLINT_LOGICOP_NOR, /* DPon 2 */
__GLINT_LOGICOP_AND_INVERTED, /* DPna 3 */
__GLINT_LOGICOP_COPY_INVERT, /* Pn 4 */
__GLINT_LOGICOP_AND_REVERSE, /* PDna 5 */
__GLINT_LOGICOP_INVERT, /* Dn 6 */
__GLINT_LOGICOP_XOR, /* DPx 7 */
__GLINT_LOGICOP_NAND, /* DPan 8 */
__GLINT_LOGICOP_AND, /* DPa 9 */
__GLINT_LOGICOP_EQUIV, /* DPxn 10 */
__GLINT_LOGICOP_NOOP, /* D 11 */
__GLINT_LOGICOP_OR_INVERT, /* DPno 12 */
__GLINT_LOGICOP_COPY, /* P 13 */
__GLINT_LOGICOP_OR_REVERSE, /* PDno 14 */
__GLINT_LOGICOP_OR, /* DPo 15 */
__GLINT_LOGICOP_SET, /* 1 16 */
};
BOOL
PatternFillRect(PPDEV, RECTL *, CLIPOBJ *, BRUSHOBJ *,
POINTL *, ULONG, ULONG);
BOOL
SourceFillRect(PPDEV, RECTL *, CLIPOBJ *, SURFOBJ *, XLATEOBJ *,
POINTL *, ULONG, ULONG);
BOOL
PatSrcPatBlt(PPDEV, SURFOBJ*, CLIPOBJ*, XLATEOBJ*, RECTL*,
POINTL*, BRUSHOBJ*, POINTL*, RopTablePtr);
BOOL
SrcPatSrcBlt(PPDEV, SURFOBJ*, CLIPOBJ*, XLATEOBJ*, RECTL*,
POINTL*, BRUSHOBJ*, POINTL*, RopTablePtr);
BOOL
MaskCopyBlt(PPDEV, RECTL*, CLIPOBJ*, SURFOBJ*, SURFOBJ*, POINTL*,
POINTL*, ULONG, ULONG);
BOOL
bUploadRect(PPDEV, CLIPOBJ *, SURFOBJ *, SURFOBJ *, POINTL *, RECTL *);
BOOL bUploadBlt(
PPDEV,
SURFOBJ *,
SURFOBJ *,
SURFOBJ *,
CLIPOBJ *,
XLATEOBJ *,
RECTL *,
POINTL *,
POINTL *,
BRUSHOBJ *,
POINTL *,
ROP4);
#if defined(_X86_)
// Mono upload functions
BOOL DoScreenToMono(
PDEV* ppdev,
RECTL *prclDst,
CLIPOBJ *pco,
SURFOBJ* psoSrc, // Source surface
SURFOBJ* psoDst, // Destination surface
POINTL* pptlSrc, // Original unclipped source point
XLATEOBJ* pxlo); // Provides colour-compressions information
VOID vXferScreenTo1bpp(
PDEV* ppdev,
LONG c, // Count of rectangles, can't be zero
RECTL* prcl, // List of destination rectangles, in
// relative coordinates
ULONG ulHwMix, // Not used
SURFOBJ* psoSrc, // Source surface
SURFOBJ* psoDst, // Destination surface
POINTL* pptlSrc, // Original unclipped source point
RECTL* prclDst, // Original unclipped destination rectangle
XLATEOBJ* pxlo); // Provides colour-compressions information
#endif // defined(_X86_)
/******************************Public*Routine******************************\
* BOOL bIntersect
*
* If 'prcl1' and 'prcl2' intersect, has a return value of TRUE and returns
* the intersection in 'prclResult'. If they don't intersect, has a return
* value of FALSE, and 'prclResult' is undefined.
*
\**************************************************************************/
BOOL bIntersect(
RECTL* prcl1,
RECTL* prcl2,
RECTL* prclResult)
{
prclResult->left = max(prcl1->left, prcl2->left);
prclResult->right = min(prcl1->right, prcl2->right);
if (prclResult->left < prclResult->right)
{
prclResult->top = max(prcl1->top, prcl2->top);
prclResult->bottom = min(prcl1->bottom, prcl2->bottom);
if (prclResult->top < prclResult->bottom)
{
return(TRUE);
}
}
return(FALSE);
}
/******************************Public*Routine******************************\
* LONG cIntersect
*
* This routine takes a list of rectangles from 'prclIn' and clips them
* in-place to the rectangle 'prclClip'. The input rectangles don't
* have to intersect 'prclClip'; the return value will reflect the
* number of input rectangles that did intersect, and the intersecting
* rectangles will be densely packed.
*
\**************************************************************************/
LONG cIntersect(
RECTL* prclClip,
RECTL* prclIn, // List of rectangles
LONG c) // Can be zero
{
LONG cIntersections;
RECTL* prclOut;
cIntersections = 0;
prclOut = prclIn;
for (; c != 0; prclIn++, c--)
{
prclOut->left = max(prclIn->left, prclClip->left);
prclOut->right = min(prclIn->right, prclClip->right);
if (prclOut->left < prclOut->right)
{
prclOut->top = max(prclIn->top, prclClip->top);
prclOut->bottom = min(prclIn->bottom, prclClip->bottom);
if (prclOut->top < prclOut->bottom)
{
prclOut++;
cIntersections++;
}
}
}
return(cIntersections);
}
/******************************Public*Routine******************************\
* VOID vGlintChangeFBDepth
*
* Change the GLINT packing mode for different depths. We use this to speed
* up rendering for 8 and 16 bpp where we can process up to 4 pixels at a
* time.
*
\**************************************************************************/
VOID vGlintChangeFBDepth(
PPDEV ppdev,
ULONG cPelSize)
{
ULONG cFlags;
GLINT_DECL;
DISPDBG((DBGLVL, "setting current pixel depth to %d",
(cPelSize == 0) ? 8 : (cPelSize == 1) ? 16 : 32));
glintInfo->FBReadMode = glintInfo->packing[cPelSize].readMode;
glintInfo->currentPelSize = cPelSize;
// Toggle the FBReadMode cache flag
DISPDBG((DBGLVL, "setting FBReadMode to 0x%08x", glintInfo->FBReadMode));
cFlags = CHECK_CACHEFLAGS (ppdev, 0xFFFFFFFF);
SET_CACHEFLAGS (ppdev, (cFlags & ~cFlagFBReadDefault));
// set FX pixel depth
// 0 - 8 bits, 1 - 16 bits and 2 - 32 bits.
DISPDBG((DBGLVL, "Changing FBDepth for PERMEDIA"));
WAIT_GLINT_FIFO(1);
LD_GLINT_FIFO(__PermediaTagFBReadPixel, cPelSize);
}
/******************************Public*Routine******************************\
* BOOL DrvBitBlt
*
* Implements the workhorse routine of a display driver.
*
\**************************************************************************/
BOOL DrvBitBlt(
SURFOBJ *psoDst,
SURFOBJ *psoSrc,
SURFOBJ *psoMsk,
CLIPOBJ *pco,
XLATEOBJ *pxlo,
RECTL *prclDst,
POINTL *pptlSrc,
POINTL *pptlMsk,
BRUSHOBJ *pbo,
POINTL *pptlBrush,
ROP4 rop4)
{
BOOL bRet;
PPDEV ppdev;
DSURF *pdsurfDst;
DSURF *pdsurfSrc;
UCHAR funcIndexFore;
UCHAR funcIndexBack;
XLATECOLORS xlc;
XLATEOBJ xlo;
RopTablePtr pTableFore;
RopTablePtr pTableBack;
HSURF hsurfSrcBitmap, hsurfDstBitmap;
SURFOBJ *psoSrcBitmap, *psoDstBitmap;
SURFOBJ *psoSrcOrig = psoSrc, *psoDstOrig = psoDst;
GLINT_DECL_VARS;
// We need to remove the pointer, but we dont know which surface is valid
// (if either).
if ((psoDst->iType != STYPE_BITMAP) &&
(((DSURF *)(psoDst->dhsurf))->dt & DT_SCREEN))
{
ppdev = (PDEV *)psoDst->dhpdev;
REMOVE_SWPOINTER(psoDst);
}
else if (psoSrc &&
(psoSrc->iType != STYPE_BITMAP) &&
(((DSURF *)(psoSrc->dhsurf))->dt & DT_SCREEN))
{
ppdev = (PDEV *)psoSrc->dhpdev;
REMOVE_SWPOINTER(psoSrc);
}
// GDI will never give us a Rop4 with the bits in the high-word set
// (so that we can check if it's actually a Rop3 via the expression
// (rop4 >> 8) == (rop4 & 0xff))
ASSERTDD((rop4 >> 16) == 0, "Didn't expect a rop4 with high bits set");
#if !defined(_WIN64) && WNT_DDRAW
// Touch the source surface 1st and then the destination surface
vSurfUsed(psoSrc);
vSurfUsed(psoDst);
#endif
pdsurfDst = (DSURF *)psoDst->dhsurf;
if (psoSrc == NULL)
{
///////////////////////////////////////////////////////////////////
// Fills
///////////////////////////////////////////////////////////////////
// Fills are this function's "raison d'etre", so we handle them
// as quickly as possible:
ASSERTDD(pdsurfDst != NULL,
"Expect only device destinations when no source");
if (pdsurfDst->dt & DT_SCREEN)
{
OH* poh;
BOOL bMore;
CLIPENUM ce;
LONG c;
RECTL rcl;
BYTE rop3;
GFNFILL* pfnFill;
RBRUSH_COLOR rbc; // Realized brush or solid colour
DWORD fgLogicop;
DWORD bgLogicop;
ppdev = (PDEV*) psoDst->dhpdev;
GLINT_DECL_INIT;
poh = pdsurfDst->poh;
SETUP_PPDEV_OFFSETS(ppdev, pdsurfDst);
VALIDATE_DD_CONTEXT;
// Make sure it doesn't involve a mask (i.e., it's really a
// Rop3):
rop3 = (BYTE) rop4;
if ((BYTE) (rop4 >> 8) == rop3)
{
// Since 'psoSrc' is NULL, the rop3 had better not indicate
// that we need a source.
ASSERTDD((((rop4 >> 2) ^ (rop4)) & 0x33) == 0,
"Need source but GDI gave us a NULL 'psoSrc'");
pfnFill = ppdev->pgfnFillSolid; // Default to solid fill
pTableFore = &ropTable[rop4 & 0xff];
pTableBack = &ropTable[rop4 >> 8];
fgLogicop = pTableFore->logicop[0];
if ((((rop3 >> 4) ^ (rop3)) & 0xf) != 0)
{
// The rop says that a pattern is truly required
// (blackness, for instance, doesn't need one):
rbc.iSolidColor = pbo->iSolidColor;
if (rbc.iSolidColor == -1)
{
// Try and realize the pattern brush; by doing
// this call-back, GDI will eventually call us
// again through DrvRealizeBrush:
rbc.prb = pbo->pvRbrush;
if (rbc.prb == NULL)
{
rbc.prb = BRUSHOBJ_pvGetRbrush(pbo);
if (rbc.prb == NULL)
{
// If we couldn't realize the brush, punt
// the call (it may have been a non 8x8
// brush or something, which we can't be
// bothered to handle, so let GDI do the
// drawing):
DISPDBG((WRNLVL, "DrvBitBlt: BRUSHOBJ_pvGetRbrush"
"failed.calling engine_blt"));
GLINT_DECL_INIT;
goto engine_blt;
}
}
if (rbc.prb->fl & RBRUSH_2COLOR)
{
DISPDBG((DBGLVL, "monochrome brush"));
pfnFill = ppdev->pgfnFillPatMono;
}
else
{
DISPDBG((DBGLVL, "colored brush"));
pfnFill = ppdev->pgfnFillPatColor;
}
bgLogicop = pTableBack->logicop[0];
}
}
else
{
// Turn some logicops into solid block fills. We get here
// only for rops 0, 55, AA and FF.
if ((fgLogicop == __GLINT_LOGICOP_SET) ||
(fgLogicop == __GLINT_LOGICOP_CLEAR))
{
rbc.iSolidColor = 0xffffff; // does any depth
if (fgLogicop == __GLINT_LOGICOP_CLEAR)
{
rbc.iSolidColor = 0;
}
fgLogicop = __GLINT_LOGICOP_COPY;
}
else if (fgLogicop == __GLINT_LOGICOP_NOOP)
{
return(TRUE); // DST logicop is a noop
}
}
// Note that these 2 'if's are more efficient than
// a switch statement:
if ((pco == NULL) || (pco->iDComplexity == DC_TRIVIAL))
{
pfnFill(ppdev, 1, prclDst, fgLogicop, bgLogicop,
rbc, pptlBrush);
return TRUE;
}
else if (pco->iDComplexity == DC_RECT)
{
if (bIntersect(prclDst, &pco->rclBounds, &rcl))
{
pfnFill(ppdev, 1, &rcl, fgLogicop, bgLogicop,
rbc, pptlBrush);
}
return TRUE;
}
else
{
CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
do {
bMore = CLIPOBJ_bEnum(pco, sizeof(ce), (ULONG*) &ce);
c = cIntersect(prclDst, ce.arcl, ce.c);
if (c != 0)
{
pfnFill(ppdev, c, ce.arcl, fgLogicop, bgLogicop,
rbc, pptlBrush);
}
} while (bMore);
return TRUE;
}
}
}
}
#if defined(_X86_)
if ((pxlo != NULL) &&
(pxlo->flXlate & XO_TO_MONO) &&
(psoSrc != NULL) && (pptlSrc != NULL) &&
(psoDst != NULL) && (psoDst->dhsurf == NULL) &&
(psoDst->iBitmapFormat == BMF_1BPP))
{
BYTE rop3 = (BYTE) rop4; // Make rop4 into a Rop3
ppdev = (PDEV*) psoSrc->dhpdev;
pdsurfSrc = (DSURF *)psoSrc->dhsurf;
GLINT_DECL_INIT;
VALIDATE_DD_CONTEXT;
if ((ppdev->iBitmapFormat != BMF_24BPP) &&
(((rop4 >> 8) & 0xff) == (rop4 & 0xff)) &&
(psoSrc->iType != STYPE_BITMAP) &&
(pdsurfSrc->dt & DT_SCREEN) &&
(rop3 == 0xcc))
{
// We special case screen to monochrome blts because they
// happen fairly often. We only handle SRCCOPY rops and
// monochrome destinations (to handle a true 1bpp DIB
// destination, we would have to do near-colour searches
// on every colour; as it is, the foreground colour gets
// mapped to '1', and everything else gets mapped to '0'):
SETUP_PPDEV_OFFSETS(ppdev, pdsurfSrc);
ASSERTDD (pdsurfSrc->poh->cy >= psoSrc->sizlBitmap.cy ||
pdsurfSrc->poh->cx >= psoSrc->sizlBitmap.cx,
"DrvBitBlt: Got a BAD screen-to-mono size");
DISPDBG((DBGLVL, "DrvBitBlt: Screen-to-mono, size poh(%d,%d)",
pdsurfSrc->poh->cx, pdsurfSrc->poh->cy));
if (DoScreenToMono (ppdev, prclDst, pco, psoSrc,
psoDst, pptlSrc, pxlo))
return (TRUE);
}
}
#endif // defined(_X86_)
// pdsurfDst is valid only if iType != BITMAP so be careful with the ordering
//
if ((psoDst->iType == STYPE_BITMAP) || ((pdsurfDst->dt & DT_SCREEN) == 0))
{
// Destination is either a bitmap or an ex offscreen bitmap
DISPDBG((DBGLVL, "dst is a bitmap or a DIB"));
if (psoSrc)
{
DISPDBG((DBGLVL, "we have a src"));
pdsurfSrc = (DSURF *)psoSrc->dhsurf;
if ((psoSrc->iType != STYPE_BITMAP) &&
(pdsurfSrc->dt & DT_SCREEN))
{
ppdev = (PPDEV)psoSrc->dhpdev;
GLINT_DECL_INIT;
SETUP_PPDEV_OFFSETS(ppdev, pdsurfSrc);
// if we are ex offscreen, get the DIB pointer.
if (psoDst->iType != STYPE_BITMAP)
{
psoDst = pdsurfDst->pso;
}
VALIDATE_DD_CONTEXT;
DISPDBG((DBGLVL, "uploading from the screen"));
if (bUploadBlt(ppdev, psoDst, psoSrc, psoMsk, pco, pxlo, prclDst,
pptlSrc, pptlMsk, pbo, pptlBrush, rop4))
{
return (TRUE);
}
// If for some reason the upload failed go and do it.
DISPDBG((WRNLVL, "DrvBitBlt: bUploadBlt "
"failed.calling engine_blt"));
goto engine_blt;
}
}
DISPDBG((DBGLVL, "falling through to engine_blt"));
if (psoDst->iType != STYPE_BITMAP)
{
// Destination is an Ex Offscreen Bitmap
ppdev = (PPDEV)psoDst->dhpdev;
GLINT_DECL_INIT;
DISPDBG((DBGLVL, "DrvBitBlt: ex offscreen "
"bitmap.calling engine_blt"));
goto engine_blt;
}
else
{
// Destination is a Memory Bitmap. We shouldnt ever get here.
DISPDBG((DBGLVL, "DrvBitBlt: memory bitmap!!."
"calling simple_engine_blt"));
goto simple_engine_blt;
}
}
ppdev = (PPDEV)psoDst->dhpdev;
GLINT_DECL_INIT;
VALIDATE_DD_CONTEXT;
SETUP_PPDEV_OFFSETS(ppdev, pdsurfDst);
// pick out the rop table entries for the foreground and background mixes.
// if we get the same entry for both then we have a rop3.
//
pTableFore = &ropTable[rop4 & 0xff];
pTableBack = &ropTable[rop4 >> 8];
funcIndexFore = pTableFore->func_index;
// handle rop3 pattern fills where no source is needed
//
if ((psoSrc == NULL) && (pTableFore == pTableBack))
{
// really a rop3. no mask required
// solid or pattern fills
if (funcIndexFore <= PAT_FILL_1_BLT)
{
BRUSHOBJ tmpBrush;
BRUSHOBJ *pboTmp;
ULONG logicop;
pboTmp = pbo;
logicop = pTableFore->logicop[0];
// handle the 4 logicops that don't use src or pattern by turning
// them into optimized solid fills.
//
if (funcIndexFore == SOLID_FILL_1_BLT)
{
if ((logicop == __GLINT_LOGICOP_SET) ||
(logicop == __GLINT_LOGICOP_CLEAR))
{
// as solid fills we can make use of hardware block fills
tmpBrush.iSolidColor = 0xffffff; // does any depth
if (logicop == __GLINT_LOGICOP_CLEAR)
{
tmpBrush.iSolidColor = 0;
}
logicop = __GLINT_LOGICOP_COPY;
pboTmp = &tmpBrush;
}
else if (logicop == __GLINT_LOGICOP_INVERT)
{
pboTmp = NULL; // forces a solid fill
}
else
{
return(TRUE); // DST logicop is a noop
}
}
// as fills are performance critical it may be wise to make this
// code inline as in the sample driver. But for the moment, I'll
// leave it as a function call.
//
if (PatternFillRect(ppdev, prclDst, pco, pboTmp, pptlBrush,
logicop, logicop))
{
return(TRUE);
}
DISPDBG((DBGLVL, "DrvBitBlt: PatternFillRect "
"failed.calling engine_blt"));
goto engine_blt;
}
}
// this code is important in that it resets psoSrc to be a real DIB surface
// if src is a DFB converted to a DIB. SourceFillRect() depends on this
// having been done.
//
if ((psoSrc != NULL) && (psoSrc->iType == STYPE_DEVBITMAP))
{
pdsurfSrc = (DSURF *)psoSrc->dhsurf;
if (pdsurfSrc->dt & DT_DIB)
{
// Here we consider putting a DIB DFB back into off-screen
// memory. If there's a translate, it's probably not worth
// moving since we won't be able to use the hardware to do
// the blt (a similar argument could be made for weird rops
// and stuff that we'll only end up having GDI simulate, but
// those should happen infrequently enough that I don't care).
if ((pxlo == NULL) || (pxlo->flXlate & XO_TRIVIAL))
{
// See 'DrvCopyBits' for some more comments on how this
// moving-it-back-into-off-screen-memory thing works:
if (pdsurfSrc->iUniq == ppdev->iHeapUniq)
{
if (--pdsurfSrc->cBlt == 0)
{
if (bMoveDibToOffscreenDfbIfRoom(ppdev, pdsurfSrc))
{
goto Continue_It;
}
}
}
else
{
// Some space was freed up in off-screen memory,
// so reset the counter for this DFB:
pdsurfSrc->iUniq = ppdev->iHeapUniq;
pdsurfSrc->cBlt = HEAP_COUNT_DOWN;
}
}
// pick out the DIB surface that we defined for the DFB when it
// was created (as our VRAM is linear we always have this).
//
psoSrc = pdsurfSrc->pso;
}
}
Continue_It:
// we are now interested in rop3s involving a source
//
if (pTableFore == pTableBack)
{
if (funcIndexFore == SRC_FILL_1_BLT)
{
if (SourceFillRect(ppdev, prclDst, pco, psoSrc, pxlo,
pptlSrc, pTableFore->logicop[0], pTableFore->logicop[0]))
{
return(TRUE);
}
DISPDBG((DBGLVL, "DrvBitBlt: SourceFillRect"
" failed.calling engine_blt"));
goto engine_blt;
}
// handle miscellaneous other rop3s. Most of these are done in
// multiple passes of the hardware.
//
switch (funcIndexFore)
{
case PAT_SRC_2_BLT:
case PAT_SRC_PAT_3_BLT:
DISPDBG((DBGLVL, "PAT_SRC_PAT_BLT, rop 0x%x",
pTableFore - ropTable));
if (PatSrcPatBlt(ppdev, psoSrc, pco, pxlo, prclDst,pptlSrc,
pbo, pptlBrush, pTableFore))
{
return(TRUE);
}
break;
case SRC_PAT_2_BLT:
case SRC_PAT_SRC_3_BLT:
DISPDBG((DBGLVL, "SRC_PAT_SRC_BLT, rop 0x%x",
pTableFore - ropTable));
if (SrcPatSrcBlt(ppdev, psoSrc, pco, pxlo, prclDst,pptlSrc,
pbo, pptlBrush, pTableFore))
{
return(TRUE);
}
break;
case ENG_DOWNLOAD_2_BLT:
DISPDBG((DBGLVL, "ENG_DOWNLOAD_2_BLT, rop 0x%x",
pTableFore - ropTable));
break;
case ENGINE_BITBLT:
DISPDBG((DBGLVL, "ENGINE_BITBLT, rop 0x%x",
pTableFore - ropTable));
break;
default:
break;
}
DISPDBG((WRNLVL, "DrvBitBlt: Unhandled rop3.calling engine_blt"));
goto engine_blt;
}
// ROP4
// we get here if the mix is a true rop4.
// unlike the above we only handle a few well chosen rop4s.
// do later.
DISPDBG((DBGLVL, "got a true rop4 0x%x", rop4));
funcIndexBack = pTableBack->func_index;
if (psoMsk != NULL)
{
// At this point, we've made sure that we have a true ROP4.
// This is important because we're about to dereference the
// mask. I'll assert to make sure that I haven't inadvertently
// broken the logic for this:
ASSERTDD((rop4 & 0xff) != (rop4 >> 8), "This handles true ROP4's only");
///////////////////////////////////////////////////////////////////
// True ROP4's
///////////////////////////////////////////////////////////////////
// Handle ROP4 where no source is required for either Rop3:
// In this case we handle it by using the mask as a 1bpp
// source image and we download it. The foreground and
// background colors are taken from a solid brush.
if ((funcIndexFore | funcIndexBack) <= PAT_FILL_1_BLT)
{
if ((funcIndexFore | funcIndexBack) == PAT_FILL_1_BLT)
{
// Fake up a 1bpp XLATEOBJ (note that we should only
// dereference 'pbo' when it's required by the mix):
xlc.iForeColor = pbo->iSolidColor;
xlc.iBackColor = xlc.iForeColor;
if (xlc.iForeColor == -1)
{
DISPDBG((WRNLVL, "1bpp fake xlate rejected"
" as brush not solid"));
goto engine_blt; // We don't handle non-solid brushes
}
}
// Note that when neither the foreground nor the background mix
// requires a source, the colours in 'xlc' are allowed to be
// garbage.
xlo.pulXlate = (ULONG*) &xlc;
pxlo = &xlo;
psoSrc = psoMsk;
pptlSrc = pptlMsk;
DISPDBG((DBGLVL, "calling SourceFillRect for rop4 (fg %d, bg %d)",
pTableFore->logicop[0], pTableBack->logicop[0]));
if (SourceFillRect(ppdev, prclDst, pco, psoSrc, pxlo,
pptlSrc, pTableFore->logicop[0], pTableBack->logicop[0]))
{
return(TRUE);
}
DISPDBG((WRNLVL, "DrvBitBlt: SourceFillRect (2) "
"failed.calling engine_blt"));
goto engine_blt;
} // No pattern required
else if ((funcIndexFore | funcIndexBack) == SRC_FILL_1_BLT)
{
// We're about to dereference 'psoSrc' and 'pptlSrc' --
// since we already handled the case where neither ROP3
// required the source, the ROP4 must require a source,
// so we're safe.
ASSERTDD((psoSrc != NULL) && (pptlSrc != NULL),
"No source case should already have been handled!");
// The operation has to be screen-to-screen, and the rectangles
// cannot overlap:
if ((psoSrc->iType != STYPE_BITMAP) &&
(psoDst->iType != STYPE_BITMAP) &&
((pxlo == NULL) || (pxlo->flXlate & XO_TRIVIAL)) &&
!OVERLAP(prclDst, pptlSrc))
{
DISPDBG((DBGLVL, "calling MskCopyBlt for rop 4 (fg %d, bg %d)",
pTableFore->logicop[0], pTableBack->logicop[0]));
//@@BEGIN_DDKSPLIT
// TMM: 060897: Removed this for WHQL tests
//if (MaskCopyBlt(ppdev, prclDst, pco, psoSrc, psoMsk,
// pptlSrc, pptlMsk,
// pTableFore->logicop[0],
// pTableBack->logicop[0]))
// return(TRUE);
//@@END_DDKSPLIT
DISPDBG((WRNLVL, "DrvBitBlt: MaskCopyBlt "
"failed.calling engine_blt"));
goto engine_blt;
}
}
DISPDBG((DBGLVL, "rejected rop4 0x%x with mask", rop4));
}
else if ((pTableBack->logicop[0] == __GLINT_LOGICOP_NOOP) &&
(funcIndexFore <= PAT_FILL_1_BLT))
{
// The only time GDI will ask us to do a true rop4 using the brush
// mask is when the brush is 1bpp, and the background rop is AA
// (meaning it's a NOP).
DISPDBG((DBGLVL, "calling PatternFillRect for rop4 (fg %d, bg %d)",
pTableFore->logicop[0], pTableBack->logicop[0]));
if (PatternFillRect(ppdev, prclDst, pco, pbo, pptlBrush,
pTableFore->logicop[0], pTableBack->logicop[0]))
{
return(TRUE);
}
// fall through to engine_blt ...
}
DISPDBG((DBGLVL, "fell through to engine_blt"));
engine_blt:
if (glintInfo->GdiCantAccessFramebuffer)
{
// We require the original pointers to decide if we are talking to
// the screen or not.
psoSrc = psoSrcOrig;
psoDst = psoDstOrig;
hsurfSrcBitmap = (HSURF)NULL;
hsurfDstBitmap = (HSURF)NULL;
psoSrcBitmap = (SURFOBJ*)NULL;
psoDstBitmap = (SURFOBJ*)NULL;
// if source is the screen then pick out the bitmap surface
if (psoSrc && (psoSrc->iType != STYPE_BITMAP))
{
ppdev = (PPDEV)psoSrc->dhpdev;
pdsurfSrc = (DSURF *)psoSrc->dhsurf;
psoSrc = pdsurfSrc->pso;
if (pdsurfSrc->dt & DT_SCREEN)
{
RECTL rclTmp;
DISPDBG((DBGLVL, "Replacing src screen with bitmap Uploading"));
// We need to upload the area from the screen and use bitmaps
// to perform the operation
hsurfSrcBitmap = (HSURF) EngCreateBitmap(psoSrc->sizlBitmap, 0,
psoSrc->iBitmapFormat, 0, NULL);
if (hsurfSrcBitmap == NULL)
{
goto drvBitBltFailed;
}
if ((psoSrcBitmap = EngLockSurface(hsurfSrcBitmap)) == NULL)
{
goto drvBitBltFailed;
}
rclTmp.left = pptlSrc->x;
rclTmp.right = pptlSrc->x + prclDst->right - prclDst->left;
rclTmp.top = pptlSrc->y;
rclTmp.bottom = pptlSrc->y + prclDst->bottom - prclDst->top;
GLINT_DECL_INIT;
SETUP_PPDEV_OFFSETS(ppdev, pdsurfSrc);
VALIDATE_DD_CONTEXT;
// Call our function to perform image upload to tmp surface
if (!bUploadRect(ppdev, NULL, psoSrc, psoSrcBitmap,
pptlSrc, &rclTmp))
{
goto drvBitBltFailed;
}
psoSrc = psoSrcBitmap;
}
}
// if target is on screen then pick out the screen DIB surface
if (psoDst->iType != STYPE_BITMAP)
{
ppdev = (PPDEV)psoDst->dhpdev;
pdsurfDst = (DSURF *)psoDst->dhsurf;
psoDst = pdsurfDst->pso;
if (pdsurfDst->dt & DT_SCREEN)
{
POINTL ptlTmp;
DISPDBG((DBGLVL, "Replacing dst screen with bitmap Uploading"));
// We need to upload the area from the screen and use bitmaps
// to perform the operation
hsurfDstBitmap = (HSURF) EngCreateBitmap(psoDst->sizlBitmap, 0,
psoDst->iBitmapFormat, 0, NULL);
if (hsurfDstBitmap == NULL)
{
goto drvBitBltFailed;
}
if ((psoDstBitmap = EngLockSurface(hsurfDstBitmap)) == NULL)
{
goto drvBitBltFailed;
}
ptlTmp.x = prclDst->left;
ptlTmp.y = prclDst->top;
GLINT_DECL_INIT;
SETUP_PPDEV_OFFSETS(ppdev, pdsurfDst);
VALIDATE_DD_CONTEXT;
// Call our function to perform image upload to tmp surface
if (!bUploadRect(ppdev, pco, psoDst, psoDstBitmap,
&ptlTmp, prclDst))
{
goto drvBitBltFailed;
}
psoDst = psoDstBitmap;
}
}
#if DBG
if (psoDstBitmap)
{
DISPDBG((DBGLVL, "DrvBitBlt dest DIB, psoDst = 0x%08x:", psoDst));
DISPDBG((DBGLVL, "\tsize: %d x %d",
psoDst->sizlBitmap.cx,
psoDst->sizlBitmap.cy));
DISPDBG((DBGLVL, "\tcjBits = %d", psoDst->cjBits));
DISPDBG((DBGLVL, "\tpvBits = 0x%08x", psoDst->pvBits));
DISPDBG((DBGLVL, "\tpvScan0 = 0x%08x", psoDst->pvScan0));
DISPDBG((DBGLVL, "\tlDelta = %d", psoDst->lDelta));
DISPDBG((DBGLVL, "\tiBitmapFormat = %d", psoDst->iBitmapFormat));
DISPDBG((DBGLVL, "\tfjBitmap = %d", psoDst->fjBitmap));
}
if (psoSrcBitmap)
{
DISPDBG((DBGLVL, "DrvBitBlt source DIB, psoSrc = 0x%08x:", psoSrc));
DISPDBG((DBGLVL, "psoSrc != NULL"));
DISPDBG((DBGLVL, "\tsize: %d x %d",
psoSrc->sizlBitmap.cx, psoSrc->sizlBitmap.cy));
DISPDBG((DBGLVL, "\tcjBits = %d", psoSrc->cjBits));
DISPDBG((DBGLVL, "\tpvBits = 0x%08x", psoSrc->pvBits));
DISPDBG((DBGLVL, "\tpvScan0 = 0x%08x", psoSrc->pvScan0));
DISPDBG((DBGLVL, "\tlDelta = %d", psoSrc->lDelta));
DISPDBG((DBGLVL, "\tiBitmapFormat = %d", psoSrc->iBitmapFormat));
DISPDBG((DBGLVL, "\tfjBitmap = %d", psoSrc->fjBitmap));
}
#endif
DISPDBG((DBGLVL, "About to pass to GDI"));
if (pco && (pco->iDComplexity == DC_COMPLEX))
{
CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
}
// get GDI to do the blt
bRet = EngBitBlt(psoDst,
psoSrc,
psoMsk,
pco,
pxlo,
prclDst,
pptlSrc,
pptlMsk,
pbo,
pptlBrush,
rop4);
// if we need the nibbles replicated within each color component we must
// do it now since GDI will have destroyed one half of each byte.
if (psoDstBitmap)
{
POINTL ptlTmp;
// We need to upload the destination to the screen now.
ptlTmp.x = prclDst->left;
ptlTmp.y = prclDst->top;
DISPDBG((DBGLVL, "downloading Now"));
// We assume the dest upload was performed last,
// so the offsets will still be correct.
if (!SourceFillRect(ppdev, prclDst, pco, psoDstBitmap, NULL, &ptlTmp,
__GLINT_LOGICOP_COPY, __GLINT_LOGICOP_COPY))
{
goto drvBitBltFailed;
}
DISPDBG((DBGLVL, "downloading Done 0x%x 0x%x",
psoDstBitmap, hsurfDstBitmap));
// Now we can discard the destination bitmap too.
EngUnlockSurface(psoDstBitmap);
EngDeleteSurface(hsurfDstBitmap);
DISPDBG((DBGLVL, "Surface deleted"));
}
if (psoSrcBitmap)
{
// We can just discard the src bitmap if it was created.
EngUnlockSurface(psoSrcBitmap);
EngDeleteSurface(hsurfSrcBitmap);
}
DISPDBG((DBGLVL, "returning %d", bRet));
return(bRet);
drvBitBltFailed:
DISPDBG((WRNLVL, "drvBitBltFailed"));
if (psoSrcBitmap)
{
EngUnlockSurface(psoSrcBitmap);
}
if (hsurfSrcBitmap)
{
EngDeleteSurface(hsurfSrcBitmap);
}
if (psoDstBitmap)
{
EngUnlockSurface(psoDstBitmap);
}
if (hsurfDstBitmap)
{
EngDeleteSurface(hsurfDstBitmap);
}
return(FALSE);
}
simple_engine_blt:
// if target is on screen then pick out the screen DIB surface
if (psoDst->iType != STYPE_BITMAP)
{
ppdev = (PPDEV)psoDst->dhpdev;
pdsurfDst = (DSURF *)psoDst->dhsurf;
psoDst = pdsurfDst->pso;
}
// if source is the screen then pick out the bitmap surface
if (psoSrc && (psoSrc->iType != STYPE_BITMAP))
{
ppdev = (PPDEV)psoSrc->dhpdev;
pdsurfSrc = (DSURF *)psoSrc->dhsurf;
psoSrc = pdsurfSrc->pso;
}
// get GDI to do the blt
bRet = EngBitBlt(psoDst,
psoSrc,
psoMsk,
pco,
pxlo,
prclDst,
pptlSrc,
pptlMsk,
pbo,
pptlBrush,
rop4);
return(bRet);
}
/******************************Public*Routine******************************\
* BOOL PatternFillRect
*
* Fill a set of rectangles with either a solid color or a pattern. The pattern
* can be either monochrome or colored. If pbo is null then we are using a
* logicop which doesn't require a source. In this case we can set color to
* be anything we want in the low level routine. If pbo is not null then it
* can indicate either a solid color or a mono or colored pattern.
*
* Returns:
*
* True if we handled the fill, False if we want GDI to do it.
*
\**************************************************************************/
BOOL PatternFillRect(
PPDEV ppdev,
RECTL *prclDst,
CLIPOBJ *pco,
BRUSHOBJ *pbo,
POINTL *pptlBrush,
DWORD fgLogicop,
DWORD bgLogicop)
{
BYTE jClip;
BOOL bMore;
RBRUSH *prb;
RBRUSH_COLOR rbc;
CLIPENUM ce;
RECTL rcl;
LONG c;
GFNFILL *fillFn;
// if pbo is null then the caller will have ensured that the logic op
// doesn't need a source so we can do a solid fill. In that case rbc
// is irrelevant.
//
if ((pbo == NULL) || ((rbc.iSolidColor = pbo->iSolidColor) != -1))
{
DISPDBG((DBGLVL, "got a solid brush with color 0x%x "
"(fgrop %d, bgrop %d)",
rbc.iSolidColor, fgLogicop, bgLogicop));
fillFn = ppdev->pgfnFillSolid;
}
else
{
DISPDBG((DBGLVL, "Got a real patterned brush. pbo = 0x%x", pbo));
// got ourselves a real pattern so check it's realized
if ((prb = pbo->pvRbrush) == NULL)
{
DISPDBG((DBGLVL, "calling BRUSHOBJ_pvGetRbrush"));
prb = BRUSHOBJ_pvGetRbrush(pbo);
DISPDBG((DBGLVL, "BRUSHOBJ_pvGetRbrush returned 0x%x", prb));
if (prb == NULL)
{
return FALSE; // let the engine do it
}
}
if (prb->fl & RBRUSH_2COLOR)
{
DISPDBG((DBGLVL, "monochrome brush"));
fillFn = ppdev->pgfnFillPatMono;
}
else
{
DISPDBG((DBGLVL, "colored brush"));
fillFn = ppdev->pgfnFillPatColor;
}
rbc.prb = prb;
}
jClip = (pco == NULL) ? DC_TRIVIAL : pco->iDComplexity;
if (jClip == DC_TRIVIAL)
{
DISPDBG((DBGLVL, "trivial clip"));
(*fillFn)(ppdev, 1, prclDst, fgLogicop, bgLogicop, rbc, pptlBrush);
}
else if (jClip == DC_RECT)
{
DISPDBG((DBGLVL, "rect clip"));
if (bIntersect(prclDst, &pco->rclBounds, &rcl))
{
(*fillFn)(ppdev, 1, &rcl, fgLogicop, bgLogicop, rbc, pptlBrush);
}
}
else
{
DISPDBG((DBGLVL, "complex clip"));
CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
do {
bMore = CLIPOBJ_bEnum(pco, sizeof(ce), (ULONG *)&ce);
c = cIntersect(prclDst, ce.arcl, ce.c);
if (c != 0)
{
(*fillFn)(ppdev, c, ce.arcl, fgLogicop,
bgLogicop, rbc, pptlBrush);
}
} while (bMore);
}
return(TRUE);
}
/******************************Public*Routine******************************\
* BOOL SourceFillRect
*
* Fill a set of rectangles by downloading data from the source bitmap. This
* handles both memory-to-screen and screen-to-screen.
*
* Returns:
*
* True if we handled the fill, False if we want GDI to do it.
*
\**************************************************************************/
BOOL SourceFillRect(
PPDEV ppdev,
RECTL *prclDst,
CLIPOBJ *pco,
SURFOBJ *psoSrc,
XLATEOBJ *pxlo,
POINTL *pptlSrc,
ULONG fgLogicop,
ULONG bgLogicop)
{
BYTE jClip;
BOOL bMore;
CLIPENUM ce;
RECTL rcl;
LONG c;
GFNXFER *fillFn;
ULONG iSrcBitmapFormat;
DSURF *pdsurfSrc;
POINTL ptlSrc;
ULONG iDir;
GlintDataPtr glintInfo = (GlintDataPtr)(ppdev->glintInfo);
DISPDBG((DBGLVL, "SourceFillRect called"));
// we don't get into this routine unless dst is the screen
// if psoSrc was originally a DFB converted to a DIB, it must have been
// re-assigned to the DIV surface before calling this function.
jClip = (pco == NULL) ? DC_TRIVIAL : pco->iDComplexity;
if (psoSrc->iType != STYPE_BITMAP)
{
// screen to screen
pdsurfSrc = (DSURF*) psoSrc->dhsurf;
ASSERTDD(pdsurfSrc->dt & DT_SCREEN, "Expected screen source");
SETUP_PPDEV_SRC_OFFSETS(ppdev, pdsurfSrc);
ptlSrc.x = pptlSrc->x - (ppdev->xOffset - pdsurfSrc->poh->x);
ptlSrc.y = pptlSrc->y;
pptlSrc = &ptlSrc;
if ((pxlo == NULL) || (pxlo->flXlate & XO_TRIVIAL))
{
//////////////////////////////////////////////////
// Screen-to-screen blt with no translate
if (jClip == DC_TRIVIAL)
{
DISPDBG((DBGLVL, "trivial clip calling ppdev->pgfnCopyBlt"));
(*ppdev->pgfnCopyBlt)(ppdev, prclDst, 1, fgLogicop, pptlSrc,
prclDst);
}
else if (jClip == DC_RECT)
{
if (bIntersect(prclDst, &pco->rclBounds, &rcl))
{
DISPDBG((DBGLVL, "rect clip calling ppdev->pgfnCopyBlt"));
(*ppdev->pgfnCopyBlt)(ppdev, &rcl, 1, fgLogicop, pptlSrc,
prclDst);
}
}
else
{
// Don't forget that we'll have to draw the
// rectangles in the correct direction:
if (pptlSrc->y >= prclDst->top)
{
if (pptlSrc->x >= prclDst->left)
iDir = CD_RIGHTDOWN;
else
iDir = CD_LEFTDOWN;
}
else
{
if (pptlSrc->x >= prclDst->left)
iDir = CD_RIGHTUP;
else
iDir = CD_LEFTUP;
}
CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES,
iDir, 0);
do {
bMore = CLIPOBJ_bEnum(pco, sizeof(ce),
(ULONG*) &ce);
c = cIntersect(prclDst, ce.arcl, ce.c);
if (c != 0)
{
DISPDBG((DBGLVL, "complex clip calling "
"ppdev->pgfnCopyBlt"));
(*ppdev->pgfnCopyBlt)(ppdev,
ce.arcl,
c,
fgLogicop,
pptlSrc,
prclDst);
}
} while (bMore);
}
return TRUE;
}
}
else // (psoSrc->iType == STYPE_BITMAP)
{
// Image download
// here we can use a set of function pointers to handle the
// different cases. At the end loop through the cliprects
// calling the given function.
iSrcBitmapFormat = psoSrc->iBitmapFormat;
if (iSrcBitmapFormat == BMF_1BPP)
{
// do 1bpp download
fillFn = ppdev->pgfnXfer1bpp;
}
else if ((iSrcBitmapFormat == ppdev->iBitmapFormat) &&
((pxlo == NULL) || (pxlo->flXlate & XO_TRIVIAL)))
{
// native depth image download
fillFn = ppdev->pgfnXferImage;
}
else if (iSrcBitmapFormat == BMF_4BPP)
{
// 4 to 8,16,32 image download
DISPDBG((DBGLVL, "4bpp source download."));
fillFn = ppdev->pgfnXfer4bpp;
}
else if (iSrcBitmapFormat == BMF_8BPP)
{
// 8 to 8,16,32 image download
DISPDBG((DBGLVL, "8bpp source download."));
fillFn = ppdev->pgfnXfer8bpp;
}
else
{
DISPDBG((DBGLVL, "source has format %d, Punting to GDI",
iSrcBitmapFormat));
goto ReturnFalse;
}
if (jClip == DC_TRIVIAL)
{
DISPDBG((DBGLVL, "trivial clip image download"));
(*fillFn)(ppdev, prclDst, 1, fgLogicop, bgLogicop, psoSrc,
pptlSrc, prclDst, pxlo);
}
else if (jClip == DC_RECT)
{
if (bIntersect(prclDst, &pco->rclBounds, &rcl))
{
DISPDBG((DBGLVL, "rect clip image download"));
(*fillFn)(ppdev, &rcl, 1, fgLogicop, bgLogicop, psoSrc,
pptlSrc, prclDst, pxlo);
}
}
else
{
CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
do {
bMore = CLIPOBJ_bEnum(pco, sizeof(ce), (ULONG *)&ce);
c = cIntersect(prclDst, ce.arcl, ce.c);
if (c != 0)
{
DISPDBG((DBGLVL, "complex clip image download"));
(*fillFn)(ppdev, ce.arcl, c, fgLogicop, bgLogicop, psoSrc,
pptlSrc, prclDst, pxlo);
}
} while (bMore);
}
return TRUE;
}
ReturnFalse:
#if DBG
DISPDBG((WRNLVL, "SourceFillRect returning false"));
if ((pxlo != NULL) && !(pxlo->flXlate & XO_TRIVIAL))
DISPDBG((WRNLVL, "due to non-trivial xlate"));
#endif
return FALSE;
}
/******************************Public*Routine******************************\
* BOOL MaskCopyBlt
*
* We do a screen-to-screen blt through a mask. The source surface must not
* be a bitmap.
*
* Returns:
*
* True if we handled the copy, False if we want GDI to do it.
*
\**************************************************************************/
BOOL MaskCopyBlt(
PPDEV ppdev,
RECTL* prclDst,
CLIPOBJ* pco,
SURFOBJ* psoSrc,
SURFOBJ* psoMsk,
POINTL* pptlSrc,
POINTL* pptlMsk,
ULONG fgLogicop,
ULONG bgLogicop)
{
BYTE jClip;
BOOL bMore;
CLIPENUM ce;
RECTL rcl;
LONG c;
DSURF *pdsurfSrc;
POINTL ptlSrc;
DISPDBG((DBGLVL, "MaskCopyBlt called"));
if (psoSrc != NULL)
{
pdsurfSrc = (DSURF*) psoSrc->dhsurf;
ASSERTDD(pdsurfSrc->dt & DT_SCREEN, "Expected screen source");
ptlSrc.x = pptlSrc->x - (ppdev->xOffset - pdsurfSrc->poh->x);
ptlSrc.y = pptlSrc->y + pdsurfSrc->poh->y;
pptlSrc = &ptlSrc;
}
jClip = (pco == NULL) ? DC_TRIVIAL : pco->iDComplexity;
if (jClip == DC_TRIVIAL)
{
DISPDBG((DBGLVL, "trivial clip"));
(*ppdev->pgfnMaskCopyBlt)(ppdev, prclDst, 1, psoMsk, pptlMsk,
fgLogicop, bgLogicop, pptlSrc, prclDst);
}
else if (jClip == DC_RECT)
{
DISPDBG((DBGLVL, "rect clip"));
if (bIntersect(prclDst, &pco->rclBounds, &rcl))
{
(*ppdev->pgfnMaskCopyBlt)(ppdev, &rcl, 1, psoMsk, pptlMsk,
fgLogicop, bgLogicop, pptlSrc, prclDst);
}
}
else
{
DISPDBG((DBGLVL, "complex clip"));
CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
do {
bMore = CLIPOBJ_bEnum(pco, sizeof(ce), (ULONG *)&ce);
c = cIntersect(prclDst, ce.arcl, ce.c);
if (c != 0)
{
(*ppdev->pgfnMaskCopyBlt)(ppdev, ce.arcl, c, psoMsk, pptlMsk,
fgLogicop, bgLogicop, pptlSrc, prclDst);
}
} while (bMore);
}
return(TRUE);
}
/******************************Public*Routine******************************\
* BOOL PatSrcPatBlt
*
* Function to perform a rop3 by combining pattern and source fills. Does a
* pattern fill followed by a source fill. Optionally, it does a further
* pattern fill. Each fill has a separate logicop given in pLogicop.
*
* Returns:
*
* True if we handled the blt, False if we want GDI to do it.
*
\**************************************************************************/
BOOL PatSrcPatBlt(
PPDEV ppdev,
SURFOBJ *psoSrc,
CLIPOBJ *pco,
XLATEOBJ *pxlo,
RECTL *prclDst,
POINTL *pptlSrc,
BRUSHOBJ *pbo,
POINTL *pptlBrush,
RopTablePtr pTable)
{
ULONG iSrcBitmapFormat;
BOOL bRet;
DISPDBG((DBGLVL, "PatSrcPatBlt called"));
// ensure that all calls will pass before we do any rendering. The pattern
// fills will only fail if we can't realize the brush and that will be
// detected on the first call. So we only have to ensure that the source
// download will work since by the time we call the function we will
// already have done the first pattern fill and it's too late to back out.
DISPDBG((DBGLVL, "source is of type %s, depth %s",
(psoSrc->iType == STYPE_DEVBITMAP) ? "DEVBITMAP" :
(psoSrc->iType == STYPE_BITMAP) ? "BITMAP" : "SCREEN",
(psoSrc->iBitmapFormat == BMF_1BPP) ? "1" :
(psoSrc->iBitmapFormat == ppdev->iBitmapFormat) ? "native" :
"not supported"
));
// if both source and destination are the screen, we cannot handle this
// if they overlap since we may destroy the source when we do the first
// pattern fill.
//
if ((psoSrc->iType != STYPE_BITMAP) && (OVERLAP(prclDst, pptlSrc)))
{
DISPDBG((DBGLVL, "screen src and dst overlap"));
return(FALSE);
}
if (psoSrc->iType == STYPE_BITMAP)
{
iSrcBitmapFormat = psoSrc->iBitmapFormat;
if ((iSrcBitmapFormat == BMF_1BPP) ||
((iSrcBitmapFormat == ppdev->iBitmapFormat) &&
((pxlo == NULL) || (pxlo->flXlate & XO_TRIVIAL))))
{
goto Continue_It;
}
DISPDBG((DBGLVL, "failed due to bad source bitmap format"));
return(FALSE);
}
//@@BEGIN_DDKSPLIT
// else (psoSrc->iType != STYPE_BITMAP)
//@@END_DDKSPLIT
if ((pxlo != NULL) && !(pxlo->flXlate & XO_TRIVIAL))
{
DISPDBG((DBGLVL, "failed due to xlate with non-DIB source"));
return(FALSE);
}
Continue_It:
// as part of the B8 rop3 we are sometimes asked to xor with 0. As this is
// a noop I'll trap it.
//
if ((pbo->iSolidColor != 0) || (pTable->logicop[0] != __GLINT_LOGICOP_XOR))
{
// do the first pattern fill. It can only fail if a brush realize fails
//
DISPDBG((DBGLVL, "calling pattern fill function, rop %d",
pTable->logicop[0]));
if (!PatternFillRect(ppdev,
prclDst,
pco,
pbo,
pptlBrush,
pTable->logicop[0],
pTable->logicop[0]))
{
return(FALSE);
}
}
else
{
DISPDBG((DBGLVL, "ignoring xor with solid color 0"));
}
// download the source. We've already ensured that the call won't fail
DISPDBG((DBGLVL, "downloading source bitmap, rop %d",
pTable->logicop[1]));
bRet = SourceFillRect(ppdev,
prclDst,
pco,
psoSrc,
pxlo,
pptlSrc,
pTable->logicop[1],
pTable->logicop[1]);
ASSERTDD(bRet == TRUE, "PatSrcPatBlt: SourceFillRect returned FALSE");
if ((pTable->func_index == PAT_SRC_PAT_3_BLT) &&
((pbo->iSolidColor != 0) || (pTable->logicop[2] != __GLINT_LOGICOP_XOR)))
{
// fill with the pattern again. This won't fail because the first
// pattern fill succeeded.
DISPDBG((DBGLVL, "calling pattern fill function, rop %d",
pTable->logicop[2]));
bRet = PatternFillRect(ppdev,
prclDst,
pco,
pbo,
pptlBrush,
pTable->logicop[2],
pTable->logicop[2]);
ASSERTDD(bRet == TRUE,
"PatSrcPatBlt: second PatterFillRect returned FALSE");
}
#if DBG
else if (pTable->func_index == PAT_SRC_PAT_3_BLT)
{
DISPDBG((DBGLVL, "ignoring xor with solid color 0"));
}
#endif
DISPDBG((DBGLVL, "PatSrcPatBlt returning true"));
return(TRUE);
}
/******************************Public*Routine******************************\
* BOOL SrcPatSrcBlt
*
* Function to perform a rop3 by combining pattern and source fills. Does a
* source fill followed by a pattern fill. Optionally, it does a further
* source fill. Each fill has a separate logicop given in pLogicop.
*
* Returns:
*
* True if we handled the blt, False if we want GDI to do it.
*
\**************************************************************************/
BOOL SrcPatSrcBlt(
PPDEV ppdev,
SURFOBJ *psoSrc,
CLIPOBJ *pco,
XLATEOBJ *pxlo,
RECTL *prclDst,
POINTL *pptlSrc,
BRUSHOBJ *pbo,
POINTL *pptlBrush,
RopTablePtr pTable)
{
RBRUSH *prb;
BOOL bRet;
DISPDBG((DBGLVL, "SrcPatSrc called"));
// if both source and destination are the screen, we cannot handle it
// if they overlap since we may destroy the source with the first two
// operations before we get to the third one. If we're only a
// SRC_PAT_2_BLT then we're OK; SourceFillRect will handle
// the copy direction of the source fill properly.
//
if ((psoSrc->iType != STYPE_BITMAP) &&
(pTable->func_index == SRC_PAT_SRC_3_BLT) &&
(OVERLAP(prclDst, pptlSrc)))
{
return(FALSE);
}
// we must ensure that the pattern fill will succeed. It can only fail if
// we can't realize the brush so do it now.
//
if ((pbo != NULL) && (pbo->iSolidColor == -1))
{
if ((prb = pbo->pvRbrush) == NULL)
{
prb = BRUSHOBJ_pvGetRbrush(pbo);
if (prb == NULL)
{
return FALSE; // let the engine do it
}
}
}
// do the first source download. If it succeeds we know the second one
// will also work. If it fails we simply let the engine do it and we
// haven't upset anything (except we may have realized the brush without
// needing to).
//
DISPDBG((DBGLVL, "downloading source bitmap, rop %d",
pTable->logicop[0]));
if (!SourceFillRect(ppdev,
prclDst,
pco,
psoSrc,
pxlo,
pptlSrc,
pTable->logicop[0],
pTable->logicop[0]))
{
return(FALSE);
}
// fill with the pattern again. We've already ensured this will work.
DISPDBG((DBGLVL, "calling pattern fill function, rop %d",
pTable->logicop[1]));
bRet = PatternFillRect(ppdev,
prclDst,
pco,
pbo,
pptlBrush,
pTable->logicop[1],
pTable->logicop[1]);
ASSERTDD(bRet == TRUE, "SrcPatSrcBlt: PatternFillRect returned FALSE");
if (pTable->func_index == SRC_PAT_SRC_3_BLT)
{
// download the source again with the final logic op
DISPDBG((DBGLVL, "downloading source bitmap, rop %d",
pTable->logicop[2]));
bRet = SourceFillRect(ppdev,
prclDst,
pco,
psoSrc,
pxlo,
pptlSrc,
pTable->logicop[2],
pTable->logicop[2]);
ASSERTDD(bRet == TRUE,
"SrcPatSrcBlt: second SourceFillRect returned FALSE");
}
DISPDBG((DBGLVL, "SrcPatSrcBlt returning true"));
return(TRUE);
}
/******************************Public*Routine******************************\
* BOOL bUploadRect
*
* upload a rectangular area. clip to a given CLIPOBJ
*
* Returns:
*
* True if we handled the blt, otherwise False.
*
\**************************************************************************/
BOOL bUploadRect(
PPDEV ppdev,
CLIPOBJ *pco,
SURFOBJ *psoSrc,
SURFOBJ *psoDst,
POINTL *pptlSrc,
RECTL *prclDst)
{
BYTE jClip;
BOOL bMore;
CLIPENUM ce;
RECTL rcl;
LONG c;
// Perform the clipping and pass to a
// function to upload a list of rectangles.
DISPDBG((DBGLVL, "UploadRect called. Src %d %d To "
"dst (%d %d) --> (%d %d)",
pptlSrc->x, pptlSrc->y,
prclDst->left, prclDst->top,
prclDst->right, prclDst->bottom));
jClip = (pco == NULL) ? DC_TRIVIAL : pco->iDComplexity;
if (jClip == DC_TRIVIAL)
{
DISPDBG((DBGLVL, "trivial clip"));
ppdev->pgfnUpload(ppdev, 1, prclDst, psoDst, pptlSrc, prclDst);
}
else if (jClip == DC_RECT)
{
if (bIntersect(prclDst, &pco->rclBounds, &rcl))
{
DISPDBG((DBGLVL, "rect clip"));
ppdev->pgfnUpload(ppdev, 1, &rcl, psoDst, pptlSrc, prclDst);
}
}
else
{
DISPDBG((DBGLVL, "complex clip"));
CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
do {
bMore = CLIPOBJ_bEnum(pco, sizeof(ce), (ULONG *)&ce);
c = cIntersect(prclDst, ce.arcl, ce.c);
if (c != 0)
{
ppdev->pgfnUpload(ppdev, c, ce.arcl, psoDst, pptlSrc, prclDst);
}
} while (bMore);
}
return(TRUE);
}
/******************************Public*Routine******************************\
* BOOL bUploadBlt
*
* Returns:
*
* True if we handled the blt, otherwise False.
*
\**************************************************************************/
BOOL bUploadBlt(
PPDEV ppdev,
SURFOBJ *psoDst,
SURFOBJ *psoSrc,
SURFOBJ *psoMsk,
CLIPOBJ *pco,
XLATEOBJ *pxlo,
RECTL *prclDst,
POINTL *pptlSrc,
POINTL *pptlMsk,
BRUSHOBJ *pbo,
POINTL *pptlBrush,
ROP4 rop4)
{
BOOL bRet;
DISPDBG((DBGLVL, "bUploadBlt called"));
if ((rop4 == 0xCCCC) &&
((pxlo == NULL) || pxlo->flXlate & XO_TRIVIAL) &&
(psoDst->iBitmapFormat == ppdev->iBitmapFormat))
{
// We have no raster op to worry about, and no translations to perform.
// All we need to do is upload the data from GLINT and put it in the
// destination. Practically, most image uploads should be of this type.
return(bUploadRect(ppdev, pco, psoSrc, psoDst, pptlSrc, prclDst));
}
else
{
HSURF hsurfTmp;
SURFOBJ* psoTmp;
SIZEL sizl;
POINTL ptlTmp;
RECTL rclTmp;
// We cant upload directly to the destination, so we create a
// temporary bitmap, upload to this bitmap, then call EngBitBlt
// to do the hard work of the translation or raster op.
// Source point in tmp:
ptlTmp.x = 0;
ptlTmp.y = 0;
// Dest Area in tmp
rclTmp.left = 0;
rclTmp.top = 0;
rclTmp.right = prclDst->right - prclDst->left;
rclTmp.bottom = prclDst->bottom - prclDst->top;
// Work out size of tmp bitmap. We know left and top are zero.
sizl.cx = rclTmp.right;
sizl.cy = rclTmp.bottom;
// Create the bitmap
hsurfTmp = (HSURF) EngCreateBitmap(sizl, 0, ppdev->iBitmapFormat,
0, NULL);
if (hsurfTmp == NULL)
{
return(FALSE);
}
if ((psoTmp = EngLockSurface(hsurfTmp)) == NULL)
{
EngDeleteSurface(hsurfTmp);
return(FALSE);
}
// Call our function to perform image upload to tmp surface
bRet = bUploadRect(ppdev, NULL, psoSrc, psoTmp, pptlSrc, &rclTmp);
// Call GDI to blt from tmp surface to destination,
// doing all the work for us
if (bRet)
{
bRet = EngBitBlt(psoDst, psoTmp, psoMsk, pco, pxlo, prclDst,
&ptlTmp, pptlMsk, pbo, pptlBrush, rop4);
}
// Remove tmp surface
EngUnlockSurface(psoTmp);
EngDeleteSurface(hsurfTmp);
return(bRet);
}
}
/******************************Public*Routine******************************\
* BOOL DrvCopyBits
*
* Do fast bitmap copies.
*
* Note that GDI will (usually) automatically adjust the blt extents to
* adjust for any rectangular clipping, so we'll rarely see DC_RECT
* clipping in this routine (and as such, we don't bother special casing
* it).
*
* I'm not sure if the performance benefit from this routine is actually
* worth the increase in code size, since SRCCOPY BitBlts are hardly the
* most common drawing operation we'll get. But what the heck.
*
* On the S3 it's faster to do straight SRCCOPY bitblt's through the
* memory aperture than to use the data transfer register; as such, this
* routine is the logical place to put this special case.
*
\**************************************************************************/
BOOL DrvCopyBits(
SURFOBJ* psoDst,
SURFOBJ* psoSrc,
CLIPOBJ* pco,
XLATEOBJ* pxlo,
RECTL* prclDst,
POINTL* pptlSrc)
{
PDEV* ppdev;
DSURF* pdsurfSrc;
DSURF* pdsurfDst;
POINTL ptl;
RECTL rcl;
OH* pohSrc;
OH* pohDst;
CLIPENUM ce;
int cClipRects;
BOOL bMore, bRet, bCopyDone = FALSE;
GLINT_DECL_VARS;
DISPDBG((DBGLVL, "DrvCopyBits called"));
// We need to remove the pointer, but we dont know which surface is valid
// (if either).
if ((psoDst->iType != STYPE_BITMAP) &&
(((DSURF *)(psoDst->dhsurf))->dt & DT_SCREEN))
{
ppdev = (PDEV *)psoDst->dhpdev;
REMOVE_SWPOINTER(psoDst);
}
else if ((psoSrc->iType != STYPE_BITMAP) &&
(((DSURF *)(psoSrc->dhsurf))->dt & DT_SCREEN))
{
ppdev = (PDEV *)psoSrc->dhpdev;
REMOVE_SWPOINTER(psoSrc);
}
#if 0
else
{
// we shouldn't ever fall here, but we have this just as safeguard code
return EngCopyBits(psoDst, psoSrc, pco, pxlo, prclDst, pptlSrc);
}
#endif
#if !defined(_WIN64) && WNT_DDRAW
// Touch the source surface 1st and then the destination surface
vSurfUsed(psoSrc);
vSurfUsed(psoDst);
#endif
// Faster route to calling screen-to-screen BLT. The order in the if() is
// very important to avoid null pointers.
pdsurfDst = (DSURF*)psoDst->dhsurf;
pdsurfSrc = (DSURF*)psoSrc->dhsurf;
if ((psoDst->iType != STYPE_BITMAP) &&
(pdsurfDst->dt & DT_SCREEN) &&
psoSrc &&
(psoSrc->iType != STYPE_BITMAP) &&
(pdsurfSrc->dt & DT_SCREEN) &&
((pco == NULL) || (pco->iDComplexity == DC_TRIVIAL)) &&
((pxlo == NULL) || (pxlo->flXlate & XO_TRIVIAL)))
{
pohSrc = pdsurfSrc->poh;
pohDst = pdsurfDst->poh;
ptl.x = pptlSrc->x - (pohDst->x - pohSrc->x);
ptl.y = pptlSrc->y;
ppdev = (PDEV*) psoDst->dhpdev;
GLINT_DECL_INIT;
VALIDATE_DD_CONTEXT;
SETUP_PPDEV_SRC_AND_DST_OFFSETS(ppdev, pdsurfSrc, pdsurfDst);
(*ppdev->pgfnCopyBltCopyROP)(ppdev, prclDst, 1, __GLINT_LOGICOP_COPY,
&ptl, prclDst);
return(TRUE);
}
if ((psoDst->iType != STYPE_BITMAP) &&
psoSrc &&
(psoSrc->iType == STYPE_BITMAP))
{
// straight DIB->screen download with translate: see if
// we special-case it
ppdev = (PDEV*)psoDst->dhpdev;
if (((pxlo == NULL) || (pxlo->flXlate & XO_TRIVIAL)) &&
(psoSrc->iBitmapFormat == psoDst->iBitmapFormat) &&
ppdev->pgfnCopyXferImage)
{
// native depth download
pdsurfDst = (DSURF*)psoDst->dhsurf;
// only accelerate when downloading to the framebuffer
if (pdsurfDst->dt & DT_SCREEN)
{
GLINT_DECL_INIT;
VALIDATE_DD_CONTEXT;
pohDst = pdsurfDst->poh;
SETUP_PPDEV_OFFSETS(ppdev, pdsurfDst);
if(pco == NULL || pco->iDComplexity == DC_TRIVIAL)
{
ppdev->pgfnCopyXferImage(ppdev, psoSrc, pptlSrc, prclDst,
prclDst, 1);
}
else if(pco->iDComplexity == DC_RECT)
{
if (bIntersect(prclDst, &pco->rclBounds, &rcl))
{
ppdev->pgfnCopyXferImage(ppdev, psoSrc, pptlSrc,
prclDst, &rcl, 1);
}
}
else //(pco->iDComplexity == DC_COMPLEX)
{
CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
do
{
bMore = CLIPOBJ_bEnum(pco, sizeof ce, (ULONG *)&ce);
cClipRects = cIntersect(prclDst, ce.arcl, ce.c);
if(cClipRects)
{
ppdev->pgfnCopyXferImage(ppdev, psoSrc, pptlSrc,
prclDst, ce.arcl,
cClipRects);
}
}
while(bMore);
}
return(TRUE);
}
}
else if (((pxlo == NULL) || (pxlo->flXlate & XO_TRIVIAL)) &&
(psoSrc->iBitmapFormat == BMF_24BPP) &&
ppdev->pgfnCopyXfer24bpp)
{
pdsurfDst = (DSURF*)psoDst->dhsurf;
// only accelerate when downloading to the framebuffer
if (pdsurfDst->dt & DT_SCREEN)
{
GLINT_DECL_INIT;
VALIDATE_DD_CONTEXT;
pohDst = pdsurfDst->poh;
SETUP_PPDEV_OFFSETS(ppdev, pdsurfDst);
if(pco == NULL || pco->iDComplexity == DC_TRIVIAL)
{
ppdev->pgfnCopyXfer24bpp(ppdev, psoSrc, pptlSrc, prclDst,
prclDst, 1);
}
else if(pco->iDComplexity == DC_RECT)
{
if (bIntersect(prclDst, &pco->rclBounds, &rcl))
{
ppdev->pgfnCopyXfer24bpp(ppdev, psoSrc, pptlSrc,
prclDst, &rcl, 1);
}
}
else // (pco->iDComplexity == DC_COMPLEX)
{
CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
do {
bMore = CLIPOBJ_bEnum(pco, sizeof ce, (ULONG *)&ce);
cClipRects = cIntersect(prclDst, ce.arcl, ce.c);
if(cClipRects)
{
ppdev->pgfnCopyXfer24bpp(ppdev, psoSrc, pptlSrc,
prclDst, ce.arcl,
cClipRects);
}
} while(bMore);
}
return(TRUE);
}
}
else if (pxlo && (pxlo->flXlate & XO_TABLE) &&
(psoSrc->iBitmapFormat == BMF_8BPP) &&
(pxlo->cEntries == 256) && ppdev->pgfnCopyXfer8bpp)
{
pdsurfDst = (DSURF*)psoDst->dhsurf;
if (pdsurfDst->dt & DT_SCREEN)
{
BOOL bRenderLargeBitmap;
GLINT_DECL_INIT;
VALIDATE_DD_CONTEXT;
pohDst = pdsurfDst->poh;
SETUP_PPDEV_OFFSETS(ppdev, pdsurfDst);
bRenderLargeBitmap = (ppdev->pgfnCopyXfer8bppLge != NULL);
if ((pco == NULL) || (pco->iDComplexity == DC_TRIVIAL))
{
if(bRenderLargeBitmap)
{
ppdev->pgfnCopyXfer8bppLge(ppdev, psoSrc, pptlSrc,
prclDst, prclDst, 1, pxlo);
}
else
{
ppdev->pgfnCopyXfer8bpp(ppdev, psoSrc, pptlSrc, prclDst,
prclDst, 1, pxlo);
}
}
else if (pco->iDComplexity == DC_RECT)
{
if (bIntersect(prclDst, &pco->rclBounds, &rcl))
{
if(bRenderLargeBitmap)
{
ppdev->pgfnCopyXfer8bppLge(ppdev, psoSrc, pptlSrc,
prclDst, &rcl, 1, pxlo);
}
else
{
ppdev->pgfnCopyXfer8bpp(ppdev, psoSrc, pptlSrc,
prclDst, &rcl, 1, pxlo);
}
}
}
else // (pco->iDComplexity == DC_COMPLEX)
{
CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
do {
bMore = CLIPOBJ_bEnum(pco, sizeof ce, (ULONG *)&ce);
cClipRects = cIntersect(prclDst, ce.arcl, ce.c);
if(cClipRects)
{
if(bRenderLargeBitmap)
{
ppdev->pgfnCopyXfer8bppLge(ppdev, psoSrc,
pptlSrc, prclDst,
ce.arcl, cClipRects,
pxlo);
}
else
{
ppdev->pgfnCopyXfer8bpp(ppdev, psoSrc, pptlSrc,
prclDst, ce.arcl,
cClipRects, pxlo);
}
}
} while(bMore);
}
return(TRUE);
}
}
else if (pxlo && (pxlo->flXlate & XO_TABLE) &&
(psoSrc->iBitmapFormat == BMF_4BPP) &&
(pxlo->cEntries == 16) && ppdev->pgfnCopyXfer4bpp)
{
pdsurfDst = (DSURF*)psoDst->dhsurf;
if (pdsurfDst->dt & DT_SCREEN)
{
GLINT_DECL_INIT;
VALIDATE_DD_CONTEXT;
pohDst = pdsurfDst->poh;
SETUP_PPDEV_OFFSETS(ppdev, pdsurfDst);
if ((pco == NULL) || (pco->iDComplexity == DC_TRIVIAL))
{
ppdev->pgfnCopyXfer4bpp(ppdev, psoSrc, pptlSrc, prclDst,
prclDst, 1, pxlo);
}
else if (pco->iDComplexity == DC_RECT)
{
if (bIntersect(prclDst, &pco->rclBounds, &rcl))
{
ppdev->pgfnCopyXfer4bpp(ppdev, psoSrc, pptlSrc,
prclDst, &rcl, 1, pxlo);
}
}
else // (pco->iDComplexity == DC_COMPLEX)
{
CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
do {
bMore = CLIPOBJ_bEnum(pco, sizeof ce, (ULONG *)&ce);
cClipRects = cIntersect(prclDst, ce.arcl, ce.c);
if(cClipRects)
{
ppdev->pgfnCopyXfer4bpp(ppdev, psoSrc, pptlSrc,
prclDst, ce.arcl,
cClipRects, pxlo);
}
}
while(bMore);
}
return(TRUE);
}
}
//@@BEGIN_DDKSPLIT
#if DBG && 0
else if (psoSrc->iBitmapFormat != BMF_1BPP)
{
SIZEL sizl;
int cEntries = pxlo == 0 ? 0 : pxlo->cEntries;
int flXlate = pxlo == 0 ? 0 : pxlo->flXlate;
int iDComplexity = pco == 0 ? 0 : pco->iDComplexity;
sizl.cx = prclDst->right - prclDst->left;
sizl.cy = prclDst->bottom - prclDst->top;
DISPDBG((ERRLVL, "DrvCopyBits() unhandled copy download "
"bmf(%xh) pxlo(%p, cEntries=%03xh flXlate=%xh) "
"pco(%p, iDComplexity=%02xh), cxcy(%03xh,%03xh)",
psoSrc->iBitmapFormat, pxlo, cEntries, flXlate,
pco, iDComplexity, sizl.cx, sizl.cy));
}
#endif
//@@END_DDKSPLIT
}
// DrvCopyBits is a fast-path for SRCCOPY blts. But it can still be
// pretty complicated: there can be translates, clipping, RLEs,
// bitmaps that aren't the same format as the screen, plus
// screen-to-screen, DIB-to-screen or screen-to-DIB operations,
// not to mention DFBs (device format bitmaps).
//
// Rather than making this routine almost as big as DrvBitBlt, I'll
// handle here only the speed-critical cases, and punt the rest to
// our DrvBitBlt routine.
//
// We'll try to handle anything that doesn't involve clipping:
if (((pco) && (pco->iDComplexity != DC_TRIVIAL)) ||
((pxlo) && (! (pxlo->flXlate & XO_TRIVIAL))))
{
/////////////////////////////////////////////////////////////////
// A DrvCopyBits is after all just a simplified DrvBitBlt:
DISPDBG((DBGLVL, "DrvCopyBits fell through to DrvBitBlt"));
return(DrvBitBlt(psoDst, psoSrc, NULL, pco, pxlo, prclDst, pptlSrc,
NULL, NULL, NULL, 0x0000CCCC));
}
//@@BEGIN_DDKSPLIT
// Screen to screen case has already been handled at the very beginning.
//@@END_DDKSPLIT
DISPDBG((DBGLVL, "trivial clip and xlate"));
if ((psoDst->iType != STYPE_BITMAP) && (pdsurfDst->dt & DT_SCREEN))
{
// We know the destination is either a DFB or the screen:
DISPDBG((DBGLVL, "Destination is not a bitmap"));
GLINT_DECL_INIT;
VALIDATE_DD_CONTEXT;
// See if the source is a plain DIB:
ASSERTDD(((psoSrc->iType == STYPE_BITMAP) || (pdsurfSrc->dt & DT_DIB)),
"Screen-to-screen case should have been handled");
//@@BEGIN_DDKSPLIT
// Ah ha, the source is a DFB that's really a DIB.
//@@END_DDKSPLIT
if (psoSrc->iBitmapFormat == ppdev->iBitmapFormat)
{
if (pdsurfSrc) {
DISPDBG((DBGLVL, "source is DFB that's really a DIB"));
psoSrc = pdsurfSrc->pso;
ppdev = pdsurfSrc->ppdev;
}
//////////////////////////////////////////////////////
// DIB-to-screen
ASSERTDD((psoDst->iType != STYPE_BITMAP) &&
(pdsurfDst->dt & DT_SCREEN) &&
(psoSrc->iType == STYPE_BITMAP) &&
(psoSrc->iBitmapFormat == ppdev->iBitmapFormat),
"Should be a DIB-to-screen case");
SETUP_PPDEV_OFFSETS(ppdev, pdsurfDst);
DISPDBG((DBGLVL, "doing DIB-to-screen transfer"));
(*ppdev->pgfnXferImage)(ppdev,
prclDst,
1,
__GLINT_LOGICOP_COPY,
__GLINT_LOGICOP_COPY,
psoSrc,
pptlSrc,
prclDst,
NULL);
bRet = TRUE;
bCopyDone = TRUE;
}
}
else // The destination is a DIB
{
DISPDBG((DBGLVL, "Destination is a bitmap"));
if (pdsurfDst)
{
psoDst = pdsurfDst->pso;
}
if (pdsurfSrc)
{
ppdev = pdsurfSrc->ppdev;
}
if ((ppdev != NULL) &&
(psoDst->iBitmapFormat == ppdev->iBitmapFormat) &&
(psoSrc->iType != STYPE_BITMAP) &&
(pdsurfSrc->dt & DT_SCREEN))
{
VOID pxrxMemUpload (PDEV*, LONG, RECTL*, SURFOBJ*, POINTL*, RECTL*);
GLINT_DECL_INIT;
SETUP_PPDEV_OFFSETS(ppdev, pdsurfSrc);
// Perform the upload.
VALIDATE_DD_CONTEXT;
DISPDBG((DBGLVL, "doing Screen-to-DIB image upload"));
//(*ppdev->pgfnUpload)
pxrxMemUpload
(ppdev, 1, prclDst, psoDst,
pptlSrc, prclDst);
bRet = TRUE;
bCopyDone = TRUE;
}
}
//@@BEGIN_DDKSPLIT
// NB: we must never get here if the dest is actually the screen (ie. if
// pdsurfDst->dt & DT_SCREEN and we've changed psoDst to the bypass
// bitmap). This is because we don't handle nibble replication here which
// we must do if GDI ever draws directly to the framebuffer. We don't SYNC
// here because we may be doing a true DIB-to-DIB. We do a SYNC if
// necessary before jumping here. Currently this happens only if the src
// is a DFB.
//
//@@END_DDKSPLIT
if (! bCopyDone)
{
if (pdsurfDst)
{
psoDst = pdsurfDst->pso;
}
if (pdsurfSrc)
{
psoSrc = pdsurfSrc->pso;
}
ASSERTDD((psoDst->iType == STYPE_BITMAP) &&
(psoSrc->iType == STYPE_BITMAP),
"Both surfaces should be DIBs to call EngCopyBits");
DISPDBG((DBGLVL, "DrvCopyBits fell through to EngCopyBits"));
bRet = EngCopyBits(psoDst, psoSrc, pco, pxlo, prclDst, pptlSrc);
}
/////////////////////////////////////////////////////
// Put It Back Into Off-screen?
//
// We take this opportunity to decide if we want to
// put the DIB back into off-screen memory. This is
// a pretty good place to do it because we have to
// copy the bits to some portion of the screen,
// anyway. So we would incur only an extra screen-to-
// screen blt at this time, much of which will be
// over-lapped with the CPU.
//
// The simple approach we have taken is to move a DIB
// back into off-screen memory only if there's already
// room -- we won't throw stuff out to make space
// (because it's tough to know what ones to throw out,
// and it's easy to get into thrashing scenarios).
//
// Because it takes some time to see if there's room
// in off-screen memory, we only check one in
// HEAP_COUNT_DOWN times if there's room. To bias
// in favour of bitmaps that are often blt, the
// counters are reset every time any space is freed
// up in off-screen memory. We also don't bother
// checking if no space has been freed since the
// last time we checked for this DIB.
if ((! pdsurfSrc) || (pdsurfSrc->dt & DT_SCREEN))
{
return (bRet);
}
if (pdsurfSrc->iUniq == ppdev->iHeapUniq)
{
if (--pdsurfSrc->cBlt == 0)
{
DISPDBG((DBGLVL, "putting src back "
"into off-screen"));
// Failure is safe here
bMoveDibToOffscreenDfbIfRoom(ppdev, pdsurfSrc);
}
}
else
{
// Some space was freed up in off-screen memory,
// so reset the counter for this DFB:
pdsurfSrc->iUniq = ppdev->iHeapUniq;
pdsurfSrc->cBlt = HEAP_COUNT_DOWN;
}
return (bRet);
}
#if defined(_X86_)
/******************************Public*Table********************************\
* BYTE gajLeftMask[] and BYTE gajRightMask[]
*
* Edge tables for vXferScreenTo1bpp.
\**************************************************************************/
BYTE gajLeftMask[] = { 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01 };
BYTE gajRightMask[] = { 0xff, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe };
/******************************Public*Routine******************************\
* VOID DoScreenToMono
*
* This function works out the clip list and then calls vXferScreenTo1bpp()
* to do ye hard work.
*
\**************************************************************************/
BOOL DoScreenToMono(
PDEV* ppdev,
RECTL *prclDst,
CLIPOBJ *pco,
SURFOBJ* psoSrc, // Source surface
SURFOBJ* psoDst, // Destination surface
POINTL* pptlSrc, // Original unclipped source point
XLATEOBJ* pxlo) // Provides colour-compressions information
{
RECTL rcl;
if ((pco == NULL) || (pco->iDComplexity == DC_TRIVIAL))
{
DISPDBG((DBGLVL, "DoScreenToMono: Trivial clipping"));
vXferScreenTo1bpp(ppdev, 1, prclDst, 0, psoSrc,
psoDst, pptlSrc, prclDst, pxlo);
}
else if (pco->iDComplexity == DC_RECT)
{
DISPDBG((DBGLVL, "DoScreenToMono: rect clipping"));
if (bIntersect(prclDst, &pco->rclBounds, &rcl))
{
vXferScreenTo1bpp(ppdev, 1, &rcl, 0, psoSrc,
psoDst, pptlSrc, prclDst, pxlo);
}
}
else // (pco->iDComplexity == DC_COMPLEX)
{
CLIPENUM ce;
int cClipRects;
BOOL bMore;
DISPDBG((DBGLVL, "DoScreenToMono: complex clipping"));
CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
do {
bMore = CLIPOBJ_bEnum(pco, sizeof ce, (ULONG *)&ce);
cClipRects = cIntersect(prclDst, ce.arcl, ce.c);
if(cClipRects)
{
vXferScreenTo1bpp (ppdev, cClipRects, ce.arcl, 0, psoSrc,
psoDst, pptlSrc, prclDst, pxlo);
}
} while(bMore);
}
return(TRUE);
}
/******************************Public*Routine******************************\
* VOID vXferScreenTo1bpp
*
* Performs a SRCCOPY transfer from the screen (when it's 8bpp) to a 1bpp
* bitmap.
*
\**************************************************************************/
VOID vXferScreenTo1bpp( // Type FNXFER
PDEV* ppdev,
LONG c, // Count of rectangles, can't be zero
RECTL* prcl, // List of destination rectangles, in relative
// coordinates
ULONG ulHwMix, // Not used
SURFOBJ* psoSrc, // Source surface
SURFOBJ* psoDst, // Destination surface
POINTL* pptlSrc, // Original unclipped source point
RECTL* prclDst, // Original unclipped destination rectangle
XLATEOBJ* pxlo) // Provides colour-compressions information
{
LONG cjPelSize;
VOID* pfnCompute;
SURFOBJ soTmp;
ULONG* pulXlate;
ULONG ulForeColor;
RECTL rclTmp;
BYTE* pjDst;
BYTE jLeftMask;
BYTE jRightMask;
BYTE jNotLeftMask;
BYTE jNotRightMask;
LONG cjMiddle;
LONG lDstDelta;
LONG lSrcDelta;
LONG cyTmpScans;
LONG cyThis;
LONG cyToGo;
ASSERTDD(c > 0, "Can't handle zero rectangles");
ASSERTDD(psoDst->iBitmapFormat == BMF_1BPP, "Only 1bpp destinations");
ASSERTDD(TMP_BUFFER_SIZE >= (ppdev->cxMemory * ppdev->cjPelSize),
"Temp buffer has to be larger than widest possible scan");
soTmp = *psoSrc;
// When the destination is a 1bpp bitmap, the foreground colour
// maps to '1', and any other colour maps to '0'.
if (ppdev->iBitmapFormat == BMF_8BPP)
{
// When the source is 8bpp or less, we find the forground colour
// by searching the translate table for the only '1':
pulXlate = pxlo->pulXlate;
while (*pulXlate != 1)
{
pulXlate++;
}
ulForeColor = pulXlate - pxlo->pulXlate;
}
else
{
ASSERTDD((ppdev->iBitmapFormat == BMF_16BPP) ||
(ppdev->iBitmapFormat == BMF_32BPP),
"This routine only supports 8, 16 or 32bpp");
// When the source has a depth greater than 8bpp, the foreground
// colour will be the first entry in the translate table we get
// from calling 'piVector':
pulXlate = XLATEOBJ_piVector(pxlo);
ulForeColor = 0;
if (pulXlate != NULL) // This check isn't really needed...
{
ulForeColor = pulXlate[0];
}
}
// We use the temporary buffer to keep a copy of the source
// rectangle:
soTmp.pvScan0 = ppdev->pvTmpBuffer;
do {
pjDst = (BYTE*) psoDst->pvScan0 + (prcl->top * psoDst->lDelta)
+ (prcl->left >> 3);
cjPelSize = ppdev->cjPelSize;
soTmp.lDelta = (((prcl->right + 7L) & ~7L) - (prcl->left & ~7L))
* cjPelSize;
// Our temporary buffer, into which we read a copy of the source,
// may be smaller than the source rectangle. In that case, we
// process the source rectangle in batches.
//
// cyTmpScans is the number of scans we can do in each batch.
// cyToGo is the total number of scans we have to do for this
// rectangle.
//
// We take the buffer size less four so that the right edge case
// can safely read one dword past the end:
cyTmpScans = (TMP_BUFFER_SIZE - 4) / soTmp.lDelta;
cyToGo = prcl->bottom - prcl->top;
ASSERTDD(cyTmpScans > 0, "Buffer too small for largest possible scan");
// Initialize variables that don't change within the batch loop:
rclTmp.top = 0;
rclTmp.left = prcl->left & 7L;
rclTmp.right = (prcl->right - prcl->left) + rclTmp.left;
// Note that we have to be careful with the right mask so that it
// isn't zero. A right mask of zero would mean that we'd always be
// touching one byte past the end of the scan (even though we
// wouldn't actually be modifying that byte), and we must never
// access memory past the end of the bitmap (because we can access
// violate if the bitmap end is exactly page-aligned).
jLeftMask = gajLeftMask[rclTmp.left & 7];
jRightMask = gajRightMask[rclTmp.right & 7];
cjMiddle = ((rclTmp.right - 1) >> 3) - (rclTmp.left >> 3) - 1;
if (cjMiddle < 0)
{
// The blt starts and ends in the same byte:
jLeftMask &= jRightMask;
jRightMask = 0;
cjMiddle = 0;
}
jNotLeftMask = ~jLeftMask;
jNotRightMask = ~jRightMask;
lDstDelta = psoDst->lDelta - cjMiddle - 2;
// Delta from the end of the destination
// to the start on the next scan, accounting
// for 'left' and 'right' bytes
lSrcDelta = soTmp.lDelta - ((8 * (cjMiddle + 2)) * cjPelSize);
// Compute source delta for special cases
// like when cjMiddle gets bumped up to '0',
// and to correct aligned cases
do {
// This is the loop that breaks the source rectangle into
// manageable batches.
cyThis = cyTmpScans;
if( cyToGo < cyThis )
{
cyThis = cyToGo;
}
cyToGo -= cyThis;
rclTmp.bottom = cyThis;
ppdev->pgfnUpload( ppdev, 1, &rclTmp, &soTmp, pptlSrc, &rclTmp );
pptlSrc->y += cyThis;
_asm {
mov eax,ulForeColor ;eax = foreground colour
;ebx = temporary storage
;ecx = count of middle dst bytes
;dl = destination byte accumulator
;dh = temporary storage
mov esi,soTmp.pvScan0 ;esi = source pointer
mov edi,pjDst ;edi = destination pointer
; Figure out the appropriate compute routine:
mov ebx,cjPelSize
mov pfnCompute,offset Compute_Destination_Byte_From_8bpp
dec ebx
jz short Do_Left_Byte
mov pfnCompute,offset Compute_Destination_Byte_From_16bpp
dec ebx
jz short Do_Left_Byte
mov pfnCompute,offset Compute_Destination_Byte_From_32bpp
Do_Left_Byte:
call pfnCompute
and dl,jLeftMask
mov dh,jNotLeftMask
and dh,[edi]
or dh,dl
mov [edi],dh
inc edi
mov ecx,cjMiddle
dec ecx
jl short Do_Right_Byte
Do_Middle_Bytes:
call pfnCompute
mov [edi],dl
inc edi
dec ecx
jge short Do_Middle_Bytes
Do_Right_Byte:
call pfnCompute
and dl,jRightMask
mov dh,jNotRightMask
and dh,[edi]
or dh,dl
mov [edi],dh
inc edi
add edi,lDstDelta
add esi,lSrcDelta
dec cyThis
jnz short Do_Left_Byte
mov pjDst,edi ;save for next batch
jmp All_Done
Compute_Destination_Byte_From_8bpp:
mov bl,[esi]
sub bl,al
cmp bl,1
adc dl,dl ;bit 0
mov bl,[esi+1]
sub bl,al
cmp bl,1
adc dl,dl ;bit 1
mov bl,[esi+2]
sub bl,al
cmp bl,1
adc dl,dl ;bit 2
mov bl,[esi+3]
sub bl,al
cmp bl,1
adc dl,dl ;bit 3
mov bl,[esi+4]
sub bl,al
cmp bl,1
adc dl,dl ;bit 4
mov bl,[esi+5]
sub bl,al
cmp bl,1
adc dl,dl ;bit 5
mov bl,[esi+6]
sub bl,al
cmp bl,1
adc dl,dl ;bit 6
mov bl,[esi+7]
sub bl,al
cmp bl,1
adc dl,dl ;bit 7
add esi,8 ;advance the source
ret
Compute_Destination_Byte_From_16bpp:
mov bx,[esi]
sub bx,ax
cmp bx,1
adc dl,dl ;bit 0
mov bx,[esi+2]
sub bx,ax
cmp bx,1
adc dl,dl ;bit 1
mov bx,[esi+4]
sub bx,ax
cmp bx,1
adc dl,dl ;bit 2
mov bx,[esi+6]
sub bx,ax
cmp bx,1
adc dl,dl ;bit 3
mov bx,[esi+8]
sub bx,ax
cmp bx,1
adc dl,dl ;bit 4
mov bx,[esi+10]
sub bx,ax
cmp bx,1
adc dl,dl ;bit 5
mov bx,[esi+12]
sub bx,ax
cmp bx,1
adc dl,dl ;bit 6
mov bx,[esi+14]
sub bx,ax
cmp bx,1
adc dl,dl ;bit 7
add esi,16 ;advance the source
ret
Compute_Destination_Byte_From_32bpp:
mov ebx,[esi]
sub ebx,eax
cmp ebx,1
adc dl,dl ;bit 0
mov ebx,[esi+4]
sub ebx,eax
cmp ebx,1
adc dl,dl ;bit 1
mov ebx,[esi+8]
sub ebx,eax
cmp ebx,1
adc dl,dl ;bit 2
mov ebx,[esi+12]
sub ebx,eax
cmp ebx,1
adc dl,dl ;bit 3
mov ebx,[esi+16]
sub ebx,eax
cmp ebx,1
adc dl,dl ;bit 4
mov ebx,[esi+20]
sub ebx,eax
cmp ebx,1
adc dl,dl ;bit 5
mov ebx,[esi+24]
sub ebx,eax
cmp ebx,1
adc dl,dl ;bit 6
mov ebx,[esi+28]
sub ebx,eax
cmp ebx,1
adc dl,dl ;bit 7
add esi,32 ;advance the source
ret
All_Done:
}
} while (cyToGo > 0);
prcl++;
} while (--c != 0);
}
#endif // defined(_X86_)
#if (_WIN32_WINNT >= 0x500)
//*****************************************************************************
// FUNC: DrvGradientFill
// ARGS: psoDst (I) - destination surface
// pco (I) - destination clipping
// pxlo (I) - color translation for pVertex
// pVertex (I) - array of trivertex (x,y,color) coordinates
// nVertex (I) - size of pVertex
// pMesh (I) - array of GRADIENT_RECT or GRADIENT_TRIANGLE structures
// that define the connectivity of pVertex points
// nMesh (I) - size of pMesh
// prclExtents (I) - the bounding rectangle
// pptlDitherOrg (I) - unused
// ulMode (I) - specifies the fill type (rectangular or triangular)and
// direction
// RETN: TRUE if successful
//-----------------------------------------------------------------------------
// Performs a Gouraud-shaded fill for an array of rectangles or triangles.
// Rectangles can be horizontally or vertically shaded (i.e. we only step the
// color DDA in one direction).
//*****************************************************************************
BOOL DrvGradientFill(
SURFOBJ *psoDst,
CLIPOBJ *pco,
XLATEOBJ *pxlo,
TRIVERTEX *pVertex,
ULONG nVertex,
PVOID pMesh,
ULONG nMesh,
RECTL *prclExtents,
POINTL *pptlDitherOrg,
ULONG ulMode)
{
SURFOBJ *psoDstOrig = psoDst; // destination surface DIB
PDEV *ppdev;
DSURF *pdsurf;
OH *poh;
SURFOBJ *psoDIBDst;
BOOL bSuccess = FALSE;
GLINT_DECL_VARS;
DISPDBG((DBGLVL, "DrvGradientFill entered"));
ppdev = (PDEV *)psoDst->dhpdev;
pdsurf = (DSURF *)psoDst->dhsurf;
GLINT_DECL_INIT;
if(ppdev->pgfnGradientFillRect == NULL)
{
// we don't accelerate this function
goto punt;
}
if(psoDst->iType == STYPE_BITMAP)
{
DISPDBG((4, "DrvGradientFill: destination is a DIB - "
"punt back to GDI"));
goto punt;
}
if((pdsurf->dt & DT_SCREEN) == 0)
{
DISPDBG((DBGLVL, "DrvGradientFill: destination is a DFB "
"now in host memory - punt back to GDI"));
goto punt;
}
if(ulMode == GRADIENT_FILL_TRIANGLE)
{
DISPDBG((DBGLVL, "DrvGradientFill: don't support triangular fills"));
goto punt;
}
//@@BEGIN_DDKSPLIT
/* ignore pxlo: source is always in 16:16:16:16 format
if(pxlo->iDstType)
{
// xlate object is valid
if((pxlo != NULL) && !(pxlo->flXlate & XO_TRIVIAL))
{
DISPDBG((DBGLVL, "DrvGradientFill: "
"don't support color translation"));
goto punt;
}
}
*/
//@@END_DDKSPLIT
VALIDATE_DD_CONTEXT;
poh = pdsurf->poh;
SETUP_PPDEV_OFFSETS(ppdev, pdsurf);
if ((pco == NULL) || (pco->iDComplexity == DC_TRIVIAL))
{
DISPDBG((DBGLVL, "DrvGradientFill: trivial clipping"));
bSuccess = ppdev->pgfnGradientFillRect(ppdev,
pVertex,
nVertex,
(GRADIENT_RECT *)pMesh,
nMesh,
ulMode,
prclExtents,
1);
}
else if (pco->iDComplexity == DC_RECT)
{
RECTL rcl;
DISPDBG((DBGLVL, "DrvGradientFill: rectangular clipping"));
bSuccess = !bIntersect(prclExtents, &pco->rclBounds, &rcl);
if(!bSuccess)
{
bSuccess = ppdev->pgfnGradientFillRect(ppdev,
pVertex,
nVertex,
(GRADIENT_RECT *)pMesh,
nMesh,
ulMode,
&rcl,
1);
}
}
else
{
CLIPENUM ce;
LONG crcl;
BOOL bMore;
DISPDBG((DBGLVL, "DrvGradientFill: complex clipping"));
CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
do {
bMore = CLIPOBJ_bEnum(pco, sizeof ce, (ULONG *)&ce);
crcl = cIntersect(prclExtents, ce.arcl, ce.c);
if(crcl)
{
bSuccess = ppdev->pgfnGradientFillRect(ppdev,
pVertex,
nVertex,
(GRADIENT_RECT *)pMesh,
nMesh,
ulMode,
ce.arcl,
crcl);
}
} while(bMore && bSuccess);
}
DISPDBG((DBGLVL, "DrvGradientFill done, bSuccess = %d", bSuccess));
if(bSuccess)
{
return(bSuccess);
}
punt:
DISPDBG((DBGLVL, "DrvGradientFill: calling EngGradientFill"));
if(psoDstOrig->iType != STYPE_BITMAP)
{
if(!glintInfo->GdiCantAccessFramebuffer)
{
psoDstOrig = pdsurf->pso;
}
}
bSuccess = EngGradientFill(psoDstOrig,
pco,
pxlo,
pVertex,
nVertex,
pMesh,
nMesh,
prclExtents,
pptlDitherOrg,
ulMode);
return(bSuccess);
}
//*****************************************************************************
// FUNC: DrvTransparentBlt
// ARGS: psoDst (I) - destination surface
// psoSrc (I) - sources surface
// pco (I) - destination clipping
// pxlo (I) - color translation from source to destination
// prclDst (I) - destination rectangle
// prclSrc (I) - source rectangle
// iTransColor (I) - transparent color
// RETN: TRUE if successful
//-----------------------------------------------------------------------------
// Performs a chroma-keyed COPY blt. Source and Destination are guaranteed not
// to overlap.
//*****************************************************************************
BOOL DrvTransparentBlt(
SURFOBJ *psoDst,
SURFOBJ *psoSrc,
CLIPOBJ *pco,
XLATEOBJ *pxlo,
RECTL *prclDst,
RECTL *prclSrc,
ULONG iTransColor,
ULONG ulReserved)
{
SURFOBJ *psoDstOrig = psoDst;
SURFOBJ *psoSrcOrig = psoSrc;
PDEV *ppdev;
DSURF *pdsurfSrc, *pdsurfDst;
OH *pohSrc, *pohDst;
ULONG cxSrc, cySrc, cxDst, cyDst;
POINTL ptlSrc;
BOOL bSuccess = FALSE;
GLINT_DECL_VARS;
DISPDBG((DBGLVL, "DrvTransparentBlt entered"));
if ((psoSrc->iType == STYPE_BITMAP) &&
(psoDst->iType == STYPE_BITMAP))
{
// we can't obtain any valid ppdev from this
goto punt_error;
}
if (psoSrc->iType != STYPE_BITMAP)
{
pdsurfSrc = (DSURF *)psoSrc->dhsurf;
ppdev = (PDEV *)psoSrc->dhpdev;
}
if (psoDst->iType != STYPE_BITMAP)
{
pdsurfDst = (DSURF *)psoDst->dhsurf;
ppdev = (PDEV *)psoDst->dhpdev;
}
GLINT_DECL_INIT;
if (ppdev->pgfnTransparentBlt == NULL)
{
// we don't accelerate this function
goto punt;
}
if (psoSrc->iType == STYPE_BITMAP)
{
DISPDBG((DBGLVL, "DrvTransparentBlt: don't support downloads"));
goto punt;
}
if (psoDst->iType == STYPE_BITMAP)
{
DISPDBG((DBGLVL, "DrvTransparentBlt: don't support uploads"));
goto punt;
}
if (pxlo && !(pxlo->flXlate & XO_TRIVIAL))
{
DISPDBG((DBGLVL, "DrvTransparentBlt: don't support xlates"));
goto punt;
}
// screen-to-screen blt
// ensure both surfaces are in the framebuffer
if((pdsurfSrc->dt & DT_SCREEN) == 0)
{
DISPDBG((DBGLVL, "DrvTransparentBlt: source is a DFB now "
"in host memory - punt back to GDI"));
goto punt;
}
if((pdsurfDst->dt & DT_SCREEN) == 0)
{
DISPDBG((DBGLVL, "DrvTransparentBlt: destination is a DFB "
"now in host memory - punt back to GDI"));
goto punt;
}
cxSrc = prclSrc->right - prclSrc->left;
cySrc = prclSrc->bottom - prclSrc->top;
cxDst = prclDst->right - prclDst->left;
cyDst = prclDst->bottom - prclDst->top;
if ((cxSrc != cxDst) || (cySrc != cyDst))
{
DISPDBG((DBGLVL, "DrvTransparentBlt: only support 1:1 blts "
"cxySrc(%d,%d) cxyDst(%d,%d)",
cxSrc, cySrc, cxDst, cyDst));
goto punt;
}
GLINT_DECL_INIT;
VALIDATE_DD_CONTEXT;
// destination surface base offset plus x offset from that
pohDst = pdsurfDst->poh;
pohSrc = pdsurfSrc->poh;
SETUP_PPDEV_SRC_AND_DST_OFFSETS(ppdev, pdsurfSrc, pdsurfDst);
ptlSrc.x = prclSrc->left + pohSrc->x;
ptlSrc.y = prclSrc->top;
if ((pco == NULL) || (pco->iDComplexity == DC_TRIVIAL))
{
DISPDBG((DBGLVL, "DrvTransparentBlt: trivial clipping"));
bSuccess = ppdev->pgfnTransparentBlt(ppdev, prclDst, &ptlSrc,
iTransColor, prclDst, 1);
}
else if (pco->iDComplexity == DC_RECT)
{
RECTL rcl;
DISPDBG((DBGLVL, "DrvTransparentBlt: rectangular clipping"));
bSuccess = !bIntersect(prclDst, &pco->rclBounds, &rcl);
if (!bSuccess)
{
bSuccess = ppdev->pgfnTransparentBlt(ppdev, prclDst, &ptlSrc,
iTransColor, &rcl, 1);
}
}
else
{
CLIPENUM ce;
LONG crcl;
BOOL bMore;
DISPDBG((DBGLVL, "DrvTransparentBlt: complex clipping"));
CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
do {
bMore = CLIPOBJ_bEnum(pco, sizeof ce, (ULONG *)&ce);
crcl = cIntersect(prclDst, ce.arcl, ce.c);
if(crcl)
{
bSuccess = ppdev->pgfnTransparentBlt(ppdev,prclDst, &ptlSrc,
iTransColor, ce.arcl,
crcl);
}
} while(bMore && bSuccess);
}
DISPDBG((DBGLVL, "DrvTransparentBlt done, bSuccess = %d", bSuccess));
if(bSuccess)
{
return(bSuccess);
}
punt:
DISPDBG((DBGLVL, "DrvTransparentBlt: calling EngTransparentBlt"));
if(psoDstOrig->iType != STYPE_BITMAP)
{
if(!glintInfo->GdiCantAccessFramebuffer)
psoDstOrig = pdsurfDst->pso;
}
if(psoSrcOrig->iType != STYPE_BITMAP)
{
if(!glintInfo->GdiCantAccessFramebuffer)
psoSrcOrig = pdsurfSrc->pso;
}
punt_error:
bSuccess = EngTransparentBlt(psoDstOrig,
psoSrcOrig,
pco,
pxlo,
prclDst,
prclSrc,
iTransColor,
ulReserved);
return(bSuccess);
}
//*****************************************************************************
// FUNC: DrvAlphaBlend
// ARGS: psoDst (I) - destination surface
// psoSrc (I) - sources surface
// pco (I) - destination clipping
// pxlo (I) - color translation from source to destination
// prclDst (I) - destination rectangle
// prclSrc (I) - source rectangle
// pBlendObj (I) - specifies the type of alpha blending
// RETN: TRUE if successful
//-----------------------------------------------------------------------------
// Performs a blt with alpha blending. There are three types of blend
// operation:-
// 1.) Source has constant alpha. Each destination color component is
// calculated using the common blend function:-
// dC = sC.cA + dC(1 - cA)
// 2.) Source has per pixel alpha. The source is guaranteed to be 32 bits and
// to have been premultiplied with its alpha. Each destination color
// component is calculated using the premult blend function:-
// dC = sC + dC(1 - sA)
// 3.) Source has per pixel alpha and constant alpha. The source is guaranteed
// to be 32 bits and to have been premultiplied with its alpha. The
// calculation is in two stages, first we calculate the transient value of
// each component by multiplying the source with the constant alpha:-
// tC = sC * cA
// Next, we blend the destination with the premultiplied transient value:-
// dC = tC + dC(1 - tA)
//
// dC = destination component, sC = source component, tC = transient component
// cA = constant alpha, sA = source alpha, tA = transient alpha
//*****************************************************************************
BOOL DrvAlphaBlend(
SURFOBJ *psoDst,
SURFOBJ *psoSrc,
CLIPOBJ *pco,
XLATEOBJ *pxlo,
RECTL *prclDst,
RECTL *prclSrc,
BLENDOBJ *pBlendObj)
{
SURFOBJ *psoDstOrig = psoDst;
SURFOBJ *psoSrcOrig = psoSrc;
PDEV *ppdev;
DSURF *pdsurfDst, *pdsurfSrc;
OH *pohDst, *pohSrc;
ULONG cxSrc, cySrc, cxDst, cyDst;
POINTL ptlSrc;
CLIPENUM ce;
BOOL bMore;
LONG crcl;
BOOL bSuccess = FALSE;
GLINT_DECL_VARS;
DISPDBG((DBGLVL, "DrvAlphaBlend entered"));
if ((psoSrc->iType == STYPE_BITMAP) &&
(psoDst->iType == STYPE_BITMAP))
{
// we can't obtain any valid ppdev from this
goto punt_error;
}
if (psoSrc->iType != STYPE_BITMAP)
{
pdsurfSrc = (DSURF *)psoSrc->dhsurf;
ppdev = (PDEV *)psoSrc->dhpdev;
}
if (psoDst->iType != STYPE_BITMAP)
{
pdsurfDst = (DSURF *)psoDst->dhsurf;
ppdev = (PDEV *)psoDst->dhpdev;
}
GLINT_DECL_INIT;
if (ppdev->pgfnAlphaBlend == NULL)
{
// we don't accelerate this function
goto punt;
}
if (psoSrc->iType == STYPE_BITMAP)
{
DISPDBG((DBGLVL, "DrvAlphaBlend: don't support downloads"));
goto punt;
}
if (psoDst->iType == STYPE_BITMAP)
{
DISPDBG((DBGLVL, "DrvAlphaBlend: don't support uploads"));
goto punt;
}
if (pxlo && !(pxlo->flXlate & XO_TRIVIAL))
{
DISPDBG((DBGLVL, "DrvAlphaBlend: don't support xlates"));
goto punt;
}
// screen-to-screen blt
// ensure both surfaces are in the framebuffer
if((pdsurfSrc->dt & DT_SCREEN) == 0)
{
DISPDBG((DBGLVL, "DrvAlphaBlend: source is a DFB now in host memory "
"- punt back to GDI"));
goto punt;
}
if((pdsurfDst->dt & DT_SCREEN) == 0)
{
DISPDBG((DBGLVL, "DrvAlphaBlend: destination is a DFB now in host "
"memory - punt back to GDI"));
goto punt;
}
cxSrc = prclSrc->right - prclSrc->left;
cySrc = prclSrc->bottom - prclSrc->top;
cxDst = prclDst->right - prclDst->left;
cyDst = prclDst->bottom - prclDst->top;
if((cxSrc != cxDst) || (cySrc != cyDst))
{
DISPDBG((DBGLVL, "DrvAlphaBlend: only support 1:1 blts "
"cxySrc(%d,%d) cxyDst(%d,%d)",
cxSrc, cySrc, cxDst, cyDst));
goto punt;
}
GLINT_DECL_INIT;
VALIDATE_DD_CONTEXT;
// destination surface base offset plus x offset from that
pohDst = pdsurfDst->poh;
pohSrc = pdsurfSrc->poh;
SETUP_PPDEV_SRC_AND_DST_OFFSETS(ppdev, pdsurfSrc, pdsurfDst);
ptlSrc.x = prclSrc->left + pohSrc->x;
ptlSrc.y = prclSrc->top;
if ((pco == NULL) || (pco->iDComplexity == DC_TRIVIAL))
{
DISPDBG((DBGLVL, "DrvAlphaBlend: trivial clipping"));
bSuccess = ppdev->pgfnAlphaBlend(ppdev, prclDst, &ptlSrc, pBlendObj,
prclDst, 1);
}
else if (pco->iDComplexity == DC_RECT)
{
RECTL rcl;
DISPDBG((DBGLVL, "DrvAlphaBlend: rectangular clipping"));
bSuccess = !bIntersect(prclDst, &pco->rclBounds, &rcl);
if (!bSuccess)
{
bSuccess = ppdev->pgfnAlphaBlend(ppdev, prclDst, &ptlSrc,
pBlendObj, &rcl, 1);
}
}
else
{
DISPDBG((DBGLVL, "DrvAlphaBlend: complex clipping"));
CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
do {
bMore = CLIPOBJ_bEnum(pco, sizeof ce, (ULONG *)&ce);
crcl = cIntersect(prclDst, ce.arcl, ce.c);
if(crcl)
{
bSuccess = ppdev->pgfnAlphaBlend(ppdev,prclDst, &ptlSrc,
pBlendObj, ce.arcl, crcl);
}
} while(bMore && bSuccess);
}
DISPDBG((DBGLVL, "DrvAlphaBlend done, bSuccess = %d", bSuccess));
if (bSuccess)
{
return(bSuccess);
}
punt:
DISPDBG((DBGLVL, "DrvAlphaBlend: calling EngAlphaBlend"));
if (psoDstOrig->iType != STYPE_BITMAP)
{
if (!glintInfo->GdiCantAccessFramebuffer)
psoDstOrig = pdsurfDst->pso;
}
if (psoSrcOrig->iType != STYPE_BITMAP)
{
if (!glintInfo->GdiCantAccessFramebuffer)
psoSrcOrig = pdsurfSrc->pso;
}
punt_error:
bSuccess = EngAlphaBlend(psoDstOrig,
psoSrcOrig,
pco,
pxlo,
prclDst,
prclSrc,
pBlendObj);
return(bSuccess);
}
#endif //(_WIN32_WINNT >= 0x500)