/*
 * Copyright (c) 1995 FirePower Systems, Inc.
 * DO NOT DISTRIBUTE without permission
 *
 * $RCSfile: debug.c $
 * $Revision: 1.1 $
 * $Date: 1996/03/08 01:19:00 $
 * $Locker:  $
 */
/******************************Module*Header*******************************\
* Module Name: debug.c
*
* debug helpers routine
*
* Copyright (c) 1992-1995 Microsoft Corporation
*
* Copyright (c) 1994 FirePower Systems, Inc.
*	Modified for FirePower display model by Neil Ogura (9-7-1994)
*
\**************************************************************************/

#include "driver.h"

#if DBG	|| INVESTIGATE

#include <stdio.h>

#endif

#if	DBG

#define	DUMP_PARAM_LEVEL	0
ULONG	DebugLevel = 0;

#endif

#if	INVESTIGATE

#include <stdarg.h>

#define	MEMMAXBANDWIDTH	FALSE
#define	MEMCPYPERFORM	FALSE
#define	MEMCPYVERIFY	FALSE

#define	SMP_TRACE		FALSE

static	char	*bittable[256] = {
"........",".......*","......*.","......**",".....*..",".....*.*",".....**.",".....***",
"....*...","....*..*","....*.*.","....*.**","....**..","....**.*","....***.","....****",
"...*....","...*...*","...*..*.","...*..**","...*.*..","...*.*.*","...*.**.","...*.***",
"...**...","...**..*","...**.*.","...**.**","...***..","...***.*","...****.","...*****",
"..*.....","..*....*","..*...*.","..*...**","..*..*..","..*..*.*","..*..**.","..*..***",
"..*.*...","..*.*..*","..*.*.*.","..*.*.**","..*.**..","..*.**.*","..*.***.","..*.****",
"..**....","..**...*","..**..*.","..**..**","..**.*..","..**.*.*","..**.**.","..**.***",
"..***...","..***..*","..***.*.","..***.**","..****..","..****.*","..*****.","..******",
".*......",".*.....*",".*....*.",".*....**",".*...*..",".*...*.*",".*...**.",".*...***",
".*..*...",".*..*..*",".*..*.*.",".*..*.**",".*..**..",".*..**.*",".*..***.",".*..****",
".*.*....",".*.*...*",".*.*..*.",".*.*..**",".*.*.*..",".*.*.*.*",".*.*.**.",".*.*.***",
".*.**...",".*.**..*",".*.**.*.",".*.**.**",".*.***..",".*.***.*",".*.****.",".*.*****",
".**.....",".**....*",".**...*.",".**...**",".**..*..",".**..*.*",".**..**.",".**..***",
".**.*...",".**.*..*",".**.*.*.",".**.*.**",".**.**..",".**.**.*",".**.***.",".**.****",
".***....",".***...*",".***..*.",".***..**",".***.*..",".***.*.*",".***.**.",".***.***",
".****...",".****..*",".****.*.",".****.**",".*****..",".*****.*",".******.",".*******",
"*.......","*......*","*.....*.","*.....**","*....*..","*....*.*","*....**.","*....***",
"*...*...","*...*..*","*...*.*.","*...*.**","*...**..","*...**.*","*...***.","*...****",
"*..*....","*..*...*","*..*..*.","*..*..**","*..*.*..","*..*.*.*","*..*.**.","*..*.***",
"*..**...","*..**..*","*..**.*.","*..**.**","*..***..","*..***.*","*..****.","*..*****",
"*.*.....","*.*....*","*.*...*.","*.*...**","*.*..*..","*.*..*.*","*.*..**.","*.*..***",
"*.*.*...","*.*.*..*","*.*.*.*.","*.*.*.**","*.*.**..","*.*.**.*","*.*.***.","*.*.****",
"*.**....","*.**...*","*.**..*.","*.**..**","*.**.*..","*.**.*.*","*.**.**.","*.**.***",
"*.***...","*.***..*","*.***.*.","*.***.**","*.****..","*.****.*","*.*****.","*.******",
"**......","**.....*","**....*.","**....**","**...*..","**...*.*","**...**.","**...***",
"**..*...","**..*..*","**..*.*.","**..*.**","**..**..","**..**.*","**..***.","**..****",
"**.*....","**.*...*","**.*..*.","**.*..**","**.*.*..","**.*.*.*","**.*.**.","**.*.***",
"**.**...","**.**..*","**.**.*.","**.**.**","**.***..","**.***.*","**.****.","**.*****",
"***.....","***....*","***...*.","***...**","***..*..","***..*.*","***..**.","***..***",
"***.*...","***.*..*","***.*.*.","***.*.**","***.**..","***.**.*","***.***.","***.****",
"****....","****...*","****..*.","****..**","****.*..","****.*.*","****.**.","****.***",
"*****...","*****..*","*****.*.","*****.**","******..","******.*","*******.","********"
};

static	CHAR	dbgbuf[1024];

#define	MAX_CRITICAL	6				// Number of maximum critical sections where CPU switch shouldn't happen
#define	MAX_STEP		100
#define	RECORDINTERVAL	30000000		// Measure and out statistics every INTERVAL * 0.01 ms
#define	INITIALINTERVAL	12000000		// Initial addtion to the interval
#define MAX_HOOKED_OPS	20				// Number of hooked operations by DrbBitBlt

static	ULONG	FileId = 0;
static	FILE 	*stream = NULL;
static	ULONG	startsec[MAX_TRAP], activated = 0, timercount=0, clockoverhead = 0;
static	ULONG	numcalled[MAX_TRAP];
static	ULONG	totalelapse[MAX_TRAP];
static	ULONG	distribution[MAX_TRAP][MAX_STEP];
static	ULONG	enterCPU[MAX_TRAP];
static	ULONG	CPUSwitch[MAX_TRAP][4];
static	ULONG	SwitchDuringCritical[MAX_CRITICAL];
static	ULONG	TotalCritical[MAX_CRITICAL];
static	UCHAR	EnterCriticalCPU[MAX_CRITICAL];
static	CHAR	*TrapName[MAX_TRAP] = {
				"BITBLT","COPYBITS","STRETCHBLT","PLGBLT",				"FILLPATH","STROKENFIL","TEXTOUT","PAINT","STROKEPATH","REALIZE_BRUSH",
				"DRV_BITBLT","DRV_COPYBITS","DRV_STRETCHBLT","DRV_PLGBLT",				"DRV_FILLPATH","DRV_STROKENFIL","DRV_TEXTOUT","DRV_PAINT","DRV_STROKEPATH","DRV_REALIZE_BRUSH",
				"DITHER","SETPOINTERSHAPE","SETPALETTE","SAVESCREEN","DESTROYFONT"
				};
static	CHAR	*TextPerfCtgry[4] = {"Opaque no clipping", "Opaque with clipping",
					"Transparent no clipping", "Transparent with clipping" };
static	CHAR	*CriticalNames[MAX_CRITICAL] = {
				"RectFill", "RectOp", "RectCopy", "OpTgt", "PatFill", "EntireText" };
static	CHAR	*PaintCatNames[MAX_PAINT_CATEGORY] = {
				"SolidFill", "PatFill", "SolidOp", "PatOp", "NotSupported" };
static	CHAR	*PaintOpNames[MAX_PAINT_OPS] = {
				"ff", "00", "05", "0a", "0f", "50", "55", "5a", "5f", "a0",
				"a5", "aa", "af", "f0", "f5", "fa", "Pat-5a", "Pat-f0", "Pat-0f", "Pat-a5" };
static	ULONG	HookedBitBltOp[MAX_HOOKED_OPS] = {0x00000000, 0x0000ffff, 0x1111f0f0, 0xfffff0f0, 0x11110f0f, 0x00005555,
					0x11115a5a, 0x1111a5a5, 0xffff5a5a, 0xffffa5a5, 0xffff0a0a, 0xffffa0a0, 0x1111b8b8,
					0x00006666, 0x00008888, 0x0000eeee, 0x0000bbbb, 0x00004444, 0x00001111, 0x00003333 };

LONG	TimesToMeasure = 1;
ULONG	Interval = INITIALINTERVAL;
ULONG	spentindrv;
BOOL	InitTable;

ULONG	FontTblMax, GlyphTblMax, CacheTblMax;
ULONG	CopyBitsHist[MAX_CATEGORY];
ULONG	BitBltHist[MAX_CATEGORY];
ULONG	TextOutHist[MAX_TEXT_CATEGORY];
ULONG	fontSize[MAX_FONT_SIZE];
ULONG	GlyphCountTable[MAX_GLYPH_COUNT];
ULONG	FontAccl[MAX_CATEGORY];
ULONG	TextRect[MAX_TEXT_RECT];
ULONG	TextClip[MAX_CLIP_CONDITION];
ULONG	TextWidthHist[6][MAX_WIDTH_STEP];
ULONG	TextHeightHist[6][MAX_HEIGHT_STEP];
ULONG	FontWidth[MAX_FONT_SIZE];
ULONG	FontHeight[MAX_FONT_SIZE];
ULONG	StrObjCountTable[MAX_STROBJ_COUNT];
ULONG	FontIDTable[MAX_FONT_ENTRY][2];
ULONG	GlyphHndlTable[MAX_GLYPH_HNDL_ENTRY][2];
ULONG	CacheTable[MAX_CACHE_ENTRY][3];
ULONG	CopyBitWidthHist[4][MAX_WIDTH_STEP];
ULONG	CopyBitHeightHist[4][MAX_HEIGHT_STEP];
ULONG	BitBltWidthHist[6][MAX_WIDTH_STEP];
ULONG	BitBltHeightHist[6][MAX_HEIGHT_STEP];
ULONG	BitBltRop[37][MAX_ROP_ENTRY];
ULONG	BitBltBrush[2][MAX_BRUSH_ENTRY];
ULONG	TextPerfByCtgry[4][2];
ULONG	TextSubEntryCalled[MAX_TEXT_SUB_ENTRY];
ULONG	TextSubEntryDCBZCalled[MAX_TEXT_SUB_ENTRY];
ULONG	TextSubEntryTransCalled[MAX_TEXT_SUB_ENTRY];
ULONG	PaintOp[MAX_PAINT_OPS];
ULONG	PaintCategories[MAX_PAINT_CATEGORY];
ULONG	PaintClips[MAX_PAINT_CATEGORY-1][MAX_PAINT_CLIP_ENTRY];
ULONG	PaintHeight[MAX_PAINT_CATEGORY-1][MAX_PAINT_HEIGHT_ENTRY];
ULONG	PaintWidth[MAX_PAINT_CATEGORY-1][MAX_PAINT_WIDTH_ENTRY];
ULONG	PaintBounds[MAX_PAINT_CATEGORY-1][MAX_PAINT_BOUNDS_ENTRY];

VOID	DisplayPDEV();

VOID	PerformCheck(
		ULONG	start,
		ULONG	end,
		ULONG	step,
		ULONG	height);

VOID	VramAccess();

ULONG	GetTime();

LONG
SaveScreenMem(
	ULONG	FileCategory,
	ULONG	FileNumber
	);

LONG
RestoreScreenMem(
	ULONG	FileCategory,
	ULONG	FileNumber
	);

VOID
InitializeTable()
{
	ULONG	ui, uj;

	// Initialize table
	for(ui=0; ui<MAX_TRAP; ++ui) {
		startsec[ui] = numcalled[ui] = totalelapse[ui] = 0;
		for(uj=0; uj<MAX_STEP; ++uj) {
			distribution[ui][uj] = 0;
		}
		for(uj=0; uj<4; ++uj) {
			CPUSwitch[ui][uj] = 0;
		}
	}
	for(ui=0; ui<MAX_CRITICAL; ++ui) {
		SwitchDuringCritical[ui] = TotalCritical[ui] = 0;
	}
	FontTblMax = GlyphTblMax = CacheTblMax = 0;
	for(ui=0; ui<MAX_CATEGORY; ++ui) {
		CopyBitsHist[ui] = FontAccl[ui] = BitBltHist[ui] = 0;
	}
	for(ui=0; ui<MAX_TEXT_CATEGORY; ++ui) {
		TextOutHist[ui] = 0;
	}
	for(ui=0; ui<MAX_TEXT_RECT; ++ui) {
		TextRect[ui] = 0;
	}
	for(ui=0; ui<MAX_CLIP_CONDITION; ++ui) {
		TextClip[ui] = 0;
	}
	for(ui=0; ui<MAX_FONT_SIZE; ++ui) {
		fontSize[ui] = FontWidth[ui] = FontHeight[ui] = 0;
	}
	for(ui=0; ui<MAX_GLYPH_COUNT; ++ui) {
		GlyphCountTable[ui] = 0;
	}
	for(ui=0; ui<MAX_STROBJ_COUNT; ++ui) {
		StrObjCountTable[ui] = 0;
	}
	for(ui=0; ui<4; ++ui) {
		for(uj=0; uj<2; ++uj)
			TextPerfByCtgry[ui][uj] = 0;
	}
	for(ui=0; ui<MAX_TEXT_SUB_ENTRY; ++ui) {
		TextSubEntryCalled[ui] = 0;
		TextSubEntryDCBZCalled[ui] = 0;
		TextSubEntryTransCalled[ui] = 0;
	}
	for(ui=0; ui<4; ++ui) {
		for(uj=0; uj<MAX_WIDTH_STEP; ++uj) {
			CopyBitWidthHist[ui][uj] = 0;
		}
		for(uj=0; uj<MAX_HEIGHT_STEP; ++uj) {
			CopyBitHeightHist[ui][uj] = 0;
		}
	}
	for(ui=0; ui<6; ++ui) {
		for(uj=0; uj<MAX_WIDTH_STEP; ++uj) {
			BitBltWidthHist[ui][uj] = 0;
		}
		for(uj=0; uj<MAX_HEIGHT_STEP; ++uj) {
			BitBltHeightHist[ui][uj] = 0;
		}
	}
	for(ui=0; ui<6; ++ui) {
		for(uj=0; uj<MAX_WIDTH_STEP; ++uj) {
			TextWidthHist[ui][uj] = 0;
		}
		for(uj=0; uj<MAX_HEIGHT_STEP; ++uj) {
			TextHeightHist[ui][uj] = 0;
		}
	}
	for(ui=0; ui<37; ++ui) {
		for(uj=0; uj<MAX_ROP_ENTRY; ++uj)
			BitBltRop[ui][uj] = 0;
	}
	for(ui=0; ui<2; ++ui) {
		for(uj=0; uj<MAX_BRUSH_ENTRY; ++uj)
			BitBltBrush[ui][uj] = 0;
	}
	for(ui=0; ui<MAX_PAINT_CATEGORY; ++ui) {
		PaintCategories[ui] = 0;
	}
	for(ui=0; ui<MAX_PAINT_OPS; ++ui) {
		PaintOp[ui] = 0;
	}
	for(ui=0; ui<MAX_PAINT_CATEGORY-1; ++ui) {
		for(uj=0; uj<MAX_PAINT_CLIP_ENTRY; ++uj) {
			PaintClips[ui][uj] = 0;
		}
		for(uj=0; uj<MAX_PAINT_HEIGHT_ENTRY; ++uj) {
			PaintHeight[ui][uj] = 0;
		}
		for(uj=0; uj<MAX_PAINT_WIDTH_ENTRY; ++uj) {
			PaintWidth[ui][uj] = 0;
		}
		for(uj=0; uj<MAX_PAINT_BOUNDS_ENTRY; ++uj) {
			PaintBounds[ui][uj] = 0;
		}
	}
}

VOID
RecordPerformance()
{
	ULONG	ui, uj, time;

//	oneshot = 1;

	if(FileId == 0) {	// The first call
		clockoverhead = 0;
		for(ui=0; ui<10; ++ui) {
			time = GetTime();
			clockoverhead += (GetTime() - time);
		}
		clockoverhead /= 10;
		InitializeTable();
		InitTable = FALSE;
		Interval = RECORDINTERVAL;
		FileId = 1;
//		DisplayPDEV();
		DISPDBG((0,"Statistic table initialized overhead = %d.%02d\n", clockoverhead/100, clockoverhead%100));
#if	DBG
//		EngDebugBreak();
#endif
	} else {

// Change continue to break for the function you need performance data.
// It will prints function name, # of calls and elapse time.
// As a default, BitBlt and Paint information will be displayed.

		for(ui=0; ui<MAX_TRAP; ++ui) {
			switch(ui) {
				case	TRAP_BITBLT: break;
				case	TRAP_COPYBITS: continue;
				case	TRAP_STRETCHBLT: continue;
				case	TRAP_PLGBLT: continue;
				case	TRAP_FILLPATH: continue;
				case	TRAP_STROKENFIL: continue;
				case	TRAP_TEXTOUT: continue;
				case	TRAP_PAINT: break;
				case	TRAP_STROKEPATH: continue;
				case	TRAP_REALIZE_BRUSH: continue;
				
				case	DRV_TRAP_BITBLT: break;
				case	DRV_TRAP_COPYBITS: continue;
				case	DRV_TRAP_STRETCHBLT: continue;
				case	DRV_TRAP_PLGBLT: continue;
				case	DRV_TRAP_FILLPATH: continue;
				case	DRV_TRAP_STROKENFIL: continue;
				case	DRV_TRAP_TEXTOUT: continue;
				case	DRV_TRAP_PAINT: break;
				case	DRV_TRAP_STROKEPATH: continue;
				case	DRV_REALIZE_BRUSH: continue;
				
				case	TRAP_DITHER: continue;
				case	TRAP_SETPOINTER: continue;
				case	TRAP_SETPALETTE: continue;
				case	TRAP_SVSCRNBIT: continue;
				case	TRAP_DESTRYFONT: continue;
			}
			DISPDBG((1, "%s %u %u.%02u\n", TrapName[ui], numcalled[ui], totalelapse[ui]/100, totalelapse[ui]%100));
		}

		if(MAX_CATEGORY >= 10)
			DISPDBG((1, "BitBlt category: %u %u %u %u %u %u %u %u %u %u\n",
				BitBltHist[0], BitBltHist[1], BitBltHist[2], BitBltHist[3], BitBltHist[4],
				BitBltHist[5], BitBltHist[6], BitBltHist[7], BitBltHist[8], BitBltHist[9]));

		DISPDBG((1, "BitBlt ROP table            count ave-width\n"));
		for(ui=0; ui<MAX_ROP_ENTRY; ++ui) {
			if(BitBltRop[1][ui] == 0)
				break;
			for(uj=0; uj < MAX_HOOKED_OPS; ++uj) {
				if(BitBltRop[0][ui] == HookedBitBltOp[uj])
					break;
			}
			if(uj < MAX_HOOKED_OPS)
				uj = 1;
			else
				uj = 0;
			DISPDBG((1, " %6u.%02u %04x-%s %c %8u %4u\n",
				BitBltRop[2][ui]/100, BitBltRop[2][ui]%100, BitBltRop[0][ui] & 0xffff,
				(BitBltRop[0][ui] & 0xffff0000)?(((BitBltRop[0][ui] & 0xffff0000) == 0xffff0000)?"PatBrush":"SolBrush"):"NoBrush ", uj?'*':' ',
				BitBltRop[1][ui], BitBltRop[3][ui]/BitBltRop[1][ui]));
		}

//		InitTable = TRUE;

/****** sprintf and file I/O is not available from NT 4.0, so it's commented out,
	in case we need special performance data, we can use DebugPrint for the data.
	For now, only limited performance data is printed.

		CHAR	fname[30];
		ULONG	length;

		sprintf(fname, "C:\\TMP\\DSP%05d.txt", FileId++);

		if((stream = fopen(fname, "w")) != NULL) {
			length = sprintf(dbgbuf, "PSIDISP-%d #OfCalls Total", FileId-1);
			fwrite(dbgbuf, 1, length, stream);
			for(ui=1; ui<MAX_STEP; ++ui) {
				length = sprintf(dbgbuf, " ~%d.%d", ui/10, ui%10);
				fwrite(dbgbuf, 1, length, stream);
			}
			length = sprintf(dbgbuf, " %d.%d~\n", (MAX_STEP-1)/10, (MAX_STEP-1)%10);
			fwrite(dbgbuf, 1, length, stream);
			for(ui=0; ui<MAX_TRAP; ++ui) {
				length = sprintf(dbgbuf, "%s %u %u.%02u", TrapName[ui], numcalled[ui], totalelapse[ui]/100, totalelapse[ui]%100);
				fwrite(dbgbuf, 1, length, stream);

				for(uj=0; uj<MAX_STEP; ++uj) {
					length = sprintf(dbgbuf, " %u", distribution[ui][uj]);
					fwrite(dbgbuf, 1, length, stream);
				}
				length = sprintf(dbgbuf, "\n");
				fwrite(dbgbuf, 1, length, stream);
#if	SMP_TRACE
				length = sprintf(dbgbuf, "[0->0]: %d, [0->1]: %d, [1->0]: %d, [1->1]: %d\n",
					CPUSwitch[ui][0], CPUSwitch[ui][1], CPUSwitch[ui][2], CPUSwitch[ui][3]);
				fwrite(dbgbuf, 1, length, stream);
#endif
			}
#if	SMP_TRACE
			length = sprintf(dbgbuf, "\nCPU Switch dring critical section\n");
			fwrite(dbgbuf, 1, length, stream);
			for(ui=0; ui<MAX_CRITICAL; ++ui) {
				if(TotalCritical[ui]) {
					length = sprintf(dbgbuf, "[%s] %u out of %u (%d.%03d%%)\n", CriticalNames[ui], SwitchDuringCritical[ui], TotalCritical[ui],
					SwitchDuringCritical[ui]*100/TotalCritical[ui],
					(SwitchDuringCritical[ui]*100000/TotalCritical[ui])%100);
				} else {
					length = sprintf(dbgbuf, "[%s] %u out of %u (0.0%%)\n", CriticalNames[ui], SwitchDuringCritical[ui], TotalCritical[ui]);
				}
				fwrite(dbgbuf, 1, length, stream);
			}
#endif
			length = sprintf(dbgbuf, "\nBitBlt Category\n");
			fwrite(dbgbuf, 1, length, stream);
			for(ui=0; ui<MAX_CATEGORY; ++ui) {
				length = sprintf(dbgbuf, "%6u", BitBltHist[ui]);
				fwrite(dbgbuf, 1, length, stream);
			}
			length = sprintf(dbgbuf, "\nCopyBit Category\n");
			fwrite(dbgbuf, 1, length, stream);
			for(ui=0; ui<MAX_CATEGORY; ++ui) {
				length = sprintf(dbgbuf, "%6u", CopyBitsHist[ui]);
				fwrite(dbgbuf, 1, length, stream);
			}
			length = sprintf(dbgbuf, "\nTextOut Category\n");
			fwrite(dbgbuf, 1, length, stream);
			for(ui=0; ui<MAX_TEXT_CATEGORY; ++ui) {
				length = sprintf(dbgbuf, "%6u", TextOutHist[ui]);
				fwrite(dbgbuf, 1, length, stream);
			}
			length = sprintf(dbgbuf, "\nFontAccl Category\n");
			fwrite(dbgbuf, 1, length, stream);
			for(ui=0; ui<MAX_CATEGORY; ++ui) {
				length = sprintf(dbgbuf, "%6u", FontAccl[ui]);
				fwrite(dbgbuf, 1, length, stream);
			}
			length = sprintf(dbgbuf, "\nText subroutines called\n");
			fwrite(dbgbuf, 1, length, stream);
			for(ui=0; ui<MAX_TEXT_SUB_ENTRY; ++ui) {
				length = sprintf(dbgbuf, "%6u", TextSubEntryCalled[ui]);
				fwrite(dbgbuf, 1, length, stream);
			}
			length = sprintf(dbgbuf, "\nText subroutines called with DCBZ\n");
			fwrite(dbgbuf, 1, length, stream);
			for(ui=0; ui<MAX_TEXT_SUB_ENTRY; ++ui) {
				length = sprintf(dbgbuf, "%6u", TextSubEntryDCBZCalled[ui]);
				fwrite(dbgbuf, 1, length, stream);
			}
			length = sprintf(dbgbuf, "\nTransparent text subroutines called\n");
			fwrite(dbgbuf, 1, length, stream);
			for(ui=0; ui<MAX_TEXT_SUB_ENTRY; ++ui) {
				length = sprintf(dbgbuf, "%6u", TextSubEntryTransCalled[ui]);
				fwrite(dbgbuf, 1, length, stream);
			}
			length = sprintf(dbgbuf, "\nText Rectangles\n");
			fwrite(dbgbuf, 1, length, stream);
			for(ui=0; ui<MAX_TEXT_RECT; ++ui) {
				length = sprintf(dbgbuf, "%6u", TextRect[ui]);
				fwrite(dbgbuf, 1, length, stream);
			}
			length = sprintf(dbgbuf, "\nText rectangles size distribution Top, Bottom, Left, Right, Extra, Text");
			fwrite(dbgbuf, 1, length, stream);
			for(ui=0; ui<6; ++ui) {
				length = sprintf(dbgbuf, "\nText Rectangles Width Distribution\n");
				fwrite(dbgbuf, 1, length, stream);
				for(uj=0; uj<MAX_WIDTH_STEP; ++uj) {
					length = sprintf(dbgbuf, "%u ", TextWidthHist[ui][uj]);
					fwrite(dbgbuf, 1, length, stream);
				}
				length = sprintf(dbgbuf, "\n Text Rectangles Distribution\n");
				fwrite(dbgbuf, 1, length, stream);
				for(uj=0; uj<MAX_HEIGHT_STEP; ++uj) {
					length = sprintf(dbgbuf, "%u ", TextHeightHist[ui][uj]);
					fwrite(dbgbuf, 1, length, stream);
				}
			}
			length = sprintf(dbgbuf, "\nText Clipping Conditions\n");
			fwrite(dbgbuf, 1, length, stream);
			for(ui=0; ui<MAX_CLIP_CONDITION; ++ui) {
				length = sprintf(dbgbuf, "%6u", TextClip[ui]);
				fwrite(dbgbuf, 1, length, stream);
			}
			length = sprintf(dbgbuf, "\nFont Size Distribution\n");
			fwrite(dbgbuf, 1, length, stream);
			for(ui=0; ui<MAX_FONT_SIZE; ++ui) {
				length = sprintf(dbgbuf, "%u ", fontSize[ui]);
				fwrite(dbgbuf, 1, length, stream);
			}
			length = sprintf(dbgbuf, "\nFont Width Distribution\n");
			fwrite(dbgbuf, 1, length, stream);
			for(ui=0; ui<MAX_FONT_SIZE; ++ui) {
				length = sprintf(dbgbuf, "%u ", FontWidth[ui]);
				fwrite(dbgbuf, 1, length, stream);
			}
			length = sprintf(dbgbuf, "\nFont Height Distribution\n");
			fwrite(dbgbuf, 1, length, stream);
			for(ui=0; ui<MAX_FONT_SIZE; ++ui) {
				length = sprintf(dbgbuf, "%u ", FontHeight[ui]);
				fwrite(dbgbuf, 1, length, stream);
			}
			length = sprintf(dbgbuf, "\nCopyBit size distribution D->D, D->V, V->D, V->V");
			fwrite(dbgbuf, 1, length, stream);
			for(ui=0; ui<4; ++ui) {
				length = sprintf(dbgbuf, "\nWidth Distribution\n");
				fwrite(dbgbuf, 1, length, stream);
				for(uj=0; uj<MAX_WIDTH_STEP; ++uj) {
					length = sprintf(dbgbuf, "%u ", CopyBitWidthHist[ui][uj]);
					fwrite(dbgbuf, 1, length, stream);
				}
				length = sprintf(dbgbuf, "\nHeight Distribution\n");
				fwrite(dbgbuf, 1, length, stream);
				for(uj=0; uj<MAX_HEIGHT_STEP; ++uj) {
					length = sprintf(dbgbuf, "%u ", CopyBitHeightHist[ui][uj]);
					fwrite(dbgbuf, 1, length, stream);
				}
			}
			length = sprintf(dbgbuf, "\nBitBlt size distribution N->D, N->V, D->D, D->V, V->D, V->V");
			fwrite(dbgbuf, 1, length, stream);
			for(ui=0; ui<6; ++ui) {
				length = sprintf(dbgbuf, "\nWidth Distribution\n");
				fwrite(dbgbuf, 1, length, stream);
				for(uj=0; uj<MAX_WIDTH_STEP; ++uj) {
					length = sprintf(dbgbuf, "%u ", BitBltWidthHist[ui][uj]);
					fwrite(dbgbuf, 1, length, stream);
				}
				length = sprintf(dbgbuf, "\nHeight Distribution\n");
				fwrite(dbgbuf, 1, length, stream);
				for(uj=0; uj<MAX_HEIGHT_STEP; ++uj) {
					length = sprintf(dbgbuf, "%u ", BitBltHeightHist[ui][uj]);
					fwrite(dbgbuf, 1, length, stream);
				}
			}
			length = sprintf(dbgbuf, "\nGlyph Count Table\n");
			fwrite(dbgbuf, 1, length, stream);
			for(ui=0; ui<MAX_GLYPH_COUNT; ++ui) {
				length = sprintf(dbgbuf, "%u ", GlyphCountTable[ui]);
				fwrite(dbgbuf, 1, length, stream);
			}
			length = sprintf(dbgbuf, "\nSTROBJ Count Table\n");
			fwrite(dbgbuf, 1, length, stream);
			for(ui=0; ui<MAX_STROBJ_COUNT; ++ui) {
				length = sprintf(dbgbuf, "%u ", StrObjCountTable[ui]);
				fwrite(dbgbuf, 1, length, stream);
			}

			length = sprintf(dbgbuf, "\nFontId Table (%u)\n", FontTblMax);
			fwrite(dbgbuf, 1, length, stream);
			for(ui=0; ui<FontTblMax; ++ui) {
				length = sprintf(dbgbuf, "0x%08x - %d\n", FontIDTable[ui][0], FontIDTable[ui][1]);
				fwrite(dbgbuf, 1, length, stream);
			}
			length = sprintf(dbgbuf, "\nGlyph Table (%u)\n", GlyphTblMax);
			fwrite(dbgbuf, 1, length, stream);
			for(ui=0; ui<GlyphTblMax; ++ui) {
				length = sprintf(dbgbuf, "0x%08x - %d\n",
					GlyphHndlTable[ui][0], GlyphHndlTable[ui][1]);
				fwrite(dbgbuf, 1, length, stream);
			}
			length = sprintf(dbgbuf, "\nFontId Table (%u)\n", CacheTblMax);
			fwrite(dbgbuf, 1, length, stream);
			for(ui=0; ui<CacheTblMax; ++ui) {
				length = sprintf(dbgbuf, "0x%08x - 0x%08x - %d\n",
					CacheTable[ui][0], CacheTable[ui][1], CacheTable[ui][2]);
				fwrite(dbgbuf, 1, length, stream);
			}

			length = sprintf(dbgbuf, "\nBitBlt ROP table\n");
			fwrite(dbgbuf, 1, length, stream);
			for(ui=0; ui<MAX_ROP_ENTRY; ++ui) {
				if(BitBltRop[1][ui] == 0)
					break;
				for(uj=0; uj < MAX_HOOKED_OPS; ++uj) {
					if(BitBltRop[0][ui] == HookedBitBltOp[uj])
						break;
				}
				if(uj < MAX_HOOKED_OPS)
					uj = 1;
				else
					uj = 0;
				length = sprintf(dbgbuf, "%6u.%02u %04x-%s %c called:%u avg_width:%u src_VRAM:%u\n",
					BitBltRop[2][ui]/100, BitBltRop[2][ui]%100, BitBltRop[0][ui] & 0xffff,
					(BitBltRop[0][ui] & 0xffff0000)?(((BitBltRop[0][ui] & 0xffff0000) == 0xffff0000)?"PatBrush":"SolBrush"):"NoBrush", uj?'*':' ',
					BitBltRop[1][ui], BitBltRop[3][ui]/BitBltRop[1][ui], BitBltRop[4][ui]);
				fwrite(dbgbuf, 1, length, stream);
				for(uj=0; uj<32; ++uj) {
					length = sprintf(dbgbuf, " %u", BitBltRop[uj+5][ui]);
					fwrite(dbgbuf, 1, length, stream);
				}
				length = sprintf(dbgbuf, "\n");
				fwrite(dbgbuf, 1, length, stream);
			}
			for(ui=0; ui<MAX_BRUSH_ENTRY; ++ui) {
				if(BitBltBrush[1][ui] == 0)
					break;
				length = sprintf(dbgbuf, "BitBlt Sold Brush %04x:%u\n",
					BitBltBrush[0][ui], BitBltBrush[1][ui]);
				fwrite(dbgbuf, 1, length, stream);
			}
			for(ui=0; ui<4; ++ui) {
				length = sprintf(dbgbuf, "TextOut %s %u times, %d.%02d msec\n",
				TextPerfCtgry[ui], TextPerfByCtgry[ui][0],
				TextPerfByCtgry[ui][1]/100, TextPerfByCtgry[ui][1]%100);
				fwrite(dbgbuf, 1, length, stream);
			}
			for(ui=0; ui<MAX_PAINT_OPS; ++ui) {
				length = sprintf(dbgbuf, "Paint OP %s : %d\n",
						PaintOpNames[ui], PaintOp[ui]);
				fwrite(dbgbuf, 1, length, stream);
			}
			for(ui=0; ui<MAX_PAINT_CATEGORY; ++ui) {
				length = sprintf(dbgbuf, "Paint category %s : %d\n",
						PaintCatNames[ui], PaintCategories[ui]);
				fwrite(dbgbuf, 1, length, stream);
			}
			for(ui=0; ui<MAX_PAINT_CATEGORY-1; ++ui) {
				length = sprintf(dbgbuf, "\nPaint CLIP distribution for %s\n", PaintCatNames[ui]);
				fwrite(dbgbuf, 1, length, stream);
				for(uj=0; uj<MAX_PAINT_CLIP_ENTRY; ++uj) {
					length = sprintf(dbgbuf, "%u ", PaintClips[ui][uj]);
					fwrite(dbgbuf, 1, length, stream);
				}
			}
			for(ui=0; ui<MAX_PAINT_CATEGORY-1; ++ui) {
				length = sprintf(dbgbuf, "\nPaint Height distribution for %s\n", PaintCatNames[ui]);
				fwrite(dbgbuf, 1, length, stream);
				for(uj=0; uj<MAX_PAINT_HEIGHT_ENTRY; ++uj) {
					length = sprintf(dbgbuf, "%u ", PaintHeight[ui][uj]);
					fwrite(dbgbuf, 1, length, stream);
				}
			}
			for(ui=0; ui<MAX_PAINT_CATEGORY-1; ++ui) {
				length = sprintf(dbgbuf, "\nPaint Width distribution for %s\n", PaintCatNames[ui]);
				fwrite(dbgbuf, 1, length, stream);
				for(uj=0; uj<MAX_PAINT_WIDTH_ENTRY; ++uj) {
					length = sprintf(dbgbuf, "%u ", PaintWidth[ui][uj]);
					fwrite(dbgbuf, 1, length, stream);
				}
			}
			for(ui=0; ui<MAX_PAINT_CATEGORY-1; ++ui) {
				length = sprintf(dbgbuf, "\nPaint Bounds distribution for %s\n", PaintCatNames[ui]);
				fwrite(dbgbuf, 1, length, stream);
				for(uj=0; uj<MAX_PAINT_BOUNDS_ENTRY; ++uj) {
					length = sprintf(dbgbuf, "%u ", PaintBounds[ui][uj]);
					fwrite(dbgbuf, 1, length, stream);
				}
			}
			fclose(stream);
			DISPDBG((0,"### Performance file %s created ###\n", fname));
		} else {
			DISPDBG((0,"### Performance file creation error ###\n"));
		}
***************************************************************************/
		if(InitTable) {
			InitializeTable();
			InitTable = FALSE;
			DISPDBG((0,"Statistic table initialized\n"));
		}
	}

#if	MEMCPYVERIFY
{
char	buf1[1024], buf2[1024], buf3[512], buf4[512];
int		i, j, k, l, rc1, rc2;

	for(i=0; i<32; ++i) {
		for(j=0; j<32; ++j) {
			for(k=0; k<256; ++k) {
				for(l=0; l<512; ++l) {
					buf1[l] = buf3[l] = 0;
					buf2[l] = buf4[l] = l;
				}
				memcpy(buf1+128+i, buf2+128+j, k);
				memcpy2(buf3+128+i, buf4+128+j, k, TFLUSHBIT | TTOUCHBIT | SFLUSHBIT);
				if(memcmp(buf1, buf3, 512) || memcmp(buf2, buf4, 512)) {
					DISPDBG((0, "memcpy2 error 1 i=%d j=%d k=%d\n", i, j, k));
#if	DBG
					EngDebugBreak();
#endif
					for(l=0; l<512; ++l) {
						buf1[l] = buf3[l] = 0;
						buf2[l] = buf4[l] = l;
					}
					memcpy2(buf3+128+i, buf4+128+j, k, TFLUSHBIT | TTOUCHBIT | SFLUSHBIT);
				}
				for(l=0; l<512; ++l) {
					buf1[l] = buf3[l] = 0xff;
					buf2[l] = buf4[l] = l;
				}
				memcpy2(buf1+128+i, buf2+128+j, k, TFLUSHBIT | TTOUCHBIT | SFLUSHBIT);
				memcpy(buf3+128+i, buf4+128+j, k);
				if(memcmp(buf1, buf3, 512) || memcmp(buf2, buf4, 512)) {
					DISPDBG((0, "memcpy2 error 2 i=%d j=%d k=%d\n", i, j, k));
#if	DBG
					EngDebugBreak();
#endif
					for(l=0; l<512; ++l) {
						buf1[l] = buf3[l] = 0xff;
						buf2[l] = buf4[l] = l;
					}
					memcpy2(buf1+128+i, buf2+128+j, k, TFLUSHBIT | TTOUCHBIT | SFLUSHBIT);
				}
			}
		}
	DISPDBG((0, "memcpy2 Test A PASSED i=%d\n", i));
	}

	for(i=0; i<32; ++i) {
		for(j=-128; j<=128; ++j) {
			for(k=0; k<256; ++k) {
				for(l=0; l<1024; ++l) {
					buf1[l] = buf2[l] = l;
				}
				memcpy(buf1+512+i, buf1+512+i+j, k);
				memcpy2(buf2+512+i, buf2+512+i+j, k, TFLUSHBIT | TTOUCHBIT | SFLUSHBIT);
				if(memcmp(buf1, buf2, 1024)) {
					DISPDBG((0, "## memcpy2 error 3 i=%d j=%d k=%d\n", i, j, k));
#if	DBG
					EngDebugBreak();
#endif
					for(l=0; l<1024; ++l) {
						buf2[l] = l;
					}
					memcpy2(buf2+512+i, buf2+512+i+j, k, TFLUSHBIT | TTOUCHBIT | SFLUSHBIT);

				}
			}
		}
	DISPDBG((0, "memcpy2 Test B PASSED i=%d\n", i));
	}
}
#endif

#if	MEMMAXBANDWIDTH || MEMCPYPERFORM
	if(TimesToMeasure >= 0) {
#if	DBG
//		EngDebugBreak();
#endif
 		if(TimesToMeasure) {
			SaveScreenMem(0, 9999);
#if	MEMMAXBANDWIDTH
			VramAccess();
#endif
#if	MEMCPYPERFORM
 			PerformCheck(1, 64, 1, 300);
			PerformCheck(250, 350, 7, 400);
			PerformCheck(650, 750, 31, 600);
#endif
			RestoreScreenMem(0, 9999);
		}
		TimesToMeasure -= 1;
	}
#endif

}

VOID
ReportNesting(
	IN	ULONG	FunctionID
	)
{
	ULONG	i;

	DISPDBG((0,"### Nesting function call: %s is called while executing", TrapName[FunctionID]));
		for(i=0; i<MAX_TRAP; ++i) {
			if(startsec[i] != 0) {
				DISPDBG((0," %s", TrapName[i]));
			}
		}
		DISPDBG((0," ###\n"));
}	

VOID
EnterCritical(
	IN	ULONG	SectionID
	)
{
	UCHAR	tscReg;

	if(myPDEV->TscStatusReg && SectionID < MAX_CRITICAL) {
		tscReg = *(myPDEV->TscStatusReg + 7);
		EnterCriticalCPU[SectionID] = tscReg & 0x40;
	}

}

VOID
ExitCritical(
	IN	ULONG	SectionID
	)
{
	UCHAR	tscReg;

	if(myPDEV->TscStatusReg && SectionID < MAX_CRITICAL) {
		tscReg = *(myPDEV->TscStatusReg + 7);
		if((tscReg & 0x40) != EnterCriticalCPU[SectionID]) {
			SwitchDuringCritical[SectionID] += 1;
		}
		TotalCritical[SectionID] += 1;
	}
}

VOID
ClockStart(
	IN	ULONG	FunctionID
   )
{
	ULONG	i;
	UCHAR	tscReg;

	if(myPDEV->TscStatusReg) {
		tscReg = *(myPDEV->TscStatusReg + 7);
		if(tscReg & 0x40)
			enterCPU[FunctionID] = 1;
		else
			enterCPU[FunctionID] = 0;
	}

	if(timercount) {	// There are some other functions nesting
		if(FunctionID == TRAP_PAINT || FunctionID == DRV_TRAP_PAINT || FunctionID == TRAP_BITBLT || FunctionID == TRAP_DITHER || FunctionID == DRV_TRAP_BITBLT || FunctionID == DRV_REALIZE_BRUSH) {
			for(i=0; i<MAX_TRAP; ++i) {
				if(i == TRAP_PAINT || i == TRAP_STROKENFIL || i == TRAP_BITBLT || i == DRV_TRAP_BITBLT || i == DRV_TRAP_PAINT)	// We are aware of this situation
					continue;
				if(startsec[i])
					break;
			}
			if(i != MAX_TRAP)
				ReportNesting(FunctionID);
		} else {
			ReportNesting(FunctionID);
		}
	}

	timercount += 1;

	numcalled[FunctionID] += 1;

	startsec[FunctionID] = GetTime();
}

VOID
ClockEnd(
	IN	ULONG	FunctionID
   )
{
	ULONG	time, time2, index;
	UCHAR	tscReg;

	time = GetTime();

	time2 = time;

	time -= (startsec[FunctionID] + clockoverhead);
	spentindrv = time;
	totalelapse[FunctionID] += time;
	
	index = time/10;			// Histgram unit is 0.1 msec (measured time is 0.01 msec)
	if(index >= MAX_STEP)
		index = MAX_STEP-1;
	distribution[FunctionID][index] += 1;

	timercount -= 1;
	startsec[FunctionID] = 0;

	if(timercount < 0) {
		DISPDBG((0,"### Timer Count Becomes Negative ###\n", TrapName[FunctionID]));
	}

	if(activated == 0)
		activated = time2;
	else {
		if(time2 > activated + Interval && timercount == 0) {	// statistics out every INTERVAL seconds
			activated = 0;		// reset acivated counter
			RecordPerformance();
		}
	}

	if(myPDEV->TscStatusReg) {
		tscReg = *(myPDEV->TscStatusReg + 7);
		if(tscReg & 0x40) {
			if(enterCPU[FunctionID]) {
				CPUSwitch[FunctionID][3] += 1;
			} else {
				CPUSwitch[FunctionID][2] += 1;
			}
		} else {
			if(enterCPU[FunctionID]) {
				CPUSwitch[FunctionID][1] += 1;
			} else {
				CPUSwitch[FunctionID][0] += 1;
			}
		}
	}

}

VOID
CountUp(
	IN	ULONG	FunctionID
   )
{
	numcalled[FunctionID] += 1;
}

VOID
CountBreak()
{
	if(breakcnt) {	// break point counting mode?
		if(--breakcnt == 0) {
			EngDebugBreak();
		}
	} else {
		if(dbgflg)
			EngDebugBreak();
	}
}

#endif // INVESTIGATE

/*****************************************************************************
 *
 *   Routine Description:
 *
 *      This function is variable-argument, level-sensitive debug print
 *      routine.
 *      If the specified debug level for the print statement is lower or equal
 *      to the current debug level, the message will be printed.
 *
 *   Arguments:
 *
 *      DebugPrintLevel - Specifies at which debugging level the string should
 *          be printed
 *
 *      DebugMessage - Variable argument ascii c string
 *
 *   Return Value:
 *
 *      None.
 *
 ***************************************************************************/

VOID
DebugPrint(
    ULONG DebugPrintLevel,
    PCHAR DebugMessage,
    ...
    )

{

#if DBG

    va_list ap;

    va_start(ap, DebugMessage);

#endif

#if	DBG

    if (DebugPrintLevel <= DebugLevel) {

        EngDebugPrint(STANDARD_DEBUG_PREFIX, DebugMessage, ap);

    }

#endif

#if	DBG

    va_end(ap);

#endif

} // DebugPrint()

#if	INVESTIGATE

LONG
DumpSurfObj(
	char	*title,
	SURFOBJ	*pso
	)
{

#define	STYPE_MAX	9
#define	ITYPE_MAX	4

	char	*StypeString[STYPE_MAX] = {"DEVICE", "1BPP", "4BPP", "8BPP", "16BPP",
				"24BPP", "32BPP", "4RLE", "8RLE" };
	char	*ItypeString[ITYPE_MAX] = {"BITMAP", "DEVICE", "JOURNAL", "DEVBITMAP"}; 
	
	if(pso == NULL) {
		DISPDBG((DUMP_PARAM_LEVEL, "[%s] -- NULL\n", title));
		return (0);
	}
	DISPDBG((DUMP_PARAM_LEVEL, "[%s]\n", title));
	DumpHex(" device handle", (ULONG) pso->dhsurf);
	DumpHex(" logical handle for the surface", (ULONG) pso->hsurf);
	DumpHex(" pdev handle", (ULONG) pso->dhpdev);
	DumpHex(" logical handle for the pdev", (ULONG) pso->hdev);
	DumpSizel(" bitmap size", &(pso->sizlBitmap));
	DumpCombo(" buffer size", pso->cjBits);
	DumpHex(" bitmap address", (ULONG) pso->pvBits);
	DumpHex(" first scan line address", (ULONG) pso->pvScan0);
	DumpDecimal(" bytes per line", pso->lDelta);
	DumpCombo(" status", pso->iUniq);
	DumpTable(" bitmap format", pso->iBitmapFormat, StypeString, STYPE_MAX);
	DumpTable(" surface type", pso->iType, ItypeString, ITYPE_MAX);
	return(DumpDecimal(" bitmap style (direction)", pso->fjBitmap));
}

LONG
DumpClipObj(
	char	*title,
	CLIPOBJ	*pco
	)
{

#define	DCOMP_MAX	4
#define	FCOMP_MAX	4

	char	*DcompString[DCOMP_MAX] = {"TRIVIAL", "RECT", "#INVALID#", "COMPLEX"};
	char	*FcompString[FCOMP_MAX] = {"#INVALID#", "RECT", "RECT4", "COMPLEX"}; 
	
	if(pco == NULL) {
		DISPDBG((DUMP_PARAM_LEVEL, "[%s] -- NULL\n", title));
		return(0);
	}
	DISPDBG((DUMP_PARAM_LEVEL, "[%s]\n", title));
	DumpCombo(" clip region ID", pco->iUniq);
	DumpRectl(" bounding rectangle", &(pco->rclBounds));
	DumpTable(" complexity", pco->iDComplexity, DcompString, DCOMP_MAX);
	DumpTable(" whole region complexity", pco->iFComplexity, FcompString, FCOMP_MAX);
	DumpCombo(" mode", pco->iMode);
	return(DumpCombo(" options", pco->fjOptions));
}

LONG
DumpXlateObj(
	char		*title,
	XLATEOBJ	*pxlo
	)
{

#define	XLATFL_MAX	3
#define	XLATST_MAX	4

FLTABLE	xlatfltbl[XLATFL_MAX] = {	{XO_TRIVIAL, "TRIVIAL"},
									{XO_TABLE, "TABLE"},
									{XO_TO_MONO, "TO_MONO"}
								};

KEYTABLE xlatsttbl[XLATST_MAX] = {	{PAL_INDEXED, "PAL_INDEXED"},
									{PAL_BITFIELDS, "PAL_BITFIELDS"},
									{PAL_RGB, "PAL_RGB"},
									{PAL_BGR, "PAL_BGR"}
								};

	ULONG	i;
	
	if(pxlo == NULL) {
		DISPDBG((DUMP_PARAM_LEVEL, "[%s] -- NULL\n", title));
		return(0);
	}
	DISPDBG((DUMP_PARAM_LEVEL, "[%s]\n", title));
	DumpCombo(" xlate object ID", pxlo->iUniq);
	DumpFlong(" hints for translation", pxlo->flXlate, xlatfltbl, XLATFL_MAX);
	DumpKeyTable(" source palette type", pxlo->iSrcType, xlatsttbl, XLATST_MAX);
	DumpKeyTable(" target palette type", pxlo->iDstType, xlatsttbl, XLATST_MAX);
	DumpDecimal(" number of translation entries", pxlo->cEntries);
	for(i=0; i<pxlo->cEntries; ++i) {
		DumpCombo("   translation", pxlo->pulXlate[i]);
	}
	return(0);
}

LONG
DumpRectl(
	char	*title,
	RECTL	*prect
	)
{
	if(prect == NULL) {
		DISPDBG((DUMP_PARAM_LEVEL, "%s: NULL\n", title));
		return(0);
	}
	DISPDBG((DUMP_PARAM_LEVEL, "%s: (%d, %d) - (%d, %d)\n",
		title, prect->left, prect->top, prect->right, prect->bottom));
	return(0);
}

LONG
DumpPointl(
	char	*title,
	POINTL	*pptl
	)
{
	if(pptl == NULL) {
		DISPDBG((DUMP_PARAM_LEVEL, "%s: NULL\n", title));
		return(0);
	}
	DISPDBG((DUMP_PARAM_LEVEL, "%s: (%d, %d)\n", title, pptl->x, pptl->y));
	return(0);
}

LONG
DumpBrushObj(
	char		*title,
	BRUSHOBJ	*pbo
	)
{
	if(pbo == NULL) {
		DISPDBG((DUMP_PARAM_LEVEL, "[%s] -- NULL\n", title));
		return(0);
	}
	DISPDBG((DUMP_PARAM_LEVEL, "[%s]\n", title));
	DumpDecimal(" solid brush color index", pbo->iSolidColor);
	return(DumpHex(" realization of the brush", (ULONG) pbo->pvRbrush));
}

LONG
DumpColorAdjustment(
	char			*title,
	COLORADJUSTMENT *pca
	)
{

#define	CAFLG_MAX	2

static	FLTABLE	cafltbl[CAFLG_MAX] = {{CA_NEGATIVE, "NEGATIVE"}, {CA_LOG_FILTER, "LOG_FILTER"}};

#define	CAILL_MAX	9

static	char	*cailltbl[CAILL_MAX] = {"DEFAULT", "A", "B", "C", "D50", "D55", "D65", "D75", "F2"};

	if(pca == NULL) {
		DISPDBG((DUMP_PARAM_LEVEL, "[%s] -- NULL\n", title));
		return(0);
	}
	DISPDBG((DUMP_PARAM_LEVEL, "[%s]\n", title));
	DumpDecimal(" size of the structure", pca->caSize);
	DumpFlong(" color flags", pca->caFlags, cafltbl, CAFLG_MAX);
	DumpTable(" illuminant", pca->caIlluminantIndex, cailltbl, CAILL_MAX);
	DumpDecimal(" RedGamma", pca->caRedGamma);
	DumpDecimal(" GreenGamma", pca->caGreenGamma);
	DumpDecimal(" BlueGamma", pca->caBlueGamma);
	DumpDecimal(" ReferenceBlack", pca->caReferenceBlack);
	DumpDecimal(" ReferenceWhite", pca->caReferenceWhite);
	DumpDecimal(" Contrast", pca->caContrast);
	DumpDecimal(" Brightness", pca->caBrightness);
	DumpDecimal(" Colorfulness", pca->caColorfulness);
	return(DumpDecimal(" RedGreenTint", pca->caRedGreenTint));
}

LONG
DumpPointFix(
	char		*title,
	POINTFIX	*pptfx
	)
{
	if(pptfx == NULL) {
		DISPDBG((DUMP_PARAM_LEVEL, "%s: NULL\n", title));
		return(0);
	}
	DISPDBG((DUMP_PARAM_LEVEL, "%s: (%d, %d)\n", title, pptfx->x, pptfx->y));
	return(0);
}

LONG
DumpSizel(
	char	*title,
	SIZEL	*sizep
	)
{
	if(sizep == NULL) {
		DISPDBG((DUMP_PARAM_LEVEL, "%s: NULL\n", title));
		return(0);
	}
	DISPDBG((DUMP_PARAM_LEVEL, "%s: (%d, %d)\n", title, sizep->cx, sizep->cy));
	return(0);
}

LONG
DumpStrObj(
	char	*title,
	STROBJ	*pstro
	)
{
	ULONG	i;

#define	STRFL_MAX	7

static	FLTABLE	strfltbl[STRFL_MAX] = {
			{SO_FLAG_DEFAULT_PLACEMENT, "DEFAULT"},
			{SO_HORIZONTAL, "HORIZONTAL"},
			{SO_VERTICAL, "VERTICAL"},
			{SO_REVERSED, "REVERSED"},
			{SO_ZERO_BEARINGS, "ZERO_BEARINGS"},
			{SO_CHAR_INC_EQUAL_BM_BASE, "BM_BASE"},
			{SO_MAXEXT_EQUAL_BM_SIDE, "BM_SIZE"}};

	if(pstro == NULL) {
		DISPDBG((DUMP_PARAM_LEVEL, "[%s] -- NULL\n", title));
		return(0);
	}
	DISPDBG((DUMP_PARAM_LEVEL, "[%s]\n", title));
	DumpDecimal(" number of glyphs", pstro->cGlyphs);
	DumpFlong(" accelerator flag", pstro->flAccel, strfltbl, STRFL_MAX);
	DumpDecimal(" fixed pitch width", pstro->ulCharInc);
	DumpRectl(" bounding box", &(pstro->rclBkGround));
	if(pstro->pgp) {	// Has glyph
		DumpString(" glyphs\n");
		for(i=0; i<pstro->cGlyphs; ++i) {
			DumpGlyphpos("glyphpos", &(pstro->pgp[i]));
		}
	} else {
		DumpString(" no glyphs\n");
	}
	if(pstro->pwszOrg)
		DISPDBG((DUMP_PARAM_LEVEL, "  unicode string: %S\n", pstro->pwszOrg));
	else
		DISPDBG((DUMP_PARAM_LEVEL, "  unicode string: NULL\n"));
	return(0);
}

LONG
DumpGlyphpos(
	char		*title,
	GLYPHPOS	*pgp
	)
{
	if(pgp == NULL) {
		DISPDBG((DUMP_PARAM_LEVEL, "   %s: NULL\n", title));
		return(0);
	}
	DISPDBG((DUMP_PARAM_LEVEL, "   -- %s dump --\n", title));
	DumpCombo("     handle for the glyph", pgp->hg);
	if(pgp->pgdf != NULL) {
		DumpPointl("     character origin", &(pgp->pgdf->pgb->ptlOrigin));
		DumpSizel("     glyph size", &(pgp->pgdf->pgb->sizlBitmap));
/******* printing gryph pattern is not practical using DISPDBG ******
		{
			LONG	i, j;
			BYTE	*bp;

			bp = pgp->pgdf->pgb->aj;
			for(i=0; i<pgp->pgdf->pgb->sizlBitmap.cy; ++i) {
				for(j=0; j<(pgp->pgdf->pgb->sizlBitmap.cx + 7)/8; ++j) {
					DumpString(bittable[*bp++]);
				}
				DumpString("\n");
			}
		}
********************************************************************/
	}
	return(DumpPointl("     position on device space", &(pgp->ptl)));
}

LONG
DumpFontObj(
	char	*title,
	FONTOBJ	*pfo
	)
{

#define	FNTFL_MAX	6

FLTABLE	fntfltbl[FNTFL_MAX] = {
	{FO_TYPE_RASTER, "RASTER"},
	{FO_TYPE_DEVICE, "DEVICE"},
	{FO_TYPE_TRUETYPE, "TRUETYPE"},
	{FO_SIM_BOLD, "BOLD"},
	{FO_SIM_ITALIC, "ITALIC"},
	{FO_EM_HEIGHT, "EM_HEIGHT"}};

	if(pfo == NULL) {
		DISPDBG((DUMP_PARAM_LEVEL, "[%s] -- NULL\n", title));
		return(0);
	}
	DISPDBG((DUMP_PARAM_LEVEL, "[%s]\n", title));
	DumpCombo(" font ID", pfo->iUniq);
	DumpDecimal(" index to the device font", pfo->iFace);
	DumpDecimal(" maximum width", pfo->cxMax);
	DumpFlong(" font type", pfo->flFontType, fntfltbl, FNTFL_MAX);
	DumpCombo(" ID for true type font", pfo->iTTUniq);
	DumpCombo(" ID for device font", pfo->iFile);
	DumpSizel(" resolution", &(pfo->sizLogResPpi));
	DumpDecimal(" size in point", pfo->ulStyleSize);
	DumpHex(" consumer", (ULONG) pfo->pvConsumer);
	return(DumpHex(" producer", (ULONG) pfo->pvProducer));
}

LONG
DumpMix(
	char	*title,
	MIX		mix
	)
{

#define	OP_MAX	17

static	char	*optbl[OP_MAX] = { "NULL", "BLACK (0)", "NOTMERGEPEN (DPon)", "MASKNOTPEN (DPna)",
	"NOTCOPYPEN (PN)", "MASKPENNOT (PDna)", "NOT (Dn)", "XORPEN (DPx)", "NOTMASKPEN (DPan)",
	"MASKPEN (DPa)", "NOTXORPEN (DPxn)", "NOP (D)", "MERGENOTPEN (DPno)", "COPYPEN (P)",
	"MERGEPENNOT (PDno)", "MERGEPEN (DPo)", "WHITE (1)" };

	DumpTable(title, (mix & 0xff00) >> 8, optbl, OP_MAX);
	return(DumpTable(title, (mix & 0xff), optbl, OP_MAX));
}

LONG
DumpPathObj(
	char	*title,
	PATHOBJ   *ppo
	)
{

#define	PATHFL_MAX	2

FLTABLE	pathfltbl[PATHFL_MAX] = {{PO_BEZIERS, "BEZIERS"} , {PO_ELLIPSE, "ELLIPSE"}};

	if(ppo == NULL) {
		DISPDBG((DUMP_PARAM_LEVEL, "[%s] -- NULL\n", title));
		return(0);
	}
	DISPDBG((DUMP_PARAM_LEVEL, "[%s]\n", title));
	DumpFlong(" hint flags", ppo->fl, pathfltbl, PATHFL_MAX);
	return(DumpDecimal(" number of curves", ppo->cCurves));
}

LONG
DumpXformObj(
	char	*title,
	XFORMOBJ  *pxo
	)
{
	if(pxo == NULL) {
		DISPDBG((DUMP_PARAM_LEVEL, "[%s] -- NULL\n", title));
		return(0);
	}
	DISPDBG((DUMP_PARAM_LEVEL, "[%s]\n", title));
	return(0);
}

LONG
DumpLineAttrs(
	char	*title,
	LINEATTRS *plineattrs
	)
{

#define	LINEFL_MAX	3

FLTABLE	linefltbl[LINEFL_MAX] = {{LA_GEOMETRIC, "Geometric"}, {LA_ALTERNATE, "Alternate"},
			{LA_STARTGAP, "StartGap"}};

#define	LINEJOIN_MAX	3

char	*linejointbl[LINEJOIN_MAX] = {"Round", "Bevel", "Mitter"};

#define	LINEEND_MAX		3

char	*linenedtbl[LINEEND_MAX] = {"Round", "Square", "Butt"};

	if(plineattrs == NULL) {
		DISPDBG((DUMP_PARAM_LEVEL, "   %s: NULL\n", title));
		return(0);
	}
	DISPDBG((DUMP_PARAM_LEVEL, "   -- %s dump --\n", title));
	DumpFlong("     option flag", plineattrs->fl, linefltbl, LINEFL_MAX);
	DumpTable("     join style", plineattrs->iJoin, linejointbl, LINEJOIN_MAX);
	DumpTable("     end style", plineattrs->iEndCap, linenedtbl, LINEEND_MAX);
	return(DumpDecimal("     number of style array", plineattrs->cstyle));
}

LONG
DumpDecimal(
	char	*title,
	ULONG	value
	)
{
	DISPDBG((DUMP_PARAM_LEVEL, "%s: %d\n", title, value));
	return(0);
}

LONG
DumpHex(
	char	*title,
	ULONG	value
	)
{
	DISPDBG((DUMP_PARAM_LEVEL, "%s: 0x%08x)\n", title, value));
	return(0);
}

LONG
DumpCombo(
	char	*title,
	ULONG	value
	)
{
	DISPDBG((DUMP_PARAM_LEVEL, "%s: %d (0x%x)\n", title, value, value));
	return(0);
}

LONG
DumpFlong(
	char	*title,
	FLONG	value,
	FLTABLE	*fltblp,
	ULONG	numentry
	)
{
	ULONG	i;

	DISPDBG((DUMP_PARAM_LEVEL, "%s\n", title));
	for(i=0; i<numentry; ++i) {
		if(value & fltblp[i].mask)
			DISPDBG((DUMP_PARAM_LEVEL, "   %s\n", fltblp[i].string));
	}
	return(0);
}

LONG
DumpKeyTable(
	char	*title,
	FLONG	value,
	KEYTABLE	*keytblp,
	ULONG	numentry
	)
{
	ULONG	i;

	DISPDBG((DUMP_PARAM_LEVEL, "%s\n", title));
	for(i=0; i<numentry; ++i) {
		if(value == keytblp[i].key) {
			DISPDBG((DUMP_PARAM_LEVEL, "   %s\n", keytblp[i].string));
			break;
		}
	}
	if(i == numentry) {
			DISPDBG((DUMP_PARAM_LEVEL, "Key not found (%d 0x%x)\n", value, value));
	}
	return(0);
}

LONG
DumpTable(
	char	*title,
	FLONG	value,
	char	**tablep,
	ULONG	numentry
	)
{
	DISPDBG((DUMP_PARAM_LEVEL, "%s: %s\n", title, (value < numentry)?tablep[value]:"Table index over"));
	return(0);
}

LONG
DumpString(
	char	*string
	)
{
	DISPDBG((DUMP_PARAM_LEVEL, string));
	return(0);
}

#endif	// INVESTIGATE