|
|
/******************************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)
|