renderspu_wgl.c revision 1eb84e3fba012c8764e32737ab18b4973b70b301
/* Copyright (c) 2001, Stanford University
* All rights reserved
*
* See the file LICENSE.txt for information on redistributing this software.
*/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#include "cr_environment.h"
#include "cr_error.h"
#include "cr_string.h"
#include "renderspu.h"
#include "cr_mem.h"
/* IAT patcher stuff */
#define RVA2PTR(_t, _base, _off) ((_t*)(((uint8_t*)(_base)) + (_off)))
int renderspuIatPatcherGetImportAddress(HMODULE hModule, LPCSTR pszLib, LPCSTR pszName, void** ppAdr)
{
PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)hModule;
PIMAGE_NT_HEADERS pNtHdr;
PIMAGE_IMPORT_DESCRIPTOR pImportDr;
DWORD rvaImport;
crDebug("searching entry %s from %s", pszName, pszLib);
*ppAdr = 0;
if (pDosHdr->e_magic != IMAGE_DOS_SIGNATURE)
{
crWarning("invalid dos signature");
return VERR_INVALID_HANDLE;
}
pNtHdr = RVA2PTR(IMAGE_NT_HEADERS, pDosHdr, pDosHdr->e_lfanew);
if (pNtHdr->Signature != IMAGE_NT_SIGNATURE)
{
crWarning("invalid nt signature");
return VERR_INVALID_HANDLE;
}
rvaImport = pNtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
if (!rvaImport)
{
crWarning("no imports found");
return VERR_NOT_FOUND;
}
pImportDr = RVA2PTR(IMAGE_IMPORT_DESCRIPTOR, pDosHdr, rvaImport);
for ( ;pImportDr->TimeDateStamp != 0 || pImportDr->Name != 0; ++pImportDr)
{
DWORD rvaINT, rvaIAT;
PIMAGE_THUNK_DATA pINT, pIAT;
LPCSTR pszLibCur = RVA2PTR(char, pDosHdr, pImportDr->Name);
if (stricmp(pszLibCur, pszLib))
continue;
/* got the necessary lib! */
crDebug("got info for lib");
rvaINT = pImportDr->OriginalFirstThunk;
rvaIAT = pImportDr->FirstThunk;
if (!rvaINT || !rvaIAT)
{
crWarning("either rvaINT(0x%x) or rvaIAT(0x%x) are NULL, nothing found!", rvaINT, rvaIAT);
return VERR_NOT_FOUND;
}
pINT = RVA2PTR(IMAGE_THUNK_DATA, pDosHdr, rvaINT);
pIAT = RVA2PTR(IMAGE_THUNK_DATA, pDosHdr, rvaIAT);
for ( ; pINT->u1.AddressOfData; ++pINT, ++pIAT)
{
PIMAGE_IMPORT_BY_NAME pIbn;
if (IMAGE_SNAP_BY_ORDINAL(pINT->u1.Ordinal))
continue;
pIbn = RVA2PTR(IMAGE_IMPORT_BY_NAME, pDosHdr, pINT->u1.AddressOfData);
if (stricmp(pszName, (char*)pIbn->Name))
continue;
*ppAdr = &pIAT->u1.Function;
crDebug("search succeeded!");
return VINF_SUCCESS;
}
}
crDebug("not found");
return VERR_NOT_FOUND;
}
int renderspuIatPatcherPatchEntry(void *pvEntry, void *pvValue, void **ppvOldVal)
{
void **ppfn = (void**)pvEntry;
DWORD dwOldProtect = 0;
if (!VirtualProtect(pvEntry, sizeof (pvEntry), PAGE_READWRITE, &dwOldProtect))
{
crWarning("VirtualProtect 1 failed, %d", GetLastError());
return VERR_ACCESS_DENIED;
}
if (ppvOldVal)
*ppvOldVal = *ppfn;
*ppfn = pvValue;
if (!VirtualProtect(pvEntry, sizeof (pvEntry), dwOldProtect, &dwOldProtect))
{
crWarning("VirtualProtect 2 failed, %d.. ignoring", GetLastError());
}
return VINF_SUCCESS;
}
int renderspuIatPatcherPatchFunction(HMODULE hModule, LPCSTR pszLib, LPCSTR pszName, void* pfn)
{
void* pAdr;
int rc = renderspuIatPatcherGetImportAddress(hModule, pszLib, pszName, &pAdr);
if (RT_FAILURE(rc))
{
crDebug("renderspuIatPatcherGetImportAddress failed, %d", rc);
return rc;
}
rc = renderspuIatPatcherPatchEntry(pAdr, pfn, NULL);
if (RT_FAILURE(rc))
{
crWarning("renderspuIatPatcherPatchEntry failed, %d", rc);
return rc;
}
return VINF_SUCCESS;
}
/* patch */
static HWND __stdcall renderspuAtiQuirk_GetForegroundWindow()
{
crDebug("renderspuAtiQuirk_GetForegroundWindow");
return NULL;
}
#define CRREG_MAXKEYNAME 8
static int renderspuAtiQuirk_GetICDDriverList(char *pBuf, DWORD cbBuf, DWORD *pcbResult)
{
static LPCSTR aValueNames[] = {"OpenGLVendorName", "OpenGLDriverName"};
char *pBufPos = pBuf;
DWORD cbBufRemain = cbBuf, cbTotal = 0;
HKEY hKey, hSubkey;
DWORD dwIndex = 0;
int i;
int rc = VINF_SUCCESS;
char NameBuf[CRREG_MAXKEYNAME];
LONG lRc;
if (pcbResult)
*pcbResult = 0;
lRc = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E968-E325-11CE-BFC1-08002BE10318}",
0, /* reserved*/
KEY_READ,
&hKey);
if (ERROR_SUCCESS != lRc)
{
crDebug("RegOpenKeyEx 1 failed, %d", lRc);
return VERR_OPEN_FAILED;
}
for ( ; ; ++dwIndex)
{
lRc = RegEnumKeyA(hKey, dwIndex, NameBuf, CRREG_MAXKEYNAME);
if (lRc == ERROR_NO_MORE_ITEMS)
break;
if (lRc == ERROR_MORE_DATA)
continue;
if (lRc != ERROR_SUCCESS)
{
crWarning("RegEnumKeyA failed, %d", lRc);
continue;
}
lRc = RegOpenKeyEx(hKey,
NameBuf,
0, /* reserved*/
KEY_READ,
&hSubkey);
if (ERROR_SUCCESS != lRc)
{
crDebug("RegOpenKeyEx 2 failed, %d", lRc);
RegCloseKey(hKey);
return VERR_OPEN_FAILED;
}
for (i = 0; i < RT_ELEMENTS(aValueNames); ++i)
{
DWORD cbCur = cbBufRemain;
DWORD type;
lRc = RegQueryValueExA(hSubkey, aValueNames[i], NULL, /* reserved*/
&type,
(PBYTE)pBufPos, &cbCur);
/* exclude second null termination */
--cbCur;
if (ERROR_MORE_DATA == lRc)
{
if (REG_MULTI_SZ != type)
{
crWarning("unexpected data type! %d", type);
continue;
}
rc = VERR_BUFFER_OVERFLOW;
pBufPos = NULL;
cbBufRemain = 0;
CRASSERT(cbCur > 0 && cbCur < UINT32_MAX/2);
cbTotal += cbCur;
continue;
}
if (ERROR_SUCCESS != lRc)
{
crDebug("RegQueryValueExA failed, %d", lRc);
continue;
}
if (REG_MULTI_SZ != type)
{
crWarning("unexpected data type! %d", type);
continue;
}
/* succeeded */
CRASSERT(cbCur > 0 && cbCur < UINT32_MAX/2);
pBufPos += cbCur;
cbBufRemain -= cbCur;
cbTotal += cbCur;
CRASSERT(cbBufRemain < UINT32_MAX/2);
}
RegCloseKey(hSubkey);
}
RegCloseKey(hKey);
if (cbTotal)
{
/* include second null termination */
CRASSERT(!pBufPos || pBufPos[0] == '\0');
++cbTotal;
}
if (pcbResult)
*pcbResult = cbTotal;
return rc;
}
static int renderspuAtiQuirk_ApplyForModule(LPCSTR pszAtiDll)
{
int rc;
HMODULE hAtiDll;
crDebug("renderspuAtiQuirk_ApplyForModule (%s)", pszAtiDll);
hAtiDll = GetModuleHandleA(pszAtiDll);
if (!hAtiDll)
{
crDebug("GetModuleHandle failed, %d", GetLastError());
return VERR_NOT_FOUND;
}
rc = renderspuIatPatcherPatchFunction(hAtiDll, "user32.dll", "GetForegroundWindow", (void*)renderspuAtiQuirk_GetForegroundWindow);
if (RT_FAILURE(rc))
{
crDebug("renderspuIatPatcherPatchFunction failed, %d", rc);
return rc;
}
crDebug("renderspuAtiQuirk_ApplyForModule SUCCEEDED!");
crInfo("ATI Fullscreen qwirk SUCCEEDED!");
return VINF_SUCCESS;
}
static LPCSTR renderspuRegMultiSzNextVal(LPCSTR pszBuf)
{
pszBuf += strlen(pszBuf) + sizeof (pszBuf[0]);
if (pszBuf[0] == '\0')
return NULL;
return pszBuf;
}
static LPCSTR renderspuRegMultiSzCurVal(LPCSTR pszBuf)
{
if (pszBuf[0] == '\0')
return NULL;
return pszBuf;
}
static int renderspuAtiQuirk_Apply()
{
char aBuf[4096];
DWORD cbResult = 0;
LPCSTR pszVal;
int rc;
crDebug("renderspuAtiQuirk_Apply..");
rc = renderspuAtiQuirk_GetICDDriverList(aBuf, sizeof (aBuf), &cbResult);
if (RT_FAILURE(rc))
{
crDebug("renderspuAtiQuirk_GetICDDriverList failed, rc(%d)", rc);
return rc;
}
for (pszVal = renderspuRegMultiSzCurVal(aBuf);
pszVal;
pszVal = renderspuRegMultiSzNextVal(pszVal))
{
renderspuAtiQuirk_ApplyForModule(pszVal);
}
return VINF_SUCCESS;
}
static GLboolean renderspuAtiQuirk_Needed()
{
const char * pszString = render_spu.ws.glGetString(GL_VENDOR);
if (pszString && strstr(pszString, "ATI"))
return GL_TRUE;
pszString = render_spu.ws.glGetString(GL_RENDERER);
if (pszString && strstr(pszString, "ATI"))
return GL_TRUE;
return GL_FALSE;
}
static void renderspuAtiQuirk_ChkApply()
{
static GLboolean fChecked = GL_FALSE;
if (fChecked)
return;
fChecked = GL_TRUE;
if (!renderspuAtiQuirk_Needed())
return;
crInfo("This is an ATI card, taking care of fullscreen..");
/*
* ATI WDDM-based graphics have an issue with rendering fullscreen.
* See public tickets #9775 & #9267 .
* Namely ATI drivers check whether ogl window is foreground and fullscreen
* and if so - do D3DKMTSetDisplayMode for ogl surface,
* which prevented any other data from being displayed, no matter what.
*
* Here we check whether we're using an ATI card and if so, patch the ogl ICD driver's IAT
* to replace GetForegroundWindow reference with our renderspuAtiQuirk_GetForegroundWindow,
* which always returns NULL.
*/
renderspuAtiQuirk_Apply();
}
#define WINDOW_NAME window->title
static BOOL
bSetupPixelFormat( HDC hdc, GLbitfield visAttribs );
GLboolean renderspu_SystemInitVisual( VisualInfo *visual )
{
if (visual->visAttribs & CR_PBUFFER_BIT) {
crWarning("Render SPU: PBuffers not support on Windows yet.");
}
/* In the windows world, we need a window before a context.
* Use the device_context as a marker to do just that */
return TRUE;
}
void renderspu_SystemDestroyWindow( WindowInfo *window )
{
VBOX_RENDERSPU_DESTROY_WINDOW vrdw;
CRASSERT(window);
/*DestroyWindow( window->hWnd );*/
vrdw.hWnd = window->hWnd;
if (render_spu.dwWinThreadId)
{
PostThreadMessage(render_spu.dwWinThreadId, WM_VBOX_RENDERSPU_DESTROY_WINDOW, 0, (LPARAM) &vrdw);
WaitForSingleObject(render_spu.hWinThreadReadyEvent, INFINITE);
}
else
{
crError("Render SPU: window thread is not running");
}
window->hWnd = NULL;
window->visual = NULL;
if (window->hRgn)
{
DeleteObject(window->hRgn);
window->hRgn = NULL;
}
}
static LONG WINAPI
MainWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
/* int w,h; */
switch ( uMsg ) {
case WM_PAINT:
{
WindowInfo *pWindow = (WindowInfo *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
if (pWindow)
{
struct VBOXVR_SCR_COMPOSITOR * pCompositor;
pCompositor = renderspuVBoxCompositorAcquire(pWindow);
if (pCompositor)
{
HDC hDC;
PAINTSTRUCT Paint;
Assert(pWindow->device_context);
hDC = BeginPaint(pWindow->hWnd, &Paint);
if (hDC)
{
BOOL bRc;
pWindow->redraw_device_context = hDC;
renderspuVBoxPresentCompositionGeneric(pWindow, pCompositor, NULL, 1);
renderspuVBoxCompositorRelease(pWindow);
bRc = EndPaint(pWindow->hWnd, &Paint);
if (!bRc)
{
DWORD winEr = GetLastError();
crWarning("EndPaint failed, winEr %d", winEr);
}
pWindow->redraw_device_context = NULL;
}
else
{
DWORD winEr = GetLastError();
crWarning("BeginPaint failed, winEr %d", winEr);
}
}
}
break;
}
case WM_SIZE:
/* w = LOWORD( lParam );
* h = HIWORD( lParam ); */
/* glViewport( 0, 0, w, h ); */
#if 0
glViewport( -render_spu.mural_x, -render_spu.mural_y,
render_spu.mural_width, render_spu.mural_height );
glScissor( -render_spu.mural_x, -render_spu.mural_y,
render_spu.mural_width, render_spu.mural_height );
#endif
break;
case WM_CLOSE:
crWarning( "Render SPU: caught WM_CLOSE -- quitting." );
exit( 0 );
break;
case WM_DESTROY:
crDebug("Render SPU: caught WM_DESTROY for our window %x", hWnd);
break;
case WM_NCHITTEST:
crDebug("WM_NCHITTEST");
return HTNOWHERE;
}
return DefWindowProc( hWnd, uMsg, wParam, lParam );
}
static BOOL
bSetupPixelFormatEXT( HDC hdc, GLbitfield visAttribs)
{
PIXELFORMATDESCRIPTOR ppfd;
int pixelFormat;
int attribList[100];
float fattribList[] = { 0.0, 0.0 };
int numFormats;
int i = 0;
BOOL vis;
CRASSERT(visAttribs & CR_RGB_BIT); /* anybody need color index */
crWarning("Render SPU: Using WGL_EXT_pixel_format to select visual ID.");
attribList[i++] = WGL_DRAW_TO_WINDOW_EXT;
attribList[i++] = GL_TRUE;
attribList[i++] = WGL_ACCELERATION_EXT;
attribList[i++] = WGL_FULL_ACCELERATION_EXT;
attribList[i++] = WGL_COLOR_BITS_EXT;
attribList[i++] = 24;
attribList[i++] = WGL_RED_BITS_EXT;
attribList[i++] = 1;
attribList[i++] = WGL_GREEN_BITS_EXT;
attribList[i++] = 1;
attribList[i++] = WGL_BLUE_BITS_EXT;
attribList[i++] = 1;
crWarning("Render SPU: Visual chosen is... RGB");
if (visAttribs & CR_ALPHA_BIT)
{
attribList[i++] = WGL_ALPHA_BITS_EXT;
attribList[i++] = 1;
crWarning("A");
}
crWarning(", ");
if (visAttribs & CR_DOUBLE_BIT) {
attribList[i++] = WGL_DOUBLE_BUFFER_EXT;
attribList[i++] = GL_TRUE;
crWarning("DB, ");
}
if (visAttribs & CR_STEREO_BIT) {
attribList[i++] = WGL_STEREO_EXT;
attribList[i++] = GL_TRUE;
crWarning("Stereo, ");
}
if (visAttribs & CR_DEPTH_BIT)
{
attribList[i++] = WGL_DEPTH_BITS_EXT;
attribList[i++] = 1;
crWarning("Z, ");
}
if (visAttribs & CR_STENCIL_BIT)
{
attribList[i++] = WGL_STENCIL_BITS_EXT;
attribList[i++] = 1;
crWarning("Stencil, ");
}
if (visAttribs & CR_ACCUM_BIT)
{
attribList[i++] = WGL_ACCUM_RED_BITS_EXT;
attribList[i++] = 1;
attribList[i++] = WGL_ACCUM_GREEN_BITS_EXT;
attribList[i++] = 1;
attribList[i++] = WGL_ACCUM_BLUE_BITS_EXT;
attribList[i++] = 1;
crWarning("Accum, ");
if (visAttribs & CR_ALPHA_BIT)
{
attribList[i++] = WGL_ACCUM_ALPHA_BITS_EXT;
attribList[i++] = 1;
crWarning("Accum Alpha, ");
}
}
if (visAttribs & CR_MULTISAMPLE_BIT)
{
attribList[i++] = WGL_SAMPLE_BUFFERS_EXT;
attribList[i++] = 1;
attribList[i++] = WGL_SAMPLES_EXT;
attribList[i++] = 4;
crWarning("Multisample, ");
}
crWarning("\n");
/* End the list */
attribList[i++] = 0;
attribList[i++] = 0;
vis = render_spu.ws.wglChoosePixelFormatEXT( hdc, attribList, fattribList, 1, &pixelFormat, &numFormats);
crDebug("Render SPU: wglChoosePixelFormatEXT (vis 0x%x, LastError 0x%x, pixelFormat 0x%x", vis, GetLastError(), pixelFormat);
#ifdef VBOX_CR_SERVER_FORCE_WGL
render_spu.ws.wglSetPixelFormat( hdc, pixelFormat, &ppfd );
#else
SetPixelFormat( hdc, pixelFormat, &ppfd );
#endif
crDebug("Render SPU: wglSetPixelFormat (Last error 0x%x)", GetLastError());
return vis;
}
static BOOL
bSetupPixelFormatNormal( HDC hdc, GLbitfield visAttribs )
{
PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR), /* size of this pfd */
1, /* version number */
PFD_DRAW_TO_WINDOW | /* support window */
PFD_SUPPORT_OPENGL, /* support OpenGL */
PFD_TYPE_RGBA, /* RGBA type */
24, /* 24-bit color depth */
0, 0, 0, 0, 0, 0, /* color bits ignored */
0, /* no alpha buffer */
0, /* shift bit ignored */
0, /* no accumulation buffer */
0, 0, 0, 0, /* accum bits ignored */
0, /* set depth buffer */
0, /* set stencil buffer */
0, /* no auxiliary buffer */
PFD_MAIN_PLANE, /* main layer */
0, /* reserved */
0, 0, 0 /* layer masks ignored */
};
PIXELFORMATDESCRIPTOR *ppfd = &pfd;
char s[1000];
GLbitfield b = 0;
int pixelformat;
renderspuMakeVisString( visAttribs, s );
crDebug( "Render SPU: WGL wants these visual capabilities: %s", s);
/* These really come into play with sort-last configs */
if (visAttribs & CR_DEPTH_BIT)
ppfd->cDepthBits = 24;
if (visAttribs & CR_ACCUM_BIT)
ppfd->cAccumBits = 16;
if (visAttribs & CR_RGB_BIT)
ppfd->cColorBits = 24;
if (visAttribs & CR_STENCIL_BIT)
ppfd->cStencilBits = 8;
if (visAttribs & CR_ALPHA_BIT)
ppfd->cAlphaBits = 8;
if (visAttribs & CR_DOUBLE_BIT)
ppfd->dwFlags |= PFD_DOUBLEBUFFER;
if (visAttribs & CR_STEREO_BIT)
ppfd->dwFlags |= PFD_STEREO;
/*
* We call the wgl functions directly if the SPU was loaded
* by our faker library, otherwise we have to call the GDI
* versions.
*/
#ifdef VBOX_CR_SERVER_FORCE_WGL
if (crGetenv( "CR_WGL_DO_NOT_USE_GDI" ) != NULL)
{
pixelformat = render_spu.ws.wglChoosePixelFormat( hdc, ppfd );
/* doing this twice is normal Win32 magic */
pixelformat = render_spu.ws.wglChoosePixelFormat( hdc, ppfd );
if ( pixelformat == 0 )
{
crError( "render_spu.ws.wglChoosePixelFormat failed" );
}
if ( !render_spu.ws.wglSetPixelFormat( hdc, pixelformat, ppfd ) )
{
crError( "render_spu.ws.wglSetPixelFormat failed" );
}
render_spu.ws.wglDescribePixelFormat( hdc, pixelformat, sizeof(*ppfd), ppfd );
}
else
#endif
{
/* Okay, we were loaded manually. Call the GDI functions. */
pixelformat = ChoosePixelFormat( hdc, ppfd );
/* doing this twice is normal Win32 magic */
pixelformat = ChoosePixelFormat( hdc, ppfd );
if ( pixelformat == 0 )
{
crError( "ChoosePixelFormat failed" );
}
if ( !SetPixelFormat( hdc, pixelformat, ppfd ) )
{
crError( "SetPixelFormat failed (Error 0x%x)", GetLastError() );
}
DescribePixelFormat( hdc, pixelformat, sizeof(*ppfd), ppfd );
}
if (ppfd->cDepthBits > 0)
b |= CR_DEPTH_BIT;
if (ppfd->cAccumBits > 0)
b |= CR_ACCUM_BIT;
if (ppfd->cColorBits > 8)
b |= CR_RGB_BIT;
if (ppfd->cStencilBits > 0)
b |= CR_STENCIL_BIT;
if (ppfd->cAlphaBits > 0)
b |= CR_ALPHA_BIT;
if (ppfd->dwFlags & PFD_DOUBLEBUFFER)
b |= CR_DOUBLE_BIT;
if (ppfd->dwFlags & PFD_STEREO)
b |= CR_STEREO_BIT;
renderspuMakeVisString( b, s );
crDebug( "Render SPU: WGL chose these visual capabilities: %s", s);
return TRUE;
}
static BOOL
bSetupPixelFormat( HDC hdc, GLbitfield visAttribs )
{
/* According to http://www.opengl.org/resources/faq/technical/mswindows.htm
we shouldn't be using wgl functions to setup pixel formats unless we're loading ICD driver.
In particular, bSetupPixelFormatEXT bugs with Intel drivers.
*/
return bSetupPixelFormatNormal(hdc, visAttribs);
}
GLboolean renderspu_SystemCreateWindow( VisualInfo *visual, GLboolean showIt, WindowInfo *window )
{
HDESK desktop;
HINSTANCE hinstance;
WNDCLASS wc;
DWORD window_style;
int window_plus_caption_width;
int window_plus_caption_height;
window->hRgn = NULL;
window->visual = visual;
window->nativeWindow = 0;
if ( render_spu.use_L2 )
{
crWarning( "Going fullscreen because we think we're using Lightning-2." );
render_spu.fullscreen = 1;
}
/*
* Begin Windows / WGL code
*/
hinstance = GetModuleHandle( NULL );
if (!hinstance)
{
crError( "Render SPU: Couldn't get a handle to my module." );
return GL_FALSE;
}
crDebug( "Render SPU: Got the module handle: 0x%x", hinstance );
/* If we were launched from a service, telnet, or rsh, we need to
* get the input desktop. */
desktop = OpenInputDesktop( 0, FALSE,
DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW |
DESKTOP_ENUMERATE | DESKTOP_HOOKCONTROL |
DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS |
DESKTOP_SWITCHDESKTOP | GENERIC_WRITE );
if ( !desktop )
{
crError( "Render SPU: Couldn't acquire input desktop" );
return GL_FALSE;
}
crDebug( "Render SPU: Got the desktop: 0x%x", desktop );
if ( !SetThreadDesktop( desktop ) )
{
/* If this function fails, it's probably because
* it's already been called (i.e., the render SPU
* is bolted to an application?) */
/*crError( "Couldn't set thread to input desktop" ); */
}
crDebug( "Render SPU: Set the thread desktop -- this might have failed." );
if ( !GetClassInfo(hinstance, WINDOW_NAME, &wc) )
{
wc.style = CS_OWNDC;
wc.lpfnWndProc = (WNDPROC) MainWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hinstance;
wc.hIcon = LoadIcon( NULL, IDI_APPLICATION );
wc.hCursor = LoadCursor( NULL, IDC_ARROW );
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = WINDOW_NAME;
if ( !RegisterClass( &wc ) )
{
crError( "Render SPU: Couldn't register window class -- you're not trying "
"to do multi-pipe stuff on windows, are you?\n\nNote --"
"This error message is from 1997 and probably doesn't make"
"any sense any more, but it's nostalgic for Humper." );
return GL_FALSE;
}
crDebug( "Render SPU: Registered the class" );
}
crDebug( "Render SPU: Got the class information" );
/* Full screen window should be a popup (undecorated) window */
#if 1
window_style = ( render_spu.fullscreen ? WS_POPUP : WS_CAPTION );
#else
window_style = ( WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN );
window_style |= WS_SYSMENU;
#endif
crDebug( "Render SPU: Fullscreen: %s", render_spu.fullscreen ? "yes" : "no");
if ( render_spu.fullscreen )
{
#if 0
int smCxFixedFrame = GetSystemMetrics( SM_CXFIXEDFRAME );
int smCyFixedFrame = GetSystemMetrics( SM_CXFIXEDFRAME ) + 1;
int smCyCaption = GetSystemMetrics( SM_CYCAPTION );
window->BltInfo.width = GetSystemMetrics( SM_CXSCREEN ) ;
window->BltInfo.height = GetSystemMetrics( SM_CYSCREEN ) ;
crDebug( "Render SPU: Window Dims: %d, %d", window->BltInfo.width, window->BltInfo.height );
window->x = render_spu->defaultX - smCxFixedFrame - 1;
window->y = render_spu->defaultY - smCyFixedFrame - smCyCaption;
window_plus_caption_width = window->BltInfo.width + 2 * smCxFixedFrame;
window_plus_caption_height = window->BltInfo.height + 2 * smCyFixedFrame + smCyCaption;
#else
/* Since it's undecorated, we don't have to do anything fancy
* with these parameters. */
window->BltInfo.width = GetSystemMetrics( SM_CXSCREEN ) ;
window->BltInfo.height = GetSystemMetrics( SM_CYSCREEN ) ;
window->x = 0;
window->y = 0;
window_plus_caption_width = window->BltInfo.width;
window_plus_caption_height = window->BltInfo.height;
#endif
}
else
{
/* CreateWindow takes the size of the entire window, so we add
* in the size necessary for the frame and the caption. */
int smCxFixedFrame, smCyFixedFrame, smCyCaption;
smCxFixedFrame = GetSystemMetrics( SM_CXFIXEDFRAME );
crDebug( "Render SPU: Got the X fixed frame" );
smCyFixedFrame = GetSystemMetrics( SM_CYFIXEDFRAME );
crDebug( "Render SPU: Got the Y fixed frame" );
smCyCaption = GetSystemMetrics( SM_CYCAPTION );
crDebug( "Render SPU: Got the Caption " );
window_plus_caption_width = window->BltInfo.width + 2 * smCxFixedFrame;
window_plus_caption_height = window->BltInfo.height + 2 * smCyFixedFrame + smCyCaption;
window->x = render_spu.defaultX - smCxFixedFrame;
window->y = render_spu.defaultY - smCyFixedFrame - smCyCaption;
}
crDebug( "Render SPU: Creating the window: (%d,%d), (%d,%d)", render_spu.defaultX, render_spu.defaultY, window_plus_caption_width, window_plus_caption_height );
window->hWnd = CreateWindow( WINDOW_NAME, WINDOW_NAME,
window_style,
window->x, window->y,
window_plus_caption_width,
window_plus_caption_height,
NULL, NULL, hinstance, &render_spu );
if ( !window->hWnd )
{
crError( "Render SPU: Create Window failed! That's almost certainly terrible." );
return GL_FALSE;
}
window->visible = showIt;
if (!showIt)
{
renderspu_SystemShowWindow( window, 0 );
if (window->BltInfo.height <= 0 || window->BltInfo.width <= 0)
{
renderspu_SystemWindowSize(window,
window->BltInfo.width > 0 ? window->BltInfo.width : 4,
window->BltInfo.height > 0 ? window->BltInfo.height : 4);
}
}
else
{
crDebug( "Render SPU: Showing the window" );
crDebug("renderspu_SystemCreateWindow: showwindow: %x", window->hWnd);
}
CRASSERT(!window->visible == !showIt);
/* Intel drivers require a window to be visible for proper 3D rendering,
* so set it visible and handle the visibility with visible regions (see below) */
ShowWindow( window->hWnd, SW_SHOWNORMAL );
SetForegroundWindow( window->hWnd );
SetWindowPos( window->hWnd, HWND_TOP, window->x, window->y,
window_plus_caption_width, window_plus_caption_height,
( render_spu.fullscreen ? (SWP_SHOWWINDOW |
SWP_NOSENDCHANGING |
SWP_NOREDRAW |
SWP_NOACTIVATE ) :
0 ) );
if ( render_spu.fullscreen )
ShowCursor( FALSE );
window->device_context = GetDC( window->hWnd );
if (!window->device_context)
{
DWORD winEr = GetLastError();
crWarning("GetDC failed, winEr %d", winEr);
}
crDebug( "Render SPU: Got the DC: 0x%x", window->device_context );
if ( !bSetupPixelFormat( window->device_context, visual->visAttribs ) )
{
crError( "Render SPU: Couldn't set up the device context! Yikes!" );
return GL_FALSE;
}
return GL_TRUE;
}
GLboolean renderspu_SystemVBoxCreateWindow( VisualInfo *visual, GLboolean showIt, WindowInfo *window )
{
#if 0
HDESK desktop;
#endif
HINSTANCE hinstance;
WNDCLASS wc;
DWORD window_style;
int window_plus_caption_width;
int window_plus_caption_height;
window->hRgn = NULL;
window->visual = visual;
window->nativeWindow = 0;
if ( render_spu.use_L2 )
{
crWarning( "Going fullscreen because we think we're using Lightning-2." );
render_spu.fullscreen = 1;
}
/*
* Begin Windows / WGL code
*/
hinstance = GetModuleHandle( NULL );
if (!hinstance)
{
crError( "Render SPU: Couldn't get a handle to my module." );
return GL_FALSE;
}
crDebug( "Render SPU: Got the module handle: 0x%x", hinstance );
#if 0
/* If we were launched from a service, telnet, or rsh, we need to
* get the input desktop. */
desktop = OpenInputDesktop( 0, FALSE,
DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW |
DESKTOP_ENUMERATE | DESKTOP_HOOKCONTROL |
DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS |
DESKTOP_SWITCHDESKTOP | GENERIC_WRITE );
if ( !desktop )
{
crError( "Render SPU: Couldn't acquire input desktop" );
return GL_FALSE;
}
crDebug( "Render SPU: Got the desktop: 0x%x", desktop );
if ( !SetThreadDesktop( desktop ) )
{
/* If this function fails, it's probably because
* it's already been called (i.e., the render SPU
* is bolted to an application?) */
/*crError( "Couldn't set thread to input desktop" ); */
}
crDebug( "Render SPU: Set the thread desktop -- this might have failed." );
#endif
if ( !GetClassInfo(hinstance, WINDOW_NAME, &wc) )
{
wc.style = CS_OWNDC; // | CS_PARENTDC;
wc.lpfnWndProc = (WNDPROC) MainWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hinstance;
wc.hIcon = NULL; //LoadIcon( NULL, IDI_APPLICATION );
wc.hCursor = NULL; //LoadCursor( NULL, IDC_ARROW );
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = WINDOW_NAME;
if ( !RegisterClass( &wc ) )
{
crError( "Render SPU: Couldn't register window class -- you're not trying "
"to do multi-pipe stuff on windows, are you?\n\nNote --"
"This error message is from 1997 and probably doesn't make"
"any sense any more, but it's nostalgic for Humper." );
return GL_FALSE;
}
crDebug( "Render SPU: Registered the class" );
}
crDebug( "Render SPU: Got the class information" );
/* Full screen window should be a popup (undecorated) window */
#if 1
window_style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_DISABLED;
if (render_spu_parent_window_id)
{
window_style |= WS_CHILD;
}
#else
window_style = ( WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN );
window_style |= WS_SYSMENU;
#endif
crDebug( "Render SPU: Fullscreen: %s", render_spu.fullscreen ? "yes" : "no");
if ( render_spu.fullscreen )
{
#if 0
int smCxFixedFrame = GetSystemMetrics( SM_CXFIXEDFRAME );
int smCyFixedFrame = GetSystemMetrics( SM_CXFIXEDFRAME ) + 1;
int smCyCaption = GetSystemMetrics( SM_CYCAPTION );
window->BltInfo.width = GetSystemMetrics( SM_CXSCREEN ) ;
window->BltInfo.height = GetSystemMetrics( SM_CYSCREEN ) ;
crDebug( "Render SPU: Window Dims: %d, %d", window->BltInfo.width, window->BltInfo.height );
window->x = render_spu->defaultX - smCxFixedFrame - 1;
window->y = render_spu->defaultY - smCyFixedFrame - smCyCaption;
window_plus_caption_width = window->BltInfo.width + 2 * smCxFixedFrame;
window_plus_caption_height = window->BltInfo.height + 2 * smCyFixedFrame + smCyCaption;
#else
/* Since it's undecorated, we don't have to do anything fancy
* with these parameters. */
window->BltInfo.width = GetSystemMetrics( SM_CXSCREEN ) ;
window->BltInfo.height = GetSystemMetrics( SM_CYSCREEN ) ;
window->x = 0;
window->y = 0;
window_plus_caption_width = window->BltInfo.width;
window_plus_caption_height = window->BltInfo.height;
#endif
}
else
{
/* CreateWindow takes the size of the entire window, so we add
* in the size necessary for the frame and the caption. */
int smCxFixedFrame, smCyFixedFrame, smCyCaption;
smCxFixedFrame = GetSystemMetrics( SM_CXFIXEDFRAME );
crDebug( "Render SPU: Got the X fixed frame" );
smCyFixedFrame = GetSystemMetrics( SM_CYFIXEDFRAME );
crDebug( "Render SPU: Got the Y fixed frame" );
smCyCaption = GetSystemMetrics( SM_CYCAPTION );
crDebug( "Render SPU: Got the Caption " );
window_plus_caption_width = window->BltInfo.width + 2 * smCxFixedFrame;
window_plus_caption_height = window->BltInfo.height + 2 * smCyFixedFrame + smCyCaption;
window->x = render_spu.defaultX;
window->y = render_spu.defaultY;
}
crDebug( "Render SPU: Creating the window: (%d,%d), (%d,%d)", render_spu.defaultX, render_spu.defaultY, window_plus_caption_width, window_plus_caption_height );
/*window->hWnd = CreateWindowEx( WS_EX_NOACTIVATE | WS_EX_NOPARENTNOTIFY,
WINDOW_NAME, WINDOW_NAME,
window_style,
window->x, window->y,
window->BltInfo.width,
window->BltInfo.height,
(void*) render_spu_parent_window_id, NULL, hinstance, &render_spu );*/
{
CREATESTRUCT cs;
cs.lpCreateParams = window;
cs.dwExStyle = WS_EX_NOACTIVATE | WS_EX_NOPARENTNOTIFY;
cs.lpszName = WINDOW_NAME;
cs.lpszClass = WINDOW_NAME;
cs.style = window_style;
cs.x = window->x;
cs.y = window->y;
cs.cx = window->BltInfo.width;
cs.cy = window->BltInfo.height;
cs.hwndParent = (void*) render_spu_parent_window_id;
cs.hMenu = NULL;
cs.hInstance = hinstance;
if (render_spu.dwWinThreadId)
{
DWORD res;
int cnt=0;
if (!PostThreadMessage(render_spu.dwWinThreadId, WM_VBOX_RENDERSPU_CREATE_WINDOW, 0, (LPARAM) &cs))
{
crError("Render SPU: PostThreadMessage failed with %i", GetLastError());
return GL_FALSE;
}
do
{
res = WaitForSingleObject(render_spu.hWinThreadReadyEvent, 1000);
cnt++;
}
while ((res!=WAIT_OBJECT_0) && (cnt<10));
crDebug("Render SPU: window thread waited %i secs", cnt);
if (res!=WAIT_OBJECT_0)
{
crError("Render SPU: window thread not responded after %i tries", cnt);
return GL_FALSE;
}
}
else
{
crError("Render SPU: window thread is not running");
return GL_FALSE;
}
}
if ( !window->hWnd )
{
crError( "Render SPU: Create Window failed! That's almost certainly terrible." );
return GL_FALSE;
}
window->visible = 1;
if (!showIt)
{
renderspu_SystemShowWindow( window, 0 );
if (window->BltInfo.height <= 0 || window->BltInfo.width <= 0)
{
renderspu_SystemWindowSize(window,
window->BltInfo.width > 0 ? window->BltInfo.width : 4,
window->BltInfo.height > 0 ? window->BltInfo.height : 4);
}
}
else
{
crDebug( "Render SPU: Showing the window" );
crDebug("renderspu_SystemCreateWindow: showwindow: %x", window->hWnd);
}
CRASSERT(!window->visible == !showIt);
/* Intel drivers require a window to be visible for proper 3D rendering,
* so set it visible and handle the visibility with visible regions (see below) */
if (window->BltInfo.Base.id)
{
ShowWindow( window->hWnd, SW_SHOWNORMAL );
}
else
{
CRASSERT(!showIt);
/* dummy window is always hidden in any way */
}
//SetForegroundWindow( visual->hWnd );
SetWindowPos( window->hWnd, HWND_TOP, window->x, window->y,
window->BltInfo.width, window->BltInfo.height,
( render_spu.fullscreen ?
(SWP_SHOWWINDOW | SWP_NOSENDCHANGING | SWP_NOREDRAW | SWP_NOACTIVATE ) : SWP_NOACTIVATE
) );
crDebug("Render SPU: SetWindowPos (%x, %d, %d, %d, %d)", window->hWnd,
window->x, window->y, window->BltInfo.width, window->BltInfo.height);
if ( render_spu.fullscreen )
ShowCursor( FALSE );
window->device_context = GetDC( window->hWnd );
if (!window->device_context)
{
DWORD winEr = GetLastError();
crWarning("GetDC failed, winEr %d", winEr);
}
crDebug( "Render SPU: Got the DC: 0x%x", window->device_context );
if ( !bSetupPixelFormat( window->device_context, visual->visAttribs ) )
{
crError( "Render SPU: Couldn't set up the device context! Yikes!" );
return GL_FALSE;
}
/* set the window pointer data at the last step to ensure our WM_PAINT callback does not do anything until we are fully initialized */
{
LONG_PTR oldVal = SetWindowLongPtr(window->hWnd, GWLP_USERDATA, (LONG_PTR)window);
Assert(!oldVal && GetLastError() == NO_ERROR);
}
return GL_TRUE;
}
/* Either show or hide the render SPU's window. */
void renderspu_SystemShowWindow( WindowInfo *window, GLboolean showIt )
{
if (showIt)
{
crDebug("SHOW renderspu_SystemShowWindow: %x", window->hWnd);
SetWindowRgn(window->hWnd, window->hRgn, true);
}
else
{
HRGN hRgn;
crDebug("HIDE renderspu_SystemShowWindow: %x", window->hWnd);
hRgn = CreateRectRgn(0, 0, 0, 0);
SetWindowRgn(window->hWnd, hRgn, true);
DeleteObject(hRgn);
}
window->visible = showIt;
}
void renderspu_SystemVBoxPresentComposition( WindowInfo *window, struct VBOXVR_SCR_COMPOSITOR * pCompositor, struct VBOXVR_SCR_COMPOSITOR_ENTRY *pChangedEntry )
{
/* the CR_RENDER_FORCE_PRESENT_MAIN_THREAD is actually inherited from cocoa backend impl,
* here it forces rendering in WinCmd thread rather than a Main thread.
* it is used for debugging only in any way actually.
* @todo: change to some more generic macro name */
#ifndef CR_RENDER_FORCE_PRESENT_MAIN_THREAD
struct VBOXVR_SCR_COMPOSITOR *pCurCompositor;
/* we do not want to be blocked with the GUI thread here, so only draw her eif we are really able to do that w/o bllocking */
int rc = renderspuVBoxCompositorTryAcquire(window, &pCurCompositor);
if (RT_SUCCESS(rc))
{
Assert(pCurCompositor == pCompositor);
renderspuVBoxPresentCompositionGeneric(window, pCompositor, pChangedEntry, 0);
renderspuVBoxCompositorRelease(window);
}
else if (rc == VERR_SEM_BUSY)
#endif
{
render_spu.self.Flush();
renderspuVBoxPresentBlitterEnsureCreated(window, 0);
RedrawWindow(window->hWnd, NULL, NULL, RDW_INTERNALPAINT);
}
#ifndef CR_RENDER_FORCE_PRESENT_MAIN_THREAD
else
{
/* this is somewhat we do not expect */
crWarning("renderspuVBoxCompositorTryAcquire failed rc %d", rc);
}
#endif
}
GLboolean renderspu_SystemCreateContext( VisualInfo *visual, ContextInfo *context, ContextInfo *sharedContext )
{
(void) sharedContext;
context->visual = visual;
/* Found a visual, so we're o.k. to create the context now */
if (0/*visual->device_context*/) {
//crDebug( "Render SPU: Using the DC: 0x%x", visual->device_context );
//context->hRC = render_spu.ws.wglCreateContext( visual->device_context );
if (!context->hRC)
{
crError( "Render SPU: wglCreateContext failed (error 0x%x)", GetLastError() );
return GL_FALSE;
}
} else {
crDebug( "Render SPU: Delaying DC creation " );
context->hRC = NULL; /* create it later in makecurrent */
}
return GL_TRUE;
}
void renderspu_SystemDestroyContext( ContextInfo *context )
{
render_spu.ws.wglDeleteContext( context->hRC );
context->hRC = NULL;
}
static GLboolean renderspuChkActivateSharedContext(ContextInfo *sharedContext)
{
GLint crWindow;
WindowInfo *window;
if (sharedContext->hRC)
return GL_TRUE;
CRASSERT(sharedContext->BltInfo.Base.id);
if (sharedContext->shared)
renderspuChkActivateSharedContext(sharedContext->shared);
crWindow = renderspuWindowCreate(sharedContext->visual->displayName, sharedContext->visual->visAttribs);
if (!crWindow)
{
crError("renderspuChkActivateSharedContext: renderspuWindowCreate failed!");
return GL_FALSE;
}
window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, crWindow);
if (!window)
{
crError("renderspuChkActivateSharedContext: crHashtableSearch failed!");
renderspuWindowDestroy(crWindow);
return GL_FALSE;
}
CRASSERT(window->device_context);
crDebug( "Render SPU: renderspuChkActivateSharedContext: made the DC: 0x%x", window->device_context );
sharedContext->hRC = render_spu.ws.wglCreateContext(window->device_context);
if (!sharedContext->hRC)
{
crError( "Render SPU: (renderspuChkActivateSharedContext) Couldn't create the context for the window (error 0x%x)", GetLastError() );
renderspuWindowDestroy(crWindow);
return GL_FALSE;
}
return GL_TRUE;
}
void renderspu_SystemMakeCurrent( WindowInfo *window, GLint nativeWindow, ContextInfo *context )
{
CRASSERT(render_spu.ws.wglMakeCurrent);
if (context && window) {
if (window->visual != context->visual) {
/*
* XXX have to revisit this issue!!!
*
* But for now we destroy the current window
* and re-create it with the context's visual abilities
*/
/*@todo Chromium has no correct code to remove window ids and associated info from
* various tables. This is hack which just hides the root case.
*/
crWarning("Recreating window in renderspu_SystemMakeCurrent\n");
renderspu_SystemDestroyWindow( window );
renderspu_SystemVBoxCreateWindow( context->visual, window->visible, window );
}
if (0/*render_spu.render_to_app_window && nativeWindow*/)
{
/* The render_to_app_window option
* is set and we've got a nativeWindow
* handle, save the handle for
* later calls to swapbuffers().
*
* NOTE: This doesn't work, except
* for software driven Mesa.
* We'd need to object link the
* crappfaker and crserver to be able to share
* the HDC values between processes.. FIXME!
*/
if (context->shared)
{
/* first make sure we have shared context created */
renderspuChkActivateSharedContext(context->shared);
}
window->nativeWindow = (HDC) nativeWindow;
if (context->hRC == 0) {
context->hRC = render_spu.ws.wglCreateContext( window->nativeWindow );
if (!context->hRC)
{
crError( "(MakeCurrent) Couldn't create the context for the window (error 0x%x)", GetLastError() );
}
}
if (context->shared
&& context->shared->hRC
&& context->hRC)
{
/* share lists */
render_spu.ws.wglShareLists(context->shared->hRC, context->hRC);
}
render_spu.ws.wglMakeCurrent( window->nativeWindow, context->hRC );
}
else
{
if (!context->hRC) {
CRASSERT(!nativeWindow);
if (context->shared)
{
/* first make sure we have shared context created */
renderspuChkActivateSharedContext(context->shared);
}
context->hRC = render_spu.ws.wglCreateContext(window->device_context);
if (!context->hRC)
{
crError( "Render SPU: (MakeCurrent) Couldn't create the context for the window (error 0x%x)", GetLastError() );
}
if (context->shared
&& context->shared->hRC
&& context->hRC)
{
/* share lists */
BOOL bRc = render_spu.ws.wglShareLists(context->shared->hRC, context->hRC);
if (!bRc)
{
DWORD winEr = GetLastError();
crWarning("wglShareLists failed, winEr %d", winEr);
}
}
/*Requery ext function pointers, we skip dummy ctx as it should never be used with ext functions*/
if (0 && context->BltInfo.Base.id)
{
int numFuncs, i;
SPUNamedFunctionTable ext_table[1000];
crDebug("Default server ctx created, requerying ext functions");
/*requery ext functions*/
numFuncs = renderspuCreateFunctions(ext_table);
numFuncs += crLoadOpenGLExtensions( &render_spu.ws, ext_table+numFuncs);
CRASSERT(numFuncs < 1000);
/*change spu dispatch*/
crSPUChangeDispatch(&render_spu.self, ext_table);
/*cleanup temp table*/
for (i=0; i<numFuncs; ++i)
{
if (ext_table[i].name) crFree(ext_table[i].name);
}
}
}
/*crDebug("MakeCurrent 0x%x, 0x%x", window->device_context, context->hRC);*/
if (!render_spu.ws.wglMakeCurrent(!nativeWindow ? window->device_context : window->redraw_device_context, context->hRC))
{
DWORD err = GetLastError();
crError("Render SPU: (MakeCurrent) failed to make 0x%x, 0x%x current with 0x%x error.", window->device_context, context->hRC, err);
}
}
renderspuAtiQuirk_ChkApply();
}
else {
render_spu.ws.wglMakeCurrent( 0, 0 );
}
}
void renderspu_SystemWindowSize( WindowInfo *window, GLint w, GLint h )
{
int winprop;
CRASSERT(window);
CRASSERT(window->visual);
if ( render_spu.fullscreen )
winprop = SWP_SHOWWINDOW | SWP_NOSENDCHANGING |
SWP_NOREDRAW | SWP_NOACTIVATE;
else
winprop = SWP_NOACTIVATE | SWP_DEFERERASE | SWP_NOSENDCHANGING | SWP_NOZORDER; //SWP_SHOWWINDOW;
/*SetWindowRgn(window->hWnd, NULL, false);*/
if (!SetWindowPos( window->hWnd, HWND_TOP,
window->x, window->y, w, h, winprop )) {
crWarning("!!!FAILED!!! Render SPU: SetWindowPos (%x, %d, %d, %d, %d)", window->hWnd, window->x, window->y, w, h);
} else {
crDebug("Render SPU: SetWindowSize (%x, %d, %d, %d, %d)", window->hWnd, window->x, window->y, w, h);
}
/* save the new size */
window->BltInfo.width = w;
window->BltInfo.height = h;
}
void renderspu_SystemGetWindowGeometry( WindowInfo *window, GLint *x, GLint *y, GLint *w, GLint *h )
{
RECT rect;
CRASSERT(window);
CRASSERT(window->visual);
GetClientRect( window->hWnd, &rect );
*x = rect.left;
*y = rect.top;
*w = rect.right - rect.left;
*h = rect.bottom - rect.top;
}
void renderspu_SystemGetMaxWindowSize( WindowInfo *window, GLint *w, GLint *h )
{
/* XXX fix this */
(void) window;
*w = 1600;
*h = 1200;
}
void renderspu_SystemWindowPosition( WindowInfo *window, GLint x, GLint y )
{
int winprop;
CRASSERT(window);
CRASSERT(window->visual);
if ( render_spu.fullscreen )
winprop = SWP_SHOWWINDOW | SWP_NOSENDCHANGING |
SWP_NOREDRAW | SWP_NOACTIVATE;
else
winprop = SWP_NOACTIVATE | SWP_DEFERERASE | SWP_NOSENDCHANGING | SWP_NOZORDER; //SWP_SHOWWINDOW;
/*SetWindowRgn(window->visual->hWnd, NULL, false);*/
if (!SetWindowPos( window->hWnd, HWND_TOP,
x, y, window->BltInfo.width, window->BltInfo.height, winprop )) {
crWarning("!!!FAILED!!! Render SPU: SetWindowPos (%x, %d, %d, %d, %d)", window->hWnd, x, y, window->BltInfo.width, window->BltInfo.height);
} else {
crDebug("Render SPU: SetWindowPos (%x, %d, %d, %d, %d)", window->hWnd,
x, y, window->BltInfo.width, window->BltInfo.height);
}
/* save the new position */
window->x = x;
window->y = y;
}
void renderspu_SystemWindowVisibleRegion(WindowInfo *window, GLint cRects, GLint* pRects)
{
GLint i;
HRGN hRgn, hTmpRgn;
CRASSERT(window);
CRASSERT(window->visual);
if (window->hRgn)
{
DeleteObject(window->hRgn);
window->hRgn = NULL;
}
hRgn = CreateRectRgn(0, 0, 0, 0);
for (i=0; i<cRects; i++)
{
hTmpRgn = CreateRectRgn(pRects[4*i], pRects[4*i+1], pRects[4*i+2], pRects[4*i+3]);
CombineRgn(hRgn, hRgn, hTmpRgn, RGN_OR);
DeleteObject(hTmpRgn);
}
if (window->visible)
SetWindowRgn(window->hWnd, hRgn, true);
crDebug("Render SPU: SetWindowRgn (%x, cRects=%i)", window->hWnd, cRects);
window->hRgn = hRgn;
}
static void renderspuHandleWindowMessages( HWND hWnd )
{
MSG msg;
while ( PeekMessage( &msg, hWnd, 0, 0xffffffff, PM_REMOVE ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
//BringWindowToTop( hWnd );
}
void renderspu_SystemSwapBuffers( WindowInfo *w, GLint flags )
{
int return_value;
/* peek at the windows message queue */
// renderspuHandleWindowMessages( w->hWnd );
/* render_to_app_window:
* w->nativeWindow will only be non-zero if the
* render_spu.render_to_app_window option is true and
* MakeCurrent() recorded the nativeWindow handle in the WindowInfo
* structure.
*/
if (render_spu.render_to_app_window && w->nativeWindow) {
#ifdef VBOX_CR_SERVER_FORCE_WGL
return_value = render_spu.ws.wglSwapBuffers( w->nativeWindow );
#else
return_value = SwapBuffers( w->nativeWindow );
#endif
} else {
/*
HRGN hRgn1, hRgn2, hRgn3;
HWND hWndParent;
LONG ws;
hRgn1 = CreateRectRgn(0, 0, w->BltInfo.width, w->BltInfo.height);
hRgn2 = CreateRectRgn(50, 50, 100, 100);
hRgn3 = CreateRectRgn(0, 0, 0, 0);
CombineRgn(hRgn3, hRgn1, hRgn2, RGN_DIFF);
SetWindowRgn(w->visual->hWnd, hRgn3, true);
DeleteObject(hRgn1);
DeleteObject(hRgn2);
hWndParent = GetParent(w->visual->hWnd);
ws = GetWindowLong(hWndParent, GWL_STYLE);
ws &= ~WS_CLIPCHILDREN;
SetWindowLong(hWndParent, GWL_STYLE, ws);
RECT rcClip;
rcClip.left = 50;
rcClip.top = 50;
rcClip.right = 100;
rcClip.bottom = 100;
ValidateRect(w->visual->hWnd, &rcClip);
return_value = GetClipBox(w->visual->device_context, &rcClip);
crDebug("GetClipBox returned %d (NR=%d,SR=%d,CR=%d,ERR=%d)",
return_value, NULLREGION, SIMPLEREGION, COMPLEXREGION, ERROR);
crDebug("rcClip(%d, %d, %d, %d)", rcClip.left, rcClip.top, rcClip.right, rcClip.bottom);
return_value = ExcludeClipRect(w->visual->device_context, 50, 50, 100, 100);
crDebug("ExcludeClipRect returned %d (NR=%d,SR=%d,CR=%d,ERR=%d)",
return_value, NULLREGION, SIMPLEREGION, COMPLEXREGION, ERROR);
return_value = GetClipBox(w->visual->device_context, &rcClip);
crDebug("GetClipBox returned %d (NR=%d,SR=%d,CR=%d,ERR=%d)",
return_value, NULLREGION, SIMPLEREGION, COMPLEXREGION, ERROR);
crDebug("rcClip(%d, %d, %d, %d)", rcClip.left, rcClip.top, rcClip.right, rcClip.bottom);
*/
#ifdef VBOX_CR_SERVER_FORCE_WGL
return_value = render_spu.ws.wglSwapBuffers( w->device_context );
#else
return_value = SwapBuffers( w->device_context );
#endif
}
if (!return_value)
{
/* GOD DAMN IT. The latest versions of the NVIDIA drivers
* return failure from wglSwapBuffers, but it works just fine.
* WHAT THE HELL?! */
crWarning( "wglSwapBuffers failed: return value of %d!", return_value);
}
}
void renderspu_SystemReparentWindow(WindowInfo *window)
{
SetParent(window->hWnd, (HWND)render_spu_parent_window_id);
}