/*
** Copyright (C) 2003 Larry Hastings, larry@hastings.org
**
** This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
** The dx8Diagnostics / dx8Dynamic homepage is here:
** http://www.midwinter.com/~lch/programming/dx8diagnostics/
*/
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "dx8Diagnostics.h"
/*
** all of these macros assume the following
** * there is a variable "returnValue" of some sort of integer/enum type
** * there a goto label in the current function called "EXIT"
** * zero is success, nonzero is failure
*/
#define RETURN(expr) \
{ \
returnValue = expr; \
goto EXIT; \
} \
/* if the expression "expr" is nonzero, return whatever "expr" was */
#define ASSERT_SUCCESS(expr)\
{ \
returnValue = expr; \
if (returnValue) \
goto EXIT; \
} \
/* if the expression "expr" is false, return rv */
#define ASSERT_RETURN(expr, rv) \
{ \
if (!(expr)) \
{ \
returnValue = rv; \
goto EXIT; \
} \
} \
///////////////////////////////////////////////////////////////////////////
//
//
// random string helper functions
//
//
static char *collapse(char *s)
{
char *source = s;
char *destination = s;
do
{
if (isspace(*source))
source++;
else
*destination++ = *source++;
} while (*source);
*destination = 0;
return s;
};
///////////////////////////////////////////////////////////////////////////
//
//
// dx8DiagnosticsNameValue
//
//
dx8DiagnosticsNameValue *dx8DiagnosticsNameValueFind(dx8DiagnosticsNameValue *array, DWORD value)
{
while (array->name != NULL)
{
if (array->value == value)
return array;
array++;
}
return NULL;
}
///////////////////////////////////////////////////////////////////////////
//
//
// dx8DiagnosticsOutput
//
//
static char outputBuffer[2048];
static colorScheme colorSchemes[] =
{
{
{ "#0000b0", "white" }, // header
{ "#a0a0e0", "white" }, // subheader
{ "#e0e0ff", "black" } // body
},
{
{ "#d0d0d0", "white" }, // header
{ "#a0a0a0", "white" }, // subheader
{ "white", "black" } // body
},
{
{ "#0000b0", "white" }, // header
{ "#a0a0e0", "white" }, // subheader
{ "#ececff", "black" } // body
},
{
{ "#606060", "white" }, // header
{ "#a0a0a0", "white" }, // subheader
{ "#f0f0f0", "black" } // body
},
{
{ NULL, NULL }, // header
{ NULL, NULL }, // subheader
{ NULL, NULL } // body
},
};
dx8DiagnosticsOutput::dx8DiagnosticsOutput(void)
{
eos = false;
schemes = colorSchemes + 2;
scheme = colorSchemes;
}
void dx8DiagnosticsOutput::nextScheme(void)
{
scheme++;
if (scheme->header.background == NULL)
scheme = schemes;
}
HRESULT dx8DiagnosticsOutput::printEnum(char *name, DWORD value, dx8DiagnosticsNameValue *enumValues)
{
char *stringValue = "unknown?";
dx8DiagnosticsNameValue *namevalue = dx8DiagnosticsNameValueFind(enumValues, value);
if (namevalue != NULL)
stringValue = namevalue->name;
return print("<dt><b>%s</b>\n<dd><code>%s</code> (%u, <code>0x%x</code>)\n", name, stringValue, value, value);
}
HRESULT dx8DiagnosticsOutput::printBitfield(char *name, DWORD value, dx8DiagnosticsNameValue *bitValues)
{
HRESULT returnValue = S_OK;
ASSERT_SUCCESS(print("<dt><b>%s</b>\n<dd><code>0x%x</code> (%u)\n<blockquote>", name, value, value));
int i;
DWORD bitfield;
bool addBreak;
addBreak = false;
for (i = 0; i < 32; i++)
{
bitfield = 1 << i;
if ((value & bitfield) == bitfield)
{
dx8DiagnosticsNameValue *namevalue = dx8DiagnosticsNameValueFind(bitValues, bitfield);
char *stringValue = "unknown?";
if (namevalue != NULL)
stringValue = namevalue->name;
if (addBreak)
{
ASSERT_SUCCESS(print("<br>"));
}
addBreak = true;
ASSERT_SUCCESS(print("<code>%s</code> (<code>0x%x</code>, %u)\n", stringValue, bitfield, bitfield));
}
}
RETURN(print("</blockquote>\n"));
EXIT:
return returnValue;
}
HRESULT dx8DiagnosticsOutput::printInteger(char *name, DWORD value)
{
return print("<dt><b>%s</b>\n<dd>%u, <code>0x%x</code>\n", name, value, value);
}
HRESULT dx8DiagnosticsOutput::printFloat(char *name, double value)
{
return print("<dt><b>%s</b>\n<dd>%f\n", name, value);
}
HRESULT dx8DiagnosticsOutput::printString(char *name, const char *value)
{
return print("<dt><b>%s</b>\n<dd><code>%s</code>\n", name, value);
}
HRESULT dx8DiagnosticsOutput::printVersion(char *name, LARGE_INTEGER v)
{
int product = HIWORD(v.HighPart);
int version = LOWORD(v.HighPart);
int subVersion = HIWORD(v.LowPart);
int build = LOWORD(v.LowPart);
return print("<dt><b>%s</b>\n<dd>%d.%d.%d.%d\n", name, product, version, subVersion, build);
}
HRESULT dx8DiagnosticsOutput::printGUID(char *name, const GUID *value)
{
HRESULT returnValue = S_OK;
ASSERT_SUCCESS(print("<dt><b>%s</b>\n<dd><code>{%08x-%04x-%04x-", name, (DWORD)value->Data1, (DWORD)value->Data2, (DWORD)value->Data3));
int i;
for (i = 0; i < 8; i++)
{
char buffer[32];
// if you don't do this little dance, a char with its high bit set
// will result in a sign extension, and you'll wind up with FFFFFFA3
// or some such nonsense.
sprintf(buffer, "%08x", (DWORD)value->Data4[i]);
ASSERT_SUCCESS(print("%s", buffer + 6));
// canonical GUID form adds a dash here. don't ask me why.
if (i == 1)
ASSERT_SUCCESS(print("-"));
}
RETURN(print("}</code>\n"));
EXIT:
return returnValue;
}
HRESULT dx8DiagnosticsOutput::printWHQLLevel(char *name, DWORD level)
{
HRESULT returnValue = S_OK;
ASSERT_SUCCESS(print("<dt><b>%s</b>\n<dd>", name));
switch (level)
{
case 0:
RETURN(print("<i>Not digitally signed.</i>"));
case 1:
RETURN(print("WHQL digitally-signed, but no date information is available."));
default:
{
DWORD year = HIWORD(level);
DWORD month = HIBYTE(LOWORD(level));
DWORD day = LOBYTE(LOWORD(level));
RETURN(print("WHQL digitally-signed on <code>%d/%d/%d</code>.", year, month, day));
}
}
EXIT:
return returnValue;
}
HRESULT dx8DiagnosticsOutput::printWednesdaySpaced(char *string)
{
char buffer[256];
char *trace = buffer;
bool addSpace = false;
bool keepGoing = true;
char charBuffer[2];
charBuffer[1] = 0;
while (keepGoing)
{
char *append;
switch (*string)
{
case 0:
keepGoing = false;
continue;
case ' ':
append = " ";
break;
default:
append = charBuffer;
*charBuffer = *string;
break;
}
if (addSpace)
*trace++ = ' ';
addSpace = true;
lstrcpy(trace, append);
trace += lstrlen(trace);
string++;
}
return print(buffer);
}
HRESULT dx8DiagnosticsOutput::printHeading(char *title, int size)
{
HRESULT returnValue = S_OK;
char collapsedName[64];
strcpy(collapsedName, title);
collapse(collapsedName);
ASSERT_SUCCESS(print("<a name=%s><table width=100%% bgcolor=%s><tr><td><br><font size=%d color=%s><code><b>", collapsedName, scheme->header.background, size, scheme->header.foreground));
ASSERT_SUCCESS(printWednesdaySpaced(title));
RETURN(print("</b></code></font><p></td></tr></table></a>\n"));
EXIT:
return returnValue;
}
HRESULT dx8DiagnosticsOutput::printSubheading(char *title, int size)
{
HRESULT returnValue = S_OK;
ASSERT_SUCCESS(print("</dl><p><table width=100%% bgcolor=%s><tr><td><font size=%d color=%s><code><b>", scheme->subheader.background, size, scheme->subheader.foreground));
ASSERT_SUCCESS(printWednesdaySpaced(title));
RETURN(print("</b></code></font></td></tr></table></a><dl>\n"));
EXIT:
return returnValue;
}
HRESULT dx8DiagnosticsOutput::startBody(const char *subtitle, int size)
{
HRESULT returnValue = S_OK;
ASSERT_SUCCESS(print("<table width=100%% bgcolor=%s><tr><td><font color=%s>\n", scheme->body.background, scheme->body.foreground));
if (subtitle != NULL)
ASSERT_SUCCESS(print("<font size=5><b>%s</b><p></font>\n", subtitle));
RETURN(print("<dl>"));
EXIT:
return returnValue;
}
HRESULT dx8DiagnosticsOutput::endBody(void)
{
HRESULT returnValue = print("</dl></font></td></tr></table><p>\n");
nextScheme();
return returnValue;
}
///////////////////////////////////////////////////////////////////////////
//
//
// dx8DiagnosticsOutputMemory
//
//
void dx8DiagnosticsOutputMemory::initialize(char *buffer, DWORD bufferSize)
{
this->buffer = buffer;
this->bufferSize = bufferSize;
this->trace = buffer;
this->end = buffer + bufferSize;
}
dx8DiagnosticsOutputMemory::dx8DiagnosticsOutputMemory()
{
buffer = NULL;
}
HRESULT dx8DiagnosticsOutputMemory::print(char *format, ...)
{
if ((buffer == NULL) || (trace >= end))
return E_FAIL;
va_list list;
va_start(list, format);
// argh! would have used wvsprintf() here, except it doesn't support %f !
DWORD length = vsprintf(outputBuffer, format, list);
va_end(list);
#define MIN(a, b) ((a) < (b) ? (a) : (b))
length = MIN(length, (DWORD)((end - trace) - 1));
memcpy(trace, outputBuffer, length);
trace[length] = 0;
trace += length;
eos = (trace >= end);
return eos ? E_FAIL : S_OK;
}
///////////////////////////////////////////////////////////////////////////
//
//
// dx8DiagnosticsOutputFile
//
//
dx8DiagnosticsOutputFile::dx8DiagnosticsOutputFile()
{
hFile = INVALID_HANDLE_VALUE;
}
void dx8DiagnosticsOutputFile::initialize(char *filename)
{
hFile = CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
}
dx8DiagnosticsOutputFile::~dx8DiagnosticsOutputFile()
{
if (hFile != INVALID_HANDLE_VALUE)
CloseHandle(hFile);
}
HRESULT dx8DiagnosticsOutputFile::print(char *format, ...)
{
if (hFile == INVALID_HANDLE_VALUE)
return E_FAIL;
va_list list;
va_start(list, format);
// argh! would have used wvsprintf() here, except it doesn't support %f !
DWORD length = vsprintf(outputBuffer, format, list);
va_end(list);
DWORD written;
WriteFile(hFile, outputBuffer, length, &written, NULL);
eos = (length != written);
return eos ? E_FAIL : S_OK;
}
class printerTitle : public dx8DiagnosticsPrinter
{
public:
virtual HRESULT printTOC(dx8Diagnostics *diagnostics)
{
return S_OK;
}
virtual HRESULT printBody(dx8Diagnostics *diagnostics)
{
HRESULT returnValue = S_OK;
dx8DiagnosticsOutput *output = diagnostics->output;
ASSERT_SUCCESS(output->print("<html>\n\n<head>\n<title>%s Diagnostics</title>\n</head>\n\n<body>\n\n", diagnostics->applicationName));
ASSERT_SUCCESS(output->printHeading(diagnostics->applicationName, 7));
ASSERT_SUCCESS(output->printHeading("diagnostics"));
ASSERT_SUCCESS(output->startBody());
time_t now;
time(&now);
struct tm *local;
local = localtime(&now);
char buffer[64];
strftime(buffer, sizeof(buffer), "generated %Y/%m/%d %H:%M:%S", local);
ASSERT_SUCCESS(output->print("<code>"));
ASSERT_SUCCESS(output->printWednesdaySpaced(buffer));
ASSERT_SUCCESS(output->print("</code>\n"));
RETURN(output->endBody());
EXIT:
return returnValue;
}
};
class printerTOC : public dx8DiagnosticsPrinter
{
public:
virtual HRESULT printTOC(dx8Diagnostics *diagnostics)
{
return S_OK;
}
virtual HRESULT printBody(dx8Diagnostics *diagnostics)
{
HRESULT returnValue = S_OK;
dx8DiagnosticsOutput *output = diagnostics->output;
ASSERT_SUCCESS(output->printHeading("table of contents"));
ASSERT_SUCCESS(output->startBody());
dx8DiagnosticsPrinter *trace;
trace = diagnostics->head;
while (trace != NULL)
{
ASSERT_SUCCESS(trace->printTOC(diagnostics));
trace = trace->next;
}
RETURN(output->endBody());
EXIT:
return returnValue;
}
};
class printerFooter : public dx8DiagnosticsPrinter
{
public:
virtual HRESULT printTOC(dx8Diagnostics *diagnostics)
{
return S_OK;
}
virtual HRESULT printBody(dx8Diagnostics *diagnostics)
{
HRESULT returnValue = S_OK;
diagnostics->endTime = GetTickCount();
char buffer[64];
sprintf(buffer, "calculation took %dms", diagnostics->endTime - diagnostics->startTime);
dx8DiagnosticsOutput *output = diagnostics->output;
ASSERT_SUCCESS(output->printHeading(buffer, 4));
ASSERT_SUCCESS(output->print("<table width=100%% bgcolor=%s><tr><td><p><font color=%s size=-1 face=arial,helvetica><b>Generated by <a href=http://www.midwinter.com/~lch/programming/dx8diagnostics/><font color=%s>dx8Diagnostics version " DX8DIAGNOSTICS_VERSION "</font></a></b></font></td></tr></table>", output->scheme->header.background, output->scheme->header.foreground, output->scheme->header.foreground));
RETURN(diagnostics->output->print("\n\n</body>\n</html>"));
EXIT:
return returnValue;
}
};
///////////////////////////////////////////////////////////////////////////
//
//
// hardware
//
//
///////////////////////////////////////////////////////////////////////////
//
//
// IShellDispatch2 interface
// (typed in here so this compiles with MSVC6 even without the platform SDK)
//
//
#ifndef __IShellDispatch2_FWD_DEFINED__
#define __IShellDispatch2_FWD_DEFINED__
typedef interface IShellDispatch2 IShellDispatch2;
#endif /* __IShellDispatch2_FWD_DEFINED__ */
/* interface IShellDispatch2 */
/* [object][dual][hidden][oleautomation][helpstring][uuid] */
IID IID_IShellDispatch2 =
{
2764474668,
15273,
4562,
{
157,
234,
0,
192,
79,
177,
97,
98,
}
};
MIDL_INTERFACE("A4C6892C-3BA9-11d2-9DEA-00C04FB16162")
IShellDispatch2 : public IShellDispatch
{
public:
virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE IsRestricted(
/* [in] */ BSTR Group,
/* [in] */ BSTR Restriction,
/* [retval][out] */ long *plRestrictValue) = 0;
virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE ShellExecute(
/* [in] */ BSTR File,
/* [optional][in] */ VARIANT vArgs,
/* [optional][in] */ VARIANT vDir,
/* [optional][in] */ VARIANT vOperation,
/* [optional][in] */ VARIANT vShow) = 0;
virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE FindPrinter(
/* [optional][in] */ BSTR name,
/* [optional][in] */ BSTR location,
/* [optional][in] */ BSTR model) = 0;
virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE GetSystemInformation(
/* [in] */ BSTR name,
/* [retval][out] */ VARIANT *pv) = 0;
virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE ServiceStart(
/* [in] */ BSTR ServiceName,
/* [in] */ VARIANT Persistent,
/* [retval][out] */ VARIANT *pSuccess) = 0;
virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE ServiceStop(
/* [in] */ BSTR ServiceName,
/* [in] */ VARIANT Persistent,
/* [retval][out] */ VARIANT *pSuccess) = 0;
virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE IsServiceRunning(
/* [in] */ BSTR ServiceName,
/* [retval][out] */ VARIANT *pRunning) = 0;
virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE CanStartStopService(
/* [in] */ BSTR ServiceName,
/* [retval][out] */ VARIANT *pCanStartStop) = 0;
virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE ShowBrowserBar(
/* [in] */ BSTR bstrClsid,
/* [in] */ VARIANT bShow,
/* [retval][out] */ VARIANT *pSuccess) = 0;
};
class printerHardware : public dx8DiagnosticsPrinter
{
public:
virtual HRESULT printTOC(dx8Diagnostics *diagnostics)
{
dx8DiagnosticsOutput *output = diagnostics->output;
return output->print("<dd><a href=#hardware><code><b>hardware</b></code></a>\n");
}
virtual HRESULT printBody(dx8Diagnostics *diagnostics)
{
HRESULT returnValue = S_OK;
dx8DiagnosticsOutput *output = diagnostics->output;
IShellDispatch2 *shell2 = NULL;
BSTR bstr = NULL;
ASSERT_SUCCESS(output->printHeading("hardware"));
ASSERT_SUCCESS(output->startBody());
SYSTEM_INFO systemInfo;
memset(&systemInfo, 0, sizeof(systemInfo));
GetSystemInfo(&systemInfo);
#define PRINT_SYSTEM_INFO_FIELD(name, type) ASSERT_SUCCESS(PRINT_FIELD_ ## type(name, systemInfo))
PRINT_SYSTEM_INFO_FIELD(dwNumberOfProcessors, Integer);
PRINT_SYSTEM_INFO_FIELD(dwProcessorType, Integer);
PRINT_SYSTEM_INFO_FIELD(wProcessorLevel, Integer);
ASSERT_SUCCESS(output->printInteger("Model", (systemInfo.wProcessorRevision & 0xFFff) >> 8));
ASSERT_SUCCESS(output->printInteger("Stepping", systemInfo.wProcessorRevision & 0xFF));
if (CoCreateInstance(CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, IID_IShellDispatch2, (void **)&shell2) == 0)
{
VARIANT value;
bstr = SysAllocString(L"PhysicalMemoryInstalled");
ASSERT_RETURN(bstr != NULL, E_FAIL);
memset(&value, 0, sizeof(value));
if (SUCCEEDED(shell2->GetSystemInformation(bstr, &value)))
ASSERT_SUCCESS(output->printInteger("Physical Memory Installed (MB)", (DWORD)(value.dblVal / (1024 * 1024))));
SysFreeString(bstr);
bstr = SysAllocString(L"ProcessorSpeed");
ASSERT_RETURN(bstr != NULL, E_FAIL);
memset(&value, 0, sizeof(value));
if (SUCCEEDED(shell2->GetSystemInformation(bstr, &value)))
ASSERT_SUCCESS(output->printInteger("Processor Speed", value.intVal));
}
RETURN(output->endBody());
EXIT:
if (shell2 != NULL)
shell2->Release();
if (bstr != NULL)
SysFreeString(bstr);
return returnValue;
}
};
///////////////////////////////////////////////////////////////////////////
//
//
// operating system
//
//
class printerOS : public dx8DiagnosticsPrinter
{
public:
virtual HRESULT printTOC(dx8Diagnostics *diagnostics)
{
dx8DiagnosticsOutput *output = diagnostics->output;
return output->print("<dd><a href=#operatingsystem><code><b>operating system</b></code></a>\n");
}
virtual HRESULT printBody(dx8Diagnostics *diagnostics)
{
HRESULT returnValue = S_OK;
dx8DiagnosticsOutput *output = diagnostics->output;
OSVERSIONINFO osvi;
memset(&osvi, 0, sizeof(osvi));
osvi.dwOSVersionInfoSize = sizeof(osvi);
bool gotOsvi = (GetVersionEx(&osvi) != 0);
char *osName;
if (!gotOsvi)
osName = "<i>could not be determined!</i>";
else
{
osName = "<i>unknown!</i>";
switch (osvi.dwMajorVersion)
{
case 3:
{
osName = "Windows NT 3.51";
break;
}
case 4:
{
switch (osvi.dwMinorVersion)
{
case 0:
if (osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
osName = "Windows 95";
else
osName = "Windows NT 4.0";
break;
case 10:
osName = "Windows 98";
break;
case 90:
osName = "Windows ME";
break;
}
break;
}
case 5:
{
switch (osvi.dwMinorVersion)
{
case 0:
osName = "Windows 2000";
break;
case 1:
osName = "Windows XP or .NET Server";
break;
}
}
}
}
char buffer[128];
DWORD length;
ASSERT_SUCCESS(output->printHeading("operating system"));
ASSERT_SUCCESS(output->startBody(osName));
length = sizeof(buffer);
if (!GetComputerName(buffer, &length))
strcpy(buffer, "<i>could not be determined!</i>");
ASSERT_SUCCESS(output->printString("Computer Name", buffer));
length = sizeof(buffer);
if (!GetUserName(buffer, &length))
strcpy(buffer, "<i>could not be determined!</i>");
ASSERT_SUCCESS(output->printString("User Name", buffer));
#define PRINT_OSVERSIONINFO_FIELD(name, type) ASSERT_SUCCESS(PRINT_FIELD_ ## type(name, osvi))
if (gotOsvi)
{
sprintf(buffer, "%d.%d.%d", osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber);
ASSERT_SUCCESS(output->printString("OS Version", buffer));
ASSERT_SUCCESS(PRINT_FIELD_String(szCSDVersion, osvi));
OSVERSIONINFOEX osviex;
osviex.dwOSVersionInfoSize = sizeof(osviex);
if (GetVersionEx((OSVERSIONINFO *)&osviex) != 0)
{
sprintf(buffer, "%d.%d", osviex.wServicePackMajor, osviex.wServicePackMinor);
ASSERT_SUCCESS(output->printString("Service Pack Version", buffer));
}
}
RETURN(output->endBody());
EXIT:
return returnValue;
}
};
///////////////////////////////////////////////////////////////////////////
//
//
// direct 3d 8
//
//
static dx8DiagnosticsNameValue enumdwPlatformId[] =
{
dx8DiagnosticsNameValue(VER_PLATFORM_WIN32s)
dx8DiagnosticsNameValue(VER_PLATFORM_WIN32_WINDOWS)
dx8DiagnosticsNameValue(VER_PLATFORM_WIN32_NT)
{ NULL, 0}
};
static dx8DiagnosticsNameValue enumDeviceType[] =
{
dx8DiagnosticsNameValue(D3DDEVTYPE_HAL)
dx8DiagnosticsNameValue(D3DDEVTYPE_REF)
dx8DiagnosticsNameValue(D3DDEVTYPE_SW)
{ NULL, 0}
};
static dx8DiagnosticsNameValue bitfieldCaps[] =
{
dx8DiagnosticsNameValue(D3DCAPS_READ_SCANLINE)
{ NULL, 0}
};
#define D3DCAPS2_CANAUTOGENMIPMAP 0x40000000L /* DX9: The driver is capable of automatically generating mipmaps. For more information, see Automatic Generation of Mipmaps. */
static dx8DiagnosticsNameValue bitfieldCaps2[] =
{
dx8DiagnosticsNameValue(D3DCAPS2_NO2DDURING3DSCENE)
dx8DiagnosticsNameValue(D3DCAPS2_FULLSCREENGAMMA)
dx8DiagnosticsNameValue(D3DCAPS2_CANRENDERWINDOWED)
dx8DiagnosticsNameValue(D3DCAPS2_CANCALIBRATEGAMMA)
dx8DiagnosticsNameValue(D3DCAPS2_RESERVED)
dx8DiagnosticsNameValue(D3DCAPS2_CANMANAGERESOURCE)
dx8DiagnosticsNameValue(D3DCAPS2_DYNAMICTEXTURES)
dx8DiagnosticsNameValue_DX9(D3DCAPS2_CANAUTOGENMIPMAP)
{ NULL, 0}
};
//
// Caps3
//
#define D3DCAPS3_COPY_TO_VIDMEM 0x00000100L /* DX9: Device can accelerate a memory copy from system memory to local video memory. This cap guarantees that IDirect3DDevice9::UpdateSurface and IDirect3DDevice9::UpdateTexture calls will be hardware accelerated. If this cap is absent, these calls will succeed but will be slower. */
#define D3DCAPS3_COPY_TO_SYSTEMMEM 0x00000200L /* DX9: Device can accelerate a memory copy from local video memory to system memory. This cap guarantees that IDirect3DDevice9::GetRenderTargetData calls will be hardware accelerated. If this cap is absent, this call will succeed but will be slower. */
#define D3DCAPS3_LINEAR_TO_SRGB_PRESENTATION 0x00000080L /* DX9 */
static dx8DiagnosticsNameValue bitfieldCaps3[] =
{
dx8DiagnosticsNameValue(D3DCAPS3_ALPHA_FULLSCREEN_FLIP_OR_DISCARD)
dx8DiagnosticsNameValue_DX9(D3DCAPS3_LINEAR_TO_SRGB_PRESENTATION)
dx8DiagnosticsNameValue_DX9(D3DCAPS3_COPY_TO_VIDMEM)
dx8DiagnosticsNameValue_DX9(D3DCAPS3_COPY_TO_SYSTEMMEM)
{ NULL, 0}
};
//
// PresentationIntervals
//
static dx8DiagnosticsNameValue bitfieldPresentationIntervals[] =
{
dx8DiagnosticsNameValue(D3DPRESENT_INTERVAL_DEFAULT)
dx8DiagnosticsNameValue(D3DPRESENT_INTERVAL_ONE)
dx8DiagnosticsNameValue(D3DPRESENT_INTERVAL_TWO)
dx8DiagnosticsNameValue(D3DPRESENT_INTERVAL_THREE)
dx8DiagnosticsNameValue(D3DPRESENT_INTERVAL_FOUR)
dx8DiagnosticsNameValue(D3DPRESENT_INTERVAL_IMMEDIATE)
{ NULL, 0}
};
//
// CursorCaps
//
// Driver supports HW color cursor in at least hi-res modes(height >=400)
static dx8DiagnosticsNameValue bitfieldCursorCaps[] =
{
dx8DiagnosticsNameValue(D3DCURSORCAPS_COLOR)
dx8DiagnosticsNameValue(D3DCURSORCAPS_LOWRES)
{ NULL, 0}
};
//
// DevCaps
static dx8DiagnosticsNameValue bitfieldDevCaps[] =
{
dx8DiagnosticsNameValue(D3DDEVCAPS_EXECUTESYSTEMMEMORY)
dx8DiagnosticsNameValue(D3DDEVCAPS_EXECUTEVIDEOMEMORY)
dx8DiagnosticsNameValue(D3DDEVCAPS_TLVERTEXSYSTEMMEMORY)
dx8DiagnosticsNameValue(D3DDEVCAPS_TLVERTEXVIDEOMEMORY)
dx8DiagnosticsNameValue(D3DDEVCAPS_TEXTURESYSTEMMEMORY)
dx8DiagnosticsNameValue(D3DDEVCAPS_TEXTUREVIDEOMEMORY)
dx8DiagnosticsNameValue(D3DDEVCAPS_DRAWPRIMTLVERTEX)
dx8DiagnosticsNameValue(D3DDEVCAPS_CANRENDERAFTERFLIP)
dx8DiagnosticsNameValue(D3DDEVCAPS_TEXTURENONLOCALVIDMEM)
dx8DiagnosticsNameValue(D3DDEVCAPS_DRAWPRIMITIVES2)
dx8DiagnosticsNameValue(D3DDEVCAPS_SEPARATETEXTUREMEMORIES)
dx8DiagnosticsNameValue(D3DDEVCAPS_DRAWPRIMITIVES2EX)
dx8DiagnosticsNameValue(D3DDEVCAPS_HWTRANSFORMANDLIGHT)
dx8DiagnosticsNameValue(D3DDEVCAPS_CANBLTSYSTONONLOCAL)
dx8DiagnosticsNameValue(D3DDEVCAPS_HWRASTERIZATION)
dx8DiagnosticsNameValue(D3DDEVCAPS_PUREDEVICE)
dx8DiagnosticsNameValue(D3DDEVCAPS_QUINTICRTPATCHES)
dx8DiagnosticsNameValue(D3DDEVCAPS_RTPATCHES)
dx8DiagnosticsNameValue(D3DDEVCAPS_RTPATCHHANDLEZERO)
dx8DiagnosticsNameValue(D3DDEVCAPS_NPATCHES)
{ NULL, 0}
};
//
// PrimitiveMiscCaps
//
// old
#define D3DPMISCCAPS_MASKPLANES 0x00000001L
#define D3DPMISCCAPS_CONFORMANT 0x00000008L
// dx9
#define D3DPMISCCAPS_INDEPENDENTWRITEMASKS 0x00004000L /* DX9: Device supports independent write masks for multiple element textures or multiple render targets. */
#define D3DPMISCCAPS_PERSTAGECONSTANT 0x00008000L /* DX9: Device supports per-stage constants. See D3DTSS_CONSTANT in D3DTEXTURESTAGESTATETYPE. */
#define D3DPMISCCAPS_FOGANDSPECULARALPHA 0x00010000L /* DX9: Device supports separate fog and specular alpha. Many devices use the specular alpha channel to store the fog factor. */
#define D3DPMISCCAPS_SEPARATEALPHABLEND 0x00020000L /* DX9: Device supports separate blend settings for the alpha channel. */
#define D3DPMISCCAPS_MRTINDEPENDENTBITDEPTHS 0x00040000L /* DX9: Device supports different bit depths for multiple render targets. */
#define D3DPMISCCAPS_MRTPOSTPIXELSHADERBLENDING 0x00080000L /* DX9: Device supports post-pixel shader operations for multiple render targets. */
#define D3DPMISCCAPS_FOGVERTEXCLAMPED 0x00100000L
static dx8DiagnosticsNameValue bitfieldPrimitiveMiscCaps[] =
{
dx8DiagnosticsNameValue_OLD(D3DPMISCCAPS_MASKPLANES)
dx8DiagnosticsNameValue(D3DPMISCCAPS_MASKZ)
dx8DiagnosticsNameValue(D3DPMISCCAPS_LINEPATTERNREP)
dx8DiagnosticsNameValue_OLD(D3DPMISCCAPS_CONFORMANT)
dx8DiagnosticsNameValue(D3DPMISCCAPS_CULLNONE)
dx8DiagnosticsNameValue(D3DPMISCCAPS_CULLCW)
dx8DiagnosticsNameValue(D3DPMISCCAPS_CULLCCW)
dx8DiagnosticsNameValue(D3DPMISCCAPS_COLORWRITEENABLE)
dx8DiagnosticsNameValue(D3DPMISCCAPS_CLIPPLANESCALEDPOINTS)
dx8DiagnosticsNameValue(D3DPMISCCAPS_CLIPTLVERTS)
dx8DiagnosticsNameValue(D3DPMISCCAPS_TSSARGTEMP)
dx8DiagnosticsNameValue(D3DPMISCCAPS_BLENDOP)
dx8DiagnosticsNameValue(D3DPMISCCAPS_NULLREFERENCE)
dx8DiagnosticsNameValue_DX9(D3DPMISCCAPS_INDEPENDENTWRITEMASKS)
dx8DiagnosticsNameValue_DX9(D3DPMISCCAPS_PERSTAGECONSTANT)
dx8DiagnosticsNameValue_DX9(D3DPMISCCAPS_FOGANDSPECULARALPHA)
dx8DiagnosticsNameValue_DX9(D3DPMISCCAPS_SEPARATEALPHABLEND)
dx8DiagnosticsNameValue_DX9(D3DPMISCCAPS_MRTINDEPENDENTBITDEPTHS)
dx8DiagnosticsNameValue_DX9(D3DPMISCCAPS_MRTPOSTPIXELSHADERBLENDING)
dx8DiagnosticsNameValue_DX9(D3DPMISCCAPS_FOGVERTEXCLAMPED)
{ NULL, 0}
};
//
// LineCaps
//
static dx8DiagnosticsNameValue bitfieldLineCaps[] =
{
dx8DiagnosticsNameValue(D3DLINECAPS_TEXTURE)
dx8DiagnosticsNameValue(D3DLINECAPS_ZTEST)
dx8DiagnosticsNameValue(D3DLINECAPS_BLEND)
dx8DiagnosticsNameValue(D3DLINECAPS_ALPHACMP)
dx8DiagnosticsNameValue(D3DLINECAPS_FOG)
{ NULL, 0}
};
//
// RasterCaps
//
// old
#define D3DPRASTERCAPS_ROP2 0x00000002L
#define D3DPRASTERCAPS_XOR 0x00000004L
#define D3DPRASTERCAPS_SUBPIXEL 0x00000020L
#define D3DPRASTERCAPS_SUBPIXELX 0x00000040L
#define D3DPRASTERCAPS_STIPPLE 0x00000200L
#define D3DPRASTERCAPS_ANTIALIASSORTDEPENDENT 0x00000400L
#define D3DPRASTERCAPS_ANTIALIASSORTINDEPENDENT 0x00000800L
// dx9
#define D3DPRASTERCAPS_TRANSLUCENTSORTINDEPENDENT 0x00080000L
#define D3DPRASTERCAPS_SCISSORTEST 0x01000000L
#define D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS 0x02000000L
#define D3DPRASTERCAPS_DEPTHBIAS 0x04000000L
#define D3DPRASTERCAPS_MULTISAMPLE_TOGGLE 0x08000000L
static dx8DiagnosticsNameValue bitfieldRasterCaps[] =
{
dx8DiagnosticsNameValue(D3DPRASTERCAPS_DITHER)
dx8DiagnosticsNameValue_OLD(D3DPRASTERCAPS_ROP2)
dx8DiagnosticsNameValue_OLD(D3DPRASTERCAPS_XOR)
dx8DiagnosticsNameValue(D3DPRASTERCAPS_PAT)
dx8DiagnosticsNameValue(D3DPRASTERCAPS_ZTEST)
dx8DiagnosticsNameValue_OLD(D3DPRASTERCAPS_SUBPIXEL)
dx8DiagnosticsNameValue_OLD(D3DPRASTERCAPS_SUBPIXELX)
dx8DiagnosticsNameValue(D3DPRASTERCAPS_FOGVERTEX)
dx8DiagnosticsNameValue(D3DPRASTERCAPS_FOGTABLE)
dx8DiagnosticsNameValue_OLD(D3DPRASTERCAPS_STIPPLE)
dx8DiagnosticsNameValue_OLD(D3DPRASTERCAPS_ANTIALIASSORTDEPENDENT)
dx8DiagnosticsNameValue_OLD(D3DPRASTERCAPS_ANTIALIASSORTINDEPENDENT)
dx8DiagnosticsNameValue(D3DPRASTERCAPS_ANTIALIASEDGES)
dx8DiagnosticsNameValue(D3DPRASTERCAPS_MIPMAPLODBIAS)
dx8DiagnosticsNameValue(D3DPRASTERCAPS_ZBIAS)
dx8DiagnosticsNameValue(D3DPRASTERCAPS_ZBUFFERLESSHSR)
dx8DiagnosticsNameValue(D3DPRASTERCAPS_FOGRANGE)
dx8DiagnosticsNameValue(D3DPRASTERCAPS_ANISOTROPY)
dx8DiagnosticsNameValue(D3DPRASTERCAPS_WBUFFER)
dx8DiagnosticsNameValue_DX9(D3DPRASTERCAPS_TRANSLUCENTSORTINDEPENDENT)
dx8DiagnosticsNameValue(D3DPRASTERCAPS_WFOG)
dx8DiagnosticsNameValue(D3DPRASTERCAPS_ZFOG)
dx8DiagnosticsNameValue(D3DPRASTERCAPS_COLORPERSPECTIVE)
dx8DiagnosticsNameValue(D3DPRASTERCAPS_STRETCHBLTMULTISAMPLE)
dx8DiagnosticsNameValue_DX9(D3DPRASTERCAPS_SCISSORTEST)
dx8DiagnosticsNameValue_DX9(D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS)
dx8DiagnosticsNameValue_DX9(D3DPRASTERCAPS_DEPTHBIAS)
dx8DiagnosticsNameValue_DX9(D3DPRASTERCAPS_MULTISAMPLE_TOGGLE)
{ NULL, 0}
};
//
// ZCmpCaps, AlphaCmpCaps
//
static dx8DiagnosticsNameValue bitfieldZCmpCaps[] =
{
dx8DiagnosticsNameValue(D3DPCMPCAPS_NEVER)
dx8DiagnosticsNameValue(D3DPCMPCAPS_LESS)
dx8DiagnosticsNameValue(D3DPCMPCAPS_EQUAL)
dx8DiagnosticsNameValue(D3DPCMPCAPS_LESSEQUAL)
dx8DiagnosticsNameValue(D3DPCMPCAPS_GREATER)
dx8DiagnosticsNameValue(D3DPCMPCAPS_NOTEQUAL)
dx8DiagnosticsNameValue(D3DPCMPCAPS_GREATEREQUAL)
dx8DiagnosticsNameValue(D3DPCMPCAPS_ALWAYS)
{ NULL, 0}
};
static dx8DiagnosticsNameValue *bitfieldAlphaCmpCaps = bitfieldZCmpCaps;
//
// SourceBlendCaps, DestBlendCaps
//
#define D3DPBLENDCAPS_BLENDFACTOR 0x00002000L /* DX9: Supports both D3DBLEND_BLENDFACTOR and D3DBLEND_INVBLENDFACTOR */
static dx8DiagnosticsNameValue bitfieldSrcBlendCaps[] =
{
dx8DiagnosticsNameValue(D3DPBLENDCAPS_ZERO)
dx8DiagnosticsNameValue(D3DPBLENDCAPS_ONE)
dx8DiagnosticsNameValue(D3DPBLENDCAPS_SRCCOLOR)
dx8DiagnosticsNameValue(D3DPBLENDCAPS_INVSRCCOLOR)
dx8DiagnosticsNameValue(D3DPBLENDCAPS_SRCALPHA)
dx8DiagnosticsNameValue(D3DPBLENDCAPS_INVSRCALPHA)
dx8DiagnosticsNameValue(D3DPBLENDCAPS_DESTALPHA)
dx8DiagnosticsNameValue(D3DPBLENDCAPS_INVDESTALPHA)
dx8DiagnosticsNameValue(D3DPBLENDCAPS_DESTCOLOR)
dx8DiagnosticsNameValue(D3DPBLENDCAPS_INVDESTCOLOR)
dx8DiagnosticsNameValue(D3DPBLENDCAPS_SRCALPHASAT)
dx8DiagnosticsNameValue(D3DPBLENDCAPS_BOTHSRCALPHA)
dx8DiagnosticsNameValue(D3DPBLENDCAPS_BOTHINVSRCALPHA)
dx8DiagnosticsNameValue_DX9(D3DPBLENDCAPS_BLENDFACTOR)
{ NULL, 0}
};
static dx8DiagnosticsNameValue *bitfieldDestBlendCaps = bitfieldSrcBlendCaps;
//
// ShadeCaps
//
static dx8DiagnosticsNameValue bitfieldShadeCaps[] =
{
dx8DiagnosticsNameValue(D3DPSHADECAPS_COLORGOURAUDRGB)
dx8DiagnosticsNameValue(D3DPSHADECAPS_SPECULARGOURAUDRGB)
dx8DiagnosticsNameValue(D3DPSHADECAPS_ALPHAGOURAUDBLEND)
dx8DiagnosticsNameValue(D3DPSHADECAPS_FOGGOURAUD)
{ NULL, 0}
};
//
// TextureCaps
//
#define D3DPTEXTURECAPS_NOPROJECTEDBUMPENV 0x00200000L /* DX9: Device does not support projected bump env lookup operation in programmable and fixed function pixel shaders */
static dx8DiagnosticsNameValue bitfieldTextureCaps[] =
{
dx8DiagnosticsNameValue(D3DPTEXTURECAPS_PERSPECTIVE)
dx8DiagnosticsNameValue(D3DPTEXTURECAPS_POW2)
dx8DiagnosticsNameValue(D3DPTEXTURECAPS_ALPHA)
dx8DiagnosticsNameValue(D3DPTEXTURECAPS_SQUAREONLY)
dx8DiagnosticsNameValue(D3DPTEXTURECAPS_TEXREPEATNOTSCALEDBYSIZE)
dx8DiagnosticsNameValue(D3DPTEXTURECAPS_ALPHAPALETTE)
dx8DiagnosticsNameValue(D3DPTEXTURECAPS_NONPOW2CONDITIONAL)
dx8DiagnosticsNameValue(D3DPTEXTURECAPS_PROJECTED)
dx8DiagnosticsNameValue(D3DPTEXTURECAPS_CUBEMAP)
dx8DiagnosticsNameValue(D3DPTEXTURECAPS_VOLUMEMAP)
dx8DiagnosticsNameValue(D3DPTEXTURECAPS_MIPMAP)
dx8DiagnosticsNameValue(D3DPTEXTURECAPS_MIPVOLUMEMAP)
dx8DiagnosticsNameValue(D3DPTEXTURECAPS_MIPCUBEMAP)
dx8DiagnosticsNameValue(D3DPTEXTURECAPS_CUBEMAP_POW2)
dx8DiagnosticsNameValue(D3DPTEXTURECAPS_VOLUMEMAP_POW2)
dx8DiagnosticsNameValue_DX9(D3DPTEXTURECAPS_NOPROJECTEDBUMPENV)
{ NULL, 0}
};
//
// TextureFilterCaps
//
// old
#define D3DPTFILTERCAPS_NEAREST 0x00000001L
#define D3DPTFILTERCAPS_LINEAR 0x00000002L
#define D3DPTFILTERCAPS_MIPNEAREST 0x00000004L
#define D3DPTFILTERCAPS_MIPLINEAR 0x00000008L
#define D3DPTFILTERCAPS_LINEARMIPNEAREST 0x00000010L
#define D3DPTFILTERCAPS_LINEARMIPLINEAR 0x00000020L
// dx9
#define D3DPTFILTERCAPS_MINFPYRAMIDALQUAD 0x00000800L
#define D3DPTFILTERCAPS_MINFGAUSSIANQUAD 0x00001000L
#define D3DPTFILTERCAPS_MAGFPYRAMIDALQUAD 0x08000000L
#define D3DPTFILTERCAPS_MAGFGAUSSIANQUAD 0x10000000L
static dx8DiagnosticsNameValue bitfieldTextureFilterCaps[] =
{
dx8DiagnosticsNameValue_OLD(D3DPTFILTERCAPS_NEAREST)
dx8DiagnosticsNameValue_OLD(D3DPTFILTERCAPS_LINEAR)
dx8DiagnosticsNameValue_OLD(D3DPTFILTERCAPS_MIPNEAREST)
dx8DiagnosticsNameValue_OLD(D3DPTFILTERCAPS_MIPLINEAR)
dx8DiagnosticsNameValue_OLD(D3DPTFILTERCAPS_LINEARMIPNEAREST)
dx8DiagnosticsNameValue_OLD(D3DPTFILTERCAPS_LINEARMIPLINEAR)
dx8DiagnosticsNameValue(D3DPTFILTERCAPS_MINFPOINT)
dx8DiagnosticsNameValue(D3DPTFILTERCAPS_MINFLINEAR)
dx8DiagnosticsNameValue(D3DPTFILTERCAPS_MINFANISOTROPIC)
dx8DiagnosticsNameValue(D3DPTFILTERCAPS_MIPFPOINT)
dx8DiagnosticsNameValue(D3DPTFILTERCAPS_MIPFLINEAR)
dx8DiagnosticsNameValue_DX9(D3DPTFILTERCAPS_MINFPYRAMIDALQUAD)
dx8DiagnosticsNameValue_DX9(D3DPTFILTERCAPS_MINFGAUSSIANQUAD)
dx8DiagnosticsNameValue(D3DPTFILTERCAPS_MAGFPOINT)
dx8DiagnosticsNameValue(D3DPTFILTERCAPS_MAGFLINEAR)
dx8DiagnosticsNameValue(D3DPTFILTERCAPS_MAGFANISOTROPIC)
dx8DiagnosticsNameValue(D3DPTFILTERCAPS_MAGFAFLATCUBIC)
dx8DiagnosticsNameValue(D3DPTFILTERCAPS_MAGFGAUSSIANCUBIC)
dx8DiagnosticsNameValue_DX9(D3DPTFILTERCAPS_MAGFPYRAMIDALQUAD)
dx8DiagnosticsNameValue_DX9(D3DPTFILTERCAPS_MAGFGAUSSIANQUAD)
{ NULL, 0}
};
static dx8DiagnosticsNameValue *bitfieldCubeTextureFilterCaps = bitfieldTextureFilterCaps;
static dx8DiagnosticsNameValue *bitfieldVolumeTextureFilterCaps = bitfieldTextureFilterCaps;
//
// TextureAddressCaps
//
static dx8DiagnosticsNameValue bitfieldTextureAddressCaps[] =
{
dx8DiagnosticsNameValue(D3DPTADDRESSCAPS_WRAP)
dx8DiagnosticsNameValue(D3DPTADDRESSCAPS_MIRROR)
dx8DiagnosticsNameValue(D3DPTADDRESSCAPS_CLAMP)
dx8DiagnosticsNameValue(D3DPTADDRESSCAPS_BORDER)
dx8DiagnosticsNameValue(D3DPTADDRESSCAPS_INDEPENDENTUV)
dx8DiagnosticsNameValue(D3DPTADDRESSCAPS_MIRRORONCE)
{ NULL, 0}
};
static dx8DiagnosticsNameValue *bitfieldVolumeTextureAddressCaps = bitfieldTextureAddressCaps;
//
// StencilCaps
//
// dx9
#define D3DSTENCILCAPS_TWOSIDED 0x00000100L
static dx8DiagnosticsNameValue bitfieldStencilCaps[] =
{
dx8DiagnosticsNameValue(D3DSTENCILCAPS_KEEP)
dx8DiagnosticsNameValue(D3DSTENCILCAPS_ZERO)
dx8DiagnosticsNameValue(D3DSTENCILCAPS_REPLACE)
dx8DiagnosticsNameValue(D3DSTENCILCAPS_INCRSAT)
dx8DiagnosticsNameValue(D3DSTENCILCAPS_DECRSAT)
dx8DiagnosticsNameValue(D3DSTENCILCAPS_INVERT)
dx8DiagnosticsNameValue(D3DSTENCILCAPS_INCR)
dx8DiagnosticsNameValue(D3DSTENCILCAPS_DECR)
dx8DiagnosticsNameValue(D3DSTENCILCAPS_TWOSIDED)
{ NULL, 0}
};
//
// TextureOpCaps
//
static dx8DiagnosticsNameValue bitfieldTextureOpCaps[] =
{
dx8DiagnosticsNameValue(D3DTEXOPCAPS_DISABLE)
dx8DiagnosticsNameValue(D3DTEXOPCAPS_SELECTARG1)
dx8DiagnosticsNameValue(D3DTEXOPCAPS_SELECTARG2)
dx8DiagnosticsNameValue(D3DTEXOPCAPS_MODULATE)
dx8DiagnosticsNameValue(D3DTEXOPCAPS_MODULATE2X)
dx8DiagnosticsNameValue(D3DTEXOPCAPS_MODULATE4X)
dx8DiagnosticsNameValue(D3DTEXOPCAPS_ADD)
dx8DiagnosticsNameValue(D3DTEXOPCAPS_ADDSIGNED)
dx8DiagnosticsNameValue(D3DTEXOPCAPS_ADDSIGNED2X)
dx8DiagnosticsNameValue(D3DTEXOPCAPS_SUBTRACT)
dx8DiagnosticsNameValue(D3DTEXOPCAPS_ADDSMOOTH)
dx8DiagnosticsNameValue(D3DTEXOPCAPS_BLENDDIFFUSEALPHA)
dx8DiagnosticsNameValue(D3DTEXOPCAPS_BLENDTEXTUREALPHA)
dx8DiagnosticsNameValue(D3DTEXOPCAPS_BLENDFACTORALPHA)
dx8DiagnosticsNameValue(D3DTEXOPCAPS_BLENDTEXTUREALPHAPM)
dx8DiagnosticsNameValue(D3DTEXOPCAPS_BLENDCURRENTALPHA)
dx8DiagnosticsNameValue(D3DTEXOPCAPS_PREMODULATE)
dx8DiagnosticsNameValue(D3DTEXOPCAPS_MODULATEALPHA_ADDCOLOR)
dx8DiagnosticsNameValue(D3DTEXOPCAPS_MODULATECOLOR_ADDALPHA)
dx8DiagnosticsNameValue(D3DTEXOPCAPS_MODULATEINVALPHA_ADDCOLOR)
dx8DiagnosticsNameValue(D3DTEXOPCAPS_MODULATEINVCOLOR_ADDALPHA)
dx8DiagnosticsNameValue(D3DTEXOPCAPS_BUMPENVMAP)
dx8DiagnosticsNameValue(D3DTEXOPCAPS_BUMPENVMAPLUMINANCE)
dx8DiagnosticsNameValue(D3DTEXOPCAPS_DOTPRODUCT3)
dx8DiagnosticsNameValue(D3DTEXOPCAPS_MULTIPLYADD)
dx8DiagnosticsNameValue(D3DTEXOPCAPS_LERP)
{ NULL, 0}
};
//
// FVFCaps
//
static dx8DiagnosticsNameValue bitfieldFVFCaps[] =
{
dx8DiagnosticsNameValue(D3DFVFCAPS_DONOTSTRIPELEMENTS)
dx8DiagnosticsNameValue(D3DFVFCAPS_PSIZE)
{ NULL, 0}
};
//
// VertexProcessingCaps
//
// dx9
#define D3DVTXPCAPS_TEXGEN_SPHEREMAP 0x00000100L /* DX9: device supports D3DTSS_TCI_SPHEREMAP */
#define D3DVTXPCAPS_NO_TEXGEN_NONLOCALVIEWER 0x00000200L /* DX9: device does not support TexGen in non-local viewer mode */
static dx8DiagnosticsNameValue bitfieldVertexProcessingCaps[] =
{
dx8DiagnosticsNameValue(D3DVTXPCAPS_TEXGEN)
dx8DiagnosticsNameValue(D3DVTXPCAPS_MATERIALSOURCE7)
dx8DiagnosticsNameValue(D3DVTXPCAPS_DIRECTIONALLIGHTS)
dx8DiagnosticsNameValue(D3DVTXPCAPS_POSITIONALLIGHTS)
dx8DiagnosticsNameValue(D3DVTXPCAPS_LOCALVIEWER)
dx8DiagnosticsNameValue(D3DVTXPCAPS_TWEENING)
dx8DiagnosticsNameValue(D3DVTXPCAPS_NO_VSDT_UBYTE4)
dx8DiagnosticsNameValue_DX9(D3DVTXPCAPS_TEXGEN_SPHEREMAP)
dx8DiagnosticsNameValue_DX9(D3DVTXPCAPS_NO_TEXGEN_NONLOCALVIEWER)
{ NULL, 0}
};
// new D3DFORMATs for DX9
#define D3DFMT_A8B8G8R8 32
#define D3DFMT_X8B8G8R8 33
#define D3DFMT_A2R10G10B10 35
#define D3DFMT_A16B16G16R16 36
#define D3DFMT_R8G8_B8G8 MAKEFOURCC('R', 'G', 'B', 'G')
#define D3DFMT_G8R8_G8B8 MAKEFOURCC('G', 'R', 'G', 'B')
#define D3DFMT_D32F_LOCKABLE 82
#define D3DFMT_D24FS8 83
#define D3DFMT_L16 81
#define D3DFMT_Q16W16V16U16 110
#define D3DFMT_MULTI2_ARGB8 MAKEFOURCC('M','E','T','1')
#define D3DFMT_R16F 111
#define D3DFMT_G16R16F 112
#define D3DFMT_A16B16G16R16F 113
#define D3DFMT_R32F 114
#define D3DFMT_G32R32F 115
#define D3DFMT_A32B32G32R32F 116
#define D3DFMT_CxV8U8 117
static dx8DiagnosticsNameValue enumSurfaceFormats[] =
{
dx8DiagnosticsNameValue(D3DFMT_R8G8B8)
dx8DiagnosticsNameValue(D3DFMT_A8R8G8B8)
dx8DiagnosticsNameValue(D3DFMT_X8R8G8B8)
dx8DiagnosticsNameValue(D3DFMT_R5G6B5)
dx8DiagnosticsNameValue(D3DFMT_X1R5G5B5)
dx8DiagnosticsNameValue(D3DFMT_A1R5G5B5)
dx8DiagnosticsNameValue(D3DFMT_A4R4G4B4)
dx8DiagnosticsNameValue(D3DFMT_R3G3B2)
dx8DiagnosticsNameValue(D3DFMT_A8)
dx8DiagnosticsNameValue(D3DFMT_A8R3G3B2)
dx8DiagnosticsNameValue(D3DFMT_X4R4G4B4)
dx8DiagnosticsNameValue(D3DFMT_A2B10G10R10)
dx8DiagnosticsNameValue_DX9(D3DFMT_A8B8G8R8)
dx8DiagnosticsNameValue_DX9(D3DFMT_X8B8G8R8)
dx8DiagnosticsNameValue(D3DFMT_G16R16)
dx8DiagnosticsNameValue_DX9(D3DFMT_A2R10G10B10)
dx8DiagnosticsNameValue_DX9(D3DFMT_A16B16G16R16)
dx8DiagnosticsNameValue(D3DFMT_A8P8)
dx8DiagnosticsNameValue(D3DFMT_P8)
dx8DiagnosticsNameValue(D3DFMT_L8)
dx8DiagnosticsNameValue(D3DFMT_A8L8)
dx8DiagnosticsNameValue(D3DFMT_A4L4)
dx8DiagnosticsNameValue(D3DFMT_V8U8)
dx8DiagnosticsNameValue(D3DFMT_L6V5U5)
dx8DiagnosticsNameValue(D3DFMT_X8L8V8U8)
dx8DiagnosticsNameValue(D3DFMT_Q8W8V8U8)
dx8DiagnosticsNameValue(D3DFMT_V16U16)
dx8DiagnosticsNameValue(D3DFMT_A2W10V10U10)
dx8DiagnosticsNameValue(D3DFMT_UYVY)
dx8DiagnosticsNameValue_DX9(D3DFMT_R8G8_B8G8)
dx8DiagnosticsNameValue(D3DFMT_YUY2)
dx8DiagnosticsNameValue_DX9(D3DFMT_G8R8_G8B8)
dx8DiagnosticsNameValue(D3DFMT_DXT1)
dx8DiagnosticsNameValue(D3DFMT_DXT2)
dx8DiagnosticsNameValue(D3DFMT_DXT3)
dx8DiagnosticsNameValue(D3DFMT_DXT4)
dx8DiagnosticsNameValue(D3DFMT_DXT5)
dx8DiagnosticsNameValue(D3DFMT_D16_LOCKABLE)
dx8DiagnosticsNameValue(D3DFMT_D32)
dx8DiagnosticsNameValue(D3DFMT_D15S1)
dx8DiagnosticsNameValue(D3DFMT_D24S8)
dx8DiagnosticsNameValue(D3DFMT_D24X8)
dx8DiagnosticsNameValue(D3DFMT_D24X4S4)
dx8DiagnosticsNameValue(D3DFMT_D16)
dx8DiagnosticsNameValue_DX9(D3DFMT_D32F_LOCKABLE)
dx8DiagnosticsNameValue_DX9(D3DFMT_D24FS8)
dx8DiagnosticsNameValue_DX9(D3DFMT_L16)
dx8DiagnosticsNameValue(D3DFMT_VERTEXDATA)
dx8DiagnosticsNameValue(D3DFMT_INDEX16)
dx8DiagnosticsNameValue(D3DFMT_INDEX32)
dx8DiagnosticsNameValue_DX9(D3DFMT_Q16W16V16U16)
dx8DiagnosticsNameValue_DX9(D3DFMT_MULTI2_ARGB8)
dx8DiagnosticsNameValue_DX9(D3DFMT_R16F)
dx8DiagnosticsNameValue_DX9(D3DFMT_G16R16F)
dx8DiagnosticsNameValue_DX9(D3DFMT_A16B16G16R16F)
dx8DiagnosticsNameValue_DX9(D3DFMT_R32F)
dx8DiagnosticsNameValue_DX9(D3DFMT_G32R32F)
dx8DiagnosticsNameValue_DX9(D3DFMT_A32B32G32R32F)
dx8DiagnosticsNameValue_DX9(D3DFMT_CxV8U8)
{ NULL, 0}
};
static dx8DiagnosticsNameValue enumUncompressedSurfaceFormats[] =
{
dx8DiagnosticsNameValue(D3DFMT_R8G8B8)
dx8DiagnosticsNameValue(D3DFMT_A8R8G8B8)
dx8DiagnosticsNameValue(D3DFMT_X8R8G8B8)
dx8DiagnosticsNameValue(D3DFMT_R5G6B5)
dx8DiagnosticsNameValue(D3DFMT_X1R5G5B5)
dx8DiagnosticsNameValue(D3DFMT_A1R5G5B5)
dx8DiagnosticsNameValue(D3DFMT_A4R4G4B4)
dx8DiagnosticsNameValue(D3DFMT_R3G3B2)
dx8DiagnosticsNameValue(D3DFMT_A8)
dx8DiagnosticsNameValue(D3DFMT_A8R3G3B2)
dx8DiagnosticsNameValue(D3DFMT_X4R4G4B4)
dx8DiagnosticsNameValue(D3DFMT_A2B10G10R10)
dx8DiagnosticsNameValue_DX9(D3DFMT_A8B8G8R8)
dx8DiagnosticsNameValue_DX9(D3DFMT_X8B8G8R8)
dx8DiagnosticsNameValue(D3DFMT_G16R16)
dx8DiagnosticsNameValue_DX9(D3DFMT_A2R10G10B10)
dx8DiagnosticsNameValue_DX9(D3DFMT_A16B16G16R16)
dx8DiagnosticsNameValue(D3DFMT_A8P8)
dx8DiagnosticsNameValue(D3DFMT_P8)
dx8DiagnosticsNameValue(D3DFMT_L8)
dx8DiagnosticsNameValue(D3DFMT_A8L8)
dx8DiagnosticsNameValue(D3DFMT_A4L4)
dx8DiagnosticsNameValue(D3DFMT_V8U8)
dx8DiagnosticsNameValue(D3DFMT_L6V5U5)
dx8DiagnosticsNameValue(D3DFMT_X8L8V8U8)
dx8DiagnosticsNameValue(D3DFMT_Q8W8V8U8)
dx8DiagnosticsNameValue(D3DFMT_V16U16)
dx8DiagnosticsNameValue(D3DFMT_A2W10V10U10)
dx8DiagnosticsNameValue_DX9(D3DFMT_Q16W16V16U16)
dx8DiagnosticsNameValue_DX9(D3DFMT_MULTI2_ARGB8)
dx8DiagnosticsNameValue_DX9(D3DFMT_R16F)
dx8DiagnosticsNameValue_DX9(D3DFMT_G16R16F)
dx8DiagnosticsNameValue_DX9(D3DFMT_A16B16G16R16F)
dx8DiagnosticsNameValue_DX9(D3DFMT_R32F)
dx8DiagnosticsNameValue_DX9(D3DFMT_G32R32F)
dx8DiagnosticsNameValue_DX9(D3DFMT_A32B32G32R32F)
dx8DiagnosticsNameValue_DX9(D3DFMT_CxV8U8)
{ NULL, 0}
};
static dx8DiagnosticsNameValue enumCompressedSurfaceFormats[] =
{
dx8DiagnosticsNameValue(D3DFMT_UYVY)
dx8DiagnosticsNameValue_DX9(D3DFMT_R8G8_B8G8)
dx8DiagnosticsNameValue(D3DFMT_YUY2)
dx8DiagnosticsNameValue_DX9(D3DFMT_G8R8_G8B8)
dx8DiagnosticsNameValue(D3DFMT_DXT1)
dx8DiagnosticsNameValue(D3DFMT_DXT2)
dx8DiagnosticsNameValue(D3DFMT_DXT3)
dx8DiagnosticsNameValue(D3DFMT_DXT4)
dx8DiagnosticsNameValue(D3DFMT_DXT5)
{ NULL, 0}
};
class printerD3D8 : public dx8DiagnosticsPrinter
{
public:
bool wantWHQL;
IDirect3D8 *d3d;
HRESULT d3dStatusCode;
int adapterCount;
D3DADAPTER_IDENTIFIER8 *identifiers;
HRESULT d3dAdapterStatusCode;
printerD3D8(bool wantWHQL = false)
{
this->wantWHQL = wantWHQL;
adapterCount = 0;
d3dAdapterStatusCode = S_OK;
if (!dx8DynamicIsAvailable())
{
d3d = NULL;
identifiers = NULL;
d3dStatusCode = dx8DynamicStatus();
}
else
{
d3d = dx8DynamicDirect3DCreate8(D3D_SDK_VERSION);
if (d3d == NULL)
d3dStatusCode = E_FAIL;
else
{
d3dStatusCode = S_OK;
adapterCount = d3d->GetAdapterCount();
identifiers = (D3DADAPTER_IDENTIFIER8 *)calloc(adapterCount, sizeof(D3DADAPTER_IDENTIFIER8));
if (identifiers != NULL)
{
int i;
for (i = 0; i < adapterCount; i++)
{
d3dAdapterStatusCode = d3d->GetAdapterIdentifier(i, wantWHQL ? D3DENUM_NO_WHQL_LEVEL : 0, identifiers + i);
if (d3dAdapterStatusCode != S_OK)
break;
}
}
}
}
}
virtual ~printerD3D8(void)
{
if (d3d != NULL)
{
d3d->Release();
d3d = NULL;
}
d3dStatusCode = E_FAIL;
}
virtual HRESULT printTOC(dx8Diagnostics *diagnostics)
{
HRESULT returnValue = S_OK;
dx8DiagnosticsOutput *output = diagnostics->output;
if ((adapterCount == 0) || (d3dAdapterStatusCode != S_OK))
{
RETURN(output->print("<dd><a href=#displayadapters><code><b>display adapters</b></code></a>\n"));
}
int i;
for (i = 0; i < adapterCount; i++)
{
ASSERT_SUCCESS(output->print("<dd><a href=#displayadapter%d><code><b>display adapter %d</b></code></a><code><b>:</b></code> <b>%s</b>\n", i, i, identifiers[i].Description));
}
EXIT:
return returnValue;
}
static int __cdecl displayModeSorter(const D3DDISPLAYMODE *mode1, const D3DDISPLAYMODE *mode2)
{
if (mode1->Format != mode2->Format)
return (int)mode1->Format - (int)mode2->Format;
if (mode1->Width != mode2->Width)
return (int)mode1->Width - (int)mode2->Width;
if (mode1->Height != mode2->Height)
return (int)mode1->Height - (int)mode2->Height;
return (int)mode1->RefreshRate - (int)mode2->RefreshRate;
}
virtual HRESULT printBody(dx8Diagnostics *diagnostics)
{
HRESULT returnValue = S_OK;
dx8DiagnosticsOutput *output = diagnostics->output;
if ((adapterCount == 0) || (d3dAdapterStatusCode != S_OK))
{
ASSERT_SUCCESS(output->printHeading("display adapters"));
ASSERT_SUCCESS(output->startBody("Direct3D version 8 could not be started!"));
ASSERT_SUCCESS(output->printInteger("<code>Direct3DCreate8()</code> status code", d3dStatusCode));
ASSERT_SUCCESS(output->printInteger("<code>GetAdapterIdentifier()</code> status code", d3dAdapterStatusCode));
RETURN(output->endBody());
}
int i;
for (i = 0; i < adapterCount; i++)
{
#define PRINT_IDENTIFIER_FIELD(name, type) ASSERT_SUCCESS(PRINT_FIELD_ ## type(name, identifiers[i]))
char buffer[256];
sprintf(buffer, "display adapter %d", i);
ASSERT_SUCCESS(output->printHeading(buffer));
ASSERT_SUCCESS(output->startBody(identifiers[i].Description));
PRINT_IDENTIFIER_FIELD(VendorId, Integer);
PRINT_IDENTIFIER_FIELD(DeviceId, Integer);
PRINT_IDENTIFIER_FIELD(SubSysId, Integer);
PRINT_IDENTIFIER_FIELD(Revision, Integer);
ASSERT_SUCCESS(output->printSubheading("driver"));
PRINT_IDENTIFIER_FIELD(Driver, String);
PRINT_IDENTIFIER_FIELD(DriverVersion, Version);
PRINT_IDENTIFIER_FIELD(DeviceIdentifier, GUID);
if (wantWHQL)
{
PRINT_IDENTIFIER_FIELD(WHQLLevel, WHQLLevel);
}
UINT totalModeCount = d3d->GetAdapterModeCount(i);
sprintf(buffer, "%d supported modes", totalModeCount);
// cache supported display formats for the benefit of compressed textures below
UINT supportedFormatCount = 0;
D3DFORMAT *supportedFormats = NULL;
ASSERT_SUCCESS(output->printSubheading(buffer));
if (!totalModeCount)
{
ASSERT_SUCCESS(output->print("<i>no display modes reported! woah, man!</i>"));
}
else
{
D3DDISPLAYMODE *modes = (D3DDISPLAYMODE *)malloc(totalModeCount * sizeof(D3DDISPLAYMODE));
UINT enumeratedModeCount = 0;
UINT j;
for (j = 0; j < totalModeCount; j++)
{
if (SUCCEEDED(d3d->EnumAdapterModes(i, j, modes + enumeratedModeCount)))
enumeratedModeCount++;
}
if (enumeratedModeCount == 0)
{
ASSERT_SUCCESS(output->print("<i>could not enumerate display modes!</i>"));
}
else
{
// sort the modes
qsort(modes, enumeratedModeCount, sizeof(D3DDISPLAYMODE),
(int (__cdecl *)(const void *, const void *))displayModeSorter);
bool firstResolutionInFormat;
bool firstRefreshRateInResolution;
for (j = 0; j < enumeratedModeCount; j++)
{
D3DDISPLAYMODE *mode = modes + j;
D3DDISPLAYMODE *lastmode = modes + j - 1;
// changing formats
if (!j || (mode->Format != lastmode->Format))
{
char *stringValue = "unknown?";
dx8DiagnosticsNameValue *namevalue = dx8DiagnosticsNameValueFind(enumSurfaceFormats, mode->Format);
if (namevalue != NULL)
stringValue = namevalue->name;
ASSERT_SUCCESS(output->print("%s<font size=+1><code>%s</code></font><blockquote>\n", (!j ? "" : "\n</blockquote>\n"), stringValue));
firstResolutionInFormat = true;
supportedFormatCount++;
}
// changing resolutions
if (firstResolutionInFormat || (mode->Width != lastmode->Width) || (mode->Height != lastmode->Height))
{
ASSERT_SUCCESS(output->print("%s<code><b>%s%d x %s%d</b></code>: ", (firstResolutionInFormat ? "" : "<br>\n"), ((mode->Width < 1000) ? " " : ""), mode->Width, ((mode->Height < 1000) ? " " : ""), mode->Height));
firstResolutionInFormat = false;
firstRefreshRateInResolution = true;
}
if (mode->RefreshRate != 0)
sprintf(buffer, "%dHz", mode->RefreshRate);
else
strcpy(buffer, "adapter default");
ASSERT_SUCCESS(output->print("%s%s", (firstRefreshRateInResolution ? "" : ", "), buffer));
firstRefreshRateInResolution = false;
}
ASSERT_SUCCESS(output->print("</blockquote>\n"));
}
supportedFormats = (D3DFORMAT *)malloc(sizeof(D3DFORMAT) * supportedFormatCount);
D3DFORMAT *trace = supportedFormats;
for (j = 0; j < enumeratedModeCount; j++)
{
D3DDISPLAYMODE *mode = modes + j;
D3DDISPLAYMODE *lastmode = modes + j - 1;
if (!j || (mode->Format != lastmode->Format))
*trace++ = mode->Format;
}
free(modes);
}
ASSERT_SUCCESS(output->printSubheading("compressed texture support"));
dx8DiagnosticsNameValue *namevalue;
int count = 0;
ASSERT_SUCCESS(output->print("<dt><b>Supported compressed texture formats:</b><dd><blockquote>\n"));
for (namevalue = enumCompressedSurfaceFormats; namevalue->name != NULL; namevalue++)
{
*buffer = 0;
DWORD j;
for (j = 0; j < supportedFormatCount; j++)
{
D3DFORMAT format = supportedFormats[j];
if (SUCCEEDED(d3d->CheckDeviceFormat(i, D3DDEVTYPE_HAL, D3DFMT_R5G6B5, 0, D3DRTYPE_TEXTURE, format)))
{
char *stringValue = "unknown?";
dx8DiagnosticsNameValue *namevalue = dx8DiagnosticsNameValueFind(enumSurfaceFormats, format);
if (namevalue != NULL)
stringValue = namevalue->name;
sprintf(buffer + strlen(buffer), " <code>%s</code>", stringValue);
}
}
if (*buffer)
{
ASSERT_SUCCESS(output->print("%s<code><b>%s</b></code>%s",
(count ? "<br>\n" : ""),
namevalue->name,
buffer
));
count++;
}
}
if (!count)
{
ASSERT_SUCCESS(output->print("<i>no compressed texture formats supported!</i>\n"));
}
ASSERT_SUCCESS(output->print("</blockquote>\n"));
free(supportedFormats);
ASSERT_SUCCESS(output->printSubheading("capabilities"));
#define PRINT_CAPS_FIELD(name, type) ASSERT_SUCCESS(PRINT_FIELD_ ## type(name, caps))
D3DCAPS8 caps;
memset(&caps, 0, sizeof(caps));
HRESULT result = d3d->GetDeviceCaps(i, D3DDEVTYPE_HAL, &caps);
if (result != D3D_OK)
{
ASSERT_SUCCESS(output->printInteger("<code>GetDeviceCaps()</code> status code", result));
}
else
{
PRINT_CAPS_FIELD(DeviceType, Enum);
PRINT_CAPS_FIELD(AdapterOrdinal, Integer);
PRINT_CAPS_FIELD(Caps, Bitfield);
PRINT_CAPS_FIELD(Caps2, Bitfield);
PRINT_CAPS_FIELD(Caps3, Bitfield);
PRINT_CAPS_FIELD(PresentationIntervals, Bitfield);
PRINT_CAPS_FIELD(CursorCaps, Bitfield);
PRINT_CAPS_FIELD(DevCaps, Bitfield);
PRINT_CAPS_FIELD(PrimitiveMiscCaps, Bitfield);
PRINT_CAPS_FIELD(RasterCaps, Bitfield);
PRINT_CAPS_FIELD(ZCmpCaps, Bitfield);
PRINT_CAPS_FIELD(SrcBlendCaps, Bitfield);
PRINT_CAPS_FIELD(DestBlendCaps, Bitfield);
PRINT_CAPS_FIELD(AlphaCmpCaps, Bitfield);
PRINT_CAPS_FIELD(ShadeCaps, Bitfield);
PRINT_CAPS_FIELD(TextureCaps, Bitfield);
PRINT_CAPS_FIELD(TextureFilterCaps, Bitfield); // D3DPTFILTERCAPS for IDirect3DTexture8's
PRINT_CAPS_FIELD(CubeTextureFilterCaps, Bitfield); // D3DPTFILTERCAPS for IDirect3DCubeTexture8's
PRINT_CAPS_FIELD(VolumeTextureFilterCaps, Bitfield); // D3DPTFILTERCAPS for IDirect3DVolumeTexture8's
PRINT_CAPS_FIELD(TextureAddressCaps, Bitfield); // D3DPTADDRESSCAPS for IDirect3DTexture8's
PRINT_CAPS_FIELD(VolumeTextureAddressCaps, Bitfield); // D3DPTADDRESSCAPS for IDirect3DVolumeTexture8's
PRINT_CAPS_FIELD(LineCaps, Bitfield); // D3DLINECAPS
PRINT_CAPS_FIELD(MaxTextureWidth, Integer);
PRINT_CAPS_FIELD(MaxTextureHeight, Integer);
PRINT_CAPS_FIELD(MaxVolumeExtent, Integer);
PRINT_CAPS_FIELD(MaxTextureRepeat, Integer);
PRINT_CAPS_FIELD(MaxTextureAspectRatio, Integer);
PRINT_CAPS_FIELD(MaxAnisotropy, Integer);
PRINT_CAPS_FIELD(MaxVertexW, Float);
PRINT_CAPS_FIELD(GuardBandLeft, Float);
PRINT_CAPS_FIELD(GuardBandTop, Float);
PRINT_CAPS_FIELD(GuardBandRight, Float);
PRINT_CAPS_FIELD(GuardBandBottom, Float);
PRINT_CAPS_FIELD(ExtentsAdjust, Float);
PRINT_CAPS_FIELD(StencilCaps, Bitfield);
ASSERT_SUCCESS(output->printInteger("FVF Maximum Texture Coordinate Sets", caps.FVFCaps & D3DFVFCAPS_TEXCOORDCOUNTMASK));
ASSERT_SUCCESS(output->printBitfield("FVFCaps", caps.FVFCaps & ~D3DFVFCAPS_TEXCOORDCOUNTMASK, bitfieldFVFCaps));
PRINT_CAPS_FIELD(TextureOpCaps, Bitfield);
PRINT_CAPS_FIELD(MaxTextureBlendStages, Integer);
PRINT_CAPS_FIELD(MaxSimultaneousTextures, Integer);
PRINT_CAPS_FIELD(VertexProcessingCaps, Bitfield);
PRINT_CAPS_FIELD(MaxActiveLights, Integer);
PRINT_CAPS_FIELD(MaxUserClipPlanes, Integer);
PRINT_CAPS_FIELD(MaxVertexBlendMatrices, Integer);
PRINT_CAPS_FIELD(MaxVertexBlendMatrixIndex, Integer);
PRINT_CAPS_FIELD(MaxPointSize, Float);
PRINT_CAPS_FIELD(MaxPrimitiveCount, Integer); // max number of primitives per DrawPrimitive call
PRINT_CAPS_FIELD(MaxVertexIndex, Integer);
PRINT_CAPS_FIELD(MaxStreams, Integer);
PRINT_CAPS_FIELD(MaxStreamStride, Integer); // max stride for SetStreamSource
PRINT_CAPS_FIELD(VertexShaderVersion, Integer);
PRINT_CAPS_FIELD(MaxVertexShaderConst, Integer); // number of vertex shader constant registers
PRINT_CAPS_FIELD(PixelShaderVersion, Integer);
PRINT_CAPS_FIELD(MaxPixelShaderValue, Float); // max value of pixel shader arithmetic component
}
ASSERT_SUCCESS(output->endBody());
}
EXIT:
return returnValue;
}
};
///////////////////////////////////////////////////////////////////////////
//
//
// direct sound 8
//
//
static dx8DiagnosticsNameValue bitfielddwFlags[] =
{
dx8DiagnosticsNameValue(DSCAPS_PRIMARYMONO)
dx8DiagnosticsNameValue(DSCAPS_PRIMARYSTEREO)
dx8DiagnosticsNameValue(DSCAPS_PRIMARY8BIT)
dx8DiagnosticsNameValue(DSCAPS_PRIMARY16BIT)
dx8DiagnosticsNameValue(DSCAPS_CONTINUOUSRATE)
dx8DiagnosticsNameValue(DSCAPS_EMULDRIVER)
dx8DiagnosticsNameValue(DSCAPS_CERTIFIED)
dx8DiagnosticsNameValue(DSCAPS_SECONDARYMONO)
dx8DiagnosticsNameValue(DSCAPS_SECONDARYSTEREO)
dx8DiagnosticsNameValue(DSCAPS_SECONDARY8BIT)
dx8DiagnosticsNameValue(DSCAPS_SECONDARY16BIT)
{ NULL, 0 }
};
static BOOL CALLBACK dSound8CallbackTOC(LPGUID guid, LPCSTR description, LPCSTR module, LPVOID context);
static BOOL CALLBACK dSound8CallbackBody(LPGUID guid, LPCSTR description, LPCSTR module, LPVOID context);
class printerDSound8 : public dx8DiagnosticsPrinter
{
public:
DWORD counter;
dx8DiagnosticsOutput *output;
bool noDevices;
printerDSound8(void)
{
noDevices = false;
}
virtual HRESULT printTOC(dx8Diagnostics *diagnostics)
{
this->output = diagnostics->output;
if (!dx8DynamicIsAvailable())
return output->print("<dd><a href=#soundadapters><code><b>sound adapters</b></code></a>\n");
counter = 0;
dx8DynamicDirectSoundEnumerateA(dSound8CallbackTOC, this);
if (counter == 0)
{
noDevices = true;
return output->print("<dd><a href=#soundadapters><code><b>sound adapters</b></code></a>\n");
}
return S_OK;
}
BOOL tocCallback(LPGUID guid, LPCSTR description, LPCSTR module)
{
output->print("<dd><a href=#soundadapter%d><code><b>sound adapter %d</b></code></a><code><b>:</b></code> <b>%s</b>\n", counter, counter, description);
counter++;
return TRUE;
}
virtual HRESULT printBody(dx8Diagnostics *diagnostics)
{
HRESULT returnValue = S_OK;
this->output = diagnostics->output;
if (!dx8DynamicIsAvailable())
{
ASSERT_SUCCESS(output->printHeading("sound adapters"));
ASSERT_SUCCESS(output->startBody("DirectSound version 8 could not be started!"));
RETURN(output->endBody());
}
if (noDevices)
{
ASSERT_SUCCESS(output->printHeading("sound adapters"));
ASSERT_SUCCESS(output->startBody("No sound adapters detected"));
RETURN(output->endBody());
}
counter = 0;
dx8DynamicDirectSoundEnumerateA(dSound8CallbackBody, this);
EXIT:
return returnValue;
}
BOOL bodyCallback(LPGUID guid, LPCSTR description, LPCSTR module)
{
HRESULT returnValue = S_OK;
LPDIRECTSOUND8 ds8 = NULL;
HRESULT hResult;
char buffer[64];
sprintf(buffer, "sound adapter %d", counter++);
ASSERT_SUCCESS(output->printHeading(buffer));
ASSERT_SUCCESS(output->startBody(description));
hResult = dx8DynamicDirectSoundCreate8(guid, &ds8, NULL);
if (ds8 == NULL)
{
ASSERT_SUCCESS(output->printInteger("<code>DirectSoundCreate8()</code> status code", hResult));
RETURN(output->endBody());
}
DSCAPS dscaps;
memset(&dscaps, 0, sizeof(dscaps));
dscaps.dwSize = sizeof(dscaps);
ds8->GetCaps(&dscaps);
#define PRINT_DSCAPS_FIELD(name, type) ASSERT_SUCCESS(PRINT_FIELD_ ## type(name, dscaps))
PRINT_DSCAPS_FIELD(dwFlags, Bitfield);
PRINT_DSCAPS_FIELD(dwMinSecondarySampleRate, Integer);
PRINT_DSCAPS_FIELD(dwMaxSecondarySampleRate, Integer);
PRINT_DSCAPS_FIELD(dwPrimaryBuffers, Integer);
PRINT_DSCAPS_FIELD(dwMaxHwMixingAllBuffers, Integer);
PRINT_DSCAPS_FIELD(dwMaxHwMixingStaticBuffers, Integer);
PRINT_DSCAPS_FIELD(dwMaxHwMixingStreamingBuffers, Integer);
PRINT_DSCAPS_FIELD(dwFreeHwMixingAllBuffers, Integer);
PRINT_DSCAPS_FIELD(dwFreeHwMixingStaticBuffers, Integer);
PRINT_DSCAPS_FIELD(dwFreeHwMixingStreamingBuffers, Integer);
PRINT_DSCAPS_FIELD(dwMaxHw3DAllBuffers, Integer);
PRINT_DSCAPS_FIELD(dwMaxHw3DStaticBuffers, Integer);
PRINT_DSCAPS_FIELD(dwMaxHw3DStreamingBuffers, Integer);
PRINT_DSCAPS_FIELD(dwFreeHw3DAllBuffers, Integer);
PRINT_DSCAPS_FIELD(dwFreeHw3DStaticBuffers, Integer);
PRINT_DSCAPS_FIELD(dwFreeHw3DStreamingBuffers, Integer);
PRINT_DSCAPS_FIELD(dwTotalHwMemBytes, Integer);
PRINT_DSCAPS_FIELD(dwFreeHwMemBytes, Integer);
PRINT_DSCAPS_FIELD(dwMaxContigFreeHwMemBytes, Integer);
PRINT_DSCAPS_FIELD(dwUnlockTransferRateHwBuffers, Integer);
PRINT_DSCAPS_FIELD(dwPlayCpuOverheadSwBuffers, Integer);
RETURN(output->endBody());
EXIT:
if (ds8 != NULL)
ds8->Release();
return TRUE;
}
};
static BOOL CALLBACK dSound8CallbackTOC(LPGUID guid, LPCSTR description, LPCSTR module, LPVOID context)
{
printerDSound8 *printer = (printerDSound8 *)context;
return printer->tocCallback(guid, description, module);
}
static BOOL CALLBACK dSound8CallbackBody(LPGUID guid, LPCSTR description, LPCSTR module, LPVOID context)
{
printerDSound8 *printer = (printerDSound8 *)context;
return printer->bodyCallback(guid, description, module);
}
///////////////////////////////////////////////////////////////////////////
//
//
// direct input 8
//
//
static dx8DiagnosticsNameValue inputType[] =
{
dx8DiagnosticsNameValue(DI8DEVTYPE_DEVICE)
dx8DiagnosticsNameValue(DI8DEVTYPE_MOUSE)
dx8DiagnosticsNameValue(DI8DEVTYPE_KEYBOARD)
dx8DiagnosticsNameValue(DI8DEVTYPE_JOYSTICK)
dx8DiagnosticsNameValue(DI8DEVTYPE_GAMEPAD)
dx8DiagnosticsNameValue(DI8DEVTYPE_DRIVING)
dx8DiagnosticsNameValue(DI8DEVTYPE_FLIGHT)
dx8DiagnosticsNameValue(DI8DEVTYPE_1STPERSON)
dx8DiagnosticsNameValue(DI8DEVTYPE_DEVICECTRL)
dx8DiagnosticsNameValue(DI8DEVTYPE_SCREENPOINTER)
dx8DiagnosticsNameValue(DI8DEVTYPE_REMOTE)
dx8DiagnosticsNameValue(DI8DEVTYPE_SUPPLEMENTAL)
{ NULL, 0 }
};
static dx8DiagnosticsNameValue inputSubtypeMouse[] =
{
dx8DiagnosticsNameValue(DI8DEVTYPEMOUSE_UNKNOWN)
dx8DiagnosticsNameValue(DI8DEVTYPEMOUSE_TRADITIONAL)
dx8DiagnosticsNameValue(DI8DEVTYPEMOUSE_FINGERSTICK)
dx8DiagnosticsNameValue(DI8DEVTYPEMOUSE_TOUCHPAD)
dx8DiagnosticsNameValue(DI8DEVTYPEMOUSE_TRACKBALL)
dx8DiagnosticsNameValue(DI8DEVTYPEMOUSE_ABSOLUTE)
{ NULL, 0 }
};
static dx8DiagnosticsNameValue inputSubtypeKeyboard[] =
{
dx8DiagnosticsNameValue(DI8DEVTYPEKEYBOARD_UNKNOWN)
dx8DiagnosticsNameValue(DI8DEVTYPEKEYBOARD_PCXT)
dx8DiagnosticsNameValue(DI8DEVTYPEKEYBOARD_OLIVETTI)
dx8DiagnosticsNameValue(DI8DEVTYPEKEYBOARD_PCAT)
dx8DiagnosticsNameValue(DI8DEVTYPEKEYBOARD_PCENH)
dx8DiagnosticsNameValue(DI8DEVTYPEKEYBOARD_NOKIA1050)
dx8DiagnosticsNameValue(DI8DEVTYPEKEYBOARD_NOKIA9140)
dx8DiagnosticsNameValue(DI8DEVTYPEKEYBOARD_NEC98)
dx8DiagnosticsNameValue(DI8DEVTYPEKEYBOARD_NEC98LAPTOP)
dx8DiagnosticsNameValue(DI8DEVTYPEKEYBOARD_NEC98106)
dx8DiagnosticsNameValue(DI8DEVTYPEKEYBOARD_JAPAN106)
dx8DiagnosticsNameValue(DI8DEVTYPEKEYBOARD_JAPANAX)
dx8DiagnosticsNameValue(DI8DEVTYPEKEYBOARD_J3100)
{ NULL, 0 }
};
static dx8DiagnosticsNameValue inputSubtypeJoystick[] =
{
dx8DiagnosticsNameValue(DI8DEVTYPEJOYSTICK_LIMITED)
dx8DiagnosticsNameValue(DI8DEVTYPEJOYSTICK_STANDARD)
{ NULL, 0 }
};
static dx8DiagnosticsNameValue inputSubtypeGamepad[] =
{
dx8DiagnosticsNameValue(DI8DEVTYPEGAMEPAD_LIMITED)
dx8DiagnosticsNameValue(DI8DEVTYPEGAMEPAD_STANDARD)
dx8DiagnosticsNameValue(DI8DEVTYPEGAMEPAD_TILT)
{ NULL, 0 }
};
static dx8DiagnosticsNameValue inputSubtypeDriving[] =
{
dx8DiagnosticsNameValue(DI8DEVTYPEDRIVING_LIMITED)
dx8DiagnosticsNameValue(DI8DEVTYPEDRIVING_COMBINEDPEDALS)
dx8DiagnosticsNameValue(DI8DEVTYPEDRIVING_DUALPEDALS)
dx8DiagnosticsNameValue(DI8DEVTYPEDRIVING_THREEPEDALS)
dx8DiagnosticsNameValue(DI8DEVTYPEDRIVING_HANDHELD)
{ NULL, 0 }
};
static dx8DiagnosticsNameValue inputSubtypeFlight[] =
{
dx8DiagnosticsNameValue(DI8DEVTYPEFLIGHT_LIMITED)
dx8DiagnosticsNameValue(DI8DEVTYPEFLIGHT_STICK)
dx8DiagnosticsNameValue(DI8DEVTYPEFLIGHT_YOKE)
dx8DiagnosticsNameValue(DI8DEVTYPEFLIGHT_RC)
{ NULL, 0 }
};
static dx8DiagnosticsNameValue inputSubtype1stPerson[] =
{
dx8DiagnosticsNameValue(DI8DEVTYPE1STPERSON_LIMITED)
dx8DiagnosticsNameValue(DI8DEVTYPE1STPERSON_UNKNOWN)
dx8DiagnosticsNameValue(DI8DEVTYPE1STPERSON_SIXDOF)
dx8DiagnosticsNameValue(DI8DEVTYPE1STPERSON_SHOOTER)
{ NULL, 0 }
};
static dx8DiagnosticsNameValue inputSubtypeScreenPointer[] =
{
dx8DiagnosticsNameValue(DI8DEVTYPESCREENPTR_UNKNOWN)
dx8DiagnosticsNameValue(DI8DEVTYPESCREENPTR_LIGHTGUN)
dx8DiagnosticsNameValue(DI8DEVTYPESCREENPTR_LIGHTPEN)
dx8DiagnosticsNameValue(DI8DEVTYPESCREENPTR_TOUCH)
{ NULL, 0 }
};
static dx8DiagnosticsNameValue inputSubtypeRemote[] =
{
dx8DiagnosticsNameValue(DI8DEVTYPEREMOTE_UNKNOWN)
{ NULL, 0 }
};
static dx8DiagnosticsNameValue inputSubtypeDeviceCtrl[] =
{
dx8DiagnosticsNameValue(DI8DEVTYPEDEVICECTRL_UNKNOWN)
dx8DiagnosticsNameValue(DI8DEVTYPEDEVICECTRL_COMMSSELECTION)
dx8DiagnosticsNameValue(DI8DEVTYPEDEVICECTRL_COMMSSELECTION_HARDWIRED)
{ NULL, 0 }
};
static dx8DiagnosticsNameValue inputSubtypeSupplemental[] =
{
dx8DiagnosticsNameValue(DI8DEVTYPESUPPLEMENTAL_UNKNOWN)
dx8DiagnosticsNameValue(DI8DEVTYPESUPPLEMENTAL_2NDHANDCONTROLLER)
dx8DiagnosticsNameValue(DI8DEVTYPESUPPLEMENTAL_HEADTRACKER)
dx8DiagnosticsNameValue(DI8DEVTYPESUPPLEMENTAL_HANDTRACKER)
dx8DiagnosticsNameValue(DI8DEVTYPESUPPLEMENTAL_SHIFTSTICKGATE)
dx8DiagnosticsNameValue(DI8DEVTYPESUPPLEMENTAL_SHIFTER)
dx8DiagnosticsNameValue(DI8DEVTYPESUPPLEMENTAL_THROTTLE)
dx8DiagnosticsNameValue(DI8DEVTYPESUPPLEMENTAL_SPLITTHROTTLE)
dx8DiagnosticsNameValue(DI8DEVTYPESUPPLEMENTAL_COMBINEDPEDALS)
dx8DiagnosticsNameValue(DI8DEVTYPESUPPLEMENTAL_DUALPEDALS)
dx8DiagnosticsNameValue(DI8DEVTYPESUPPLEMENTAL_THREEPEDALS)
dx8DiagnosticsNameValue(DI8DEVTYPESUPPLEMENTAL_RUDDERPEDALS)
{ NULL, 0 }
};
static dx8DiagnosticsNameValue inputSubtypeInvalid[] =
{
{ NULL, 0 }
};
static BOOL CALLBACK dInput8CallbackTOC(LPCDIDEVICEINSTANCE ddi, LPVOID context);
static BOOL CALLBACK dInput8CallbackBody(LPCDIDEVICEINSTANCE ddi, LPVOID context);
class printerDInput8 : public dx8DiagnosticsPrinter
{
public:
DWORD counter;
dx8DiagnosticsOutput *output;
IDirectInput8 *dInput;
bool noDevices;
HRESULT enumStatusCode;
HRESULT createStatusCode;
printerDInput8()
{
noDevices = false;
enumStatusCode = S_OK;
dInput = NULL;
enumStatusCode = E_FAIL;
if (!dx8DynamicIsAvailable())
createStatusCode = E_FAIL;
else
createStatusCode = dx8DynamicDirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8A, (void **)&dInput, NULL);
}
virtual ~printerDInput8()
{
if (dInput != NULL)
{
dInput->Release();
dInput = NULL;
}
}
virtual HRESULT printTOC(dx8Diagnostics *diagnostics)
{
counter = 0;
this->output = diagnostics->output;
if (createStatusCode != S_OK)
goto EXIT;
enumStatusCode = dInput->EnumDevices(DI8DEVCLASS_ALL, dInput8CallbackTOC, this, DIEDFL_ALLDEVICES);
EXIT:
if (counter == 0)
{
noDevices = true;
return output->print("<dd><a href=inputdevice><code><b>input devices</b></code></a>\n");
}
return S_OK;
}
virtual HRESULT printBody(dx8Diagnostics *diagnostics)
{
HRESULT returnValue = S_OK;
this->output = diagnostics->output;
if (noDevices)
{
ASSERT_SUCCESS(output->printHeading("input devices"));
ASSERT_SUCCESS(output->startBody("No input devices detected"));
ASSERT_SUCCESS(output->printInteger("<code>DirectInput8Create()</code> status code", createStatusCode));
ASSERT_SUCCESS(output->printInteger("<code>EnumDevices()</code> status code", enumStatusCode));
RETURN(output->endBody());
}
counter = 0;
dInput->EnumDevices(DI8DEVCLASS_ALL, dInput8CallbackBody, this, DIEDFL_ALLDEVICES);
EXIT:
return returnValue;
}
BOOL tocCallback(LPCDIDEVICEINSTANCE ddi)
{
output->print("<dd><a href=#inputdevice%d><code><b>input device %d</b></code></a><code><b>:</b></code> <b>%s</b>\n", counter, counter, ddi->tszInstanceName);
counter++;
return TRUE;
}
BOOL bodyCallback(LPCDIDEVICEINSTANCE ddi)
{
HRESULT returnValue = S_OK;
char buffer[64];
sprintf(buffer, "input device %d", counter++);
ASSERT_SUCCESS(output->printHeading(buffer));
ASSERT_SUCCESS(output->startBody(ddi->tszInstanceName));
#define PRINT_DDI_FIELD(name, type) ASSERT_SUCCESS(PRINT_FIELD_ ## type(name, (*ddi)))
PRINT_DDI_FIELD(tszProductName, String);
PRINT_DDI_FIELD(guidInstance, GUID);
PRINT_DDI_FIELD(guidProduct, GUID);
ASSERT_SUCCESS(output->printEnum("dwDevType", GET_DIDEVICE_TYPE(ddi->dwDevType), inputType));
dx8DiagnosticsNameValue *subtype;
subtype = inputSubtypeInvalid;
switch (GET_DIDEVICE_TYPE(ddi->dwDevType))
{
case DI8DEVTYPE_MOUSE:
subtype = inputSubtypeMouse;
break;
case DI8DEVTYPE_KEYBOARD:
subtype = inputSubtypeKeyboard;
break;
case DI8DEVTYPE_JOYSTICK:
subtype = inputSubtypeJoystick;
break;
case DI8DEVTYPE_GAMEPAD:
subtype = inputSubtypeGamepad;
break;
case DI8DEVTYPE_DRIVING:
subtype = inputSubtypeDriving;
break;
case DI8DEVTYPE_FLIGHT:
subtype = inputSubtypeFlight;
break;
case DI8DEVTYPE_1STPERSON:
subtype = inputSubtype1stPerson;
break;
case DI8DEVTYPE_DEVICECTRL:
subtype = inputSubtypeDeviceCtrl;
break;
case DI8DEVTYPE_SCREENPOINTER:
subtype = inputSubtypeScreenPointer;
break;
case DI8DEVTYPE_REMOTE:
subtype = inputSubtypeRemote;
break;
case DI8DEVTYPE_SUPPLEMENTAL:
subtype = inputSubtypeSupplemental;
break;
}
ASSERT_SUCCESS(output->printEnum("dwDevSubType", GET_DIDEVICE_SUBTYPE(ddi->dwDevType), subtype));
ASSERT_SUCCESS(output->endBody());
EXIT:
return TRUE;
}
};
static BOOL CALLBACK dInput8CallbackTOC(LPCDIDEVICEINSTANCE ddi, LPVOID context)
{
printerDInput8 *printer = (printerDInput8 *)context;
return printer->tocCallback(ddi);
}
static BOOL CALLBACK dInput8CallbackBody(LPCDIDEVICEINSTANCE ddi, LPVOID context)
{
printerDInput8 *printer = (printerDInput8 *)context;
return printer->bodyCallback(ddi);
}
///////////////////////////////////////////////////////////////////////////
//
//
// dlls
//
//
class printerDLLs : public dx8DiagnosticsPrinter
{
public:
virtual HRESULT printTOC(dx8Diagnostics *diagnostics)
{
dx8DiagnosticsOutput *output = diagnostics->output;
return output->print("<dd><a href=#dlls><code><b>dlls</b></code></a>\n");
}
virtual HRESULT printDLL(dx8DiagnosticsOutput *output, char *filename, char *filePath)
{
HRESULT returnValue = S_OK;
DWORD stupidVariable;
char buffer[256];
char versionBuffer[128];
strcpy(buffer, "version ");
strcpy(versionBuffer, "<i>unknown!</i>");
DWORD versionSize = GetFileVersionInfoSize(filePath, &stupidVariable);
if (versionSize)
{
void *version = malloc(versionSize);
if (GetFileVersionInfo(filePath, 0, versionSize, version) == 0)
sprintf(versionBuffer, "could not be determined (<code>GetFileVersionInfo()</code> returned %d)", GetLastError());
else
{
// the "file version" is often stored in two places
// in a Win32 PE header. (the mark of EXCELLENT design.)
// one is a normal string in StringFileInfo, the other
// is four words in the FIXEDFILEINFO structure.
// which one to use? it seems like if the string is set,
// use that, otherwise use the four words.
unsigned int length;
char *value;
VerQueryValue(version,
TEXT("\\StringFileInfo\\040904E4\\FileVersion"),
(void **)&value, &length);
if ((value != NULL) && length)
strcpy(versionBuffer, value);
else
{
VS_FIXEDFILEINFO *ffi;
VerQueryValue(version, "\\", (void **)&ffi, &length);
sprintf(versionBuffer, "%d.%d.%d.%d",
HIWORD(ffi->dwProductVersionMS),
LOWORD(ffi->dwProductVersionMS),
HIWORD(ffi->dwProductVersionLS),
LOWORD(ffi->dwProductVersionLS));
}
}
free(version);
}
strcat(buffer, versionBuffer);
strcat(buffer, ", size ");
HANDLE hFile = CreateFile(filePath, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE)
sprintf(buffer + strlen(buffer), "<i>unknown!</i> <code>CreateFile()</code> returned %d", GetLastError());
else
{
DWORD size = GetFileSize(hFile, NULL);
if (size == INVALID_FILE_SIZE)
sprintf(buffer + strlen(buffer), "<i>unknown!</i> <code>GetFileSize()</code> returned %d", GetLastError());
else
sprintf(buffer + strlen(buffer), "%d bytes", size);
CloseHandle(hFile);
}
RETURN(output->printString(filename, buffer));
EXIT:
return returnValue;
}
HRESULT findDLL(dx8DiagnosticsOutput *output, char *filename)
{
char filePath[_MAX_PATH];
char *ignored;
if (SearchPath(NULL, filename, NULL, sizeof(filePath), filePath, &ignored))
return printDLL(output, filename, filePath);
GetSystemDirectory(filePath, sizeof(filePath));
char *trace = filePath + strlen(filePath) - 1;
while ((*trace == '/') || (*trace == '\\'))
trace--;
trace++;
*trace++ = '\\';
#define TRY_DIRECTORY(x) \
strcpy(trace, x "\\"); \
strcat(trace, filename); \
if (GetFileAttributes(filePath) != 0xFFFFffff) \
return printDLL(output, filename, filePath) \
TRY_DIRECTORY("drivers");
TRY_DIRECTORY("dxxpdbg");
TRY_DIRECTORY("dllcache");
return output->printString(filename, "<i>not found!</i>");
}
HRESULT printBody(dx8Diagnostics *diagnostics)
{
HRESULT returnValue = S_OK;
dx8DiagnosticsOutput *output = diagnostics->output;
ASSERT_SUCCESS(output->printHeading("dlls"));
ASSERT_SUCCESS(output->startBody());
#define PROCESS_DLL(name) ASSERT_SUCCESS(findDLL(output, #name));
ASSERT_SUCCESS(output->printSubheading("directx"));
PROCESS_DLL(d3d8.dll)
PROCESS_DLL(d3d8d.dll)
PROCESS_DLL(d3d8thk.dll)
PROCESS_DLL(d3d9.dll)
PROCESS_DLL(d3d9d.dll)
PROCESS_DLL(d3dim.dll)
PROCESS_DLL(d3dim700.dll)
PROCESS_DLL(d3dpmesh.dll)
PROCESS_DLL(d3dramp.dll)
PROCESS_DLL(d3dref.dll)
PROCESS_DLL(d3dref8.dll)
PROCESS_DLL(d3dref9.dll)
PROCESS_DLL(d3drm.dll)
PROCESS_DLL(d3dx8d.dll)
PROCESS_DLL(d3dx9d.dll)
PROCESS_DLL(d3dxof.dll)
PROCESS_DLL(ddraw.dll)
PROCESS_DLL(ddrawex.dll)
PROCESS_DLL(diactfrm.dll)
PROCESS_DLL(dimap.dll)
PROCESS_DLL(dinput.dll)
PROCESS_DLL(dinput8.dll)
PROCESS_DLL(dinput8d.dll)
PROCESS_DLL(directx.cpl)
PROCESS_DLL(dmband.dll)
PROCESS_DLL(dmbandd.dll)
PROCESS_DLL(dmcompod.dll)
PROCESS_DLL(dmcompos.dll)
PROCESS_DLL(dmime.dll)
PROCESS_DLL(dmimed.dll)
PROCESS_DLL(dmloaded.dll)
PROCESS_DLL(dmloader.dll)
PROCESS_DLL(dmscripd.dll)
PROCESS_DLL(dmscript.dll)
PROCESS_DLL(dmstyle.dll)
PROCESS_DLL(dmstyled.dll)
PROCESS_DLL(dmsynth.dll)
PROCESS_DLL(dmsynthd.dll)
PROCESS_DLL(dmusic.dll)
PROCESS_DLL(dmusicd.dll)
PROCESS_DLL(dplay.dll)
PROCESS_DLL(dplaysvr.exe)
PROCESS_DLL(dplayx.dll)
PROCESS_DLL(dpmodemx.dll)
PROCESS_DLL(dpnaddr.dll)
PROCESS_DLL(dpnet.dll)
PROCESS_DLL(dpnetd.dll)
PROCESS_DLL(dpnhpast.dll)
PROCESS_DLL(dpnhpastd.dll)
PROCESS_DLL(dpnhupnp.dll)
PROCESS_DLL(dpnhupnpd.dll)
PROCESS_DLL(dpnlobby.dll)
PROCESS_DLL(dpnsvr.exe)
PROCESS_DLL(dpnsvrd.exe)
PROCESS_DLL(dpserial.dll)
PROCESS_DLL(dpvacm.dll)
PROCESS_DLL(dpvacmd.dll)
PROCESS_DLL(dpvoice.dll)
PROCESS_DLL(dpvoiced.dll)
PROCESS_DLL(dpvsetup.exe)
PROCESS_DLL(dpvvox.dll)
PROCESS_DLL(dpvvoxd.dll)
PROCESS_DLL(dpwsock.dll)
PROCESS_DLL(dpwsockx.dll)
PROCESS_DLL(dsdmo.dll)
PROCESS_DLL(dsdmoprp.dll)
PROCESS_DLL(dsound.dll)
PROCESS_DLL(dsound3d.dll)
PROCESS_DLL(dswave.dll)
PROCESS_DLL(dswaved.dll)
PROCESS_DLL(dx7vb.dll)
PROCESS_DLL(dx8vb.dll)
PROCESS_DLL(dxapi.sys)
PROCESS_DLL(dxdiagn.dll)
PROCESS_DLL(gcdef.dll)
PROCESS_DLL(joy.cpl)
PROCESS_DLL(Microsoft.DirectX.AudioVideoPlayback.dll)
PROCESS_DLL(Microsoft.DirectX.Diagnostics.dll)
PROCESS_DLL(Microsoft.DirectX.Direct3D.dll)
PROCESS_DLL(Microsoft.DirectX.Direct3DX.dll)
PROCESS_DLL(Microsoft.DirectX.DirectDraw.dll)
PROCESS_DLL(Microsoft.DirectX.DirectInput.dll)
PROCESS_DLL(Microsoft.DirectX.DirectPlay.dll)
PROCESS_DLL(Microsoft.DirectX.DirectSound.dll)
PROCESS_DLL(Microsoft.DirectX.dll)
PROCESS_DLL(pid.dll)
PROCESS_DLL(system.dll)
ASSERT_SUCCESS(output->printSubheading("c run-time library"));
PROCESS_DLL(mfc40.dll)
PROCESS_DLL(mfc42.dll)
PROCESS_DLL(msvcirt.dll)
PROCESS_DLL(msvcirtd.dll)
PROCESS_DLL(msvcp50.dll)
PROCESS_DLL(msvcp60.dll)
PROCESS_DLL(msvcp60d.dll)
PROCESS_DLL(msvcrt.dll)
PROCESS_DLL(msvcrtd.dll)
ASSERT_SUCCESS(output->printSubheading("windows"));
PROCESS_DLL(comctl32.dll)
PROCESS_DLL(comdlg32.dll)
PROCESS_DLL(ctl3d32.dll)
PROCESS_DLL(gdi32.dll)
PROCESS_DLL(kernel32.dll)
PROCESS_DLL(user32.dll)
PROCESS_DLL(version.dll)
PROCESS_DLL(wsock32.dll)
ASSERT_SUCCESS(output->printSubheading("internet explorer"));
PROCESS_DLL(shdocvw.dll)
ASSERT_SUCCESS(output->printSubheading("miscellaneous"));
PROCESS_DLL(amstream.dll)
PROCESS_DLL(bdaplgin.ax)
PROCESS_DLL(bdasup.sys)
PROCESS_DLL(ccdecode.sys)
PROCESS_DLL(devenum.dll)
PROCESS_DLL(dxmasf.dll)
PROCESS_DLL(encapi.dll)
PROCESS_DLL(iac25_32.ax)
PROCESS_DLL(ipsink.ax)
PROCESS_DLL(ir41_32.ax)
PROCESS_DLL(ir41_qc.dll)
PROCESS_DLL(ir41_qcx.dll)
PROCESS_DLL(ir50_32.dll)
PROCESS_DLL(ir50_qc.dll)
PROCESS_DLL(ir50_qcx.dll)
PROCESS_DLL(ivfsrc.ax)
PROCESS_DLL(ks.sys)
PROCESS_DLL(ksproxy.ax)
PROCESS_DLL(kstvtune.ax)
PROCESS_DLL(ksuser.dll)
PROCESS_DLL(kswdmcap.ax)
PROCESS_DLL(ksxbar.ax)
PROCESS_DLL(mciqtz32.dll)
PROCESS_DLL(mpe.sys)
PROCESS_DLL(mpeg2data.ax)
PROCESS_DLL(mpg2splt.ax)
PROCESS_DLL(msdmo.dll)
PROCESS_DLL(msdv.sys)
PROCESS_DLL(msdvbnp.ax)
PROCESS_DLL(mskssrv.sys)
PROCESS_DLL(mspclock.sys)
PROCESS_DLL(mspqm.sys)
PROCESS_DLL(mstee.sys)
PROCESS_DLL(msvidctl.dll)
PROCESS_DLL(mswebdvd.dll)
PROCESS_DLL(msyuv.dll)
PROCESS_DLL(nabtsfec.sys)
PROCESS_DLL(ndisip.sys)
PROCESS_DLL(psisdecd.dll)
PROCESS_DLL(psisrndr.ax)
PROCESS_DLL(qasf.dll)
PROCESS_DLL(qcap.dll)
PROCESS_DLL(qdv.dll)
PROCESS_DLL(qdvd.dll)
PROCESS_DLL(qedit.dll)
PROCESS_DLL(qedwipes.dll)
PROCESS_DLL(quartz.dll)
PROCESS_DLL(slip.sys)
PROCESS_DLL(stream.sys)
PROCESS_DLL(streamip.sys)
PROCESS_DLL(strmdll.dll)
PROCESS_DLL(swenum.sys)
PROCESS_DLL(vbisurf.ax)
PROCESS_DLL(vfwwdm32.dll)
PROCESS_DLL(wstcodec.sys)
PROCESS_DLL(wstdecod.dll)
RETURN(output->endBody());
EXIT:
return returnValue;
}
};
///////////////////////////////////////////////////////////////////////////
//
//
// finally! our main entry point.
//
//
dx8Diagnostics::dx8Diagnostics(char *applicationName)
{
output = NULL;
head = tail = NULL;
this->applicationName = applicationName;
}
dx8Diagnostics::~dx8Diagnostics(void)
{
if (output != NULL)
{
delete output;
output = NULL;
}
dx8DiagnosticsPrinter *trace = head;
while (trace != NULL)
{
dx8DiagnosticsPrinter *next = trace->next;
delete trace;
trace = next;
}
head = tail = NULL;
}
HRESULT dx8Diagnostics::append(dx8DiagnosticsPrinter *printer)
{
if (head == NULL)
head = printer;
else
tail->next = printer;
printer->next = NULL;
tail = printer;
return S_OK;
}
HRESULT dx8Diagnostics::write(void)
{
if (head == NULL)
dx8DiagnosticsAddDiagnostics(this, DX8DIAGNOSTICS_DEFAULT);
if (output == NULL)
dx8DiagnosticsWriteToFile(this, "dx8diagnostics.html");
if ((head == NULL) || (output == NULL))
return E_FAIL;
startTime = GetTickCount();
dx8DiagnosticsPrinter *trace = head;
while (trace != NULL)
{
trace->printBody(this);
trace = trace->next;
}
return S_OK;
}
HRESULT dx8DiagnosticsStartup(void)
{
CoInitialize(NULL);
dx8DynamicStartup();
return S_OK;
}
HRESULT dx8DiagnosticsShutdown(void)
{
dx8DynamicShutdown();
CoUninitialize();
return S_OK;
}
HRESULT dx8DiagnosticsCreate(dx8Diagnostics **diagnostics, char *applicationName)
{
*diagnostics = new dx8Diagnostics(applicationName);
return S_OK;
}
HRESULT dx8DiagnosticsWrite(dx8Diagnostics *diagnostics)
{
return diagnostics->write();
}
HRESULT dx8DiagnosticsDestroy(dx8Diagnostics **diagnostics)
{
dx8Diagnostics *d = *diagnostics;
*diagnostics = NULL;
delete d;
return S_OK;
}
HRESULT dx8DiagnosticsWriteToFile(dx8Diagnostics *diagnostics, char *filename)
{
dx8DiagnosticsOutputFile *outputFile = new dx8DiagnosticsOutputFile();
outputFile->initialize(filename);
diagnostics->output = outputFile;
return S_OK;
}
HRESULT dx8DiagnosticsWriteToMemory(dx8Diagnostics *diagnostics, char *buffer, size_t bufferSize)
{
dx8DiagnosticsOutputMemory *outputMemory = new dx8DiagnosticsOutputMemory();
outputMemory->initialize(buffer, bufferSize);
diagnostics->output = outputMemory;
return S_OK;
}
HRESULT dx8DiagnosticsAddDiagnostics(dx8Diagnostics *diagnostics, DWORD whichDiagnostics)
{
#define HANDLE_BITFIELD(bit, class) \
if (whichDiagnostics & bit) \
{ \
dx8DiagnosticsPrinter *printer = new class; \
diagnostics->append(printer); \
} \
HANDLE_BITFIELD(DX8DIAGNOSTICS_TITLE, printerTitle)
HANDLE_BITFIELD(DX8DIAGNOSTICS_TABLE_OF_CONTENTS, printerTOC)
HANDLE_BITFIELD(DX8DIAGNOSTICS_HARDWARE, printerHardware)
HANDLE_BITFIELD(DX8DIAGNOSTICS_OPERATING_SYSTEM, printerOS)
if (whichDiagnostics & (DX8DIAGNOSTICS_D3D8 | DX8DIAGNOSTICS_D3D8_WITH_WHQL))
{
printerD3D8 *printer = new printerD3D8((whichDiagnostics & DX8DIAGNOSTICS_D3D8_WITH_WHQL) != 0);
diagnostics->append(printer);
}
HANDLE_BITFIELD(DX8DIAGNOSTICS_DSOUND8, printerDSound8)
HANDLE_BITFIELD(DX8DIAGNOSTICS_DINPUT8, printerDInput8)
HANDLE_BITFIELD(DX8DIAGNOSTICS_DLLS, printerDLLs)
HANDLE_BITFIELD(DX8DIAGNOSTICS_FOOTER, printerFooter)
return S_OK;
}
|