511 lines
15 KiB
C++
511 lines
15 KiB
C++
|
#include <stdlib.h>
|
||
|
#include <stdio.h> // for debugging
|
||
|
#include <windows.h>
|
||
|
#include <commctrl.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/timeb.h>
|
||
|
#include <time.h>
|
||
|
#include <gl\gl.h>
|
||
|
|
||
|
#include "macros.h"
|
||
|
#include "prfl.h"
|
||
|
#include "skeltest.h"
|
||
|
#include "hugetest.h"
|
||
|
#include "primtest.h"
|
||
|
#include "teapot.h"
|
||
|
|
||
|
// Window procedure, handles all messages for this program
|
||
|
LRESULT CALLBACK prfl_WndProc(HWND, UINT msg, WPARAM, LPARAM);
|
||
|
|
||
|
extern HINSTANCE hInstance;
|
||
|
|
||
|
static LPCTSTR lpszClassName = "GL Profiler";
|
||
|
static SkeletonTest *pst = NULL;
|
||
|
static HINSTANCE hInst = NULL;
|
||
|
static HWND hwndTest = NULL;
|
||
|
static long lIdleCount = 0;
|
||
|
|
||
|
static struct _timeb timeStart;
|
||
|
static struct _timeb timeEnd;
|
||
|
|
||
|
void_void *prfl_EndFunct = NULL;
|
||
|
|
||
|
// Select the pixel format for a given device context
|
||
|
void SetDCPixelFormat(HDC hDC)
|
||
|
{
|
||
|
int nPixelFormat;
|
||
|
|
||
|
DWORD mode =
|
||
|
PFD_DRAW_TO_WINDOW | // Draw to Window (not to bitmap)
|
||
|
PFD_SUPPORT_OPENGL | // Support OpenGL calls in window
|
||
|
(pst->td.swapbuffers ? PFD_DOUBLEBUFFER : 0); // Double buffered mode?
|
||
|
|
||
|
static PIXELFORMATDESCRIPTOR pfd = {
|
||
|
sizeof(PIXELFORMATDESCRIPTOR), // Size of this structure
|
||
|
1, // Version of this structure
|
||
|
-1,
|
||
|
PFD_TYPE_RGBA, // RGBA Color mode
|
||
|
-1,
|
||
|
0,0,0,0,0,0, // Not used to select mode
|
||
|
0,0, // Not used to select mode
|
||
|
0,0,0,0,0, // Not used to select mode
|
||
|
-1,
|
||
|
0, // Not used to select mode
|
||
|
0, // Not used to select mode
|
||
|
PFD_MAIN_PLANE, // Draw in main plane
|
||
|
0, // Not used to select mode
|
||
|
0,0,0 }; // Not used to select mode
|
||
|
|
||
|
pfd.dwFlags = mode;
|
||
|
pfd.cDepthBits = pst->bd.cDepthBits;
|
||
|
pfd.cColorBits = GetDeviceCaps(hDC,BITSPIXEL)*GetDeviceCaps(hDC,PLANES);
|
||
|
|
||
|
// Choose a pixel format that best matches that described in pfd
|
||
|
nPixelFormat = ChoosePixelFormat(hDC, &pfd);
|
||
|
|
||
|
// Set the pixel format for the device context
|
||
|
SetPixelFormat(hDC, nPixelFormat, &pfd);
|
||
|
}
|
||
|
|
||
|
HWND prfl_InitWindow(LPCTSTR lpszWinName)
|
||
|
{
|
||
|
if (prfl_RegisterClass(NULL) == FALSE) {
|
||
|
fprintf(stderr,"Can't register class for test window.\n");
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
if (hwndTest != NULL)
|
||
|
return NULL;
|
||
|
|
||
|
hwndTest = CreateWindow(lpszClassName, lpszWinName,
|
||
|
// OpenGL requires WS_CLIPCHILDREN and WS_CLIPSIBLINGS
|
||
|
WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
|
||
|
WS_VISIBLE | DS_SYSMODAL,
|
||
|
// Window position and size
|
||
|
pst->td.iX, pst->td.iY, pst->td.iW, pst->td.iH,
|
||
|
NULL, NULL, hInst, NULL);
|
||
|
if (!hwndTest) {
|
||
|
fprintf(stderr,"Couldn't create test window.\n");
|
||
|
return NULL;
|
||
|
}
|
||
|
SetWindowPos(hwndTest, HWND_TOPMOST, 0, 0, 0, 0,
|
||
|
SWP_NOMOVE|SWP_NOSIZE|SWP_NOSENDCHANGING);
|
||
|
return hwndTest;
|
||
|
}
|
||
|
|
||
|
// If necessary, creates a 3-3-2 palette for the device context listed.
|
||
|
HPALETTE GetOpenGLPalette(HDC hDC)
|
||
|
{
|
||
|
HPALETTE hRetPal = NULL; // Handle to palette to be created
|
||
|
PIXELFORMATDESCRIPTOR pfd; // Pixel Format Descriptor
|
||
|
LOGPALETTE *pPal; // Pointer to memory for logical palette
|
||
|
int nPixelFormat; // Pixel format index
|
||
|
int nColors; // Number of entries in palette
|
||
|
int i; // Counting variable
|
||
|
BYTE RedRange,GreenRange,BlueRange;
|
||
|
// Range for each color entry (7,7,and 3)
|
||
|
|
||
|
// Get the pixel format index and retrieve the pixel format description
|
||
|
nPixelFormat = GetPixelFormat(hDC);
|
||
|
DescribePixelFormat(hDC, nPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
|
||
|
|
||
|
// Does this pixel format require a palette? If not, do not create a
|
||
|
// palette and just return NULL
|
||
|
if(!(pfd.dwFlags & PFD_NEED_PALETTE))
|
||
|
return NULL;
|
||
|
|
||
|
// Number of entries in palette. 8 bits yeilds 256 entries
|
||
|
nColors = 1 << pfd.cColorBits;
|
||
|
|
||
|
// Allocate space for a logical palette structure
|
||
|
// plus all the palette entries
|
||
|
pPal = (LOGPALETTE*)malloc(sizeof(LOGPALETTE)+nColors*sizeof(PALETTEENTRY));
|
||
|
|
||
|
// Fill in palette header
|
||
|
pPal->palVersion = 0x300; // Windows 3.0
|
||
|
pPal->palNumEntries = nColors; // table size
|
||
|
|
||
|
// Build mask of all 1's. This creates a number represented by having
|
||
|
// the low order x bits set, where x = pfd.cRedBits, pfd.cGreenBits, and
|
||
|
// pfd.cBlueBits.
|
||
|
RedRange = (1 << pfd.cRedBits) - 1;
|
||
|
GreenRange = (1 << pfd.cGreenBits) - 1;
|
||
|
BlueRange = (1 << pfd.cBlueBits) - 1;
|
||
|
|
||
|
// Loop through all the palette entries
|
||
|
for(i = 0; i < nColors; i++) {
|
||
|
// Fill in the 8-bit equivalents for each component
|
||
|
pPal->palPalEntry[i].peRed = (i >> pfd.cRedShift) & RedRange;
|
||
|
pPal->palPalEntry[i].peRed =
|
||
|
(unsigned char)((double) pPal->palPalEntry[i].peRed
|
||
|
* 255.0 / RedRange);
|
||
|
|
||
|
pPal->palPalEntry[i].peGreen = (i >> pfd.cGreenShift) & GreenRange;
|
||
|
pPal->palPalEntry[i].peGreen =
|
||
|
(unsigned char)((double)pPal->palPalEntry[i].peGreen
|
||
|
* 255.0 / GreenRange);
|
||
|
|
||
|
pPal->palPalEntry[i].peBlue = (i >> pfd.cBlueShift) & BlueRange;
|
||
|
pPal->palPalEntry[i].peBlue =
|
||
|
(unsigned char)((double)pPal->palPalEntry[i].peBlue
|
||
|
* 255.0 / BlueRange);
|
||
|
|
||
|
pPal->palPalEntry[i].peFlags = (unsigned char) NULL;
|
||
|
}
|
||
|
|
||
|
// Create the palette
|
||
|
hRetPal = CreatePalette(pPal);
|
||
|
|
||
|
// Go ahead and select and realize the palette for this device context
|
||
|
SelectPalette(hDC, hRetPal, FALSE);
|
||
|
RealizePalette(hDC);
|
||
|
|
||
|
// Free the memory used for the logical palette structure
|
||
|
free(pPal);
|
||
|
|
||
|
// Return the handle to the new palette
|
||
|
return hRetPal;
|
||
|
}
|
||
|
|
||
|
// Window procedure, handles all messages for this program
|
||
|
LRESULT CALLBACK prfl_WndProc(HWND hWnd, UINT msg,WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
static HGLRC hRC; // Permenant Rendering context
|
||
|
static HDC hDC; // Private GDI Device context
|
||
|
static HPALETTE hPalette = NULL;
|
||
|
//!!! Debug
|
||
|
static BOOL bStartOnce = TRUE;
|
||
|
|
||
|
switch (msg)
|
||
|
{
|
||
|
case WM_CREATE:
|
||
|
// Window creation, setup for OpenGL
|
||
|
// Store the device context
|
||
|
hDC = GetDC(hWnd);
|
||
|
|
||
|
// Select the pixel format
|
||
|
SetDCPixelFormat(hDC);
|
||
|
|
||
|
// Create the rendering context and make it current
|
||
|
hRC = wglCreateContext(hDC);
|
||
|
wglMakeCurrent(hDC, hRC);
|
||
|
|
||
|
// Create the palette
|
||
|
hPalette = GetOpenGLPalette(hDC);
|
||
|
|
||
|
// New window, restart timer state
|
||
|
bStartOnce = TRUE;
|
||
|
break;
|
||
|
|
||
|
case WM_SIZE:
|
||
|
if (bStartOnce) {
|
||
|
// do any initialization
|
||
|
if (pst)
|
||
|
pst->initfunct(LOWORD(lParam), HIWORD(lParam));
|
||
|
|
||
|
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT
|
||
|
| GL_STENCIL_BUFFER_BIT | GL_ACCUM_BUFFER_BIT);
|
||
|
glFlush();
|
||
|
if (pst && pst->td.swapbuffers) {
|
||
|
SwapBuffers(hDC);
|
||
|
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT
|
||
|
| GL_STENCIL_BUFFER_BIT | GL_ACCUM_BUFFER_BIT);
|
||
|
glFlush();
|
||
|
}
|
||
|
ValidateRect(hWnd,NULL);
|
||
|
lIdleCount = 0;
|
||
|
|
||
|
// Create a timer that fires every millisecond
|
||
|
SetTimer(hWnd,101,1,NULL);
|
||
|
// Only run for X seconds
|
||
|
SetTimer(hWnd,102,pst->td.iDuration,NULL);
|
||
|
_ftime(&timeStart);
|
||
|
// Only once!
|
||
|
bStartOnce = FALSE;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case WM_DESTROY:
|
||
|
_ftime(&timeEnd);
|
||
|
// Kill the timers that we created
|
||
|
KillTimer(hWnd,101);
|
||
|
KillTimer(hWnd,102);
|
||
|
|
||
|
// do any test-specific cleaning up
|
||
|
if (pst)
|
||
|
pst->destfunct();
|
||
|
|
||
|
// Deselect the current rendering context and delete it
|
||
|
wglMakeCurrent(hDC,NULL);
|
||
|
wglDeleteContext(hRC);
|
||
|
|
||
|
// Delete the palette
|
||
|
if(hPalette != NULL)
|
||
|
DeleteObject(hPalette);
|
||
|
|
||
|
hwndTest = NULL;
|
||
|
break;
|
||
|
|
||
|
case WM_TIMER:
|
||
|
// Call the idle function, if it exists, then force a repaint
|
||
|
if (wParam == 101) {
|
||
|
if (pst)
|
||
|
pst->idlefunct();
|
||
|
lIdleCount++;
|
||
|
InvalidateRect(hWnd,NULL,FALSE);
|
||
|
} else if (wParam == 102) {
|
||
|
DestroyWindow(hWnd);
|
||
|
// alert the caller of the test that it's over.
|
||
|
if (prfl_EndFunct)
|
||
|
prfl_EndFunct();
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case WM_PAINT:
|
||
|
// Call OpenGL drawing code
|
||
|
if (pst)
|
||
|
pst->rendfunct();
|
||
|
|
||
|
// Call function to swap the buffers
|
||
|
if (pst && pst->td.swapbuffers)
|
||
|
SwapBuffers(hDC);
|
||
|
|
||
|
// Validate the newly painted client area
|
||
|
ValidateRect(hWnd,NULL);
|
||
|
break;
|
||
|
|
||
|
case WM_QUERYNEWPALETTE:
|
||
|
// Windows is telling the application that it may modify
|
||
|
// the system palette. This message in essance asks the
|
||
|
// application for a new palette.
|
||
|
//
|
||
|
// If the palette was created.
|
||
|
if(hPalette) {
|
||
|
int nRet;
|
||
|
|
||
|
// Selects the palette into the current device context
|
||
|
SelectPalette(hDC, hPalette, FALSE);
|
||
|
|
||
|
// Map entries from the currently selected palette to
|
||
|
// the system palette. The return value is the number
|
||
|
// of palette entries modified.
|
||
|
nRet = RealizePalette(hDC);
|
||
|
|
||
|
// Repaint, forces remap of palette in current window
|
||
|
InvalidateRect(hWnd,NULL,FALSE);
|
||
|
|
||
|
return TRUE; // nRet
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case WM_PALETTECHANGED:
|
||
|
// This window may set the palette, even though it is not the
|
||
|
// currently active window.
|
||
|
//
|
||
|
// Don't do anything if the palette does not exist, or if
|
||
|
// this is the window that changed the palette.
|
||
|
if((hPalette != NULL) && ((HWND)wParam != hWnd)) {
|
||
|
// Select the palette into the device context
|
||
|
SelectPalette(hDC,hPalette,FALSE);
|
||
|
|
||
|
// Map entries to system palette
|
||
|
RealizePalette(hDC);
|
||
|
|
||
|
// Remap the current colors to the newly realized palette
|
||
|
UpdateColors(hDC);
|
||
|
return TRUE; // 0
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default: // Passes it on if unproccessed
|
||
|
return (DefWindowProc(hWnd, msg, wParam, lParam));
|
||
|
// return FALSE;
|
||
|
}
|
||
|
// return TRUE;
|
||
|
return (0L);
|
||
|
}
|
||
|
|
||
|
// Above are internal functions
|
||
|
|
||
|
|
||
|
// Below are public functions
|
||
|
|
||
|
void *prfl_AutoLoad(const char *szFileName, int *piError)
|
||
|
{
|
||
|
static char szErrorMsg[120];
|
||
|
static SkeletonTest st;
|
||
|
SkeletonTest *pst = NULL;
|
||
|
HANDLE hFile;
|
||
|
int i;
|
||
|
char *szType;
|
||
|
DWORD dwPointer;
|
||
|
|
||
|
if (!piError || !szFileName)
|
||
|
return NULL;
|
||
|
|
||
|
*piError = PRFL_NO_ERROR;
|
||
|
|
||
|
hFile = CreateFile(szFileName, GENERIC_READ, 0, NULL,
|
||
|
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||
|
if (hFile == INVALID_HANDLE_VALUE) {
|
||
|
sprintf(szErrorMsg, "Error opening file: %d\n", GetLastError());
|
||
|
*piError = PRFL_ERROR_OPENFILE;
|
||
|
return szErrorMsg;
|
||
|
}
|
||
|
i = st.Load(hFile);
|
||
|
if (i < 0) {
|
||
|
CloseHandle(hFile);
|
||
|
sprintf(szErrorMsg, "Error number %d while reading file", i);
|
||
|
*piError = PRFL_ERROR_LOADFILE;
|
||
|
return szErrorMsg;
|
||
|
}
|
||
|
dwPointer = SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
|
||
|
if (dwPointer == 0xFFFFFFFF) {
|
||
|
sprintf(szErrorMsg, "Error rewinding file: %d\n", GetLastError());
|
||
|
*piError = PRFL_ERROR_FILESEEK;
|
||
|
CloseHandle(hFile); // hope for no errors
|
||
|
return szErrorMsg;
|
||
|
}
|
||
|
|
||
|
szType = (char*) st.QueryType();
|
||
|
pst = NULL;
|
||
|
switch(szType[0])
|
||
|
{
|
||
|
case 's':
|
||
|
case 'S':
|
||
|
if (!strcasecmp(szType, "skeleton"))
|
||
|
pst = new(SkeletonTest);
|
||
|
break;
|
||
|
|
||
|
case 'h':
|
||
|
case 'H':
|
||
|
if (!strcasecmp(szType, "huge"))
|
||
|
pst = new(HugeTest);
|
||
|
break;
|
||
|
|
||
|
case 'p':
|
||
|
case 'P':
|
||
|
if (!strcasecmp(szType, "primative"))
|
||
|
pst = new(PrimativeTest);
|
||
|
break;
|
||
|
|
||
|
case 't':
|
||
|
case 'T':
|
||
|
if (!strcasecmp(szType, "teapot"))
|
||
|
pst = new(TeapotTest);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
sprintf(szErrorMsg, "Unknown test type: %s", szType);
|
||
|
*piError = PRFL_ERROR_UNKNOWN_TYPE;
|
||
|
return szErrorMsg;
|
||
|
}
|
||
|
|
||
|
i = pst->Load(hFile);
|
||
|
if (i < 0) {
|
||
|
CloseHandle(hFile);
|
||
|
sprintf(szErrorMsg, "Error number %d while reading file", i);
|
||
|
*piError = PRFL_ERROR_LOADFILE;
|
||
|
return szErrorMsg;
|
||
|
}
|
||
|
if (!CloseHandle(hFile)) {
|
||
|
sprintf(szErrorMsg, "Error closing file: %d\n", GetLastError());
|
||
|
*piError = PRFL_ERROR_CLOSEFILE;
|
||
|
return szErrorMsg;
|
||
|
}
|
||
|
|
||
|
return pst;
|
||
|
}
|
||
|
|
||
|
BOOL prfl_RegisterClass(HINSTANCE hInstance)
|
||
|
{
|
||
|
static BOOL fRet = FALSE;
|
||
|
WNDCLASS wc; // Windows class structure
|
||
|
|
||
|
if ((fRet == TRUE) || (!hInstance))
|
||
|
return fRet;
|
||
|
|
||
|
fRet = TRUE;
|
||
|
hInst = hInstance;
|
||
|
|
||
|
// Register Window style
|
||
|
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||
|
wc.lpfnWndProc = (WNDPROC) prfl_WndProc;
|
||
|
wc.cbClsExtra = 0;
|
||
|
wc.cbWndExtra = 0;
|
||
|
wc.hInstance = hInstance;
|
||
|
wc.hIcon = NULL;
|
||
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||
|
|
||
|
// No need for background brush for OpenGL window
|
||
|
wc.hbrBackground = NULL;
|
||
|
|
||
|
wc.lpszMenuName = NULL;
|
||
|
wc.lpszClassName = lpszClassName;
|
||
|
|
||
|
// Register the window class
|
||
|
if(RegisterClass(&wc) == 0)
|
||
|
fRet = FALSE;
|
||
|
|
||
|
return fRet;
|
||
|
}
|
||
|
|
||
|
BOOL prfl_StartTest(SkeletonTest *ptest, LPCTSTR lpzWinName, void_void EndFn)
|
||
|
{
|
||
|
prfl_EndFunct = EndFn;
|
||
|
|
||
|
if (hwndTest) {
|
||
|
fprintf(stderr,"Error: Test is already running.\n");
|
||
|
return FALSE;
|
||
|
}
|
||
|
if (ptest)
|
||
|
pst = ptest;
|
||
|
else
|
||
|
return FALSE;
|
||
|
|
||
|
if (NULL == prfl_InitWindow(lpzWinName)) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL prfl_StopTest(void)
|
||
|
{
|
||
|
if (hwndTest == NULL)
|
||
|
return TRUE;
|
||
|
DestroyWindow(hwndTest);
|
||
|
hwndTest = NULL;
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL prfl_TestRunning()
|
||
|
{
|
||
|
return (BOOL) hwndTest;
|
||
|
}
|
||
|
|
||
|
double prfl_GetDuration()
|
||
|
{
|
||
|
long lSecDiff;
|
||
|
long lMilDiff;
|
||
|
double dRet;
|
||
|
|
||
|
lSecDiff = (timeEnd.time - timeStart.time);
|
||
|
lMilDiff = (timeEnd.millitm - timeStart.millitm);
|
||
|
dRet = 1000*(lSecDiff + ((double) lMilDiff/1000));
|
||
|
return dRet;
|
||
|
}
|
||
|
|
||
|
double prfl_GetCount()
|
||
|
{
|
||
|
return (double) lIdleCount;
|
||
|
}
|
||
|
|
||
|
double prfl_GetResult()
|
||
|
{
|
||
|
if (!pst)
|
||
|
return -1.0;
|
||
|
return (pst->td.dResult * lIdleCount);
|
||
|
}
|