summaryrefslogtreecommitdiffstats
path: root/src/VBox/HostServices/SharedOpenGL/render
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/VBox/HostServices/SharedOpenGL/render/Makefile.kup0
-rw-r--r--src/VBox/HostServices/SharedOpenGL/render/VBoxOGLrenderspu.rc51
-rw-r--r--src/VBox/HostServices/SharedOpenGL/render/render.def7
-rw-r--r--src/VBox/HostServices/SharedOpenGL/render/renderspu.c1960
-rw-r--r--src/VBox/HostServices/SharedOpenGL/render/renderspu.h506
-rw-r--r--src/VBox/HostServices/SharedOpenGL/render/renderspu_agl.c907
-rw-r--r--src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa.c479
-rw-r--r--src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa_helper.h65
-rw-r--r--src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa_helper.m3283
-rw-r--r--src/VBox/HostServices/SharedOpenGL/render/renderspu_config.c392
-rw-r--r--src/VBox/HostServices/SharedOpenGL/render/renderspu_glx.c2042
-rw-r--r--src/VBox/HostServices/SharedOpenGL/render/renderspu_init.c623
-rw-r--r--src/VBox/HostServices/SharedOpenGL/render/renderspu_wgl.c1741
13 files changed, 12056 insertions, 0 deletions
diff --git a/src/VBox/HostServices/SharedOpenGL/render/Makefile.kup b/src/VBox/HostServices/SharedOpenGL/render/Makefile.kup
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/render/Makefile.kup
diff --git a/src/VBox/HostServices/SharedOpenGL/render/VBoxOGLrenderspu.rc b/src/VBox/HostServices/SharedOpenGL/render/VBoxOGLrenderspu.rc
new file mode 100644
index 00000000..2cfbc4d9
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/render/VBoxOGLrenderspu.rc
@@ -0,0 +1,51 @@
+/* $Id: VBoxOGLrenderspu.rc $ */
+/** @file
+ * VBoxOGLrenderspu - Resource file containing version info and icon.
+ */
+
+/*
+ * Copyright (C) 2015-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include <windows.h>
+#include <VBox/version.h>
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION VBOX_RC_FILE_VERSION
+ PRODUCTVERSION VBOX_RC_FILE_VERSION
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+ FILEFLAGS VBOX_RC_FILE_FLAGS
+ FILEOS VBOX_RC_FILE_OS
+ FILETYPE VBOX_RC_TYPE_DLL
+ FILESUBTYPE VFT2_UNKNOWN
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0" // Lang=US English, CharSet=Unicode
+ BEGIN
+ VALUE "FileDescription", "VirtualBox crOpenGL ICD\0"
+ VALUE "InternalName", "VBoxOGLrenderspu\0"
+ VALUE "OriginalFilename", "VBoxOGLrenderspu.dll\0"
+ VALUE "CompanyName", VBOX_RC_COMPANY_NAME
+ VALUE "FileVersion", VBOX_RC_FILE_VERSION_STR
+ VALUE "LegalCopyright", VBOX_RC_LEGAL_COPYRIGHT
+ VALUE "ProductName", VBOX_RC_PRODUCT_NAME_STR
+ VALUE "ProductVersion", VBOX_RC_PRODUCT_VERSION_STR
+ VBOX_RC_MORE_STRINGS
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/src/VBox/HostServices/SharedOpenGL/render/render.def b/src/VBox/HostServices/SharedOpenGL/render/render.def
new file mode 100644
index 00000000..870d7494
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/render/render.def
@@ -0,0 +1,7 @@
+; Copyright (c) 2001, Stanford University
+; All rights reserved.
+;
+; See the file LICENSE.txt for information on redistributing this software.
+EXPORTS
+SPULoad
+renderspuSetWindowId
diff --git a/src/VBox/HostServices/SharedOpenGL/render/renderspu.c b/src/VBox/HostServices/SharedOpenGL/render/renderspu.c
new file mode 100644
index 00000000..52a1dfca
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/render/renderspu.c
@@ -0,0 +1,1960 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "cr_environment.h"
+#include "cr_string.h"
+#include "cr_error.h"
+#include "cr_mem.h"
+#include "cr_spu.h"
+#include "cr_environment.h"
+#include "renderspu.h"
+#include "cr_extstring.h"
+
+#include <iprt/asm.h>
+
+uint32_t renderspuContextRelease(ContextInfo *context);
+uint32_t renderspuContextRetain(ContextInfo *context);
+
+static void
+DoSync(void)
+{
+ CRMessage *in, out;
+
+ out.header.type = CR_MESSAGE_OOB;
+
+ if (render_spu.is_swap_master)
+ {
+ int a;
+
+ for (a = 0; a < render_spu.num_swap_clients; a++)
+ {
+ crNetGetMessage( render_spu.swap_conns[a], &in );
+ crNetFree( render_spu.swap_conns[a], in);
+ }
+
+ for (a = 0; a < render_spu.num_swap_clients; a++)
+ crNetSend( render_spu.swap_conns[a], NULL, &out, sizeof(CRMessage));
+ }
+ else
+ {
+ crNetSend( render_spu.swap_conns[0], NULL, &out, sizeof(CRMessage));
+
+ crNetGetMessage( render_spu.swap_conns[0], &in );
+ crNetFree( render_spu.swap_conns[0], in);
+ }
+}
+
+
+
+/*
+ * Visual functions
+ */
+
+/**
+ * used for debugging and giving info to the user.
+ */
+void
+renderspuMakeVisString( GLbitfield visAttribs, char *s )
+{
+ s[0] = 0;
+
+ if (visAttribs & CR_RGB_BIT)
+ crStrcat(s, "RGB");
+ if (visAttribs & CR_ALPHA_BIT)
+ crStrcat(s, "A");
+ if (visAttribs & CR_DOUBLE_BIT)
+ crStrcat(s, ", Doublebuffer");
+ if (visAttribs & CR_STEREO_BIT)
+ crStrcat(s, ", Stereo");
+ if (visAttribs & CR_DEPTH_BIT)
+ crStrcat(s, ", Z");
+ if (visAttribs & CR_STENCIL_BIT)
+ crStrcat(s, ", Stencil");
+ if (visAttribs & CR_ACCUM_BIT)
+ crStrcat(s, ", Accum");
+ if (visAttribs & CR_MULTISAMPLE_BIT)
+ crStrcat(s, ", Multisample");
+ if (visAttribs & CR_OVERLAY_BIT)
+ crStrcat(s, ", Overlay");
+ if (visAttribs & CR_PBUFFER_BIT)
+ crStrcat(s, ", PBuffer");
+}
+
+GLboolean renderspuInitVisual(VisualInfo *pVisInfo, const char *displayName, GLbitfield visAttribs)
+{
+ pVisInfo->displayName = crStrdup(displayName);
+ pVisInfo->visAttribs = visAttribs;
+ return renderspu_SystemInitVisual(pVisInfo);
+}
+
+/*
+ * Find a VisualInfo which matches the given display name and attribute
+ * bitmask, or return a pointer to a new visual.
+ */
+VisualInfo *
+renderspuFindVisual(const char *displayName, GLbitfield visAttribs)
+{
+ int i;
+
+ if (!displayName)
+ displayName = "";
+
+ /* first, try to find a match */
+#if defined(WINDOWS) || defined(DARWIN)
+ for (i = 0; i < render_spu.numVisuals; i++) {
+ if (visAttribs == render_spu.visuals[i].visAttribs) {
+ return &(render_spu.visuals[i]);
+ }
+ }
+#elif defined(GLX)
+ for (i = 0; i < render_spu.numVisuals; i++) {
+ if (crStrcmp(displayName, render_spu.visuals[i].displayName) == 0
+ && visAttribs == render_spu.visuals[i].visAttribs) {
+ return &(render_spu.visuals[i]);
+ }
+ }
+#endif
+
+ if (render_spu.numVisuals >= MAX_VISUALS)
+ {
+ crWarning("Render SPU: Couldn't create a visual, too many visuals already");
+ return NULL;
+ }
+
+ /* create a new visual */
+ i = render_spu.numVisuals;
+ if (renderspuInitVisual(&(render_spu.visuals[i]), displayName, visAttribs)) {
+ render_spu.numVisuals++;
+ return &(render_spu.visuals[i]);
+ }
+ else {
+ crWarning("Render SPU: Couldn't get a visual, renderspu_SystemInitVisual failed");
+ return NULL;
+ }
+}
+
+static ContextInfo * renderspuCreateContextInternal(const char *dpyName, GLint visBits, GLint idCtx, ContextInfo * sharedContext)
+{
+ ContextInfo *context;
+ VisualInfo *visual;
+
+ if (idCtx <= 0)
+ {
+ idCtx = (GLint)crHashtableAllocKeys(render_spu.contextTable, 1);
+ if (idCtx <= 0)
+ {
+ crWarning("failed to allocate context id");
+ return NULL;
+ }
+ }
+ else
+ {
+ if (crHashtableIsKeyUsed(render_spu.contextTable, idCtx))
+ {
+ crWarning("the specified ctx key %d is in use", idCtx);
+ return NULL;
+ }
+ }
+
+
+ if (!dpyName || crStrlen(render_spu.display_string)>0)
+ dpyName = render_spu.display_string;
+
+ visual = renderspuFindVisual(dpyName, visBits);
+ if (!visual)
+ return NULL;
+
+ context = (ContextInfo *) crCalloc(sizeof(ContextInfo));
+ if (!context)
+ return NULL;
+ context->BltInfo.Base.id = idCtx;
+ context->shared = sharedContext;
+ if (!renderspu_SystemCreateContext(visual, context, sharedContext))
+ return NULL;
+
+ crHashtableAdd(render_spu.contextTable, idCtx, context);
+
+ context->BltInfo.Base.visualBits = visual->visAttribs;
+ /*
+ crDebug("Render SPU: CreateContext(%s, 0x%x) returning %d",
+ dpyName, visBits, context->BltInfo.Base.id);
+ */
+
+ if (sharedContext)
+ renderspuContextRetain(sharedContext);
+
+ context->cRefs = 1;
+
+ return context;
+}
+
+GLint renderspuCreateContextEx(const char *dpyName, GLint visBits, GLint id, GLint shareCtx)
+{
+ ContextInfo *context, *sharedContext = NULL;
+
+ if (shareCtx) {
+ sharedContext
+ = (ContextInfo *) crHashtableSearch(render_spu.contextTable, shareCtx);
+ CRASSERT(sharedContext);
+ }
+
+ context = renderspuCreateContextInternal(dpyName, visBits, id, sharedContext);
+ if (context)
+ return context->BltInfo.Base.id;
+ return -1;
+}
+
+/*
+ * Context functions
+ */
+
+GLint RENDER_APIENTRY
+renderspuCreateContext(const char *dpyName, GLint visBits, GLint shareCtx)
+{
+ return renderspuCreateContextEx(dpyName, visBits, 0, shareCtx);
+}
+
+static void renderspuDestroyContextTerminate( ContextInfo *context )
+{
+ CRASSERT(context->BltInfo.Base.id == -1);
+ renderspu_SystemDestroyContext( context );
+ if (context->extensionString) {
+ crFree(context->extensionString);
+ context->extensionString = NULL;
+ }
+
+ if (context->shared)
+ renderspuContextRelease( context->shared );
+
+ crFree(context);
+}
+
+uint32_t renderspuContextRetain( ContextInfo *context )
+{
+ Assert(context->cRefs);
+ return ASMAtomicIncU32(&context->cRefs);
+}
+
+uint32_t renderspuContextRelease( ContextInfo *context )
+{
+ uint32_t cRefs = ASMAtomicDecU32(&context->cRefs);
+ if (!cRefs)
+ renderspuDestroyContextTerminate( context );
+ else
+ CRASSERT(cRefs < UINT32_MAX/2);
+ return cRefs;
+}
+
+uint32_t renderspuContextMarkDeletedAndRelease( ContextInfo *context )
+{
+ /* invalidate the context id to mark it as deleted */
+ context->BltInfo.Base.id = -1;
+
+ /* some drivers do not like when the base (shared) context is deleted before its referals,
+ * this is why we keep a context refference counting the base (shared) context will be destroyed as soon as*/
+ return renderspuContextRelease( context );
+}
+
+ContextInfo * renderspuDefaultSharedContextAcquire()
+{
+ ContextInfo * pCtx = render_spu.defaultSharedContext;
+ if (!pCtx)
+ return NULL;
+
+ renderspuContextRetain(pCtx);
+ return pCtx;
+}
+
+void renderspuDefaultSharedContextRelease(ContextInfo * pCtx)
+{
+ renderspuContextRelease(pCtx);
+}
+
+
+static void RENDER_APIENTRY
+renderspuDestroyContext( GLint ctx )
+{
+ ContextInfo *context, *curCtx;
+
+ CRASSERT(ctx);
+
+ if (ctx == CR_RENDER_DEFAULT_CONTEXT_ID)
+ {
+ crWarning("request to destroy a default context, ignoring");
+ return;
+ }
+
+ context = (ContextInfo *) crHashtableSearch(render_spu.contextTable, ctx);
+
+ if (!context)
+ {
+ crWarning("request to delete inexistent context");
+ return;
+ }
+
+ if (render_spu.defaultSharedContext == context)
+ {
+ renderspuSetDefaultSharedContext(NULL);
+ }
+
+ curCtx = GET_CONTEXT_VAL();
+// CRASSERT(curCtx);
+ if (curCtx == context)
+ {
+ renderspuMakeCurrent( CR_RENDER_DEFAULT_WINDOW_ID, 0, CR_RENDER_DEFAULT_CONTEXT_ID );
+ curCtx = GET_CONTEXT_VAL();
+ Assert(curCtx);
+ Assert(curCtx != context);
+ }
+
+ crHashtableDelete(render_spu.contextTable, ctx, NULL);
+
+ renderspuContextMarkDeletedAndRelease(context);
+}
+
+WindowInfo* renderspuWinCreate(GLint visBits, GLint id)
+{
+ WindowInfo* window = (WindowInfo *)crAlloc(sizeof (*window));
+ if (!window)
+ {
+ crWarning("crAlloc failed");
+ return NULL;
+ }
+
+ if (!renderspuWinInit(window, NULL, visBits, id))
+ {
+ crWarning("renderspuWinInit failed");
+ crFree(window);
+ return NULL;
+ }
+
+ return window;
+}
+
+void renderspuWinTermOnShutdown(WindowInfo *window)
+{
+ renderspuVBoxCompositorSet(window, NULL);
+ renderspuVBoxPresentBlitterCleanup(window);
+ window->BltInfo.Base.id = -1;
+ renderspu_SystemDestroyWindow( window );
+}
+
+static void renderspuCheckCurrentCtxWindowCB(unsigned long key, void *data1, void *data2)
+{
+ ContextInfo *pCtx = (ContextInfo *) data1;
+ WindowInfo *pWindow = data2;
+ (void) key;
+
+ if (pCtx->currentWindow==pWindow)
+ {
+ WindowInfo* pDummy = renderspuGetDummyWindow(pCtx->BltInfo.Base.visualBits);
+ if (pDummy)
+ {
+ renderspuPerformMakeCurrent(pDummy, 0, pCtx);
+ }
+ else
+ {
+ crWarning("failed to get dummy window");
+ renderspuMakeCurrent(CR_RENDER_DEFAULT_WINDOW_ID, 0, pCtx->BltInfo.Base.id);
+ }
+ }
+}
+
+void renderspuWinTerm( WindowInfo *window )
+{
+ if (!renderspuWinIsTermed(window))
+ {
+
+ GET_CONTEXT(pOldCtx);
+ WindowInfo * pOldWindow = pOldCtx ? pOldCtx->currentWindow : NULL;
+ CRASSERT(!pOldCtx == !pOldWindow);
+ /* ensure no concurrent draws can take place */
+ renderspuWinTermOnShutdown(window);
+ /* check if this window is bound to some ctx. Note: window pointer is already freed here */
+ crHashtableWalk(render_spu.contextTable, renderspuCheckCurrentCtxWindowCB, window);
+ /* restore current context */
+ {
+ GET_CONTEXT(pNewCtx);
+ WindowInfo * pNewWindow = pNewCtx ? pNewCtx->currentWindow : NULL;
+ CRASSERT(!pNewCtx == !pNewWindow);
+
+ if (pOldWindow == window)
+ renderspuMakeCurrent(CR_RENDER_DEFAULT_WINDOW_ID, 0, CR_RENDER_DEFAULT_CONTEXT_ID);
+ else if (pNewCtx != pOldCtx || pOldWindow != pNewWindow)
+ {
+ if (pOldCtx)
+ renderspuPerformMakeCurrent(pOldWindow, 0, pOldCtx);
+ else
+ renderspuMakeCurrent(CR_RENDER_DEFAULT_WINDOW_ID, 0, CR_RENDER_DEFAULT_CONTEXT_ID);
+ }
+ }
+
+ }
+}
+
+void renderspuWinCleanup(WindowInfo *window)
+{
+ renderspuWinTerm( window );
+ RTCritSectDelete(&window->CompositorLock);
+}
+
+void renderspuWinDestroy(WindowInfo *window)
+{
+ renderspuWinCleanup(window);
+ crFree(window);
+}
+
+WindowInfo* renderspuGetDummyWindow(GLint visBits)
+{
+ WindowInfo *window = (WindowInfo *) crHashtableSearch(render_spu.dummyWindowTable, visBits);
+ if (!window)
+ {
+ window = renderspuWinCreate(visBits, -1);
+ if (!window)
+ {
+ WARN(("renderspuWinCreate failed"));
+ return NULL;
+ }
+
+ crHashtableAdd(render_spu.dummyWindowTable, visBits, window);
+ }
+
+ return window;
+}
+
+/* Check that OpenGL extensions listed in pszRequiredExts string also exist in the pszAvailableExts string. */
+static void renderCompareGLExtensions(const char *pszAvailableExts, const char *pszRequiredExts)
+{
+ unsigned char fPrintHeader = 1;
+ const char *pszExt = pszRequiredExts;
+
+ for (;;)
+ {
+ const char *pszSrc = pszAvailableExts;
+ size_t offExtEnd;
+
+ while (*pszExt == ' ')
+ ++pszExt;
+
+ if (!*pszExt)
+ break;
+
+ offExtEnd = RTStrOffCharOrTerm(pszExt, ' ');
+
+ for (;;)
+ {
+ size_t offSrcEnd;
+
+ while (*pszSrc == ' ')
+ ++pszSrc;
+
+ if (!*pszSrc)
+ break;
+
+ offSrcEnd = RTStrOffCharOrTerm(pszSrc, ' ');
+
+ if ( offSrcEnd == offExtEnd
+ && memcmp(pszSrc, pszExt, offSrcEnd) == 0)
+ break;
+
+ pszSrc += offSrcEnd;
+ }
+
+ if (!*pszSrc)
+ {
+ if (fPrintHeader)
+ {
+ fPrintHeader = 0;
+ crInfo("Host does not support OpenGL extension(s):");
+ }
+ crInfo(" %.*s", offExtEnd, pszExt);
+ }
+
+ pszExt += offExtEnd;
+ }
+}
+
+void renderspuPerformMakeCurrent(WindowInfo *window, GLint nativeWindow, ContextInfo *context)
+{
+ if (window && context)
+ {
+#ifdef CHROMIUM_THREADSAFE
+ crSetTSD(&_RenderTSD, context);
+#else
+ render_spu.currentContext = context;
+#endif
+ context->currentWindow = window;
+
+ renderspu_SystemMakeCurrent( window, nativeWindow, context );
+ if (!context->everCurrent) {
+ static volatile uint32_t u32ExtCompared = 0;
+ /* print OpenGL info */
+ const char *extString = (const char *) render_spu.ws.glGetString( GL_EXTENSIONS );
+ /*
+ crDebug( "Render SPU: GL_EXTENSIONS: %s", render_spu.ws.glGetString( GL_EXTENSIONS ) );
+ */
+ crInfo( "Render SPU: GL_VENDOR: %s", render_spu.ws.glGetString( GL_VENDOR ) );
+ crInfo( "Render SPU: GL_RENDERER: %s", render_spu.ws.glGetString( GL_RENDERER ) );
+ crInfo( "Render SPU: GL_VERSION: %s", render_spu.ws.glGetString( GL_VERSION ) );
+ crInfo( "Render SPU: GL_EXTENSIONS: %s", render_spu.ws.glGetString( GL_EXTENSIONS ) );
+
+ if (ASMAtomicCmpXchgU32(&u32ExtCompared, 1, 0))
+ renderCompareGLExtensions(extString, crExtensions);
+
+ if (crStrstr(extString, "GL_ARB_window_pos"))
+ context->haveWindowPosARB = GL_TRUE;
+ else
+ context->haveWindowPosARB = GL_FALSE;
+ context->everCurrent = GL_TRUE;
+ }
+ if (window->BltInfo.Base.id == CR_RENDER_DEFAULT_WINDOW_ID && window->mapPending &&
+ !render_spu.render_to_app_window && !render_spu.render_to_crut_window) {
+ /* Window[CR_RENDER_DEFAULT_CONTEXT_ID] is special, it's the default window and normally hidden.
+ * If the mapPending flag is set, then we should now make the window
+ * visible.
+ */
+ /*renderspu_SystemShowWindow( window, GL_TRUE );*/
+ window->mapPending = GL_FALSE;
+ }
+ window->everCurrent = GL_TRUE;
+ }
+ else if (!window && !context)
+ {
+ renderspu_SystemMakeCurrent( NULL, 0, NULL );
+#ifdef CHROMIUM_THREADSAFE
+ crSetTSD(&_RenderTSD, NULL);
+#else
+ render_spu.currentContext = NULL;
+#endif
+ }
+ else
+ {
+ crError("renderspuMakeCurrent invalid ids: crWindow(%d), ctx(%d)",
+ window ? window->BltInfo.Base.id : 0,
+ context ? context->BltInfo.Base.id : 0);
+ }
+}
+
+void RENDER_APIENTRY
+renderspuMakeCurrent(GLint crWindow, GLint nativeWindow, GLint ctx)
+{
+ WindowInfo *window = NULL;
+ ContextInfo *context = NULL;
+
+ /*
+ crDebug("%s win=%d native=0x%x ctx=%d", __FUNCTION__, crWindow, (int) nativeWindow, ctx);
+ */
+
+ if (crWindow)
+ {
+ window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, crWindow);
+ if (!window)
+ {
+ crWarning("invalid window %d specified", crWindow);
+ return;
+ }
+ }
+
+ if (ctx)
+ {
+ context = (ContextInfo *) crHashtableSearch(render_spu.contextTable, ctx);
+ if (!context)
+ {
+ crWarning("invalid context %d specified", ctx);
+ return;
+ }
+ }
+
+ if (!context != !window)
+ {
+ crWarning("either window %d or context %d are zero", crWindow, ctx);
+ return;
+ }
+
+ renderspuPerformMakeCurrent(window, nativeWindow, context);
+}
+
+GLboolean renderspuWinInitWithVisual( WindowInfo *window, VisualInfo *visual, GLboolean showIt, GLint id )
+{
+ crMemset(window, 0, sizeof (*window));
+ RTCritSectInit(&window->CompositorLock);
+ window->pCompositor = NULL;
+
+ window->BltInfo.Base.id = id;
+
+ window->x = render_spu.defaultX;
+ window->y = render_spu.defaultY;
+ window->BltInfo.width = render_spu.defaultWidth;
+ window->BltInfo.height = render_spu.defaultHeight;
+
+ /* Set window->title, replacing %i with the window ID number */
+ {
+ const char *s = crStrstr(render_spu.window_title, "%i");
+ if (s) {
+ int i, j, k;
+ window->title = crAlloc(crStrlen(render_spu.window_title) + 10);
+ for (i = 0; render_spu.window_title[i] != '%'; i++)
+ window->title[i] = render_spu.window_title[i];
+ k = sprintf(window->title + i, "%d", window->BltInfo.Base.id);
+ CRASSERT(k < 10);
+ i++; /* skip the 'i' after the '%' */
+ j = i + k;
+ for (; (window->title[j] = s[i]) != 0; i++, j++)
+ ;
+ }
+ else {
+ window->title = crStrdup(render_spu.window_title);
+ }
+ }
+
+ window->BltInfo.Base.visualBits = visual->visAttribs;
+
+ window->cRefs = 1;
+
+ /*
+ crDebug("Render SPU: Creating window (visBits=0x%x, id=%d)", visBits, window->BltInfo.Base.id);
+ */
+ /* Have GLX/WGL/AGL create the window */
+ if (!renderspu_SystemVBoxCreateWindow( visual, showIt, window ))
+ {
+ crWarning( "Render SPU: Couldn't create a window, renderspu_SystemCreateWindow failed" );
+ return GL_FALSE;
+ }
+
+ window->visible = !!showIt;
+
+ CRASSERT(window->visual == visual);
+ return GL_TRUE;
+}
+
+/*
+ * Window functions
+ */
+GLboolean renderspuWinInit(WindowInfo *pWindow, const char *dpyName, GLint visBits, GLint id)
+{
+ VisualInfo *visual;
+
+ crMemset(pWindow, 0, sizeof (*pWindow));
+
+ if (!dpyName || crStrlen(render_spu.display_string) > 0)
+ dpyName = render_spu.display_string;
+
+ visual = renderspuFindVisual( dpyName, visBits );
+ if (!visual)
+ {
+ crWarning( "Render SPU: Couldn't create a window, renderspuFindVisual returned NULL" );
+ return GL_FALSE;
+ }
+
+ /*
+ crDebug("Render SPU: Creating window (visBits=0x%x, id=%d)", visBits, window->BltInfo.Base.id);
+ */
+ /* Have GLX/WGL/AGL create the window */
+ if (!renderspuWinInitWithVisual( pWindow, visual, 0, id ))
+ {
+ crWarning( "Render SPU: Couldn't create a window, renderspu_SystemCreateWindow failed" );
+ return GL_FALSE;
+ }
+
+ return GL_TRUE;
+}
+
+GLint renderspuWindowCreateEx( const char *dpyName, GLint visBits, GLint id )
+{
+ WindowInfo *window;
+
+ if (id <= 0)
+ {
+ id = (GLint)crHashtableAllocKeys(render_spu.windowTable, 1);
+ if (id <= 0)
+ {
+ crWarning("failed to allocate window id");
+ return -1;
+ }
+ }
+ else
+ {
+ if (crHashtableIsKeyUsed(render_spu.windowTable, id))
+ {
+ crWarning("the specified window key %d is in use", id);
+ return -1;
+ }
+ }
+
+ /* Allocate WindowInfo */
+ window = renderspuWinCreate(visBits, id);
+
+ if (!window)
+ {
+ crWarning("renderspuWinCreate failed");
+ crFree(window);
+ return -1;
+ }
+
+ crHashtableAdd(render_spu.windowTable, id, window);
+ return window->BltInfo.Base.id;
+}
+
+GLint RENDER_APIENTRY
+renderspuWindowCreate( const char *dpyName, GLint visBits )
+{
+ return renderspuWindowCreateEx( dpyName, visBits, 0 );
+}
+
+void renderspuWinReleaseCb(void*pvWindow)
+{
+ renderspuWinRelease((WindowInfo*)pvWindow);
+}
+
+void
+RENDER_APIENTRY renderspuWindowDestroy( GLint win )
+{
+ WindowInfo *window;
+
+ CRASSERT(win >= 0);
+ if (win == CR_RENDER_DEFAULT_WINDOW_ID)
+ {
+ crWarning("request to destroy a default mural, ignoring");
+ return;
+ }
+ window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, win);
+ if (window) {
+ crDebug("Render SPU: Destroy window (%d)", win);
+ /* since os-specific backend can hold its own reference to the window object (e.g. on OSX),
+ * we need to explicitly issue a window destroy command
+ * this ensures the backend will eventually release the reference,
+ * the window object itself will remain valid until its ref count reaches zero */
+ renderspuWinTerm( window );
+
+ /* remove window info from hash table, and free it */
+ crHashtableDelete(render_spu.windowTable, win, renderspuWinReleaseCb);
+
+ }
+ else {
+ crDebug("Render SPU: Attempt to destroy invalid window (%d)", win);
+ }
+}
+
+
+static void RENDER_APIENTRY
+renderspuWindowSize( GLint win, GLint w, GLint h )
+{
+ WindowInfo *window;
+ CRASSERT(win >= 0);
+ window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, win);
+ if (window) {
+ if (w != window->BltInfo.width
+ || h != window->BltInfo.height)
+ {
+ /* window is resized, compositor data is no longer valid
+ * this set also ensures all redraw operations are done in the redraw thread
+ * and that no redraw is started until new Present request comes containing a valid presentation data */
+ renderspuVBoxCompositorSet( window, NULL);
+ renderspu_SystemWindowSize( window, w, h );
+ window->BltInfo.width = w;
+ window->BltInfo.height = h;
+ }
+ }
+ else {
+ WARN(("Render SPU: Attempt to resize invalid window (%d)", win));
+ }
+}
+
+
+static void RENDER_APIENTRY
+renderspuWindowPosition( GLint win, GLint x, GLint y )
+{
+ if (!render_spu.ignore_window_moves) {
+ WindowInfo *window;
+ CRASSERT(win >= 0);
+ window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, win);
+ if (window) {
+ renderspu_SystemWindowPosition( window, x, y );
+ window->x = x;
+ window->y = y;
+ }
+ else {
+ crDebug("Render SPU: Attempt to move invalid window (%d)", win);
+ }
+ }
+}
+
+#ifdef DEBUG_misha
+# define CR_DBG_DUMP_VISIBLE_REGIONS
+#endif
+
+#ifdef CR_DBG_DUMP_VISIBLE_REGIONS
+static void renderspuDbgDumpVisibleRegion(GLint win, GLint cRects, const GLint *pRects)
+{
+ GLint i;
+ const RTRECT *pRtRects = (const RTRECT *)((const void*)pRects);
+
+ crInfo("Window %d, Vidible Regions%d", win, cRects);
+ for (i = 0; i < cRects; ++i)
+ {
+ crInfo("%d: (%d,%d), (%d,%d)", i, pRtRects[i].xLeft, pRtRects[i].yTop, pRtRects[i].xRight, pRtRects[i].yBottom);
+ }
+ crInfo("======");
+}
+#endif
+
+static void RENDER_APIENTRY
+renderspuWindowVisibleRegion(GLint win, GLint cRects, const GLint *pRects)
+{
+ WindowInfo *window;
+ CRASSERT(win >= 0);
+
+#ifdef CR_DBG_DUMP_VISIBLE_REGIONS
+ renderspuDbgDumpVisibleRegion(win, cRects, pRects);
+#endif
+
+ window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, win);
+ if (window) {
+ renderspu_SystemWindowVisibleRegion( window, cRects, pRects );
+ }
+ else {
+ crWarning("Render SPU: Attempt to set VisibleRegion for invalid window (%d)", win);
+ }
+}
+
+static void RENDER_APIENTRY
+renderspuWindowShow( GLint win, GLint flag )
+{
+ WindowInfo *window;
+ CRASSERT(win >= 0);
+ window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, win);
+ if (window) {
+ GLboolean visible;
+ if (window->nativeWindow) {
+ /* We're rendering back to the native app window instead of the
+ * new window which we (the Render SPU) created earlier.
+ * So, we never want to show the Render SPU's window.
+ */
+ flag = 0;
+ }
+
+ visible = !!flag;
+
+// if (window->visible != visible)
+ {
+ renderspu_SystemShowWindow( window, visible );
+ window->visible = visible;
+ }
+ }
+ else {
+ crDebug("Render SPU: Attempt to hide/show invalid window (%d)", win);
+ }
+}
+
+static void RENDER_APIENTRY
+renderspuVBoxPresentComposition( GLint win, const struct VBOXVR_SCR_COMPOSITOR * pCompositor, const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pChangedEntry )
+{
+ WindowInfo *window;
+ CRASSERT(win >= 0);
+ window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, win);
+ if (window) {
+ if (renderspuVBoxCompositorSet(window, pCompositor))
+ {
+ renderspu_SystemVBoxPresentComposition(window, pChangedEntry);
+ }
+ }
+ else {
+ crDebug("Render SPU: Attempt to PresentComposition for invalid window (%d)", win);
+ }
+}
+
+void renderspuVBoxCompositorBlitStretched ( const struct VBOXVR_SCR_COMPOSITOR * pCompositor, PCR_BLITTER pBlitter, GLfloat scaleX, GLfloat scaleY)
+{
+ VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR CIter;
+ const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry;
+ CrVrScrCompositorConstIterInit(pCompositor, &CIter);
+ while ((pEntry = CrVrScrCompositorConstIterNext(&CIter)) != NULL)
+ {
+ uint32_t cRegions;
+ const RTRECT *paSrcRegions, *paDstRegions;
+ int rc = CrVrScrCompositorEntryRegionsGet(pCompositor, pEntry, &cRegions, &paSrcRegions, &paDstRegions, NULL);
+ uint32_t fFlags = CrVrScrCompositorEntryFlagsCombinedGet(pCompositor, pEntry);
+ if (RT_SUCCESS(rc))
+ {
+ uint32_t i;
+ for (i = 0; i < cRegions; ++i)
+ {
+ RTRECT DstRect;
+ const CR_TEXDATA *pTexData = CrVrScrCompositorEntryTexGet(pEntry);
+ DstRect.xLeft = paDstRegions[i].xLeft * scaleX;
+ DstRect.yTop = paDstRegions[i].yTop * scaleY;
+ DstRect.xRight = paDstRegions[i].xRight * scaleX;
+ DstRect.yBottom = paDstRegions[i].yBottom * scaleY;
+ CrBltBlitTexMural(pBlitter, true, CrTdTexGet(pTexData), &paSrcRegions[i], &DstRect, 1, fFlags);
+ }
+ }
+ else
+ {
+ crWarning("BlitStretched: CrVrScrCompositorEntryRegionsGet failed rc %d", rc);
+ }
+ }
+}
+
+void renderspuVBoxCompositorBlit ( const struct VBOXVR_SCR_COMPOSITOR * pCompositor, PCR_BLITTER pBlitter)
+{
+ VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR CIter;
+ const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry;
+ CrVrScrCompositorConstIterInit(pCompositor, &CIter);
+ while ((pEntry = CrVrScrCompositorConstIterNext(&CIter)) != NULL)
+ {
+ uint32_t cRegions;
+ const RTRECT *paSrcRegions, *paDstRegions;
+ int rc = CrVrScrCompositorEntryRegionsGet(pCompositor, pEntry, &cRegions, &paSrcRegions, &paDstRegions, NULL);
+ uint32_t fFlags = CrVrScrCompositorEntryFlagsCombinedGet(pCompositor, pEntry);
+ if (RT_SUCCESS(rc))
+ {
+ const CR_TEXDATA *pTexData = CrVrScrCompositorEntryTexGet(pEntry);
+ CrBltBlitTexMural(pBlitter, true, CrTdTexGet(pTexData), paSrcRegions, paDstRegions, cRegions, fFlags);
+ }
+ else
+ {
+ crWarning("Blit: CrVrScrCompositorEntryRegionsGet failed rc %d", rc);
+ }
+ }
+}
+
+void renderspuVBoxPresentBlitterCleanup( WindowInfo *window )
+{
+ if (!window->pBlitter)
+ return;
+
+ if (render_spu.blitterTable)
+ {
+ const CR_BLITTER_WINDOW * pBltInfo = CrBltMuralGetCurrentInfo(window->pBlitter);
+ if (pBltInfo && pBltInfo->Base.id == window->BltInfo.Base.id)
+ {
+ CrBltMuralSetCurrentInfo(window->pBlitter, NULL);
+ }
+ }
+ else
+ {
+ CRASSERT(CrBltMuralGetCurrentInfo(window->pBlitter)->Base.id == window->BltInfo.Base.id);
+ CrBltMuralSetCurrentInfo(window->pBlitter, NULL);
+ CrBltTerm(window->pBlitter);
+ }
+ window->pBlitter = NULL;
+}
+
+PCR_BLITTER renderspuVBoxPresentBlitterGet( WindowInfo *window )
+{
+ PCR_BLITTER pBlitter = window->pBlitter;
+ if (!pBlitter)
+ {
+ if (render_spu.blitterTable)
+ {
+ crHashtableLock(render_spu.blitterTable);
+ pBlitter = (PCR_BLITTER)crHashtableSearch(render_spu.blitterTable, window->visual->visAttribs);
+ }
+
+ if (!pBlitter)
+ {
+ int rc;
+ ContextInfo * pDefaultCtxInfo;
+
+ pBlitter = (PCR_BLITTER)crCalloc(sizeof (*pBlitter));
+ if (!pBlitter)
+ {
+ crWarning("failed to allocate blitter");
+ return NULL;
+ }
+
+ pDefaultCtxInfo = renderspuDefaultSharedContextAcquire();
+ if (!pDefaultCtxInfo)
+ {
+ crWarning("no default ctx info!");
+ crFree(pBlitter);
+ return NULL;
+ }
+
+ rc = CrBltInit(pBlitter, &pDefaultCtxInfo->BltInfo, true, true, NULL, &render_spu.blitterDispatch);
+
+ /* we can release it either way, since it will be retained when used as a shared context */
+ renderspuDefaultSharedContextRelease(pDefaultCtxInfo);
+
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("CrBltInit failed, rc %d", rc);
+ crFree(pBlitter);
+ return NULL;
+ }
+
+ if (render_spu.blitterTable)
+ {
+ crHashtableAdd( render_spu.blitterTable, window->visual->visAttribs, pBlitter );
+ }
+ }
+
+ if (render_spu.blitterTable)
+ crHashtableUnlock(render_spu.blitterTable);
+
+ Assert(pBlitter);
+ window->pBlitter = pBlitter;
+ }
+
+ CrBltMuralSetCurrentInfo(pBlitter, &window->BltInfo);
+ return pBlitter;
+}
+
+int renderspuVBoxPresentBlitterEnter( PCR_BLITTER pBlitter, int32_t i32MakeCurrentUserData)
+{
+ int rc;
+
+ CrBltSetMakeCurrentUserData(pBlitter, i32MakeCurrentUserData);
+
+ rc = CrBltEnter(pBlitter);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("CrBltEnter failed, rc %d", rc);
+ return rc;
+ }
+ return VINF_SUCCESS;
+}
+
+PCR_BLITTER renderspuVBoxPresentBlitterGetAndEnter( WindowInfo *window, int32_t i32MakeCurrentUserData, bool fRedraw )
+{
+ PCR_BLITTER pBlitter = fRedraw ? window->pBlitter : renderspuVBoxPresentBlitterGet(window);
+ if (pBlitter)
+ {
+ int rc = renderspuVBoxPresentBlitterEnter(pBlitter, i32MakeCurrentUserData);
+ if (RT_SUCCESS(rc))
+ {
+ return pBlitter;
+ }
+ }
+ return NULL;
+}
+
+PCR_BLITTER renderspuVBoxPresentBlitterEnsureCreated( WindowInfo *window, int32_t i32MakeCurrentUserData )
+{
+ if (!window->pBlitter)
+ {
+ const struct VBOXVR_SCR_COMPOSITOR * pTmpCompositor;
+ /* just use compositor lock to synchronize */
+ pTmpCompositor = renderspuVBoxCompositorAcquire(window);
+ CRASSERT(pTmpCompositor);
+ if (pTmpCompositor)
+ {
+ PCR_BLITTER pBlitter = renderspuVBoxPresentBlitterGet( window );
+ if (pBlitter)
+ {
+ if (!CrBltIsEverEntered(pBlitter))
+ {
+ int rc = renderspuVBoxPresentBlitterEnter(pBlitter, i32MakeCurrentUserData);
+ if (RT_SUCCESS(rc))
+ {
+ CrBltLeave(pBlitter);
+ }
+ else
+ {
+ crWarning("renderspuVBoxPresentBlitterEnter failed rc %d", rc);
+ }
+ }
+ }
+ else
+ {
+ crWarning("renderspuVBoxPresentBlitterGet failed");
+ }
+
+ renderspuVBoxCompositorRelease(window);
+ }
+ else
+ {
+ crWarning("renderspuVBoxCompositorAcquire failed");
+ }
+ }
+ return window->pBlitter;
+}
+
+void renderspuVBoxPresentCompositionGeneric( WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR * pCompositor,
+ const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pChangedEntry, int32_t i32MakeCurrentUserData,
+ bool fRedraw )
+{
+ PCR_BLITTER pBlitter = renderspuVBoxPresentBlitterGetAndEnter(window, i32MakeCurrentUserData, fRedraw);
+ if (!pBlitter)
+ return;
+
+ renderspuVBoxCompositorBlit(pCompositor, pBlitter);
+
+ renderspu_SystemSwapBuffers(window, 0);
+
+ CrBltLeave(pBlitter);
+}
+
+GLboolean renderspuVBoxCompositorSet( WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR * pCompositor)
+{
+ int rc;
+ GLboolean fEmpty = pCompositor && CrVrScrCompositorIsEmpty(pCompositor);
+ GLboolean fNeedPresent;
+
+ /* renderspuVBoxCompositorSet can be invoked from the chromium thread only and is not reentrant,
+ * no need to synch here
+ * the lock is actually needed to ensure we're in synch with the redraw thread */
+ if (window->pCompositor == pCompositor && !fEmpty)
+ return !!pCompositor;
+
+ rc = RTCritSectEnter(&window->CompositorLock);
+ if (RT_SUCCESS(rc))
+ {
+ if (!fEmpty)
+ fNeedPresent = !!pCompositor;
+ else
+ {
+ fNeedPresent = renderspu_SystemWindowNeedEmptyPresent(window);
+ pCompositor = NULL;
+ }
+
+ window->pCompositor = !fEmpty ? pCompositor : NULL;
+ RTCritSectLeave(&window->CompositorLock);
+ return fNeedPresent;
+ }
+ else
+ {
+ WARN(("RTCritSectEnter failed rc %d", rc));
+ }
+
+ return GL_FALSE;
+}
+
+static void renderspuVBoxCompositorClearAllCB(unsigned long key, void *data1, void *data2)
+{
+ WindowInfo *window = (WindowInfo *) data1;
+ renderspuVBoxCompositorSet(window, NULL);
+}
+
+void renderspuVBoxCompositorClearAll()
+{
+ /* we need to clear window compositor, which is not that trivial though,
+ * since the lock order used in presentation thread is compositor lock() -> hash table lock (aquired for id->window resolution)
+ * this is why, to prevent potential deadlocks, we use crHashtableWalkUnlocked that does not hold the table lock
+ * we are can be sure noone will modify the table here since renderspuVBoxCompositorClearAll can be called in the command (hgcm) thread only,
+ * and the table can be modified from that thread only as well */
+ crHashtableWalkUnlocked(render_spu.windowTable, renderspuVBoxCompositorClearAllCB, NULL);
+}
+
+const struct VBOXVR_SCR_COMPOSITOR * renderspuVBoxCompositorAcquire( WindowInfo *window)
+{
+ int rc = RTCritSectEnter(&window->CompositorLock);
+ if (RT_SUCCESS(rc))
+ {
+ const VBOXVR_SCR_COMPOSITOR * pCompositor = window->pCompositor;
+ if (pCompositor)
+ {
+ Assert(!CrVrScrCompositorIsEmpty(window->pCompositor));
+ return pCompositor;
+ }
+
+ /* if no compositor is set, release the lock and return */
+ RTCritSectLeave(&window->CompositorLock);
+ }
+ else
+ {
+ crWarning("RTCritSectEnter failed rc %d", rc);
+ }
+ return NULL;
+}
+
+int renderspuVBoxCompositorLock(WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR **ppCompositor)
+{
+ int rc = RTCritSectEnter(&window->CompositorLock);
+ if (RT_SUCCESS(rc))
+ {
+ if (ppCompositor)
+ *ppCompositor = window->pCompositor;
+ }
+ else
+ WARN(("RTCritSectEnter failed %d", rc));
+ return rc;
+}
+
+int renderspuVBoxCompositorUnlock(WindowInfo *window)
+{
+ int rc = RTCritSectLeave(&window->CompositorLock);
+ AssertRC(rc);
+ return rc;
+}
+
+int renderspuVBoxCompositorTryAcquire(WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR **ppCompositor)
+{
+ int rc = RTCritSectTryEnter(&window->CompositorLock);
+ if (RT_SUCCESS(rc))
+ {
+ *ppCompositor = window->pCompositor;
+ if (*ppCompositor)
+ {
+ Assert(!CrVrScrCompositorIsEmpty(window->pCompositor));
+ return VINF_SUCCESS;
+ }
+
+ /* if no compositor is set, release the lock and return */
+ RTCritSectLeave(&window->CompositorLock);
+ rc = VERR_INVALID_STATE;
+ }
+ else
+ {
+ *ppCompositor = NULL;
+ }
+ return rc;
+}
+
+void renderspuVBoxCompositorRelease( WindowInfo *window)
+{
+ int rc;
+ Assert(window->pCompositor);
+ Assert(!CrVrScrCompositorIsEmpty(window->pCompositor));
+ rc = RTCritSectLeave(&window->CompositorLock);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("RTCritSectLeave failed rc %d", rc);
+ }
+}
+
+
+/*
+ * Set the current raster position to the given window coordinate.
+ */
+static void
+SetRasterPos( GLint winX, GLint winY )
+{
+ GLfloat fx, fy;
+
+ /* Push current matrix mode and viewport attributes */
+ render_spu.self.PushAttrib( GL_TRANSFORM_BIT | GL_VIEWPORT_BIT );
+
+ /* Setup projection parameters */
+ render_spu.self.MatrixMode( GL_PROJECTION );
+ render_spu.self.PushMatrix();
+ render_spu.self.LoadIdentity();
+ render_spu.self.MatrixMode( GL_MODELVIEW );
+ render_spu.self.PushMatrix();
+ render_spu.self.LoadIdentity();
+
+ render_spu.self.Viewport( winX - 1, winY - 1, 2, 2 );
+
+ /* set the raster (window) position */
+ /* huh ? */
+ fx = (GLfloat) (winX - (int) winX);
+ fy = (GLfloat) (winY - (int) winY);
+ render_spu.self.RasterPos4f( fx, fy, 0.0, 1.0 );
+
+ /* restore matrices, viewport and matrix mode */
+ render_spu.self.PopMatrix();
+ render_spu.self.MatrixMode( GL_PROJECTION );
+ render_spu.self.PopMatrix();
+
+ render_spu.self.PopAttrib();
+}
+
+
+/*
+ * Draw the mouse pointer bitmap at (x,y) in window coords.
+ */
+static void DrawCursor( GLint x, GLint y )
+{
+#define POINTER_WIDTH 32
+#define POINTER_HEIGHT 32
+ /* Somebody artistic could probably do better here */
+ static const char *pointerImage[POINTER_HEIGHT] =
+ {
+ "XX..............................",
+ "XXXX............................",
+ ".XXXXX..........................",
+ ".XXXXXXX........................",
+ "..XXXXXXXX......................",
+ "..XXXXXXXXXX....................",
+ "...XXXXXXXXXXX..................",
+ "...XXXXXXXXXXXXX................",
+ "....XXXXXXXXXXXXXX..............",
+ "....XXXXXXXXXXXXXXXX............",
+ ".....XXXXXXXXXXXXXXXXX..........",
+ ".....XXXXXXXXXXXXXXXXXXX........",
+ "......XXXXXXXXXXXXXXXXXXXX......",
+ "......XXXXXXXXXXXXXXXXXXXXXX....",
+ ".......XXXXXXXXXXXXXXXXXXXXXXX..",
+ ".......XXXXXXXXXXXXXXXXXXXXXXXX.",
+ "........XXXXXXXXXXXXX...........",
+ "........XXXXXXXX.XXXXX..........",
+ ".........XXXXXX...XXXXX.........",
+ ".........XXXXX.....XXXXX........",
+ "..........XXX.......XXXXX.......",
+ "..........XX.........XXXXX......",
+ "......................XXXXX.....",
+ ".......................XXXXX....",
+ "........................XXX.....",
+ ".........................X......",
+ "................................",
+ "................................",
+ "................................",
+ "................................",
+ "................................",
+ "................................"
+
+ };
+ static GLubyte pointerBitmap[POINTER_HEIGHT][POINTER_WIDTH / 8];
+ static GLboolean firstCall = GL_TRUE;
+ GLboolean lighting, depthTest, scissorTest;
+
+ if (firstCall) {
+ /* Convert pointerImage into pointerBitmap */
+ GLint i, j;
+ for (i = 0; i < POINTER_HEIGHT; i++) {
+ for (j = 0; j < POINTER_WIDTH; j++) {
+ if (pointerImage[POINTER_HEIGHT - i - 1][j] == 'X') {
+ GLubyte bit = 128 >> (j & 0x7);
+ pointerBitmap[i][j / 8] |= bit;
+ }
+ }
+ }
+ firstCall = GL_FALSE;
+ }
+
+ render_spu.self.GetBooleanv(GL_LIGHTING, &lighting);
+ render_spu.self.GetBooleanv(GL_DEPTH_TEST, &depthTest);
+ render_spu.self.GetBooleanv(GL_SCISSOR_TEST, &scissorTest);
+ render_spu.self.Disable(GL_LIGHTING);
+ render_spu.self.Disable(GL_DEPTH_TEST);
+ render_spu.self.Disable(GL_SCISSOR_TEST);
+ render_spu.self.PixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+ render_spu.self.Color3f(1, 1, 1);
+
+ /* save current raster pos */
+ render_spu.self.PushAttrib(GL_CURRENT_BIT);
+ SetRasterPos(x, y);
+ render_spu.self.Bitmap(POINTER_WIDTH, POINTER_HEIGHT, 1.0, 31.0, 0, 0,
+ (const GLubyte *) pointerBitmap);
+ /* restore current raster pos */
+ render_spu.self.PopAttrib();
+
+ if (lighting)
+ render_spu.self.Enable(GL_LIGHTING);
+ if (depthTest)
+ render_spu.self.Enable(GL_DEPTH_TEST);
+ if (scissorTest)
+ render_spu.self.Enable(GL_SCISSOR_TEST);
+}
+
+void RENDER_APIENTRY renderspuSwapBuffers( GLint window, GLint flags )
+{
+ WindowInfo *w = (WindowInfo *) crHashtableSearch(render_spu.windowTable, window);
+
+ if (!w)
+ {
+ crDebug("Render SPU: SwapBuffers invalid window id: %d", window);
+ return;
+ }
+
+ if (flags & CR_SUPPRESS_SWAP_BIT)
+ {
+ render_spu.self.Finish();
+ return;
+ }
+
+ if (render_spu.drawCursor)
+ DrawCursor( render_spu.cursorX, render_spu.cursorY );
+
+ if (render_spu.swap_master_url)
+ DoSync();
+
+ renderspu_SystemSwapBuffers( w, flags );
+}
+
+
+/*
+ * Barrier functions
+ * Normally, we'll have a crserver somewhere that handles the barrier calls.
+ * However, if we're running the render SPU on the client node, then we
+ * should handle barriers here. The threadtest demo illustrates this.
+ * If we have N threads calling using this SPU we need these barrier
+ * functions to synchronize them.
+ */
+
+static void RENDER_APIENTRY renderspuBarrierCreateCR( GLuint name, GLuint count )
+{
+ Barrier *b;
+
+ if (render_spu.ignore_papi)
+ return;
+
+ b = (Barrier *) crHashtableSearch( render_spu.barrierHash, name );
+ if (b) {
+ /* HACK -- this allows everybody to create a barrier, and all
+ but the first creation are ignored, assuming the count
+ match. */
+ if ( b->count != count ) {
+ crError( "Render SPU: Barrier name=%u created with count=%u, but already "
+ "exists with count=%u", name, count, b->count );
+ }
+ }
+ else {
+ b = (Barrier *) crAlloc( sizeof(Barrier) );
+ b->count = count;
+ crInitBarrier( &b->barrier, count );
+ crHashtableAdd( render_spu.barrierHash, name, b );
+ }
+}
+
+static void RENDER_APIENTRY renderspuBarrierDestroyCR( GLuint name )
+{
+ if (render_spu.ignore_papi)
+ return;
+ crHashtableDelete( render_spu.barrierHash, name, crFree );
+}
+
+static void RENDER_APIENTRY renderspuBarrierExecCR( GLuint name )
+{
+ Barrier *b;
+
+ if (render_spu.ignore_papi)
+ return;
+
+ b = (Barrier *) crHashtableSearch( render_spu.barrierHash, name );
+ if (b) {
+ crWaitBarrier( &(b->barrier) );
+ }
+ else {
+ crWarning("Render SPU: Bad barrier name %d in BarrierExec()", name);
+ }
+}
+
+
+/*
+ * Semaphore functions
+ * XXX we should probably implement these too, for the same reason as
+ * barriers (see above).
+ */
+
+static void RENDER_APIENTRY renderspuSemaphoreCreateCR( GLuint name, GLuint count )
+{
+ (void) name;
+ (void) count;
+}
+
+static void RENDER_APIENTRY renderspuSemaphoreDestroyCR( GLuint name )
+{
+ (void) name;
+}
+
+static void RENDER_APIENTRY renderspuSemaphorePCR( GLuint name )
+{
+ (void) name;
+}
+
+static void RENDER_APIENTRY renderspuSemaphoreVCR( GLuint name )
+{
+ (void) name;
+}
+
+
+/*
+ * Misc functions
+ */
+void renderspuSetDefaultSharedContext(ContextInfo *pCtx)
+{
+ if (pCtx == render_spu.defaultSharedContext)
+ return;
+
+ renderspu_SystemDefaultSharedContextChanged(render_spu.defaultSharedContext, pCtx);
+
+ if (render_spu.defaultSharedContext)
+ renderspuContextRelease(render_spu.defaultSharedContext);
+
+ if (pCtx)
+ renderspuContextRetain(pCtx);
+ render_spu.defaultSharedContext = pCtx;
+}
+
+static void RENDER_APIENTRY renderspuChromiumParameteriCR(GLenum target, GLint value)
+{
+ switch (target)
+ {
+ case GL_HH_SET_DEFAULT_SHARED_CTX:
+ {
+ ContextInfo * pCtx = NULL;
+ if (value)
+ pCtx = (ContextInfo *)crHashtableSearch(render_spu.contextTable, value);
+ else
+ crWarning("invalid default shared context id %d", value);
+
+ renderspuSetDefaultSharedContext(pCtx);
+ break;
+ }
+ case GL_HH_RENDERTHREAD_INFORM:
+ {
+ if (value)
+ {
+ int rc = renderspuDefaultCtxInit();
+ if (RT_FAILURE(rc))
+ {
+ WARN(("renderspuDefaultCtxInit failed"));
+ break;
+ }
+ }
+ else
+ {
+ renderspuCleanupBase(false);
+ }
+ break;
+ }
+ default:
+// crWarning("Unhandled target in renderspuChromiumParameteriCR()");
+ break;
+ }
+}
+
+static void RENDER_APIENTRY
+renderspuChromiumParameterfCR(GLenum target, GLfloat value)
+{
+ (void) target;
+ (void) value;
+
+#if 0
+ switch (target) {
+ default:
+ crWarning("Unhandled target in renderspuChromiumParameterfCR()");
+ break;
+ }
+#endif
+}
+
+bool renderspuCalloutAvailable()
+{
+ return render_spu.pfnClientCallout != NULL;
+}
+
+bool renderspuCalloutClient(PFNVCRSERVER_CLIENT_CALLOUT_CB pfnCb, void *pvCb)
+{
+ if (render_spu.pfnClientCallout)
+ {
+ render_spu.pfnClientCallout(pfnCb, pvCb);
+ return true;
+ }
+ return false;
+}
+
+static void RENDER_APIENTRY
+renderspuChromiumParametervCR(GLenum target, GLenum type, GLsizei count,
+ const GLvoid *values)
+{
+ int client_num;
+ unsigned short port;
+ CRMessage *msg, pingback;
+ unsigned char *privbuf = NULL;
+
+ switch (target) {
+ case GL_HH_SET_CLIENT_CALLOUT:
+ render_spu.pfnClientCallout = (PFNVCRSERVER_CLIENT_CALLOUT)values;
+ break;
+ case GL_GATHER_CONNECT_CR:
+ if (render_spu.gather_userbuf_size)
+ privbuf = (unsigned char *)crAlloc(1024*768*4);
+
+ port = ((GLint *) values)[0];
+
+ if (render_spu.gather_conns == NULL)
+ render_spu.gather_conns = crAlloc(render_spu.server->numClients*sizeof(CRConnection *));
+ else
+ {
+ crError("Oh bother! duplicate GL_GATHER_CONNECT_CR getting through");
+ }
+
+ for (client_num=0; client_num< render_spu.server->numClients; client_num++)
+ {
+ switch (render_spu.server->clients[client_num]->conn->type)
+ {
+ case CR_TCPIP:
+ crDebug("Render SPU: AcceptClient from %s on %d",
+ render_spu.server->clients[client_num]->conn->hostname, render_spu.gather_port);
+ render_spu.gather_conns[client_num] =
+ crNetAcceptClient("tcpip", NULL, port, 1024*1024, 1);
+ break;
+
+ case CR_GM:
+ render_spu.gather_conns[client_num] =
+ crNetAcceptClient("gm", NULL, port, 1024*1024, 1);
+ break;
+
+ default:
+ crError("Render SPU: Unknown Network Type to Open Gather Connection");
+ }
+
+
+ if (render_spu.gather_userbuf_size)
+ {
+ render_spu.gather_conns[client_num]->userbuf = privbuf;
+ render_spu.gather_conns[client_num]->userbuf_len = render_spu.gather_userbuf_size;
+ }
+ else
+ {
+ render_spu.gather_conns[client_num]->userbuf = NULL;
+ render_spu.gather_conns[client_num]->userbuf_len = 0;
+ }
+
+ if (render_spu.gather_conns[client_num])
+ {
+ crDebug("Render SPU: success! from %s", render_spu.gather_conns[client_num]->hostname);
+ }
+ }
+
+ break;
+
+ case GL_GATHER_DRAWPIXELS_CR:
+ pingback.header.type = CR_MESSAGE_OOB;
+
+ for (client_num=0; client_num< render_spu.server->numClients; client_num++)
+ {
+ crNetGetMessage(render_spu.gather_conns[client_num], &msg);
+ if (msg->header.type == CR_MESSAGE_GATHER)
+ {
+ crNetFree(render_spu.gather_conns[client_num], msg);
+ }
+ else
+ {
+ crError("Render SPU: expecting MESSAGE_GATHER. got crap! (%d of %d)",
+ client_num, render_spu.server->numClients-1);
+ }
+ }
+
+ /*
+ * We're only hitting the case if we're not actually calling
+ * child.SwapBuffers from readback, so a switch about which
+ * call to DoSync() we really want [this one, or the one
+ * in SwapBuffers above] is not necessary -- karl
+ */
+
+ if (render_spu.swap_master_url)
+ DoSync();
+
+ for (client_num=0; client_num< render_spu.server->numClients; client_num++)
+ crNetSend(render_spu.gather_conns[client_num], NULL, &pingback,
+ sizeof(CRMessageHeader));
+
+ render_spu.self.RasterPos2i(((GLint *)values)[0], ((GLint *)values)[1]);
+ render_spu.self.DrawPixels( ((GLint *)values)[2], ((GLint *)values)[3],
+ ((GLint *)values)[4], ((GLint *)values)[5],
+ render_spu.gather_conns[0]->userbuf);
+
+
+ render_spu.self.SwapBuffers(((GLint *)values)[6], 0);
+ break;
+
+ case GL_CURSOR_POSITION_CR:
+ if (type == GL_INT && count == 2) {
+ render_spu.cursorX = ((GLint *) values)[0];
+ render_spu.cursorY = ((GLint *) values)[1];
+ crDebug("Render SPU: GL_CURSOR_POSITION_CR (%d, %d)", render_spu.cursorX, render_spu.cursorY);
+ }
+ else {
+ crWarning("Render SPU: Bad type or count for ChromiumParametervCR(GL_CURSOR_POSITION_CR)");
+ }
+ break;
+
+ case GL_WINDOW_SIZE_CR:
+ /* XXX this is old code that should be removed.
+ * NOTE: we can only resize the default (id=CR_RENDER_DEFAULT_WINDOW_ID) window!!!
+ */
+ {
+ GLint w, h;
+ WindowInfo *window;
+ CRASSERT(type == GL_INT);
+ CRASSERT(count == 2);
+ CRASSERT(values);
+ w = ((GLint*)values)[0];
+ h = ((GLint*)values)[1];
+ window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, CR_RENDER_DEFAULT_WINDOW_ID);
+ if (window)
+ {
+ renderspu_SystemWindowSize(window, w, h);
+ }
+ }
+ break;
+
+ case GL_HH_SET_TMPCTX_MAKE_CURRENT:
+ if (type == GL_BYTE && count == sizeof (void*))
+ memcpy(&render_spu.blitterDispatch.MakeCurrent, values, count);
+ else
+ WARN(("unexpected type(%#x) - count(%d) pair", type, count));
+ break;
+
+ default:
+#if 0
+ WARN(("Unhandled target in renderspuChromiumParametervCR(0x%x)", (int) target));
+#endif
+ break;
+ }
+}
+
+
+static void RENDER_APIENTRY
+renderspuGetChromiumParametervCR(GLenum target, GLuint index, GLenum type,
+ GLsizei count, GLvoid *values)
+{
+ switch (target) {
+ case GL_WINDOW_SIZE_CR:
+ {
+ GLint x, y, w, h, *size = (GLint *) values;
+ WindowInfo *window;
+ CRASSERT(type == GL_INT);
+ CRASSERT(count == 2);
+ CRASSERT(values);
+ size[0] = size[1] = 0; /* default */
+ window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, index);
+ if (window)
+ {
+ renderspu_SystemGetWindowGeometry(window, &x, &y, &w, &h);
+ size[0] = w;
+ size[1] = h;
+ }
+ }
+ break;
+ case GL_WINDOW_POSITION_CR:
+ /* return window position, as a screen coordinate */
+ {
+ GLint *pos = (GLint *) values;
+ GLint x, y, w, h;
+ WindowInfo *window;
+ CRASSERT(type == GL_INT);
+ CRASSERT(count == 2);
+ CRASSERT(values);
+ pos[0] = pos[1] = 0; /* default */
+ window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, index);
+ if (window)
+ {
+ renderspu_SystemGetWindowGeometry(window, &x, &y, &w, &h);
+ pos[0] = x;/*window->x;*/
+ pos[1] = y;/*window->y;*/
+ }
+ }
+ break;
+ case GL_MAX_WINDOW_SIZE_CR:
+ {
+ GLint *maxSize = (GLint *) values;
+ WindowInfo *window;
+ CRASSERT(type == GL_INT);
+ CRASSERT(count == 2);
+ CRASSERT(values);
+ window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, index);
+ if (window)
+ {
+ renderspu_SystemGetMaxWindowSize(window, maxSize + 0, maxSize + 1);
+ }
+ }
+ break;
+ case GL_WINDOW_VISIBILITY_CR:
+ {
+ GLint *vis = (GLint *) values;
+ WindowInfo *window;
+ CRASSERT(type == GL_INT);
+ CRASSERT(count == 1);
+ CRASSERT(values);
+ vis[0] = 0; /* default */
+ window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, index);
+ if (window)
+ {
+ vis[0] = window->visible;
+ }
+ }
+ break;
+ default:
+ ; /* nothing - silence compiler */
+ }
+}
+
+
+static void RENDER_APIENTRY
+renderspuBoundsInfoCR( CRrecti *bounds, GLbyte *payload, GLint len,
+ GLint num_opcodes )
+{
+ (void) bounds;
+ (void) payload;
+ (void) len;
+ (void) num_opcodes;
+ /* draw the bounding box */
+ if (render_spu.draw_bbox) {
+ GET_CONTEXT(context);
+ WindowInfo *window = context->currentWindow;
+ GLint x, y, w, h;
+
+ renderspu_SystemGetWindowGeometry(window, &x, &y, &w, &h);
+
+ render_spu.self.PushMatrix();
+ render_spu.self.LoadIdentity();
+ render_spu.self.MatrixMode(GL_PROJECTION);
+ render_spu.self.PushMatrix();
+ render_spu.self.LoadIdentity();
+ render_spu.self.Ortho(0, w, 0, h, -1, 1);
+ render_spu.self.Color3f(1, 1, 1);
+ render_spu.self.Begin(GL_LINE_LOOP);
+ render_spu.self.Vertex2i(bounds->x1, bounds->y1);
+ render_spu.self.Vertex2i(bounds->x2, bounds->y1);
+ render_spu.self.Vertex2i(bounds->x2, bounds->y2);
+ render_spu.self.Vertex2i(bounds->x1, bounds->y2);
+ render_spu.self.End();
+ render_spu.self.PopMatrix();
+ render_spu.self.MatrixMode(GL_MODELVIEW);
+ render_spu.self.PopMatrix();
+ }
+}
+
+
+static void RENDER_APIENTRY
+renderspuWriteback( GLint *writeback )
+{
+ (void) writeback;
+}
+
+
+static void
+remove_trailing_space(char *s)
+{
+ int k = crStrlen(s);
+ while (k > 0 && s[k-1] == ' ')
+ k--;
+ s[k] = 0;
+}
+
+static const GLubyte * RENDER_APIENTRY
+renderspuGetString(GLenum pname)
+{
+ static char tempStr[1000];
+ GET_CONTEXT(context);
+
+ if (pname == GL_EXTENSIONS)
+ {
+ const char *nativeExt;
+ char *crExt, *s1, *s2;
+
+ if (!render_spu.ws.glGetString)
+ return NULL;
+
+ nativeExt = (const char *) render_spu.ws.glGetString(GL_EXTENSIONS);
+ if (!nativeExt) {
+ /* maybe called w/out current context. */
+ return NULL;
+ }
+
+ if (!context)
+ return (const GLubyte *)nativeExt;
+
+ crExt = crStrjoin3(crExtensions, " ", crAppOnlyExtensions);
+ s1 = crStrIntersect(nativeExt, crExt);
+ remove_trailing_space(s1);
+ s2 = crStrjoin3(s1, " ", crChromiumExtensions);
+ remove_trailing_space(s2);
+ crFree(crExt);
+ crFree(s1);
+ if (context->extensionString)
+ crFree(context->extensionString);
+ context->extensionString = s2;
+ return (const GLubyte *) s2;
+ }
+ else if (pname == GL_VENDOR)
+ return (const GLubyte *) CR_VENDOR;
+ else if (pname == GL_VERSION)
+ return render_spu.ws.glGetString(GL_VERSION);
+ else if (pname == GL_RENDERER) {
+#ifdef VBOX
+ snprintf(tempStr, sizeof(tempStr), "Chromium (%s)", (char *) render_spu.ws.glGetString(GL_RENDERER));
+#else
+ sprintf(tempStr, "Chromium (%s)", (char *) render_spu.ws.glGetString(GL_RENDERER));
+#endif
+ return (const GLubyte *) tempStr;
+ }
+#ifdef CR_OPENGL_VERSION_2_0
+ else if (pname == GL_SHADING_LANGUAGE_VERSION)
+ return render_spu.ws.glGetString(GL_SHADING_LANGUAGE_VERSION);
+#endif
+#ifdef GL_CR_real_vendor_strings
+ else if (pname == GL_REAL_VENDOR)
+ return render_spu.ws.glGetString(GL_VENDOR);
+ else if (pname == GL_REAL_VERSION)
+ return render_spu.ws.glGetString(GL_VERSION);
+ else if (pname == GL_REAL_RENDERER)
+ return render_spu.ws.glGetString(GL_RENDERER);
+ else if (pname == GL_REAL_EXTENSIONS)
+ return render_spu.ws.glGetString(GL_EXTENSIONS);
+#endif
+ else
+ return NULL;
+}
+
+static void renderspuReparentWindowCB(unsigned long key, void *data1, void *data2)
+{
+ WindowInfo *pWindow = (WindowInfo *)data1;
+
+ renderspu_SystemReparentWindow(pWindow);
+}
+
+DECLEXPORT(void) renderspuReparentWindow(GLint window)
+{
+ WindowInfo *pWindow;
+ CRASSERT(window >= 0);
+
+ pWindow = (WindowInfo *) crHashtableSearch(render_spu.windowTable, window);
+
+ if (!pWindow)
+ {
+ crDebug("Render SPU: Attempt to reparent invalid window (%d)", window);
+ return;
+ }
+
+ renderspu_SystemReparentWindow(pWindow);
+
+ /* special case: reparent all internal windows as well */
+ if (window == CR_RENDER_DEFAULT_WINDOW_ID)
+ {
+ crHashtableWalk(render_spu.dummyWindowTable, renderspuReparentWindowCB, NULL);
+ }
+}
+
+DECLEXPORT(void) renderspuSetUnscaledHiDPI(bool fEnable)
+{
+ render_spu.fUnscaledHiDPI = fEnable;
+}
+
+#define FILLIN( NAME, FUNC ) \
+ table[i].name = crStrdup(NAME); \
+ table[i].fn = (SPUGenericFunction) FUNC; \
+ i++;
+
+
+/* These are the functions which the render SPU implements, not OpenGL.
+ */
+int
+renderspuCreateFunctions(SPUNamedFunctionTable table[])
+{
+ int i = 0;
+ FILLIN( "SwapBuffers", renderspuSwapBuffers );
+ FILLIN( "CreateContext", renderspuCreateContext );
+ FILLIN( "DestroyContext", renderspuDestroyContext );
+ FILLIN( "MakeCurrent", renderspuMakeCurrent );
+ FILLIN( "WindowCreate", renderspuWindowCreate );
+ FILLIN( "WindowDestroy", renderspuWindowDestroy );
+ FILLIN( "WindowSize", renderspuWindowSize );
+ FILLIN( "WindowPosition", renderspuWindowPosition );
+ FILLIN( "WindowVisibleRegion", renderspuWindowVisibleRegion );
+ FILLIN( "WindowShow", renderspuWindowShow );
+ FILLIN( "BarrierCreateCR", renderspuBarrierCreateCR );
+ FILLIN( "BarrierDestroyCR", renderspuBarrierDestroyCR );
+ FILLIN( "BarrierExecCR", renderspuBarrierExecCR );
+ FILLIN( "BoundsInfoCR", renderspuBoundsInfoCR );
+ FILLIN( "SemaphoreCreateCR", renderspuSemaphoreCreateCR );
+ FILLIN( "SemaphoreDestroyCR", renderspuSemaphoreDestroyCR );
+ FILLIN( "SemaphorePCR", renderspuSemaphorePCR );
+ FILLIN( "SemaphoreVCR", renderspuSemaphoreVCR );
+ FILLIN( "Writeback", renderspuWriteback );
+ FILLIN( "ChromiumParameteriCR", renderspuChromiumParameteriCR );
+ FILLIN( "ChromiumParameterfCR", renderspuChromiumParameterfCR );
+ FILLIN( "ChromiumParametervCR", renderspuChromiumParametervCR );
+ FILLIN( "GetChromiumParametervCR", renderspuGetChromiumParametervCR );
+ FILLIN( "GetString", renderspuGetString );
+ FILLIN( "VBoxPresentComposition", renderspuVBoxPresentComposition );
+ return i;
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/render/renderspu.h b/src/VBox/HostServices/SharedOpenGL/render/renderspu.h
new file mode 100644
index 00000000..dfd591e8
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/render/renderspu.h
@@ -0,0 +1,506 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved.
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#ifndef CR_RENDERSPU_H
+#define CR_RENDERSPU_H
+
+#ifdef WINDOWS
+#define WIN32_LEAN_AND_MEAN
+#include <iprt/win/windows.h>
+#define RENDER_APIENTRY __stdcall
+#define snprintf _snprintf
+#elif defined(DARWIN)
+# ifndef VBOX_WITH_COCOA_QT
+# include <AGL/AGL.h>
+# else
+# include "renderspu_cocoa_helper.h"
+# endif
+#define RENDER_APIENTRY
+#else
+#include <GL/glx.h>
+#define RENDER_APIENTRY
+#endif
+#include "cr_threads.h"
+#include "cr_spu.h"
+#include "cr_hash.h"
+#include "cr_server.h"
+#include "cr_blitter.h"
+#include "cr_compositor.h"
+
+#include <iprt/cdefs.h>
+#include <iprt/critsect.h>
+#if defined(GLX) /* @todo: unify windows and glx thread creation code */
+#include <iprt/thread.h>
+#include <iprt/semaphore.h>
+
+/* special window id used for representing the command window CRWindowInfo */
+#define CR_RENDER_WINCMD_ID (INT32_MAX-2)
+AssertCompile(CR_RENDER_WINCMD_ID != CR_RENDER_DEFAULT_WINDOW_ID);
+/* CRHashTable is using unsigned long keys, we use it to trore X Window -> CRWindowInfo association */
+AssertCompile(sizeof (Window) == sizeof (unsigned long));
+#endif
+
+
+#define MAX_VISUALS 32
+
+#ifdef RT_OS_DARWIN
+# ifndef VBOX_WITH_COCOA_QT
+enum
+{
+ /* Event classes */
+ kEventClassVBox = 'vbox',
+ /* Event kinds */
+ kEventVBoxShowWindow = 'swin',
+ kEventVBoxHideWindow = 'hwin',
+ kEventVBoxMoveWindow = 'mwin',
+ kEventVBoxResizeWindow = 'rwin',
+ kEventVBoxDisposeWindow = 'dwin',
+ kEventVBoxUpdateDock = 'udck',
+ kEventVBoxUpdateContext = 'uctx',
+ kEventVBoxBoundsChanged = 'bchg'
+};
+pascal OSStatus windowEvtHndlr(EventHandlerCallRef myHandler, EventRef event, void* userData);
+# endif
+#endif /* RT_OS_DARWIN */
+
+/**
+ * Visual info
+ */
+typedef struct {
+ GLbitfield visAttribs;
+ const char *displayName;
+#if defined(WINDOWS)
+// HDC device_context;
+#elif defined(DARWIN)
+# ifndef VBOX_WITH_COCOA_QT
+ WindowRef window;
+# endif
+#elif defined(GLX)
+ Display *dpy;
+ XVisualInfo *visual;
+#ifdef GLX_VERSION_1_3
+ GLXFBConfig fbconfig;
+#endif /* GLX_VERSION_1_3 */
+#endif
+} VisualInfo;
+
+/**
+ * Window info
+ */
+typedef struct WindowInfo {
+ int x, y;
+// int width, height;
+// int id; /**< integer window ID */
+ CR_BLITTER_WINDOW BltInfo;
+
+ VisualInfo *visual;
+
+ volatile uint32_t cRefs;
+
+ GLboolean mapPending;
+ GLboolean visible;
+ GLboolean everCurrent; /**< has this window ever been bound? */
+ char *title;
+
+ const VBOXVR_SCR_COMPOSITOR *pCompositor;
+ /* the composotor lock is used to synchronize the current compositor access,
+ * i.e. the compositor can be accessed by a gui refraw thread,
+ * while chromium thread might try to set a new compositor
+ * note that the compositor internally has its own lock to be used for accessing its data
+ * see CrVrScrCompositorLock/Unlock; renderspu and crserverlib would use it for compositor data access */
+ RTCRITSECT CompositorLock;
+ PCR_BLITTER pBlitter;
+#if defined(WINDOWS)
+ HDC nativeWindow; /**< for render_to_app_window */
+ HWND hWnd;
+ HDC device_context;
+ HDC redraw_device_context;
+ HRGN hRgn;
+#elif defined(DARWIN)
+# ifndef VBOX_WITH_COCOA_QT
+ WindowRef window;
+ WindowRef nativeWindow; /**< for render_to_app_window */
+ WindowRef appWindow;
+ EventHandlerUPP event_handler;
+ GLint bufferName;
+ AGLContext dummyContext;
+ RgnHandle hVisibleRegion;
+ /* unsigned long context_ptr; */
+# else
+ NativeNSViewRef window;
+ NativeNSViewRef nativeWindow; /**< for render_to_app_window */
+ NativeNSOpenGLContextRef *currentCtx;
+# endif
+#elif defined(GLX)
+ Window window;
+ Window nativeWindow; /**< for render_to_app_window */
+ Window appWindow; /**< Same as nativeWindow but for garbage collections purposes */
+#endif
+ int nvSwapGroup;
+
+#ifdef USE_OSMESA
+ GLubyte *buffer; /**< for rendering to off screen buffer. */
+ int in_buffer_width;
+ int in_buffer_height;
+#endif
+
+} WindowInfo;
+
+/**
+ * Context Info
+ */
+typedef struct _ContextInfo {
+// int id; /**< integer context ID */
+ CR_BLITTER_CONTEXT BltInfo;
+ VisualInfo *visual;
+ GLboolean everCurrent;
+ GLboolean haveWindowPosARB;
+ WindowInfo *currentWindow;
+#if defined(WINDOWS)
+ HGLRC hRC;
+#elif defined(DARWIN)
+# ifndef VBOX_WITH_COCOA_QT
+ AGLContext context;
+# else
+ NativeNSOpenGLContextRef context;
+# endif
+#elif defined(GLX)
+ GLXContext context;
+#endif
+ struct _ContextInfo *shared;
+ char *extensionString;
+ volatile uint32_t cRefs;
+} ContextInfo;
+
+/**
+ * Barrier info
+ */
+typedef struct {
+ CRbarrier barrier;
+ GLuint count;
+} Barrier;
+
+#ifdef GLX
+typedef enum
+{
+ CR_RENDER_WINCMD_TYPE_UNDEFINED = 0,
+ /* create the window (not used for now) */
+ CR_RENDER_WINCMD_TYPE_WIN_CREATE,
+ /* destroy the window (not used for now) */
+ CR_RENDER_WINCMD_TYPE_WIN_DESTROY,
+ /* notify the WinCmd thread about window creation */
+ CR_RENDER_WINCMD_TYPE_WIN_ON_CREATE,
+ /* notify the WinCmd thread about window destroy */
+ CR_RENDER_WINCMD_TYPE_WIN_ON_DESTROY,
+ /* nop used to synchronize with the WinCmd thread */
+ CR_RENDER_WINCMD_TYPE_NOP,
+ /* exit Win Cmd thread */
+ CR_RENDER_WINCMD_TYPE_EXIT,
+} CR_RENDER_WINCMD_TYPE;
+
+typedef struct CR_RENDER_WINCMD
+{
+ /* command type */
+ CR_RENDER_WINCMD_TYPE enmCmd;
+ /* command result */
+ int rc;
+ /* valid for WIN_CREATE & WIN_DESTROY only */
+ WindowInfo *pWindow;
+} CR_RENDER_WINCMD, *PCR_RENDER_WINCMD;
+#endif
+
+#ifdef RT_OS_DARWIN
+typedef void (*PFNDELETE_OBJECT)(GLhandleARB obj);
+typedef void (*PFNGET_ATTACHED_OBJECTS)( GLhandleARB containerObj, GLsizei maxCount, GLsizei * count, GLhandleARB * obj );
+typedef GLhandleARB (*PFNGET_HANDLE)(GLenum pname);
+typedef void (*PFNGET_INFO_LOG)( GLhandleARB obj, GLsizei maxLength, GLsizei * length, GLcharARB * infoLog );
+typedef void (*PFNGET_OBJECT_PARAMETERFV)( GLhandleARB obj, GLenum pname, GLfloat * params );
+typedef void (*PFNGET_OBJECT_PARAMETERIV)( GLhandleARB obj, GLenum pname, GLint * params );
+#endif
+
+typedef DECLCALLBACKPTR(void, PFNVCRSERVER_CLIENT_CALLOUT_CB)(void *pvCb);
+typedef DECLCALLBACKPTR(void, PFNVCRSERVER_CLIENT_CALLOUT)(PFNVCRSERVER_CLIENT_CALLOUT_CB pfnCb, void*pvCb);
+
+
+/**
+ * Renderspu state info
+ */
+typedef struct {
+ SPUDispatchTable self;
+ int id;
+
+ /** config options */
+ /*@{*/
+ char *window_title;
+ int defaultX, defaultY;
+ unsigned int defaultWidth, defaultHeight;
+ int default_visual;
+ int use_L2;
+ int fullscreen, ontop;
+ char display_string[100];
+#if defined(GLX)
+ int try_direct;
+ int force_direct;
+ int sync;
+#endif
+ int force_present_main_thread;
+ int render_to_app_window;
+ int render_to_crut_window;
+ int crut_drawable;
+ int resizable;
+ int use_lut8, lut8[3][256];
+ int borderless;
+ int nvSwapGroup;
+ int ignore_papi;
+ int ignore_window_moves;
+ int pbufferWidth, pbufferHeight;
+ int use_glxchoosevisual;
+ int draw_bbox;
+ /*@}*/
+
+ CRServer *server;
+ int gather_port;
+ int gather_userbuf_size;
+ CRConnection **gather_conns;
+
+ GLint drawCursor;
+ GLint cursorX, cursorY;
+
+ int numVisuals;
+ VisualInfo visuals[MAX_VISUALS];
+
+ CRHashTable *windowTable;
+ CRHashTable *contextTable;
+
+ CRHashTable *dummyWindowTable;
+
+ ContextInfo *defaultSharedContext;
+
+#ifndef CHROMIUM_THREADSAFE
+ ContextInfo *currentContext;
+#endif
+
+ crOpenGLInterface ws; /**< Window System interface */
+
+ CRHashTable *barrierHash;
+
+ int is_swap_master, num_swap_clients;
+ int swap_mtu;
+ char *swap_master_url;
+ CRConnection **swap_conns;
+
+ SPUDispatchTable blitterDispatch;
+ CRHashTable *blitterTable;
+
+ PFNVCRSERVER_CLIENT_CALLOUT pfnClientCallout;
+
+#ifdef USE_OSMESA
+ /** Off screen rendering hooks. */
+ int use_osmesa;
+
+ OSMesaContext (*OSMesaCreateContext)( GLenum format, OSMesaContext sharelist );
+ GLboolean (* OSMesaMakeCurrent)( OSMesaContext ctx,
+ GLubyte *buffer,
+ GLenum type,
+ GLsizei width,
+ GLsizei height );
+ void (*OSMesaDestroyContext)( OSMesaContext ctx );
+#endif
+
+#if defined(GLX)
+ RTTHREAD hWinCmdThread;
+ VisualInfo WinCmdVisual;
+ WindowInfo WinCmdWindow;
+ RTSEMEVENT hWinCmdCompleteEvent;
+ /* display connection used to send data to the WinCmd thread */
+ Display *pCommunicationDisplay;
+ Atom WinCmdAtom;
+ /* X Window -> CRWindowInfo table */
+ CRHashTable *pWinToInfoTable;
+#endif
+
+#ifdef RT_OS_WINDOWS
+ DWORD dwWinThreadId;
+ HANDLE hWinThreadReadyEvent;
+#endif
+
+#ifdef RT_OS_DARWIN
+# ifdef VBOX_WITH_COCOA_QT
+ PFNDELETE_OBJECT pfnDeleteObject;
+ PFNGET_ATTACHED_OBJECTS pfnGetAttachedObjects;
+ PFNGET_HANDLE pfnGetHandle;
+ PFNGET_INFO_LOG pfnGetInfoLog;
+ PFNGET_OBJECT_PARAMETERFV pfnGetObjectParameterfv;
+ PFNGET_OBJECT_PARAMETERIV pfnGetObjectParameteriv;
+
+ CR_GLSL_CACHE GlobalShaders;
+# else
+ RgnHandle hRootVisibleRegion;
+ RTSEMFASTMUTEX syncMutex;
+ EventHandlerUPP hParentEventHandler;
+ WindowGroupRef pParentGroup;
+ WindowGroupRef pMasterGroup;
+ GLint currentBufferName;
+ uint64_t uiDockUpdateTS;
+ bool fInit;
+# endif
+#endif /* RT_OS_DARWIN */
+ /* If TRUE, render should tell window server to prevent artificial content
+ * up-scaling when displayed on HiDPI monitor. */
+ bool fUnscaledHiDPI;
+} RenderSPU;
+
+#ifdef RT_OS_WINDOWS
+
+/* Asks window thread to create new window.
+ msg.lParam - holds pointer to CREATESTRUCT structure
+ note that lpCreateParams is used to specify address to store handle of created window
+ msg.wParam - unused, should be NULL
+*/
+#define WM_VBOX_RENDERSPU_CREATE_WINDOW (WM_APP+1)
+
+typedef struct _VBOX_RENDERSPU_DESTROY_WINDOW {
+ HWND hWnd; /* handle to window to destroy */
+} VBOX_RENDERSPU_DESTROY_WINDOW;
+
+/* Asks window thread to destroy previously created window.
+ msg.lParam - holds pointer to RENDERSPU_VBOX_WINDOW_DESTROY structure
+ msg.wParam - unused, should be NULL
+*/
+#define WM_VBOX_RENDERSPU_DESTROY_WINDOW (WM_APP+2)
+
+#endif
+
+extern RenderSPU render_spu;
+
+/* @todo remove this hack */
+extern uint64_t render_spu_parent_window_id;
+
+#ifdef CHROMIUM_THREADSAFE
+extern CRtsd _RenderTSD;
+#define GET_CONTEXT_VAL() ((ContextInfo *) crGetTSD(&_RenderTSD))
+#define SET_CONTEXT_VAL(_v) do { \
+ crSetTSD(&_RenderTSD, (_v)); \
+ } while (0)
+#else
+#define GET_CONTEXT_VAL() (render_spu.currentContext)
+#define SET_CONTEXT_VAL(_v) do { \
+ render_spu.currentContext = (_v); \
+ } while (0)
+
+#endif
+
+#define GET_CONTEXT(T) ContextInfo *T = GET_CONTEXT_VAL()
+
+
+extern void renderspuSetDefaultSharedContext(ContextInfo *pCtx);
+extern void renderspuSetVBoxConfiguration( RenderSPU *spu );
+extern void renderspuMakeVisString( GLbitfield visAttribs, char *s );
+extern VisualInfo *renderspuFindVisual(const char *displayName, GLbitfield visAttribs );
+extern GLboolean renderspu_SystemInitVisual( VisualInfo *visual );
+extern GLboolean renderspu_SystemCreateContext( VisualInfo *visual, ContextInfo *context, ContextInfo *sharedContext );
+extern void renderspu_SystemDestroyContext( ContextInfo *context );
+extern GLboolean renderspu_SystemCreateWindow( VisualInfo *visual, GLboolean showIt, WindowInfo *window );
+extern GLboolean renderspu_SystemVBoxCreateWindow( VisualInfo *visual, GLboolean showIt, WindowInfo *window );
+extern void renderspu_SystemDestroyWindow( WindowInfo *window );
+extern void renderspu_SystemWindowSize( WindowInfo *window, GLint w, GLint h );
+extern void renderspu_SystemGetWindowGeometry( WindowInfo *window, GLint *x, GLint *y, GLint *w, GLint *h );
+extern void renderspu_SystemGetMaxWindowSize( WindowInfo *window, GLint *w, GLint *h );
+extern void renderspu_SystemWindowPosition( WindowInfo *window, GLint x, GLint y );
+extern void renderspu_SystemWindowVisibleRegion(WindowInfo *window, GLint cRects, const GLint* pRects);
+extern GLboolean renderspu_SystemWindowNeedEmptyPresent(WindowInfo *window);
+extern int renderspu_SystemInit();
+extern int renderspu_SystemTerm();
+extern void renderspu_SystemDefaultSharedContextChanged(ContextInfo *fromContext, ContextInfo *toContext);
+extern void renderspu_SystemShowWindow( WindowInfo *window, GLboolean showIt );
+extern void renderspu_SystemMakeCurrent( WindowInfo *window, GLint windowInfor, ContextInfo *context );
+extern void renderspu_SystemSwapBuffers( WindowInfo *window, GLint flags );
+extern void renderspu_SystemReparentWindow(WindowInfo *window);
+extern void renderspu_SystemVBoxPresentComposition( WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pChangedEntry );
+uint32_t renderspu_SystemPostprocessFunctions(SPUNamedFunctionTable *aFunctions, uint32_t cFunctions, uint32_t cTable);
+extern void renderspu_GCWindow(void);
+extern int renderspuCreateFunctions( SPUNamedFunctionTable table[] );
+extern GLboolean renderspuVBoxCompositorSet( WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR * pCompositor);
+extern void renderspuVBoxCompositorClearAll();
+extern int renderspuVBoxCompositorLock(WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR **ppCompositor);
+extern int renderspuVBoxCompositorUnlock(WindowInfo *window);
+extern const struct VBOXVR_SCR_COMPOSITOR * renderspuVBoxCompositorAcquire( WindowInfo *window);
+extern int renderspuVBoxCompositorTryAcquire(WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR **ppCompositor);
+extern void renderspuVBoxCompositorRelease( WindowInfo *window);
+extern void renderspuVBoxPresentCompositionGeneric( WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR * pCompositor,
+ const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pChangedEntry, int32_t i32MakeCurrentUserData,
+ bool fRedraw);
+extern PCR_BLITTER renderspuVBoxPresentBlitterGet( WindowInfo *window );
+void renderspuVBoxPresentBlitterCleanup( WindowInfo *window );
+extern int renderspuVBoxPresentBlitterEnter( PCR_BLITTER pBlitter, int32_t i32MakeCurrentUserData );
+extern PCR_BLITTER renderspuVBoxPresentBlitterGetAndEnter( WindowInfo *window, int32_t i32MakeCurrentUserData, bool fRedraw );
+extern PCR_BLITTER renderspuVBoxPresentBlitterEnsureCreated( WindowInfo *window, int32_t i32MakeCurrentUserData );
+WindowInfo* renderspuWinCreate(GLint visBits, GLint id);
+void renderspuWinTermOnShutdown(WindowInfo *window);
+void renderspuWinTerm( WindowInfo *window );
+void renderspuWinCleanup(WindowInfo *window);
+void renderspuWinDestroy(WindowInfo *window);
+GLboolean renderspuWinInitWithVisual( WindowInfo *window, VisualInfo *visual, GLboolean showIt, GLint id );
+GLboolean renderspuWinInit(WindowInfo *pWindow, const char *dpyName, GLint visBits, GLint id);
+
+DECLINLINE(void) renderspuWinRetain(WindowInfo *window)
+{
+ ASMAtomicIncU32(&window->cRefs);
+}
+
+DECLINLINE(bool) renderspuWinIsTermed(WindowInfo *window)
+{
+ return window->BltInfo.Base.id < 0;
+}
+
+DECLINLINE(void) renderspuWinRelease(WindowInfo *window)
+{
+ uint32_t cRefs = ASMAtomicDecU32(&window->cRefs);
+ if (!cRefs)
+ {
+ renderspuWinDestroy(window);
+ }
+}
+
+extern WindowInfo* renderspuGetDummyWindow(GLint visBits);
+extern void renderspuPerformMakeCurrent(WindowInfo *window, GLint nativeWindow, ContextInfo *context);
+extern GLboolean renderspuInitVisual(VisualInfo *pVisInfo, const char *displayName, GLbitfield visAttribs);
+extern void renderspuVBoxCompositorBlit ( const struct VBOXVR_SCR_COMPOSITOR * pCompositor, PCR_BLITTER pBlitter);
+extern void renderspuVBoxCompositorBlitStretched ( const struct VBOXVR_SCR_COMPOSITOR * pCompositor, PCR_BLITTER pBlitter, GLfloat scaleX, GLfloat scaleY);
+extern GLint renderspuCreateContextEx(const char *dpyName, GLint visBits, GLint id, GLint shareCtx);
+extern GLint renderspuWindowCreateEx( const char *dpyName, GLint visBits, GLint id );
+
+extern GLint RENDER_APIENTRY renderspuWindowCreate( const char *dpyName, GLint visBits );
+void RENDER_APIENTRY renderspuWindowDestroy( GLint win );
+extern GLint RENDER_APIENTRY renderspuCreateContext( const char *dpyname, GLint visBits, GLint shareCtx );
+extern void RENDER_APIENTRY renderspuMakeCurrent(GLint crWindow, GLint nativeWindow, GLint ctx);
+extern void RENDER_APIENTRY renderspuSwapBuffers( GLint window, GLint flags );
+
+extern uint32_t renderspuContextMarkDeletedAndRelease( ContextInfo *context );
+
+int renderspuDefaultCtxInit();
+void renderspuCleanupBase(bool fDeleteTables);
+
+ContextInfo * renderspuDefaultSharedContextAcquire();
+void renderspuDefaultSharedContextRelease(ContextInfo * pCtx);
+uint32_t renderspuContextRelease(ContextInfo *context);
+uint32_t renderspuContextRetain(ContextInfo *context);
+
+bool renderspuCalloutAvailable();
+bool renderspuCalloutClient(PFNVCRSERVER_CLIENT_CALLOUT_CB pfnCb, void *pvCb);
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+DECLEXPORT(void) renderspuSetWindowId(uint64_t winId);
+DECLEXPORT(void) renderspuReparentWindow(GLint window);
+DECLEXPORT(void) renderspuSetUnscaledHiDPI(bool fEnable);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CR_RENDERSPU_H */
diff --git a/src/VBox/HostServices/SharedOpenGL/render/renderspu_agl.c b/src/VBox/HostServices/SharedOpenGL/render/renderspu_agl.c
new file mode 100644
index 00000000..de55160e
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/render/renderspu_agl.c
@@ -0,0 +1,907 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include <Carbon/Carbon.h>
+#include <AGL/agl.h>
+#include <OpenGL/OpenGL.h>
+
+#include <iprt/time.h>
+#include <iprt/assert.h>
+#include <iprt/semaphore.h>
+
+#include <stdio.h>
+
+#include "cr_environment.h"
+#include "cr_error.h"
+#include "cr_string.h"
+#include "cr_mem.h"
+#include "renderspu.h"
+
+#ifdef __LP64__ /** @todo port to 64-bit darwin. */
+# define renderspuSetWindowContext(w, c) \
+ AssertFailed()
+# define renderspuGetWindowContext(w) \
+ ( (ContextInfo *) GetWRefCon( ((w)->nativeWindow ? (w)->nativeWindow : (w)->window) ) )
+#else
+# define renderspuSetWindowContext(w, c) \
+ ( SetWRefCon( (w), (unsigned long) (c) ) )
+# define renderspuGetWindowContext(w) \
+ ( (ContextInfo *) GetWRefCon( ((w)->nativeWindow ? (w)->nativeWindow : (w)->window) ) )
+#endif
+
+/* Debug macros */
+#ifdef DEBUG_poetzsch
+#define DEBUG_MSG_POETZSCH(text) \
+ printf text
+#else
+#define DEBUG_MSG_POETZSCH(text) \
+ do {} while (0)
+#endif
+
+#define DEBUG_MSG_RESULT(result, text) \
+ crDebug(text" (%d; %s:%d)", (int)(result), __FILE__, __LINE__)
+
+#define CHECK_CARBON_RC(result, text) \
+ if((result) != noErr) \
+ DEBUG_MSG_RESULT(result, text);
+
+#define CHECK_CARBON_RC_RETURN(result, text, ret) \
+ if((result) != noErr) \
+ { \
+ DEBUG_MSG_RESULT(result, text); \
+ return ret; \
+ }
+
+#define CHECK_CARBON_RC_RETURN_VOID(result, text) \
+ CHECK_CARBON_RC_RETURN(result, text,)
+
+#define CHECK_AGL_RC(result, text) \
+ if(!(result)) \
+ { \
+ GLenum error = render_spu.ws.aglGetError(); \
+ DEBUG_MSG_RESULT(result, text); \
+ }
+
+static void renderspu_SystemWindowApplyVisibleRegion(WindowInfo *window);
+static void renderspu_SystemSetRootVisibleRegion(GLint cRects, GLint *pRects);
+
+/* In some case (like compiz which doesn't provide us with clipping regions) we
+ * have to make sure that *all* open OpenGL windows are clipped to the main
+ * application window. This is done here when called from the event handler
+ * which monitor bounding changes of the main window. */
+static void crClipRootHelper(unsigned long key, void *data1, void *data2)
+{
+ /* The window with id zero is the base window, which isn't displayed at
+ * all. So ignore it. */
+ if (key > 0)
+ {
+ /* Fetch the actually window info & the user data */
+ WindowInfo *pWin = (WindowInfo *) data1;
+ /* We need to assign the context with this window */
+ ContextInfo *context = renderspuGetWindowContext(pWin);
+ if (context &&
+ context->context)
+ {
+ RTSemFastMutexRequest(render_spu.syncMutex);
+ GLboolean result = render_spu.ws.aglSetCurrentContext(context->context);
+ CHECK_AGL_RC (result, "Render SPU (crClipRootHelper): SetCurrentContext Failed");
+ if (result)
+ {
+ result = render_spu.ws.aglUpdateContext(context->context);
+ CHECK_AGL_RC (result, "Render SPU (crClipRootHelper): UpdateContext Failed");
+ /* Update the clipping region */
+ renderspu_SystemWindowApplyVisibleRegion(pWin);
+ }
+ RTSemFastMutexRelease(render_spu.syncMutex);
+ /* Make sure that the position is updated relative to the Qt main
+ * view */
+ renderspu_SystemWindowPosition(pWin, pWin->x, pWin->y);
+ }
+ }
+}
+
+/* Window event handler */
+pascal OSStatus
+windowEvtHndlr(EventHandlerCallRef myHandler, EventRef event, void* userData)
+{
+ WindowRef window = NULL;
+ OSStatus eventResult = eventNotHandledErr;
+ UInt32 class = GetEventClass (event);
+ UInt32 kind = GetEventKind (event);
+
+ /* If we aren't initialized or even deinitialized already (as on VM
+ * shutdown) do nothing. */
+ if (!render_spu.fInit)
+ return eventNotHandledErr;
+
+ /* Fetch the sender of the event */
+ GetEventParameter(event, kEventParamDirectObject, typeWindowRef,
+ NULL, sizeof(WindowRef), NULL, &window);
+ switch (class)
+ {
+ case kEventClassVBox:
+ {
+ switch (kind)
+ {
+ case kEventVBoxUpdateContext:
+ {
+#ifndef __LP64__ /** @todo port to 64-bit darwin! Need to check if this event is generated or not (it probably isn't). */
+ WindowInfo *wi1;
+ GetEventParameter(event, kEventParamUserData, typeVoidPtr,
+ NULL, sizeof(wi1), NULL, &wi1);
+ ContextInfo *context = renderspuGetWindowContext(wi1);
+ if (context &&
+ context->context)
+ {
+ AGLContext tmpContext = render_spu.ws.aglGetCurrentContext();
+ DEBUG_MSG_POETZSCH (("kEventVBoxUpdateContext %x %x\n", wi1, context->context));
+ RTSemFastMutexRequest(render_spu.syncMutex);
+ GLboolean result = render_spu.ws.aglSetCurrentContext(context->context);
+ if (result)
+ {
+ result = render_spu.ws.aglUpdateContext(context->context);
+ CHECK_AGL_RC (result, "Render SPU (windowEvtHndlr): UpdateContext Failed");
+ renderspu_SystemWindowApplyVisibleRegion(wi1);
+ /* Reapply the last active context */
+ if (tmpContext)
+ {
+ result = render_spu.ws.aglSetCurrentContext(tmpContext);
+ CHECK_AGL_RC (result, "Render SPU (windowEvtHndlr): SetCurrentContext Failed");
+ if (result)
+ {
+ result = render_spu.ws.aglUpdateContext(tmpContext);
+ CHECK_AGL_RC (result, "Render SPU (windowEvtHndlr): UpdateContext Failed");
+ }
+ }
+ }
+ RTSemFastMutexRelease(render_spu.syncMutex);
+ }
+ eventResult = noErr;
+#endif
+ break;
+ }
+ case kEventVBoxBoundsChanged:
+ {
+#ifndef __LP64__ /** @todo port to 64-bit darwin! Need to check if this event is generated or not (it probably isn't). */
+ HIPoint p;
+ GetEventParameter(event, kEventParamOrigin, typeHIPoint,
+ NULL, sizeof(p), NULL, &p);
+ HISize s;
+ GetEventParameter(event, kEventParamDimensions, typeHISize,
+ NULL, sizeof(s), NULL, &s);
+ HIRect r = CGRectMake (0, 0, s.width, s.height);
+ DEBUG_MSG_POETZSCH (("kEventVBoxBoundsChanged %f %f %f %f\n", p.x, p.y, s.width, s.height));
+ GLint l[4] = { 0,
+ 0,
+ r.size.width,
+ r.size.height };
+ /* Update the root window clip region */
+ renderspu_SystemSetRootVisibleRegion(1, l);
+ /* Temporary save the current active context */
+ AGLContext tmpContext = render_spu.ws.aglGetCurrentContext();
+ crHashtableWalk(render_spu.windowTable, crClipRootHelper, NULL);
+ /* Reapply the last active context */
+ if (tmpContext)
+ {
+ RTSemFastMutexRequest(render_spu.syncMutex);
+ GLboolean result = render_spu.ws.aglSetCurrentContext(tmpContext);
+ CHECK_AGL_RC (result, "Render SPU (windowEvtHndlr): SetCurrentContext Failed");
+ /* Doesn't work with DirectX; Anyway doesn't */
+/* if (result)*/
+/* {*/
+/* result = render_spu.ws.aglUpdateContext(tmpContext);*/
+/* CHECK_AGL_RC (result, "Render SPU (windowEvtHndlr): UpdateContext Failed");*/
+/* }*/
+ RTSemFastMutexRelease(render_spu.syncMutex);
+ }
+ eventResult = noErr;
+#endif
+ break;
+ }
+ };
+ break;
+ }
+ break;
+ };
+
+ return eventResult;
+}
+
+GLboolean
+renderspu_SystemInitVisual(VisualInfo *visual)
+{
+ if(visual->visAttribs & CR_PBUFFER_BIT)
+ crWarning("Render SPU (renderspu_SystemInitVisual): PBuffers not support on Darwin/AGL yet.");
+
+ return GL_TRUE;
+}
+
+GLboolean
+renderspuChoosePixelFormat(ContextInfo *context, AGLPixelFormat *pix)
+{
+ GLbitfield visAttribs = context->visual->visAttribs;
+ GLint attribs[32];
+ GLint ind = 0;
+
+#define ATTR_ADD(s) ( attribs[ind++] = (s) )
+#define ATTR_ADDV(s,v) ( ATTR_ADD((s)), ATTR_ADD((v)) )
+
+ CRASSERT(render_spu.ws.aglChoosePixelFormat);
+
+ ATTR_ADD(AGL_RGBA);
+/* ATTR_ADDV(AGL_RED_SIZE, 1);
+ ATTR_ADDV(AGL_GREEN_SIZE, 1);
+ ATTR_ADDV(AGL_BLUE_SIZE, 1); */
+
+/* if( render_spu.fullscreen )*/
+/* ATTR_ADD(AGL_FULLSCREEN);*/
+
+ if( visAttribs & CR_ALPHA_BIT )
+ ATTR_ADDV(AGL_ALPHA_SIZE, 1);
+
+ if( visAttribs & CR_DOUBLE_BIT )
+ ATTR_ADD(AGL_DOUBLEBUFFER);
+
+ if( visAttribs & CR_STEREO_BIT )
+ ATTR_ADD(AGL_STEREO);
+
+ if( visAttribs & CR_DEPTH_BIT )
+ ATTR_ADDV(AGL_DEPTH_SIZE, 1);
+
+ if( visAttribs & CR_STENCIL_BIT )
+ ATTR_ADDV(AGL_STENCIL_SIZE, 1);
+
+ if( visAttribs & CR_ACCUM_BIT ) {
+ ATTR_ADDV(AGL_ACCUM_RED_SIZE, 1);
+ ATTR_ADDV(AGL_ACCUM_GREEN_SIZE, 1);
+ ATTR_ADDV(AGL_ACCUM_BLUE_SIZE, 1);
+ if( visAttribs & CR_ALPHA_BIT )
+ ATTR_ADDV(AGL_ACCUM_ALPHA_SIZE, 1);
+ }
+
+ if( visAttribs & CR_MULTISAMPLE_BIT ) {
+ ATTR_ADDV(AGL_SAMPLE_BUFFERS_ARB, 1);
+ ATTR_ADDV(AGL_SAMPLES_ARB, 4);
+ }
+
+ if( visAttribs & CR_OVERLAY_BIT )
+ ATTR_ADDV(AGL_LEVEL, 1);
+
+ ATTR_ADD(AGL_NONE);
+
+ *pix = render_spu.ws.aglChoosePixelFormat( NULL, 0, attribs );
+
+ return (*pix != NULL);
+}
+
+void
+renderspuDestroyPixelFormat(ContextInfo *context, AGLPixelFormat *pix)
+{
+ render_spu.ws.aglDestroyPixelFormat( *pix );
+ *pix = NULL;
+}
+
+GLboolean
+renderspu_SystemCreateContext(VisualInfo *visual, ContextInfo *context, ContextInfo *sharedContext)
+{
+ AGLPixelFormat pix;
+
+ (void) sharedContext;
+ CRASSERT(visual);
+ CRASSERT(context);
+
+ context->visual = visual;
+
+ if( !renderspuChoosePixelFormat(context, &pix) ) {
+ crError( "Render SPU (renderspu_SystemCreateContext): Unable to create pixel format" );
+ return GL_FALSE;
+ }
+
+ context->context = render_spu.ws.aglCreateContext( pix, NULL );
+ renderspuDestroyPixelFormat( context, &pix );
+
+ if( !context->context ) {
+ crError( "Render SPU (renderspu_SystemCreateContext): Could not create rendering context" );
+ return GL_FALSE;
+ }
+
+ return GL_TRUE;
+}
+
+void
+renderspu_SystemDestroyContext(ContextInfo *context)
+{
+ if(!context)
+ return;
+
+ render_spu.ws.aglSetDrawable(context->context, NULL);
+ render_spu.ws.aglSetCurrentContext(NULL);
+ if(context->context)
+ {
+ render_spu.ws.aglDestroyContext(context->context);
+ context->context = NULL;
+ }
+
+ context->visual = NULL;
+}
+
+void
+renderspuFullscreen(WindowInfo *window, GLboolean fullscreen)
+{
+ /* Real fullscreen isn't supported by VirtualBox */
+}
+
+GLboolean
+renderspuWindowAttachContext(WindowInfo *wi, WindowRef window,
+ ContextInfo *context)
+{
+ GLboolean result;
+
+ if(!context || !wi)
+ return render_spu.ws.aglSetCurrentContext( NULL );
+
+/* DEBUG_MSG_POETZSCH (("WindowAttachContext %d\n", wi->BltInfo.Base.id));*/
+
+ /* Flush old context first */
+ if (context->currentWindow->window != window)
+ render_spu.self.Flush();
+ /* If the window buffer name is uninitialized we have to create a new
+ * dummy context. */
+ if (wi->bufferName == -1)
+ {
+ DEBUG_MSG_POETZSCH (("WindowAttachContext: create context %d\n", wi->BltInfo.Base.id));
+ /* Use the same visual bits as those in the context structure */
+ AGLPixelFormat pix;
+ if( !renderspuChoosePixelFormat(context, &pix) )
+ {
+ crError( "Render SPU (renderspuWindowAttachContext): Unable to create pixel format" );
+ return GL_FALSE;
+ }
+ /* Create the dummy context */
+ wi->dummyContext = render_spu.ws.aglCreateContext( pix, NULL );
+ renderspuDestroyPixelFormat( context, &pix );
+ if( !wi->dummyContext )
+ {
+ crError( "Render SPU (renderspuWindowAttachContext): Could not create rendering context" );
+ return GL_FALSE;
+ }
+ AGLDrawable drawable;
+#ifdef __LP64__ /** @todo port to 64-bit darwin. */
+ drawable = NULL;
+#else
+ drawable = (AGLDrawable) GetWindowPort(window);
+#endif
+ /* New global buffer name */
+ wi->bufferName = render_spu.currentBufferName++;
+ /* Set the new buffer name to the dummy context. This enable the
+ * sharing of the same hardware buffer afterwards. */
+ result = render_spu.ws.aglSetInteger(wi->dummyContext, AGL_BUFFER_NAME, &wi->bufferName);
+ CHECK_AGL_RC (result, "Render SPU (renderspuWindowAttachContext): SetInteger Failed");
+ /* Assign the dummy context to the window */
+ result = render_spu.ws.aglSetDrawable(wi->dummyContext, drawable);
+ CHECK_AGL_RC (result, "Render SPU (renderspuWindowAttachContext): SetDrawable Failed");
+ }
+
+ AGLDrawable oldDrawable;
+ AGLDrawable newDrawable;
+
+ oldDrawable = render_spu.ws.aglGetDrawable(context->context);
+#ifdef __LP64__ /** @todo port to 64-bit darwin. */
+ newDrawable = oldDrawable;
+#else
+ newDrawable = (AGLDrawable) GetWindowPort(window);
+#endif
+ RTSemFastMutexRequest(render_spu.syncMutex);
+ /* Only switch the context if the drawable has changed */
+ if (oldDrawable != newDrawable)
+ {
+ /* Reset the current context */
+ result = render_spu.ws.aglSetDrawable(context->context, NULL);
+ CHECK_AGL_RC (result, "Render SPU (renderspuWindowAttachContext): SetDrawable Failed");
+ /* Set the buffer name of the dummy context to the current context
+ * also. After that both share the same hardware buffer. */
+ render_spu.ws.aglSetInteger (context->context, AGL_BUFFER_NAME, &wi->bufferName);
+ CHECK_AGL_RC (result, "Render SPU (renderspuWindowAttachContext): SetInteger Failed");
+ /* Set the new drawable */
+#ifdef __LP64__ /** @todo port to 64-bit darwin. */
+ result = -1;
+#else
+ result = render_spu.ws.aglSetDrawable(context->context, newDrawable);
+#endif
+ CHECK_AGL_RC (result, "Render SPU (renderspuWindowAttachContext): SetDrawable Failed");
+ renderspuSetWindowContext(window, context);
+ }
+ result = render_spu.ws.aglSetCurrentContext(context->context);
+ CHECK_AGL_RC (result, "Render SPU (renderspuWindowAttachContext): SetCurrentContext Failed");
+ result = render_spu.ws.aglUpdateContext(context->context);
+ CHECK_AGL_RC (result, "Render SPU (renderspuWindowAttachContext): UpdateContext Failed");
+ RTSemFastMutexRelease(render_spu.syncMutex);
+
+ return result;
+}
+
+GLboolean
+renderspu_SystemCreateWindow(VisualInfo *visual, GLboolean showIt,
+ WindowInfo *window)
+{
+ return GL_TRUE;
+}
+
+void renderspu_SystemReparentWindow(WindowInfo *)
+{
+ /* stub only */
+}
+
+void
+renderspu_SystemDestroyWindow(WindowInfo *window)
+{
+ CRASSERT(window);
+ CRASSERT(window->visual);
+
+ if(!window->nativeWindow)
+ {
+ EventRef evt;
+ OSStatus status = CreateEvent(NULL, kEventClassVBox, kEventVBoxDisposeWindow, 0, kEventAttributeNone, &evt);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemDestroyWindow): CreateEvent Failed");
+ status = SetEventParameter(evt, kEventParamWindowRef, typeWindowRef, sizeof (window->window), &window->window);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemDestroyWindow): SetEventParameter Failed");
+ status = PostEventToQueue(GetMainEventQueue(), evt, kEventPriorityStandard);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemDestroyWindow): PostEventToQueue Failed");
+ }
+
+ /* Delete the dummy context */
+ if(window->dummyContext)
+ {
+ render_spu.ws.aglSetDrawable(window->dummyContext, NULL);
+ render_spu.ws.aglDestroyContext(window->dummyContext);
+ window->dummyContext = NULL;
+ }
+
+ /* Reset some values */
+ window->bufferName = -1;
+ window->visual = NULL;
+ window->window = NULL;
+
+ if (window->hVisibleRegion)
+ {
+ DisposeRgn(window->hVisibleRegion);
+ window->hVisibleRegion = 0;
+ }
+}
+
+void
+renderspu_SystemWindowPosition(WindowInfo *window,
+ GLint x, GLint y)
+{
+ CRASSERT(window);
+ CRASSERT(window->window);
+
+ OSStatus status = noErr;
+ /* Send a event to the main thread, cause some function of Carbon aren't
+ * thread safe */
+ EventRef evt;
+ status = CreateEvent(NULL, kEventClassVBox, kEventVBoxMoveWindow, 0, kEventAttributeNone, &evt);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemWindowPosition): CreateEvent Failed");
+ status = SetEventParameter(evt, kEventParamWindowRef, typeWindowRef, sizeof(window->window), &window->window);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemWindowPosition): SetEventParameter Failed");
+ HIPoint p = CGPointMake (x, y);
+ status = SetEventParameter(evt, kEventParamOrigin, typeHIPoint, sizeof (p), &p);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemWindowPosition): SetEventParameter Failed");
+ status = SetEventParameter(evt, kEventParamUserData, typeVoidPtr, sizeof (window), &window);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemWindowPosition): SetEventParameter Failed");
+ status = PostEventToQueue(GetMainEventQueue(), evt, kEventPriorityStandard);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemWindowPosition): PostEventToQueue Failed");
+
+ /* save the new pos */
+ window->x = x;
+ window->y = y;
+}
+
+void
+renderspu_SystemWindowSize(WindowInfo *window, GLint w, GLint h)
+{
+ CRASSERT(window);
+ CRASSERT(window->window);
+
+ OSStatus status = noErr;
+ /* Send a event to the main thread, cause some function of Carbon aren't
+ * thread safe */
+ EventRef evt;
+ status = CreateEvent(NULL, kEventClassVBox, kEventVBoxResizeWindow, 0, kEventAttributeNone, &evt);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemWindowSize): CreateEvent Failed ");
+ status = SetEventParameter(evt, kEventParamWindowRef, typeWindowRef, sizeof(window->window), &window->window);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemWindowSize): SetEventParameter Failed");
+ HISize s = CGSizeMake (w, h);
+ status = SetEventParameter(evt, kEventParamDimensions, typeHISize, sizeof (s), &s);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemWindowSize): SetEventParameter Failed");
+ status = SetEventParameter(evt, kEventParamUserData, typeVoidPtr, sizeof (window), &window);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemWindowSize): SetEventParameter Failed");
+ status = PostEventToQueue(GetMainEventQueue(), evt, kEventPriorityStandard);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemWindowSize): SendEventToEventTarget Failed");
+
+ DEBUG_MSG_POETZSCH (("Size %d visible %d\n", window->BltInfo.Base.id, IsWindowVisible (window->window)));
+ /* 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)
+{
+ CRASSERT(window);
+ CRASSERT(window->window);
+
+ OSStatus status = noErr;
+ Rect r;
+ status = GetWindowBounds(window->window, kWindowStructureRgn, &r);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemGetWindowGeometry): GetWindowBounds Failed");
+
+ *x = (int) r.left;
+ *y = (int) r.top;
+ *w = (int) (r.right - r.left);
+ *h = (int) (r.bottom - r.top);
+}
+
+void
+renderspu_SystemGetMaxWindowSize(WindowInfo *window,
+ GLint *w, GLint *h)
+{
+ CRASSERT(window);
+ CRASSERT(window->window);
+
+ OSStatus status = noErr;
+ HISize s;
+#ifdef __LP64__ /** @todo port to 64-bit darwin. */
+ status = -1;
+#else
+ status = GetWindowResizeLimits (window->window, NULL, &s);
+#endif
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemGetMaxWindowSize): GetWindowResizeLimits Failed");
+
+ *w = s.width;
+ *h = s.height;
+}
+
+/* Either show or hide the render SPU's window. */
+void
+renderspu_SystemShowWindow(WindowInfo *window, GLboolean showIt)
+{
+ CRASSERT(window);
+ CRASSERT(window->window);
+
+ if (!IsValidWindowPtr(window->window))
+ return;
+
+ if(showIt)
+ {
+ /* Force moving the win to the right position before we show it */
+ renderspu_SystemWindowPosition (window, window->x, window->y);
+ OSStatus status = noErr;
+ /* Send a event to the main thread, cause some function of Carbon
+ * aren't thread safe */
+ EventRef evt;
+ status = CreateEvent(NULL, kEventClassVBox, kEventVBoxShowWindow, 0, kEventAttributeNone, &evt);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemShowWindow): CreateEvent Failed");
+ status = SetEventParameter(evt, kEventParamWindowRef, typeWindowRef, sizeof (window->window), &window->window);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemShowWindow): SetEventParameter Failed");
+ status = SetEventParameter(evt, kEventParamUserData, typeVoidPtr, sizeof (window), &window);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemWindowShow): SetEventParameter Failed");
+ //status = SendEventToEventTarget (evt, GetWindowEventTarget (HIViewGetWindow ((HIViewRef)render_spu_parent_window_id)));
+ status = PostEventToQueue(GetMainEventQueue(), evt, kEventPriorityStandard);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemShowWindow): PostEventToQueue Failed");
+ }
+ else
+ {
+ EventRef evt;
+ OSStatus status = CreateEvent(NULL, kEventClassVBox, kEventVBoxHideWindow, 0, kEventAttributeNone, &evt);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemShowWindow): CreateEvent Failed");
+ status = SetEventParameter(evt, kEventParamWindowRef, typeWindowRef, sizeof (window->window), &window->window);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemShowWindow): SetEventParameter Failed");
+ status = PostEventToQueue(GetMainEventQueue(), evt, kEventPriorityStandard);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemShowWindow): PostEventToQueue Failed");
+ }
+}
+
+void renderspu_SystemVBoxPresentComposition( WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR * pCompositor, const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pChangedEntry )
+{
+ renderspuVBoxPresentCompositionGeneric(window, pCompositor, pChangedEntry, 0, false);
+}
+
+void
+renderspu_SystemMakeCurrent(WindowInfo *window, GLint nativeWindow,
+ ContextInfo *context)
+{
+ Boolean result;
+/* DEBUG_MSG_POETZSCH (("makecurrent %d: \n", window->BltInfo.Base.id));*/
+
+ CRASSERT(render_spu.ws.aglSetCurrentContext);
+ //crDebug( "renderspu_SystemMakeCurrent( %x, %i, %x )", window, nativeWindow, context );
+
+ nativeWindow = 0;
+
+ if(window && context)
+ {
+ CRASSERT(window->window);
+ CRASSERT(context->context);
+
+ if(window->visual != context->visual)
+ {
+ crDebug("Render SPU (renderspu_SystemMakeCurrent): MakeCurrent visual mismatch (0x%x != 0x%x); remaking window.",
+ (uint)window->visual->visAttribs, (uint)context->visual->visAttribs);
+ /*
+ * XXX have to revisit this issue!!!
+ *
+ * But for now we destroy the current window
+ * and re-create it with the context's visual abilities
+ */
+ renderspu_SystemDestroyWindow(window);
+ renderspu_SystemCreateWindow(context->visual, window->visible,
+ window);
+ }
+
+ /* This is the normal case: rendering to the render SPU's own window */
+ result = renderspuWindowAttachContext(window, window->window,
+ context);
+ /* XXX this is a total hack to work around an NVIDIA driver bug */
+ if(render_spu.self.GetFloatv && context->haveWindowPosARB)
+ {
+ GLfloat f[4];
+ render_spu.self.GetFloatv(GL_CURRENT_RASTER_POSITION, f);
+ if (!window->everCurrent || f[1] < 0.0)
+ {
+ crDebug("Render SPU (renderspu_SystemMakeCurrent): Resetting raster pos");
+ render_spu.self.WindowPos2iARB(0, 0);
+ }
+ }
+ /* Reapply the visible regions */
+ renderspu_SystemWindowApplyVisibleRegion(window);
+ }
+ else
+ renderspuWindowAttachContext (0, 0, 0);
+}
+
+void
+renderspu_SystemSwapBuffers(WindowInfo *window, GLint flags)
+{
+ CRASSERT(window);
+ CRASSERT(window->window);
+
+ ContextInfo *context = renderspuGetWindowContext(window);
+
+ if(!context)
+ crError("Render SPU (renderspu_SystemSwapBuffers): SwapBuffers got a null context from the window");
+
+ RTSemFastMutexRequest(render_spu.syncMutex);
+// DEBUG_MSG_POETZSCH (("Swapped %d context %x visible: %d\n", window->BltInfo.Base.id, context->context, IsWindowVisible (window->window)));
+ if (context->visual &&
+ context->visual->visAttribs & CR_DOUBLE_BIT)
+ render_spu.ws.aglSwapBuffers(context->context);
+ else
+ glFlush();
+ RTSemFastMutexRelease(render_spu.syncMutex);
+
+ /* This method seems called very often. To prevent the dock using all free
+ * resources we update the dock only two times per second. */
+ uint64_t curTS = RTTimeMilliTS();
+ if ((curTS - render_spu.uiDockUpdateTS) > 500)
+ {
+ OSStatus status = noErr;
+ /* Send a event to the main thread, cause some function of Carbon aren't
+ * thread safe */
+ EventRef evt;
+ status = CreateEvent(NULL, kEventClassVBox, kEventVBoxUpdateDock, 0, kEventAttributeNone, &evt);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemSwapBuffers): CreateEvent Failed");
+ status = PostEventToQueue(GetMainEventQueue(), evt, kEventPriorityStandard);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemSwapBuffers): PostEventToQueue Failed");
+
+ render_spu.uiDockUpdateTS = curTS;
+ }
+}
+
+GLboolean renderspu_SystemWindowNeedEmptyPresent(WindowInfo *window)
+{
+ return GL_FALSE;
+}
+
+void renderspu_SystemWindowVisibleRegion(WindowInfo *window, GLint cRects, const GLint* pRects)
+{
+ CRASSERT(window);
+ CRASSERT(window->window);
+
+ /* Remember any additional clipping stuff e.g. seamless regions */
+ if (window->hVisibleRegion)
+ {
+ DisposeRgn(window->hVisibleRegion);
+ window->hVisibleRegion = 0;
+ }
+
+ if (cRects>0)
+ {
+ int i;
+ /* Create some temporary regions */
+ RgnHandle rgn = NewRgn();
+ SetEmptyRgn (rgn);
+ RgnHandle tmpRgn = NewRgn();
+ for (i=0; i<cRects; ++i)
+ {
+ SetRectRgn (tmpRgn,
+ pRects[4*i] , pRects[4*i+1],
+ pRects[4*i+2], pRects[4*i+3]);
+ //DEBUG_MSG_POETZSCH (("visible rect %d %d %d %d\n", pRects[4*i] , pRects[4*i+1],
+ // pRects[4*i+2], pRects[4*i+3]));
+ UnionRgn (rgn, tmpRgn, rgn);
+ }
+ DisposeRgn (tmpRgn);
+ window->hVisibleRegion = rgn;
+ }
+
+ renderspu_SystemWindowApplyVisibleRegion(window);
+}
+
+static void renderspu_SystemSetRootVisibleRegion(GLint cRects, GLint *pRects)
+{
+ /* Remember the visible region of the root window if there is one */
+ if (render_spu.hRootVisibleRegion)
+ {
+ DisposeRgn(render_spu.hRootVisibleRegion);
+ render_spu.hRootVisibleRegion = 0;
+ }
+
+ if (cRects>0)
+ {
+ int i;
+ render_spu.hRootVisibleRegion = NewRgn();
+ SetEmptyRgn (render_spu.hRootVisibleRegion);
+ RgnHandle tmpRgn = NewRgn();
+ for (i=0; i<cRects; ++i)
+ {
+ SetRectRgn (tmpRgn,
+ pRects[4*i] , pRects[4*i+1],
+ pRects[4*i+2], pRects[4*i+3]);
+ UnionRgn (render_spu.hRootVisibleRegion, tmpRgn, render_spu.hRootVisibleRegion);
+ }
+ DisposeRgn (tmpRgn);
+ }
+}
+
+/*Assumes that all regions are in the guest coordinates system*/
+static void renderspu_SystemWindowApplyVisibleRegion(WindowInfo *window)
+{
+ ContextInfo *c = renderspuGetWindowContext(window);
+ RgnHandle rgn;
+ GLboolean result = true;
+
+ DEBUG_MSG_POETZSCH (("ApplyVisibleRegion %x\n", window));
+
+ if (!c || !c->context) return;
+
+ rgn = NewRgn();
+ SetEmptyRgn(rgn);
+
+ if (render_spu.hRootVisibleRegion)
+ {
+ /* The render_spu.hRootVisibleRegion has coordinates from the root
+ * window. We intersect it with the rect of the OpenGL window we
+ * currently process. */
+ SetRectRgn(rgn,
+ window->x, window->y,
+ window->x + window->BltInfo.width,
+ window->y + window->BltInfo.height);
+ SectRgn(render_spu.hRootVisibleRegion, rgn, rgn);
+ /* Because the clipping is done in the coordinate space of the OpenGL
+ * window we have to remove the x/y position from the newly created
+ * region. */
+ OffsetRgn (rgn, -window->x, -window->y);
+ }
+ else
+ {
+ /* If there is not root clipping region is available, create a base
+ * region with the size of the target window. This covers all
+ * needed/possible space. */
+ SetRectRgn(rgn, 0, 0, window->BltInfo.width, window->BltInfo.height);
+ }
+
+ /* Now intersect the window clipping region with a additional region e.g.
+ * for the seamless mode. */
+ if (window->hVisibleRegion)
+ SectRgn(rgn, window->hVisibleRegion, rgn);
+
+ if (rgn && !EmptyRgn(rgn))
+ {
+ /* Set the clip region to the context */
+ result = render_spu.ws.aglSetInteger(c->context, AGL_CLIP_REGION, (const GLint*)rgn);
+ CHECK_AGL_RC (result, "Render SPU (renderspu_SystemWindowVisibleRegion): SetInteger Failed");
+ result = render_spu.ws.aglEnable(c->context, AGL_CLIP_REGION);
+ CHECK_AGL_RC (result, "Render SPU (renderspu_SystemWindowVisibleRegion): Enable Failed");
+ }
+ /* Clear the region structure */
+ DisposeRgn (rgn);
+}
+
+GLboolean
+renderspu_SystemVBoxCreateWindow(VisualInfo *visual, GLboolean showIt,
+ WindowInfo *window)
+{
+ CRASSERT(visual);
+ CRASSERT(window);
+
+ WindowAttributes winAttr = kWindowNoShadowAttribute | kWindowCompositingAttribute | kWindowIgnoreClicksAttribute | kWindowStandardHandlerAttribute | kWindowLiveResizeAttribute;
+ WindowClass winClass = kOverlayWindowClass;
+ Rect windowRect;
+ OSStatus status = noErr;
+
+ window->visual = visual;
+ window->nativeWindow = NULL;
+
+ if(window->window && IsValidWindowPtr(window->window))
+ {
+ EventRef evt;
+ status = CreateEvent(NULL, kEventClassVBox, kEventVBoxDisposeWindow, 0, kEventAttributeNone, &evt);
+ CHECK_CARBON_RC_RETURN (status, "Render SPU (renderspu_SystemVBoxCreateWindow): CreateEvent Failed", false);
+ status = SetEventParameter(evt, kEventParamWindowRef, typeWindowRef, sizeof (window->window), &window->window);
+ CHECK_CARBON_RC_RETURN (status, "Render SPU (renderspu_SystemVBoxCreateWindow): SetEventParameter Failed", false);
+ status = PostEventToQueue(GetMainEventQueue(), evt, kEventPriorityStandard);
+ CHECK_CARBON_RC_RETURN (status, "Render SPU (renderspu_SystemVBoxCreateWindow): PostEventToQueue Failed", false);
+ }
+
+ windowRect.left = window->x;
+ windowRect.top = window->y;
+ windowRect.right = window->x + window->BltInfo.width;
+ windowRect.bottom = window->y + window->BltInfo.height;
+
+ status = CreateNewWindow(winClass, winAttr, &windowRect, &window->window);
+ CHECK_CARBON_RC_RETURN (status, "Render SPU (renderspu_SystemVBoxCreateWindow): CreateNewWindow Failed", GL_FALSE);
+
+ /* We set a title for debugging purposes */
+ CFStringRef title_string;
+ title_string = CFStringCreateWithCStringNoCopy(NULL, window->title,
+ kCFStringEncodingMacRoman, NULL);
+ SetWindowTitleWithCFString(window->BltInfo.window, title_string);
+ CFRelease(title_string);
+
+ /* The parent has to be in its own group */
+ WindowRef parent = NULL;
+ if (render_spu_parent_window_id)
+ {
+ parent = HIViewGetWindow ((HIViewRef)render_spu_parent_window_id);
+ SetWindowGroup (parent, render_spu.pParentGroup);
+
+ }
+
+ /* Add the new window to the master group */
+ SetWindowGroup(window->window, render_spu.pMasterGroup);
+
+ /* This will be initialized on the first attempt to attach the global
+ * context to this new window */
+ window->bufferName = -1;
+ window->dummyContext = NULL;
+ window->hVisibleRegion = 0;
+
+ if(showIt)
+ renderspu_SystemShowWindow(window, GL_TRUE);
+
+ crDebug("Render SPU (renderspu_SystemVBoxCreateWindow): actual window (x, y, width, height): %d, %d, %d, %d",
+ window->x, window->y, window->BltInfo.width, window->BltInfo.height);
+
+ return GL_TRUE;
+}
+
+int renderspu_SystemInit()
+{
+ return VINF_SUCCESS;
+}
+
+int renderspu_SystemTerm()
+{
+ return VINF_SUCCESS;
+}
+
+void renderspu_SystemDefaultSharedContextChanged(ContextInfo *fromContext, ContextInfo *toContext)
+{
+
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa.c b/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa.c
new file mode 100644
index 00000000..583398a3
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa.c
@@ -0,0 +1,479 @@
+/* $Id: renderspu_cocoa.c $ */
+/** @file
+ * VirtualBox OpenGL Cocoa Window System implementation
+ */
+
+/*
+ * Copyright (C) 2009-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include <OpenGL/OpenGL.h>
+
+#include "renderspu.h"
+#include <iprt/process.h>
+#include <iprt/string.h>
+#include <iprt/path.h>
+
+#include <cr_string.h>
+#include <cr_mem.h>
+
+GLboolean renderspu_SystemInitVisual(VisualInfo *pVisInfo)
+{
+ CRASSERT(pVisInfo);
+
+/* cocoaGLVisualCreate(&pCtxInfo->context);*/
+
+ return GL_TRUE;
+}
+
+GLboolean renderspu_SystemCreateContext(VisualInfo *pVisInfo, ContextInfo *pCtxInfo, ContextInfo *pSharedCtxInfo)
+{
+ CRASSERT(pVisInfo);
+ CRASSERT(pCtxInfo);
+
+ pCtxInfo->currentWindow = NULL;
+
+ cocoaGLCtxCreate(&pCtxInfo->context, pVisInfo->visAttribs, pSharedCtxInfo ? pSharedCtxInfo->context : NULL);
+
+ return GL_TRUE;
+}
+
+void renderspu_SystemDestroyContext(ContextInfo *pCtxInfo)
+{
+ if(!pCtxInfo)
+ return;
+
+ if(pCtxInfo->context)
+ {
+ cocoaGLCtxDestroy(pCtxInfo->context);
+ pCtxInfo->context = NULL;
+ }
+}
+
+void renderspuFullscreen(WindowInfo *pWinInfo, GLboolean fFullscreen)
+{
+ /* Real fullscreen isn't supported by VirtualBox */
+}
+
+GLboolean renderspu_SystemVBoxCreateWindow(VisualInfo *pVisInfo, GLboolean fShowIt, WindowInfo *pWinInfo)
+{
+ CRASSERT(pVisInfo);
+ CRASSERT(pWinInfo);
+
+ /* VirtualBox is the only frontend which support 3D right now. */
+ char pszName[256];
+ if (RTProcGetExecutablePath(pszName, sizeof(pszName)))
+ /* Check for VirtualBox and VirtualBoxVM */
+ if (RTStrNICmp(RTPathFilename(pszName), "VirtualBox", 10) != 0)
+ return GL_FALSE;
+
+ pWinInfo->visual = pVisInfo;
+ pWinInfo->window = NULL;
+ pWinInfo->nativeWindow = NULL;
+ pWinInfo->currentCtx = NULL;
+
+ NativeNSViewRef pParentWin = (NativeNSViewRef)(uintptr_t)render_spu_parent_window_id;
+
+ cocoaViewCreate(&pWinInfo->window, pWinInfo, pParentWin, pVisInfo->visAttribs);
+
+ if (fShowIt)
+ renderspu_SystemShowWindow(pWinInfo, fShowIt);
+
+ return GL_TRUE;
+}
+
+void renderspu_SystemReparentWindow(WindowInfo *pWinInfo)
+{
+ NativeNSViewRef pParentWin = (NativeNSViewRef)(uintptr_t)render_spu_parent_window_id;
+ cocoaViewReparent(pWinInfo->window, pParentWin);
+}
+
+void renderspu_SystemDestroyWindow(WindowInfo *pWinInfo)
+{
+ CRASSERT(pWinInfo);
+
+ cocoaViewDestroy(pWinInfo->window);
+}
+
+void renderspu_SystemWindowPosition(WindowInfo *pWinInfo, GLint x, GLint y)
+{
+ CRASSERT(pWinInfo);
+ NativeNSViewRef pParentWin = (NativeNSViewRef)(uintptr_t)render_spu_parent_window_id;
+
+ /*pParentWin is unused in the call, otherwise it might hold incorrect value if for ex. last reparent call was for
+ a different screen*/
+ cocoaViewSetPosition(pWinInfo->window, pParentWin, x, y);
+}
+
+void renderspu_SystemWindowSize(WindowInfo *pWinInfo, GLint w, GLint h)
+{
+ CRASSERT(pWinInfo);
+
+ cocoaViewSetSize(pWinInfo->window, w, h);
+}
+
+void renderspu_SystemGetWindowGeometry(WindowInfo *pWinInfo, GLint *pX, GLint *pY, GLint *pW, GLint *pH)
+{
+ CRASSERT(pWinInfo);
+
+ cocoaViewGetGeometry(pWinInfo->window, pX, pY, pW, pH);
+}
+
+void renderspu_SystemGetMaxWindowSize(WindowInfo *pWinInfo, GLint *pW, GLint *pH)
+{
+ CRASSERT(pWinInfo);
+
+ *pW = 10000;
+ *pH = 10000;
+}
+
+void renderspu_SystemShowWindow(WindowInfo *pWinInfo, GLboolean fShowIt)
+{
+ CRASSERT(pWinInfo);
+
+ cocoaViewShow(pWinInfo->window, fShowIt);
+}
+
+void renderspu_SystemVBoxPresentComposition( WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pChangedEntry )
+{
+ cocoaViewPresentComposition(window->window, pChangedEntry);
+}
+
+void renderspu_SystemMakeCurrent(WindowInfo *pWinInfo, GLint nativeWindow, ContextInfo *pCtxInfo)
+{
+/* if(pWinInfo->visual != pCtxInfo->visual)*/
+/* printf ("visual mismatch .....................\n");*/
+
+ nativeWindow = 0;
+
+ if (pWinInfo && pCtxInfo)
+ cocoaViewMakeCurrentContext(pWinInfo->window, pCtxInfo->context);
+ else
+ cocoaViewMakeCurrentContext(NULL, NULL);
+}
+
+void renderspu_SystemSwapBuffers(WindowInfo *pWinInfo, GLint flags)
+{
+ CRASSERT(pWinInfo);
+
+ cocoaViewDisplay(pWinInfo->window);
+}
+
+GLboolean renderspu_SystemWindowNeedEmptyPresent(WindowInfo *pWinInfo)
+{
+ return cocoaViewNeedsEmptyPresent(pWinInfo->window);
+}
+
+void renderspu_SystemWindowVisibleRegion(WindowInfo *pWinInfo, GLint cRects, const GLint* paRects)
+{
+ CRASSERT(pWinInfo);
+
+ cocoaViewSetVisibleRegion(pWinInfo->window, cRects, paRects);
+}
+
+void renderspu_SystemWindowApplyVisibleRegion(WindowInfo *pWinInfo)
+{
+}
+
+int renderspu_SystemInit()
+{
+ return VINF_SUCCESS;
+}
+
+int renderspu_SystemTerm()
+{
+ CrGlslTerm(&render_spu.GlobalShaders);
+ return VINF_SUCCESS;
+}
+
+static SPUNamedFunctionTable * renderspuFindEntry(SPUNamedFunctionTable *aFunctions, const char *pcszName)
+{
+ SPUNamedFunctionTable *pCur;
+
+ for (pCur = aFunctions ; pCur->name != NULL ; pCur++)
+ {
+ if (!crStrcmp( pcszName, pCur->name ) )
+ {
+ return pCur;
+ }
+ }
+
+ AssertFailed();
+
+ return NULL;
+}
+
+typedef struct CR_RENDER_CTX_INFO
+{
+ ContextInfo * pContext;
+ WindowInfo * pWindow;
+} CR_RENDER_CTX_INFO;
+
+void renderspuCtxInfoInitCurrent(CR_RENDER_CTX_INFO *pInfo)
+{
+ GET_CONTEXT(pCurCtx);
+ pInfo->pContext = pCurCtx;
+ pInfo->pWindow = pCurCtx ? pCurCtx->currentWindow : NULL;
+}
+
+void renderspuCtxInfoRestoreCurrent(CR_RENDER_CTX_INFO *pInfo)
+{
+ GET_CONTEXT(pCurCtx);
+ if (pCurCtx == pInfo->pContext && (!pCurCtx || pCurCtx->currentWindow == pInfo->pWindow))
+ return;
+ renderspuPerformMakeCurrent(pInfo->pWindow, 0, pInfo->pContext);
+}
+
+GLboolean renderspuCtxSetCurrentWithAnyWindow(ContextInfo * pContext, CR_RENDER_CTX_INFO *pInfo)
+{
+ WindowInfo * window;
+ renderspuCtxInfoInitCurrent(pInfo);
+
+ if (pInfo->pContext == pContext)
+ return GL_TRUE;
+
+ window = pContext->currentWindow;
+ if (!window)
+ {
+ window = renderspuGetDummyWindow(pContext->BltInfo.Base.visualBits);
+ if (!window)
+ {
+ WARN(("renderspuGetDummyWindow failed"));
+ return GL_FALSE;
+ }
+ }
+
+ Assert(window);
+
+ renderspuPerformMakeCurrent(window, 0, pContext);
+ return GL_TRUE;
+}
+
+void renderspu_SystemDefaultSharedContextChanged(ContextInfo *fromContext, ContextInfo *toContext)
+{
+ CRASSERT(fromContext != toContext);
+
+ if (!CrGlslIsInited(&render_spu.GlobalShaders))
+ {
+ CrGlslInit(&render_spu.GlobalShaders, &render_spu.blitterDispatch);
+ }
+
+ if (fromContext)
+ {
+ if (CrGlslNeedsCleanup(&render_spu.GlobalShaders))
+ {
+ CR_RENDER_CTX_INFO Info;
+ if (renderspuCtxSetCurrentWithAnyWindow(fromContext, &Info))
+ {
+ CrGlslCleanup(&render_spu.GlobalShaders);
+ renderspuCtxInfoRestoreCurrent(&Info);
+ }
+ else
+ WARN(("renderspuCtxSetCurrentWithAnyWindow failed!"));
+ }
+ }
+ else
+ {
+ CRASSERT(!CrGlslNeedsCleanup(&render_spu.GlobalShaders));
+ }
+
+ CRASSERT(!CrGlslNeedsCleanup(&render_spu.GlobalShaders));
+
+ if (toContext)
+ {
+ CR_RENDER_CTX_INFO Info;
+ if (renderspuCtxSetCurrentWithAnyWindow(toContext, &Info))
+ {
+ int rc = CrGlslProgGenAllNoAlpha(&render_spu.GlobalShaders);
+ if (!RT_SUCCESS(rc))
+ WARN(("CrGlslProgGenAllNoAlpha failed, rc %d", rc));
+
+ renderspuCtxInfoRestoreCurrent(&Info);
+ }
+ else
+ crWarning("renderspuCtxSetCurrentWithAnyWindow failed!");
+ }
+}
+
+AssertCompile(sizeof (GLhandleARB) == sizeof (void*));
+
+static VBoxGLhandleARB crHndlSearchVBox(GLhandleARB hNative)
+{
+ CRASSERT(!(((uintptr_t)hNative) >> 32));
+ return (VBoxGLhandleARB)((uintptr_t)hNative);
+}
+
+static GLhandleARB crHndlSearchNative(VBoxGLhandleARB hVBox)
+{
+ return (GLhandleARB)((uintptr_t)hVBox);
+}
+
+static VBoxGLhandleARB crHndlAcquireVBox(GLhandleARB hNative)
+{
+ CRASSERT(!(((uintptr_t)hNative) >> 32));
+ return (VBoxGLhandleARB)((uintptr_t)hNative);
+}
+
+static GLhandleARB crHndlReleaseVBox(VBoxGLhandleARB hVBox)
+{
+ return (GLhandleARB)((uintptr_t)hVBox);
+}
+
+static void SPU_APIENTRY renderspu_SystemDeleteObjectARB(VBoxGLhandleARB obj)
+{
+ GLhandleARB hNative = crHndlReleaseVBox(obj);
+ if (!hNative)
+ {
+ crWarning("no native for %d", obj);
+ return;
+ }
+
+ render_spu.pfnDeleteObject(hNative);
+}
+
+static void SPU_APIENTRY renderspu_SystemGetAttachedObjectsARB( VBoxGLhandleARB containerObj, GLsizei maxCount, GLsizei * pCount, VBoxGLhandleARB * obj )
+{
+ GLhandleARB *paAttachments;
+ GLhandleARB hNative = crHndlSearchNative(containerObj);
+ GLsizei count, i;
+
+ if (pCount)
+ *pCount = 0;
+
+ if (!hNative)
+ {
+ crWarning("no native for %d", obj);
+ return;
+ }
+
+ paAttachments = crCalloc(maxCount * sizeof (*paAttachments));
+ if (!paAttachments)
+ {
+ crWarning("crCalloc failed");
+ return;
+ }
+
+ render_spu.pfnGetAttachedObjects(hNative, maxCount, &count, paAttachments);
+ if (pCount)
+ *pCount = count;
+ if (count > maxCount)
+ {
+ crWarning("count too big");
+ count = maxCount;
+ }
+
+ for (i = 0; i < count; ++i)
+ {
+ obj[i] = crHndlSearchVBox(paAttachments[i]);
+ CRASSERT(obj[i]);
+ }
+
+ crFree(paAttachments);
+}
+
+static VBoxGLhandleARB SPU_APIENTRY renderspu_SystemGetHandleARB(GLenum pname)
+{
+ GLhandleARB hNative = render_spu.pfnGetHandle(pname);
+ VBoxGLhandleARB hVBox;
+ if (!hNative)
+ {
+ crWarning("pfnGetHandle failed");
+ return 0;
+ }
+ hVBox = crHndlAcquireVBox(hNative);
+ CRASSERT(hVBox);
+ return hVBox;
+}
+
+static void SPU_APIENTRY renderspu_SystemGetInfoLogARB( VBoxGLhandleARB obj, GLsizei maxLength, GLsizei * length, GLcharARB * infoLog )
+{
+ GLhandleARB hNative = crHndlSearchNative(obj);
+ if (!hNative)
+ {
+ crWarning("invalid handle!");
+ return;
+ }
+
+ render_spu.pfnGetInfoLog(hNative, maxLength, length, infoLog);
+}
+
+static void SPU_APIENTRY renderspu_SystemGetObjectParameterfvARB( VBoxGLhandleARB obj, GLenum pname, GLfloat * params )
+{
+ GLhandleARB hNative = crHndlSearchNative(obj);
+ if (!hNative)
+ {
+ crWarning("invalid handle!");
+ return;
+ }
+
+ render_spu.pfnGetObjectParameterfv(hNative, pname, params);
+}
+
+static void SPU_APIENTRY renderspu_SystemGetObjectParameterivARB( VBoxGLhandleARB obj, GLenum pname, GLint * params )
+{
+ GLhandleARB hNative = crHndlSearchNative(obj);
+ if (!hNative)
+ {
+ crWarning("invalid handle!");
+ return;
+ }
+
+ render_spu.pfnGetObjectParameteriv(hNative, pname, params);
+}
+
+uint32_t renderspu_SystemPostprocessFunctions(SPUNamedFunctionTable *aFunctions, uint32_t cFunctions, uint32_t cTable)
+{
+ SPUNamedFunctionTable * pEntry;
+
+ pEntry = renderspuFindEntry(aFunctions, "DeleteObjectARB");
+ if (pEntry)
+ {
+ render_spu.pfnDeleteObject = (PFNDELETE_OBJECT)pEntry->fn;
+ pEntry->fn = (SPUGenericFunction)renderspu_SystemDeleteObjectARB;
+ }
+
+ pEntry = renderspuFindEntry(aFunctions, "GetAttachedObjectsARB");
+ if (pEntry)
+ {
+ render_spu.pfnGetAttachedObjects = (PFNGET_ATTACHED_OBJECTS)pEntry->fn;
+ pEntry->fn = (SPUGenericFunction)renderspu_SystemGetAttachedObjectsARB;
+ }
+
+ pEntry = renderspuFindEntry(aFunctions, "GetHandleARB");
+ if (pEntry)
+ {
+ render_spu.pfnGetHandle = (PFNGET_HANDLE)pEntry->fn;
+ pEntry->fn = (SPUGenericFunction)renderspu_SystemGetHandleARB;
+ }
+
+ pEntry = renderspuFindEntry(aFunctions, "GetInfoLogARB");
+ if (pEntry)
+ {
+ render_spu.pfnGetInfoLog = (PFNGET_INFO_LOG)pEntry->fn;
+ pEntry->fn = (SPUGenericFunction)renderspu_SystemGetInfoLogARB;
+ }
+
+ pEntry = renderspuFindEntry(aFunctions, "GetObjectParameterfvARB");
+ if (pEntry)
+ {
+ render_spu.pfnGetObjectParameterfv = (PFNGET_OBJECT_PARAMETERFV)pEntry->fn;
+ pEntry->fn = (SPUGenericFunction)renderspu_SystemGetObjectParameterfvARB;
+ }
+
+ pEntry = renderspuFindEntry(aFunctions, "GetObjectParameterivARB");
+ if (pEntry)
+ {
+ render_spu.pfnGetObjectParameteriv = (PFNGET_OBJECT_PARAMETERIV)pEntry->fn;
+ pEntry->fn = (SPUGenericFunction)renderspu_SystemGetObjectParameterivARB;
+ }
+
+ return cFunctions;
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa_helper.h b/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa_helper.h
new file mode 100644
index 00000000..11333083
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa_helper.h
@@ -0,0 +1,65 @@
+/* $Id: renderspu_cocoa_helper.h $ */
+/** @file
+ * VirtualBox OpenGL Cocoa Window System Helper definition
+ */
+
+/*
+ * Copyright (C) 2009-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef ___renderspu_cocoa_helper_h
+#define ___renderspu_cocoa_helper_h
+
+#include <iprt/cdefs.h>
+#include <VBox/VBoxCocoa.h>
+#include <OpenGL/OpenGL.h>
+#ifdef IN_VMSVGA3D
+# include "../../../GuestHost/OpenGL/include/cr_vreg.h"
+# include "../../../GuestHost/OpenGL/include/cr_compositor.h"
+#else
+# include <cr_vreg.h>
+# include <cr_compositor.h>
+#endif
+
+
+RT_C_DECLS_BEGIN
+
+struct WindowInfo;
+
+ADD_COCOA_NATIVE_REF(NSView);
+ADD_COCOA_NATIVE_REF(NSOpenGLContext);
+
+/** @name OpenGL context management
+ * @{ */
+void cocoaGLCtxCreate(NativeNSOpenGLContextRef *ppCtx, GLbitfield fVisParams, NativeNSOpenGLContextRef pSharedCtx);
+void cocoaGLCtxDestroy(NativeNSOpenGLContextRef pCtx);
+/** @} */
+
+/** @name View management
+ * @{ */
+void cocoaViewCreate(NativeNSViewRef *ppView, struct WindowInfo *pWinInfo, NativeNSViewRef pParentView, GLbitfield fVisParams);
+void cocoaViewReparent(NativeNSViewRef pView, NativeNSViewRef pParentView);
+void cocoaViewDestroy(NativeNSViewRef pView);
+void cocoaViewDisplay(NativeNSViewRef pView);
+void cocoaViewShow(NativeNSViewRef pView, GLboolean fShowIt);
+void cocoaViewSetPosition(NativeNSViewRef pView, NativeNSViewRef pParentView, int x, int y);
+void cocoaViewSetSize(NativeNSViewRef pView, int cx, int cy);
+void cocoaViewGetGeometry(NativeNSViewRef pView, int *px, int *py, int *pcx, int *pcy);
+void cocoaViewMakeCurrentContext(NativeNSViewRef pView, NativeNSOpenGLContextRef pCtx);
+void cocoaViewSetVisibleRegion(NativeNSViewRef pView, GLint cRects, const GLint *paRects);
+GLboolean cocoaViewNeedsEmptyPresent(NativeNSViewRef pView);
+void cocoaViewPresentComposition(NativeNSViewRef pView, const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pChangedEntry);
+/** @} */
+
+RT_C_DECLS_END
+
+#endif /* !___renderspu_cocoa_helper_h */
+
diff --git a/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa_helper.m b/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa_helper.m
new file mode 100644
index 00000000..6c643f9c
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa_helper.m
@@ -0,0 +1,3283 @@
+/* $Id: renderspu_cocoa_helper.m $ */
+/** @file
+ * VirtualBox OpenGL Cocoa Window System Helper Implementation.
+ *
+ * This source file is shared between the SharedOpenGL HGCM service and the
+ * SVGA3d emulation.
+ */
+
+/*
+ * Copyright (C) 2009-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/** @page pg_opengl_cocoa OpenGL - Cocoa Window System Helper
+ *
+ * How this works:
+ * In general it is not so easy like on the other platforms, cause Cocoa
+ * doesn't support any clipping of already painted stuff. In Mac OS X there is
+ * the concept of translucent canvas's e.g. windows and there it is just
+ * painted what should be visible to the user. Unfortunately this isn't the
+ * concept of chromium. Therefor I reroute all OpenGL operation from the guest
+ * to a frame buffer object (FBO). This is a OpenGL extension, which is
+ * supported by all OS X versions we support (AFAIC tell). Of course the guest
+ * doesn't know that and we have to make sure that the OpenGL state always is
+ * in the right state to paint into the FBO and not to the front/back buffer.
+ * Several functions below (like cocoaBindFramebufferEXT, cocoaGetIntegerv,
+ * ...) doing this. When a swap or finish is triggered by the guest, the
+ * content (which is already bound to an texture) is painted on the screen
+ * within a separate OpenGL context. This allows the usage of the same
+ * resources (texture ids, buffers ...) but at the same time having an
+ * different internal OpenGL state. Another advantage is that we can paint a
+ * thumbnail of the current output in a much more smaller (GPU accelerated
+ * scale) version on a third context and use glReadPixels to get the actual
+ * data. glReadPixels is a very slow operation, but as we just use a much more
+ * smaller image, we can handle it (anyway this is only done 5 times per
+ * second).
+ *
+ * Other things to know:
+ * - If the guest request double buffering, we have to make sure there are two
+ * buffers. We use the same FBO with 2 color attachments. Also glDrawBuffer
+ * and glReadBuffer is intercepted to make sure it is painted/read to/from
+ * the correct buffers. On swap our buffers are swapped and not the
+ * front/back buffer.
+ * - If the guest request a depth/stencil buffer, a combined render buffer for
+ * this is created.
+ * - If the size of the guest OpenGL window changes, all FBO's, textures, ...
+ * need to be recreated.
+ * - We need to track any changes to the parent window
+ * (create/destroy/move/resize). The various classes like OverlayHelperView,
+ * OverlayWindow, ... are there for.
+ * - The HGCM service runs on a other thread than the Main GUI. Keeps this
+ * always in mind (see e.g. performSelectorOnMainThread in renderFBOToView)
+ * - We make heavy use of late binding. We can not be sure that the GUI (or any
+ * other third party GUI), overwrite our NSOpenGLContext. So we always ask if
+ * this is our own one, before use. Really neat concept of Objective-C/Cocoa
+ * ;)
+ *
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#ifdef IN_VMSVGA3D
+# define LOG_GROUP LOG_GROUP_DEV_VMSVGA
+#endif
+#include "renderspu_cocoa_helper.h"
+
+#import <Cocoa/Cocoa.h>
+#undef PVM /* sys/param.h (included via Cocoa.h) pollutes the namespace with this define. */
+
+#ifndef IN_VMSVGA3D
+# include "chromium.h" /* For the visual bits of chromium */
+#endif
+
+#include <iprt/assert.h>
+#include <iprt/critsect.h>
+#include <iprt/mem.h>
+#include <iprt/string.h>
+#include <iprt/time.h>
+#include <iprt/thread.h>
+
+#include <VBox/VBoxOGL.h>
+#include <VBox/log.h>
+
+#ifdef IN_VMSVGA3D
+# include "DevVGA-SVGA3d-cocoa.h"
+# include <OpenGL/OpenGL.h>
+# include <OpenGL/gl3.h>
+# include <OpenGL/gl3ext.h>
+# include <OpenGL/glext.h>
+#else
+# include <cr_vreg.h>
+# include <cr_error.h>
+# include <cr_blitter.h>
+# ifdef VBOX_WITH_CRDUMPER_THUMBNAIL
+# include <cr_pixeldata.h>
+# endif
+# include "renderspu.h"
+#endif
+
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+/* Debug macros */
+/** @def FBO
+ * Disable this to see how the output is without the FBO in the middle of the processing chain. */
+#define FBO 1
+/** @def SHOW_WINDOW_BACKGROUND
+ * Define this to see the window background even if the window is clipped. */
+/** @def DEBUG_VERBOSE
+ * Define this to get some debug info about the messages flow. */
+#if 0 || defined(DOXYGEN_RUNNING)
+# define SHOW_WINDOW_BACKGROUND 1
+# define DEBUG_VERBOSE
+#endif
+
+#ifdef DEBUG_VERBOSE
+# error "should be disabled!"
+# ifdef IN_VMSVGA3D
+# define DEBUG_INFO(text) do { LogRel(text); AssertFailed(); } while (0)
+# define DEBUG_WARN(text) do { LogRel(text); AssertFailed(); } while (0)
+# else
+# define DEBUG_INFO(text) do { LogRel(text); AssertFailed(); } while (0)
+# define DEBUG_WARN(text) do { LogRel(text); AssertFailed(); } while (0)
+# endif
+
+# define DEBUG_MSG(text) do { LogRel(text); } while (0)
+# define DEBUG_MSG_1(text) do { LogRel(text); } while (0)
+
+#else
+
+# ifdef IN_VMSVGA3D
+# define DEBUG_INFO(text) do { LogRel(text); } while (0)
+# define DEBUG_WARN(text) do { LogRel(text); } while (0)
+# else
+# define DEBUG_INFO(text) do { crInfo text; } while (0)
+# define DEBUG_WARN(text) do { crWarning text; } while (0)
+#endif
+# define DEBUG_MSG(text) do {} while (0)
+# define DEBUG_MSG_1(text) do {} while (0)
+
+#endif
+#ifdef IN_VMSVGA3D
+# define DEBUG_MSG_NOT_VMSVGA3D(a_TextArgs) do {} while (0)
+# define COCOA_LOG_FLOW(a_TextArgs) LogFlow(a_TextArgs)
+#else
+# define DEBUG_MSG_NOT_VMSVGA3D(a_TextArgs) DEBUG_MSG(a_TextArgs)
+# define COCOA_LOG_FLOW(a_TextArgs) DEBUG_MSG(a_TextArgs)
+#endif
+
+
+#define DEBUG_FUNC_ENTER() DEBUG_MSG(("==>%s\n", __PRETTY_FUNCTION__))
+#define DEBUG_FUNC_LEAVE() DEBUG_MSG(("<==%s\n", __PRETTY_FUNCTION__))
+
+#define DEBUG_GL_SAVE_STATE() \
+ do { \
+ glPushAttrib(GL_ALL_ATTRIB_BITS); \
+ glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS); \
+ glMatrixMode(GL_PROJECTION); \
+ glPushMatrix(); \
+ glMatrixMode(GL_TEXTURE); \
+ glPushMatrix(); \
+ glMatrixMode(GL_COLOR); \
+ glPushMatrix(); \
+ glMatrixMode(GL_MODELVIEW); \
+ glPushMatrix(); \
+ } while (0)
+
+#define DEBUG_GL_RESTORE_STATE() \
+ do { \
+ glMatrixMode(GL_MODELVIEW); \
+ glPopMatrix(); \
+ glMatrixMode(GL_COLOR); \
+ glPopMatrix(); \
+ glMatrixMode(GL_TEXTURE); \
+ glPopMatrix(); \
+ glMatrixMode(GL_PROJECTION); \
+ glPopMatrix(); \
+ glPopClientAttrib(); \
+ glPopAttrib(); \
+ } while (0)
+
+#ifdef VBOX_STRICT
+# define DEBUG_CLEAR_GL_ERRORS() \
+ do { \
+ while (glGetError() != GL_NO_ERROR) \
+ { /* nothing */ } \
+ } while (0)
+# define DEBUG_CHECK_GL_ERROR(a_szOp) \
+ do { \
+ GLenum iGlCheckErr = glGetError(); \
+ if (RT_UNLIKELY(iGlCheckErr != GL_NO_ERROR)) \
+ AssertMsgFailed((a_szOp ": iGlCheckErr=%#x\n", iGlCheckErr)); \
+ } while (0)
+#else
+# define DEBUG_CLEAR_GL_ERRORS() do {} while (0)
+# define DEBUG_CHECK_GL_ERROR(a_szOp) do {} while (0)
+#endif
+
+/* Whether we control NSView automatic content zooming on Retina/HiDPI displays. */
+#define VBOX_WITH_CONFIGURABLE_HIDPI_SCALING 1
+
+
+#ifdef IN_VMSVGA3D
+
+/*
+ * VMSVGA3D compatibility glue.
+ */
+typedef struct WindowInfo WindowInfo;
+
+# define CR_RGB_BIT RT_BIT_32(0)
+
+# define CR_ALPHA_BIT RT_BIT_32(1)
+# define CR_DEPTH_BIT RT_BIT_32(2)
+# define CR_STENCIL_BIT RT_BIT_32(3)
+# define CR_ACCUM_BIT RT_BIT_32(4)
+# define CR_DOUBLE_BIT RT_BIT_32(5)
+# define CR_STEREO_BIT RT_BIT_32(6)
+# define CR_MULTISAMPLE_BIT RT_BIT_32(7)
+
+# define CR_OVERLAY_BIT RT_BIT_32(8)
+# define CR_PBUFFER_BIT RT_BIT_32(9)
+# define VMSVGA3D_NON_DEFAULT_PROFILE_BIT RT_BIT_32(31)
+# define CR_ALL_BITS UINT32_C(0x800003ff)
+
+#endif /* IN_VMSVGA3D */
+
+
+/**
+ * Works functions that creates a NSOpenGLPixelFormat instance.
+ *
+ * @returns Instance.
+ * @param fVisParams Context flags.
+ */
+static NSOpenGLPixelFormat *vboxCreatePixelFormat(GLbitfield fVisParams)
+{
+ NSOpenGLPixelFormatAttribute attribs[24] =
+ {
+#ifdef IN_VMSVGA3D
+ NSOpenGLPFAOpenGLProfile, (NSOpenGLPixelFormatAttribute)0,
+#endif
+ NSOpenGLPFAAccelerated,
+ NSOpenGLPFAColorSize, (NSOpenGLPixelFormatAttribute)24
+ };
+#ifndef IN_VMSVGA3D
+ int i = 3;
+#else
+ int i = 3+2;
+ if (fVisParams & VMSVGA3D_NON_DEFAULT_PROFILE_BIT)
+ attribs[1] = VBOX_VMSVGA3D_DEFAULT_OGL_PROFILE >= 3.2 ? NSOpenGLProfileVersionLegacy : NSOpenGLProfileVersion3_2Core;
+ else
+ attribs[1] = VBOX_VMSVGA3D_DEFAULT_OGL_PROFILE >= 3.2 ? NSOpenGLProfileVersion3_2Core : NSOpenGLProfileVersionLegacy;
+#endif
+
+ if (fVisParams & CR_ALPHA_BIT)
+ {
+ COCOA_LOG_FLOW((" CR_ALPHA_BIT requested\n"));
+ attribs[i++] = NSOpenGLPFAAlphaSize;
+ attribs[i++] = 8;
+ }
+ if (fVisParams & CR_DEPTH_BIT)
+ {
+ COCOA_LOG_FLOW((" CR_DEPTH_BIT requested\n"));
+ attribs[i++] = NSOpenGLPFADepthSize;
+ attribs[i++] = 24;
+ }
+ if (fVisParams & CR_STENCIL_BIT)
+ {
+ COCOA_LOG_FLOW((" CR_STENCIL_BIT requested\n"));
+ attribs[i++] = NSOpenGLPFAStencilSize;
+ attribs[i++] = 8;
+ }
+ if (fVisParams & CR_ACCUM_BIT)
+ {
+ COCOA_LOG_FLOW((" CR_ACCUM_BIT requested\n"));
+ attribs[i++] = NSOpenGLPFAAccumSize;
+ if (fVisParams & CR_ALPHA_BIT)
+ attribs[i++] = 32;
+ else
+ attribs[i++] = 24;
+ }
+ if (fVisParams & CR_MULTISAMPLE_BIT)
+ {
+ COCOA_LOG_FLOW((" CR_MULTISAMPLE_BIT requested\n"));
+ attribs[i++] = NSOpenGLPFASampleBuffers;
+ attribs[i++] = 1;
+ attribs[i++] = NSOpenGLPFASamples;
+ attribs[i++] = 4;
+ }
+ if (fVisParams & CR_DOUBLE_BIT)
+ {
+ COCOA_LOG_FLOW((" CR_DOUBLE_BIT requested\n"));
+ attribs[i++] = NSOpenGLPFADoubleBuffer;
+ }
+ if (fVisParams & CR_STEREO_BIT)
+ {
+ /* We don't support that.
+ COCOA_LOG_FLOW((" CR_STEREO_BIT requested\n"));
+ attribs[i++] = NSOpenGLPFAStereo;
+ */
+ }
+
+ if (VBoxOglIsOfflineRenderingAppropriate())
+ {
+ COCOA_LOG_FLOW((" Offline rendering is enabled\n"));
+ attribs[i++] = NSOpenGLPFAAllowOfflineRenderers;
+ }
+
+ /* Mark the end */
+ attribs[i++] = 0;
+
+ /* Instantiate the pixel format object. */
+ return [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
+}
+
+
+static NSOpenGLContext *vboxCtxGetCurrent(void)
+{
+#ifdef IN_VMSVGA3D
+ return [NSOpenGLContext currentContext];
+#else
+ GET_CONTEXT(pCtxInfo);
+ if (pCtxInfo)
+ {
+ Assert(pCtxInfo->context);
+ return pCtxInfo->context;
+ }
+ return nil;
+#endif
+}
+
+static bool vboxCtxSyncCurrentInfo(void)
+{
+#ifdef IN_VMSVGA3D
+ return false;
+#else
+ bool fAdjusted = false;
+ GET_CONTEXT(pCtxInfo);
+ NSOpenGLContext *pCtx = [NSOpenGLContext currentContext];
+ NSView *pView = pCtx ? [pCtx view] : nil;
+ if (pCtxInfo)
+ {
+ WindowInfo *pWinInfo = pCtxInfo->currentWindow;
+ Assert(pWinInfo);
+ if ( pCtxInfo->context != pCtx
+ || pWinInfo->window != pView)
+ {
+ renderspu_SystemMakeCurrent(pWinInfo, 0, pCtxInfo);
+ fAdjusted = true;
+ }
+ }
+ else if (pCtx)
+ {
+ [NSOpenGLContext clearCurrentContext];
+ fAdjusted = true;
+ }
+
+ return fAdjusted;
+#endif
+}
+
+
+/**
+ * State carrying structure for use with vboxCtxEnter and vboxCtxLeave
+ */
+typedef struct VBOX_CR_RENDER_CTX_INFO
+{
+ bool fIsValid;
+ NSOpenGLContext *pCtx;
+ NSView *pView;
+} VBOX_CR_RENDER_CTX_INFO;
+/** Pointer to render context info for use with vboxCtxEnter/Leave. */
+typedef VBOX_CR_RENDER_CTX_INFO *PVBOX_CR_RENDER_CTX_INFO;
+
+static void vboxCtxEnter(NSOpenGLContext *pNewCtx, PVBOX_CR_RENDER_CTX_INFO pCtxInfo)
+{
+ NSOpenGLContext *pOldCtx = vboxCtxGetCurrent();
+ NSView *pOldView = pOldCtx ? [pOldCtx view] : nil;
+ NSView *pNewView = [pNewCtx view];
+
+ Assert(pNewCtx);
+
+ if ( pOldCtx != pNewCtx
+ || pOldView != pNewView)
+ {
+ if (pOldCtx != nil)
+ glFlush();
+
+ DEBUG_CLEAR_GL_ERRORS();
+ [pNewCtx makeCurrentContext];
+ DEBUG_CHECK_GL_ERROR("makeCurrentContext");
+
+ pCtxInfo->fIsValid = true;
+ pCtxInfo->pCtx = pOldCtx;
+ /** @todo r=bird: Why do we save the NEW VIEW here? vboxCtxLeave calls it 'pOldView'. Bug? */
+ pCtxInfo->pView = pNewView;
+ }
+ else
+ {
+ /* No context switch necessary. */
+ pCtxInfo->fIsValid = false;
+ }
+}
+
+static void vboxCtxLeave(PVBOX_CR_RENDER_CTX_INFO pCtxInfo)
+{
+ if (pCtxInfo->fIsValid)
+ {
+ NSOpenGLContext *pOldCtx = pCtxInfo->pCtx;
+ NSView *pOldView = pCtxInfo->pView;
+
+ glFlush();
+ if (pOldCtx != nil)
+ {
+ /* vboxCtxEnter saves the new view, not the old. So, what we actually
+ do here is switching the view of the old context to that of the new
+ one (wrt vboxCtxEnter) before making it current. */
+ /** @todo r=bird: Figure out what we really want to do here, and either rename
+ * pOldView or fix the code. */
+ if ([pOldCtx view] != pOldView)
+ {
+ DEBUG_CLEAR_GL_ERRORS();
+ [pOldCtx setView: pOldView];
+ DEBUG_CHECK_GL_ERROR("setView");
+ }
+
+ DEBUG_CLEAR_GL_ERRORS();
+ [pOldCtx makeCurrentContext];
+ DEBUG_CHECK_GL_ERROR("makeCurrentContext");
+
+#ifdef VBOX_STRICT
+ {
+ NSOpenGLContext *pTstOldCtx = [NSOpenGLContext currentContext];
+ NSView *pTstOldView = pTstOldCtx ? [pTstOldCtx view] : nil;
+ Assert(pTstOldCtx == pOldCtx);
+ Assert(pTstOldView == pOldView);
+ }
+#endif
+ }
+ else
+ {
+ [NSOpenGLContext clearCurrentContext];
+ }
+ }
+}
+
+
+/**
+ * Custom OpenGL context class.
+ *
+ * This implementation doesn't allow to set a view to the context, but save the
+ * view for later use. Also it saves a copy of the pixel format used to create
+ * that context for later use.
+ */
+@interface OverlayOpenGLContext: NSOpenGLContext
+{
+@private
+ NSOpenGLPixelFormat *m_pPixelFormat;
+ NSView *m_pView;
+}
+- (NSOpenGLPixelFormat *)openGLPixelFormat;
+@end
+
+/**
+ * Abstrack task class.
+ */
+@interface VBoxTask : NSObject
+{
+}
+- (void)run;
+@end
+
+@implementation VBoxTask
+/** Run method that the child classes must reimplement.
+ * This will abort the process. */
+- (void)run
+{
+ AssertReleaseFailed();
+}
+@end
+
+
+/**
+ * Generic task class for executing a given method select.
+ */
+@interface VBoxTaskPerformSelector : VBoxTask
+{
+@private
+ id m_Object;
+ SEL m_Selector;
+ id m_Arg;
+}
+- (id)initWithObject:(id)aObject selector:(SEL)aSelector arg:(id)aArg;
+- (void)run;
+- (void)dealloc;
+@end
+
+@implementation VBoxTaskPerformSelector
+
+/**
+ * Initializes a VBoxTaskPerformSelector.
+ *
+ * @param aObject The object (reference not consumed).
+ * @param aSelector The method selector.
+ * @param aArg The method argument (reference not consumed).
+ */
+- (id)initWithObject:(id)aObject selector:(SEL)aSelector arg:(id)aArg
+{
+ self = [super init];
+ if (self)
+ {
+ [aObject retain];
+ m_Object = aObject;
+ m_Selector = aSelector;
+ if (aArg != nil)
+ [aArg retain];
+ m_Arg = aArg;
+ }
+
+ return self;
+}
+
+- (void)run
+{
+ [m_Object performSelector:m_Selector withObject:m_Arg];
+}
+
+- (void)dealloc
+{
+ [m_Object release];
+ if (m_Arg != nil)
+ [m_Arg release];
+
+ [super dealloc];
+}
+@end
+
+
+/**
+ *
+ */
+@interface VBoxTaskComposite : VBoxTask
+{
+@private
+ NSUInteger m_CurIndex;
+ RTCRITSECT m_Lock;
+ NSMutableArray *m_pArray;
+}
+- (id)init;
+- (void)add:(VBoxTask *)pTask;
+- (void)run;
+- (void)dealloc;
+@end
+
+@implementation VBoxTaskComposite
+- (id)init
+{
+ self = [super init];
+
+ if (self)
+ {
+ int rc = RTCritSectInit(&m_Lock);
+ if (!RT_SUCCESS(rc))
+ {
+ DEBUG_WARN(("RTCritSectInit failed %d\n", rc));
+ return nil;
+ }
+
+ m_CurIndex = 0;
+
+ m_pArray = [[NSMutableArray alloc] init];
+ }
+
+ return self;
+}
+
+/**
+ * Adds a task to the composite task object.
+ *
+ * @param pTask Task to add. Reference is NOT consumed.
+ */
+- (void)add:(VBoxTask *)pTask
+{
+ [pTask retain];
+ int rc = RTCritSectEnter(&m_Lock);
+ if (RT_SUCCESS(rc))
+ {
+ [m_pArray addObject:pTask];
+ RTCritSectLeave(&m_Lock);
+ }
+ else
+ {
+ DEBUG_WARN(("RTCritSectEnter failed %d\n", rc));
+ [pTask release];
+ }
+}
+
+- (void)run
+{
+ for (;;)
+ {
+ /*
+ * Dequeue a task.
+ */
+ int rc = RTCritSectEnter(&m_Lock);
+ if (RT_FAILURE(rc))
+ {
+ DEBUG_WARN(("RTCritSectEnter failed %d\n", rc));
+ break;
+ }
+
+ NSUInteger count = [m_pArray count];
+ Assert(m_CurIndex <= count);
+ if (m_CurIndex == count)
+ {
+ [m_pArray removeAllObjects];
+ m_CurIndex = 0;
+ RTCritSectLeave(&m_Lock);
+ break;
+ }
+
+ VBoxTask *pTask = (VBoxTask *)[m_pArray objectAtIndex:m_CurIndex];
+ Assert(pTask != nil);
+
+ ++m_CurIndex;
+
+ /*
+ * Remove the first 1025 empty entires.
+ */
+ if (m_CurIndex > 1024)
+ {
+ NSRange range;
+ range.location = 0;
+ range.length = m_CurIndex;
+ [m_pArray removeObjectsInRange:range];
+ m_CurIndex = 0;
+ }
+ RTCritSectLeave(&m_Lock);
+
+ /*
+ * Run the task and release it.
+ */
+ [pTask run];
+ [pTask release];
+ }
+}
+
+- (void)dealloc
+{
+ NSUInteger count = [m_pArray count];
+ for (;m_CurIndex < count; ++m_CurIndex)
+ {
+ VBoxTask *pTask = (VBoxTask*)[m_pArray objectAtIndex:m_CurIndex];
+ DEBUG_WARN(("dealloc with non-empty tasks! %p\n", pTask));
+ [pTask release];
+ }
+
+ [m_pArray release];
+ RTCritSectDelete(&m_Lock);
+
+ [super dealloc];
+}
+@end
+
+
+/**
+ *
+ *
+ */
+@interface VBoxMainThreadTaskRunner : NSObject
+{
+@private
+ VBoxTaskComposite *m_pTasks;
+}
+- (id)init;
+- (void)add:(VBoxTask *)pTask;
+- (void)addObj:(id)aObject selector:(SEL)aSelector arg:(id)aArg;
+- (void)runTasks;
+- (bool)runTasksSyncIfPossible;
+- (void)dealloc;
++ (VBoxMainThreadTaskRunner *) globalInstance;
+@end
+
+@implementation VBoxMainThreadTaskRunner
+- (id)init
+{
+ self = [super init];
+ if (self)
+ {
+ m_pTasks = [[VBoxTaskComposite alloc] init];
+ }
+
+ return self;
+}
+
++ (VBoxMainThreadTaskRunner *) globalInstance
+{
+ static dispatch_once_t s_DispatchOnce;
+ static VBoxMainThreadTaskRunner *s_pRunner = nil;
+ dispatch_once(&s_DispatchOnce, ^{
+ s_pRunner = [[VBoxMainThreadTaskRunner alloc] init];
+ });
+ return s_pRunner;
+}
+
+- (void)add:(VBoxTask *)pTask
+{
+ DEBUG_FUNC_ENTER();
+ [m_pTasks add:pTask];
+ /** @todo r=bird: Unbalanced [self retain]. */
+ [self retain];
+
+ if (![self runTasksSyncIfPossible])
+ {
+ DEBUG_MSG(("task will be processed async\n"));
+ [self performSelectorOnMainThread:@selector(runTasks) withObject:nil waitUntilDone:NO];
+ }
+
+ DEBUG_FUNC_LEAVE();
+}
+
+/**
+ * Adds a task calling an object method (selector).
+ *
+ * @param aObject The object (reference not consumed)..
+ * @param aSelector The method selector.
+ * @param aArg The method argument (reference not consumed).
+ */
+- (void)addObj:(id)aObject selector:(SEL)aSelector arg:(id)aArg
+{
+ VBoxTaskPerformSelector *pSelTask = [[VBoxTaskPerformSelector alloc] initWithObject:aObject selector:aSelector arg:aArg];
+ [self add:pSelTask];
+ [pSelTask release];
+}
+
+
+/**
+ * Internal method for running the pending tasks.
+ */
+- (void)runTasks
+{
+ if ([NSThread isMainThread])
+ {
+ [m_pTasks run];
+ /** @todo r=bird: This release and the retain in the add method aren't
+ * necessarily balanced if there are more than one call to add().
+ *
+ * This could probably end up deleting the singleton prematurely and leave
+ * globalInstance() returning pointers to a stale object in freed memory,
+ * quite possibly causing crashes or/and heap corruption. */
+ [self release];
+ }
+ else
+ {
+ DEBUG_WARN(("run tasks called not on main thread!\n"));
+#ifndef DEBUG_VERBOSE
+ AssertFailed();
+#endif
+ [self performSelectorOnMainThread:@selector(runTasks) withObject:nil waitUntilDone:YES];
+ }
+}
+
+/**
+ * Callback for calling runTasks via renderspuCalloutClient.
+ * @param pvUser The VBoxMainThreadTaskRunner singleton.
+ */
+static DECLCALLBACK(void) VBoxMainThreadTaskRunner_RcdRunCallback(void *pvUser)
+{
+ DEBUG_FUNC_ENTER();
+ VBoxMainThreadTaskRunner *pRunner = (VBoxMainThreadTaskRunner *)pvUser;
+ Assert(pRunner == [VBoxMainThreadTaskRunner globalInstance]);
+ [pRunner runTasks];
+ DEBUG_FUNC_LEAVE();
+}
+
+/**
+ * Runs pending tasks synchronously, if possible in the current context.
+ *
+ * @returns true if executed tasks, false if not possible.
+ */
+- (bool)runTasksSyncIfPossible
+{
+#ifndef IN_VMSVGA3D
+ /*
+ * Call on main thread (?) via renderspuCalloutClient (whatever that is).
+ */
+ if (renderspuCalloutAvailable())
+ {
+ Assert(![NSThread isMainThread]);
+ renderspuCalloutClient(VBoxMainThreadTaskRunner_RcdRunCallback, self);
+ return true;
+ }
+#endif
+
+ /*
+ * Run directly if on main thread.
+ */
+ if ([NSThread isMainThread])
+ {
+ [self runTasks];
+ return true;
+ }
+
+ /* Not possible. */
+ return false;
+}
+
+- (void)dealloc
+{
+ /** @todo r=bird: WTF is the point of the deallocator. The object is a singelton
+ * stored in an inaccessible static variable! */
+ [m_pTasks release];
+ m_pTasks = nil;
+
+ [super dealloc];
+}
+
+@end
+
+#ifndef IN_VMSVGA3D
+@class DockOverlayView;
+#endif
+
+/**
+ * The custom view class.
+ *
+ * This is the main class of the cocoa OpenGL implementation. It manages a
+ * frame buffer object for the rendering of the guest applications. The guest
+ * applications render in this frame buffer which is bound to an OpenGL texture.
+ * To display the guest content, a secondary shared OpenGL context of the main
+ * OpenGL context is created. The secondary context is marked as non-opaque and
+ * the texture is displayed on an object which is composed out of the several
+ * visible region rectangles.
+ */
+@interface OverlayView : NSView
+{
+@private
+ NSView *m_pParentView;
+ NSWindow *m_pOverlayWin;
+
+ NSOpenGLContext *m_pGLCtx;
+ NSOpenGLContext *m_pSharedGLCtx;
+ RTTHREAD m_Thread;
+
+ GLuint m_FBOId;
+
+#ifndef IN_VMSVGA3D
+ /** The corresponding dock tile view of this OpenGL view & all helper
+ * members. */
+ DockOverlayView *m_DockTileView;
+
+ GLfloat m_FBOThumbScaleX;
+ GLfloat m_FBOThumbScaleY;
+ uint64_t m_msDockUpdateTS;
+#endif
+
+ /** @name For clipping
+ * @remarks appears to be unused and a complete waste of time + heap.
+ * @{ */
+ GLint m_cClipRects;
+ GLint *m_paClipRects;
+ /** @} */
+
+ /** @name Position/Size tracking
+ * @{ */
+ NSPoint m_Pos;
+ NSSize m_Size;
+ /** @} */
+
+ /** This is necessary for clipping on the root window */
+ NSRect m_RootRect;
+ float m_yInvRootOffset;
+
+#ifndef IN_VMSVGA3D
+ CR_BLITTER *m_pBlitter;
+ WindowInfo *m_pWinInfo;
+#endif
+ bool m_fNeedViewportUpdate;
+ bool m_fNeedCtxUpdate;
+ bool m_fDataVisible;
+ bool m_fCleanupNeeded;
+ bool m_fEverSized;
+}
+- (id)initWithFrame:(NSRect)frame thread:(RTTHREAD)aThread parentView:(NSView *)pParentView winInfo:(WindowInfo *)pWinInfo
+ fVisParams:(GLbitfield) fVisParams;
+- (void)setGLCtx:(NSOpenGLContext*)pCtx;
+- (NSOpenGLContext *)glCtx;
+
+- (void)setParentView: (NSView *)view;
+- (NSView *)parentView;
+- (void)setOverlayWin: (NSWindow *)win;
+- (NSWindow *)overlayWin;
+
+- (void)vboxSetPos:(NSPoint)pos;
+- (void)vboxSetPosUI:(NSPoint)pos;
+- (void)vboxSetPosUIObj:(NSValue *)pPos;
+- (NSPoint)pos;
+- (bool)isEverSized;
+- (void)vboxDestroy;
+- (void)vboxSetSizeUI:(NSSize)size;
+- (void)vboxSetSizeUIObj:(NSValue *)pSize;
+- (void)vboxSetSize:(NSSize)size;
+- (NSSize)size;
+- (void)updateViewportCS;
+#ifdef VBOX_WITH_CONFIGURABLE_HIDPI_SCALING
+- (NSRect)safeConvertRectToBacking:(NSRect *)pRect;
+- (CGFloat)safeGetBackingScaleFactor;
+#endif
+- (NSRect)safeConvertToScreen:(NSRect *)pRect;
+- (void)vboxReshapePerform;
+- (void)vboxReshapeOnResizePerform;
+- (void)vboxReshapeOnReparentPerform;
+
+#ifndef IN_VMSVGA3D
+- (void)createDockTile;
+- (void)deleteDockTile;
+#endif
+
+- (void)makeCurrentFBO;
+- (void)swapFBO;
+- (void)vboxSetVisible:(GLboolean)fVisible;
+- (void)vboxSetVisibleUIObj:(NSNumber *)pVisible;
+- (void)vboxSetVisibleUI:(GLboolean)fVisible;
+- (void)vboxTryDraw;
+- (void)vboxTryDrawUI;
+- (void)vboxReparent:(NSView *)pParentView;
+- (void)vboxReparentUI:(NSView *)pParentView;
+- (void)vboxPresent:(const VBOXVR_SCR_COMPOSITOR *)pCompositor;
+- (void)vboxPresentCS:(const VBOXVR_SCR_COMPOSITOR *)pCompositor;
+#ifndef IN_VMSVGA3D
+- (void)vboxPresentToDockTileCS:(const VBOXVR_SCR_COMPOSITOR *)pCompositor;
+#endif
+- (void)vboxPresentToViewCS:(const VBOXVR_SCR_COMPOSITOR *)pCompositor;
+- (void)presentComposition:(const VBOXVR_SCR_COMPOSITOR_ENTRY *)pChangedEntry;
+#ifndef IN_VMSVGA3D
+- (void)vboxBlitterSyncWindow;
+#endif
+
+- (void)clearVisibleRegions;
+- (void)setVisibleRegions:(GLint)cRects paRects:(const GLint *)paRects;
+- (GLboolean)vboxNeedsEmptyPresent;
+
+#ifndef IN_VMSVGA3D
+- (NSView *)dockTileScreen;
+- (void)reshapeDockTile;
+#endif
+- (void)cleanupData;
+@end
+
+/**
+ * Helper view.
+ *
+ * This view is added as a sub view of the parent view to track
+ * main window changes. Whenever the main window is changed
+ * (which happens on fullscreen/seamless entry/exit) the overlay
+ * window is informed & can add them self as a child window
+ * again.
+ */
+@class OverlayWindow;
+@interface OverlayHelperView: NSView
+{
+@private
+ OverlayWindow *m_pOverlayWindow;
+}
+-(id)initWithOverlayWindow:(NSRect)frame overlayWindow:(OverlayWindow *)pOverlayWindow;
+@end
+
+/**
+ * Custom window class.
+ *
+ * This is the overlay window which contains our custom NSView.
+ * Its a direct child of the Qt Main window. It marks its background
+ * transparent & non opaque to make clipping possible. It also disable mouse
+ * events and handle frame change events of the parent view.
+ */
+@interface OverlayWindow : NSWindow
+{
+@private
+ NSView *m_pParentView;
+ OverlayView *m_pOverlayView;
+ OverlayHelperView *m_pOverlayHelperView;
+ NSThread *m_Thread;
+}
+- (id)initWithParentView:(NSView *)pParentView overlayView:(OverlayView *)pOverlayView;
+- (void)parentWindowFrameChanged:(NSNotification *)note;
+- (void)parentWindowChanged:(NSWindow *)pWindow;
+@end
+
+
+#ifndef IN_VMSVGA3D
+/**
+ * Dock overlay view class.
+ */
+@interface DockOverlayView: NSView
+{
+ NSBitmapImageRep *m_ThumbBitmap;
+ NSImage *m_ThumbImage;
+ NSLock *m_Lock;
+}
+- (void)dealloc;
+- (void)cleanup;
+- (void)lock;
+- (void)unlock;
+- (void)setFrame:(NSRect)frame;
+- (void)drawRect:(NSRect)aRect;
+- (NSBitmapImageRep *)thumbBitmap;
+- (NSImage *)thumbImage;
+@end
+
+@implementation DockOverlayView
+- (id)init
+{
+ DEBUG_FUNC_ENTER();
+ self = [super init];
+ if (self)
+ {
+ /*
+ * We need a lock cause the thumb image could be accessed from the main
+ * thread when someone is calling display on the dock tile & from the
+ * OpenGL thread when the thumbnail is updated.
+ */
+ m_Lock = [[NSLock alloc] init];
+ }
+
+ DEBUG_FUNC_LEAVE();
+
+ return self;
+}
+
+- (void)dealloc
+{
+ DEBUG_FUNC_ENTER();
+
+ [self cleanup];
+ [m_Lock release];
+
+ [super dealloc];
+
+ DEBUG_FUNC_LEAVE();
+}
+
+- (void)cleanup
+{
+ DEBUG_FUNC_ENTER();
+
+ if (m_ThumbImage != nil)
+ {
+ [m_ThumbImage release];
+ m_ThumbImage = nil;
+ }
+
+ if (m_ThumbBitmap != nil)
+ {
+ [m_ThumbBitmap release];
+ m_ThumbBitmap = nil;
+ }
+
+ DEBUG_FUNC_LEAVE();
+}
+
+- (void)lock
+{
+ DEBUG_FUNC_ENTER();
+ [m_Lock lock];
+ DEBUG_FUNC_LEAVE();
+}
+
+- (void)unlock
+{
+ DEBUG_FUNC_ENTER();
+ [m_Lock unlock];
+ DEBUG_FUNC_LEAVE();
+}
+
+- (void)setFrame:(NSRect)frame
+{
+ DEBUG_FUNC_ENTER();
+ [super setFrame:frame];
+
+ [self lock];
+ [self cleanup];
+
+ if ( frame.size.width > 0
+ && frame.size.height > 0)
+ {
+ /* Create a buffer for our thumbnail image. Its in the size of this view. */
+ m_ThumbBitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
+ pixelsWide:frame.size.width
+ pixelsHigh:frame.size.height
+ bitsPerSample:8
+ samplesPerPixel:4
+ hasAlpha:YES
+ isPlanar:NO
+ colorSpaceName:NSDeviceRGBColorSpace
+ bitmapFormat:NSAlphaFirstBitmapFormat
+ bytesPerRow:frame.size.width * 4
+ bitsPerPixel:8 * 4
+ ];
+ m_ThumbImage = [[NSImage alloc] initWithSize:[m_ThumbBitmap size]];
+ [m_ThumbImage addRepresentation:m_ThumbBitmap];
+ }
+
+ [self unlock];
+ DEBUG_FUNC_LEAVE();
+}
+
+- (BOOL)isFlipped
+{
+ DEBUG_FUNC_ENTER();
+ DEBUG_FUNC_LEAVE();
+ return YES;
+}
+
+- (void)drawRect:(NSRect)aRect
+{
+ NSRect frame;
+ DEBUG_FUNC_ENTER();
+ [self lock];
+
+#ifdef SHOW_WINDOW_BACKGROUND
+ [[NSColor colorWithCalibratedRed:1.0 green:0.0 blue:0.0 alpha:0.7] set];
+ frame = [self frame];
+ [NSBezierPath fillRect:NSMakeRect(0, 0, frame.size.width, frame.size.height)];
+#endif /* SHOW_WINDOW_BACKGROUND */
+ if (m_ThumbImage != nil)
+ [m_ThumbImage drawAtPoint:NSMakePoint(0, 0) fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
+
+ [self unlock];
+ DEBUG_FUNC_LEAVE();
+}
+
+- (NSBitmapImageRep *)thumbBitmap
+{
+ DEBUG_FUNC_ENTER();
+ DEBUG_FUNC_LEAVE();
+ return m_ThumbBitmap;
+}
+
+- (NSImage *)thumbImage
+{
+ DEBUG_FUNC_ENTER();
+ DEBUG_FUNC_LEAVE();
+ return m_ThumbImage;
+}
+@end
+#endif /* !IN_VMSVGA3D */
+
+
+/********************************************************************************
+*
+* OverlayOpenGLContext class implementation
+*
+********************************************************************************/
+@implementation OverlayOpenGLContext
+
+-(id)initWithFormat:(NSOpenGLPixelFormat *)format shareContext:(NSOpenGLContext *)share
+{
+ DEBUG_FUNC_ENTER();
+
+ m_pPixelFormat = NULL;
+ m_pView = NULL;
+
+ self = [super initWithFormat:format shareContext:share];
+ Assert(self != nil);
+ if (self)
+ m_pPixelFormat = format;
+
+ DEBUG_MSG(("OCTX(%p): init OverlayOpenGLContext\n", (void *)self));
+ DEBUG_FUNC_LEAVE();
+ return self;
+}
+
+- (void)dealloc
+{
+ DEBUG_FUNC_ENTER();
+ DEBUG_MSG(("OCTX(%p): dealloc OverlayOpenGLContext\n", (void *)self));
+
+ [m_pPixelFormat release];
+
+ [super dealloc];
+
+ DEBUG_FUNC_LEAVE();
+}
+
+-(bool)isDoubleBuffer
+{
+ DEBUG_FUNC_ENTER();
+
+ GLint val;
+ [m_pPixelFormat getValues:&val forAttribute:NSOpenGLPFADoubleBuffer forVirtualScreen:0];
+
+ DEBUG_FUNC_LEAVE();
+ return val == GL_TRUE ? YES : NO;
+}
+
+-(void)setView:(NSView *)view
+{
+ DEBUG_FUNC_ENTER();
+ DEBUG_MSG(("OCTX(%p): setView: new view: %p\n", (void *)self, (void *)view));
+
+#if 1 /* def FBO */
+ m_pView = view;;
+#else
+ [super setView: view];
+#endif
+
+ DEBUG_FUNC_LEAVE();
+}
+
+-(NSView *)view
+{
+ DEBUG_FUNC_ENTER();
+ DEBUG_FUNC_LEAVE();
+#if 1 /* def FBO */
+ return m_pView;
+#else
+ return [super view];
+#endif
+}
+
+-(void)clearDrawable
+{
+ DEBUG_FUNC_ENTER();
+ DEBUG_MSG(("OCTX(%p): clearDrawable\n", (void *)self));
+
+ m_pView = NULL;;
+ [super clearDrawable];
+
+ DEBUG_FUNC_LEAVE();
+}
+
+-(NSOpenGLPixelFormat *)openGLPixelFormat
+{
+ DEBUG_FUNC_ENTER();
+ DEBUG_FUNC_LEAVE();
+
+ return m_pPixelFormat;
+}
+
+@end /* @implementation OverlayOpenGLContext */
+
+
+/********************************************************************************
+*
+* OverlayHelperView class implementation
+*
+********************************************************************************/
+@implementation OverlayHelperView
+
+-(id)initWithOverlayWindow:(NSRect)frame overlayWindow:(OverlayWindow *)pOverlayWindow
+{
+ DEBUG_FUNC_ENTER();
+
+ self = [super initWithFrame:frame];
+#ifdef IN_VMSVGA3D
+ self.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
+#endif
+
+ m_pOverlayWindow = pOverlayWindow;
+
+ DEBUG_MSG(("OHVW(%p): init OverlayHelperView\n", (void *)self));
+ DEBUG_FUNC_LEAVE();
+ return self;
+}
+
+-(void)viewDidMoveToWindow
+{
+ DEBUG_FUNC_ENTER();
+ DEBUG_MSG(("OHVW(%p): viewDidMoveToWindow: new win: %p\n", (void *)self, (void *)[self window]));
+
+ [m_pOverlayWindow parentWindowChanged:[self window]];
+
+ DEBUG_FUNC_LEAVE();
+}
+
+@end
+
+
+/********************************************************************************
+*
+* OverlayWindow class implementation
+*
+********************************************************************************/
+@implementation OverlayWindow
+
+- (id)initWithParentView:(NSView *)pParentView overlayView:(OverlayView *)pOverlayView
+{
+ DEBUG_FUNC_ENTER();
+ NSWindow *pParentWin = nil;
+
+ self = [super initWithContentRect:NSZeroRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO];
+ if (self)
+ {
+ m_pParentView = pParentView;
+ m_pOverlayView = pOverlayView;
+ m_Thread = [NSThread currentThread];
+
+ [m_pOverlayView setOverlayWin: self];
+
+#ifdef IN_VMSVGA3D
+ NSRect frame = [pParentView frame];
+ frame.origin.x = frame.origin.x = 0;
+ m_pOverlayHelperView = [[OverlayHelperView alloc] initWithOverlayWindow:frame
+ overlayWindow:self];
+#else
+ m_pOverlayHelperView = [[OverlayHelperView alloc] initWithOverlayWindow:NSZeroRect
+ overlayWindow:self];
+#endif
+
+ /* Add the helper view as a child of the parent view to get notifications */
+ [pParentView addSubview:m_pOverlayHelperView];
+
+ /* Make sure this window is transparent */
+#ifdef SHOW_WINDOW_BACKGROUND
+ /* For debugging */
+ [self setBackgroundColor:[NSColor colorWithCalibratedRed:1.0 green:0.0 blue:0.0 alpha:0.7]];
+#else
+ [self setBackgroundColor:[NSColor clearColor]];
+#endif
+ [self setOpaque:NO];
+ [self setAlphaValue:.999];
+
+ /* Disable mouse events for this window */
+ [self setIgnoresMouseEvents:YES];
+
+ pParentWin = [m_pParentView window];
+
+ /* Initial set the position to the parents view top/left (Compiz fix). */
+ [self setFrameOrigin:
+ [pParentWin convertBaseToScreen:
+ [m_pParentView convertPoint:NSZeroPoint toView:nil]]];
+
+ /* Set the overlay view as our content view */
+ [self setContentView:m_pOverlayView];
+
+ /* Add ourself as a child to the parent views window. Note: this has to
+ * be done last so that everything else is setup in
+ * parentWindowChanged. */
+ [pParentWin addChildWindow:self ordered:NSWindowAbove];
+ }
+
+ DEBUG_MSG(("OWIN(%p): init OverlayWindow\n", (void *)self));
+ DEBUG_FUNC_LEAVE();
+ return self;
+}
+
+- (void)dealloc
+{
+ DEBUG_FUNC_ENTER();
+ DEBUG_MSG(("OWIN(%p): dealloc OverlayWindow\n", (void *)self));
+
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+
+ [m_pOverlayHelperView removeFromSuperview];
+ [m_pOverlayHelperView release];
+
+ [super dealloc];
+
+ DEBUG_FUNC_LEAVE();
+}
+
+- (void)parentWindowFrameChanged:(NSNotification *)pNote
+{
+ DEBUG_FUNC_ENTER();
+ DEBUG_MSG(("OWIN(%p): parentWindowFrameChanged\n", (void *)self));
+
+ /*
+ * Reposition this window with the help of the OverlayView. Perform the
+ * call in the OpenGL thread.
+ */
+ /*
+ [m_pOverlayView performSelector:@selector(vboxReshapePerform) onThread:m_Thread withObject:nil waitUntilDone:YES];
+ */
+
+ if ([m_pOverlayView isEverSized])
+ {
+ if ([NSThread isMainThread])
+ [m_pOverlayView vboxReshapePerform];
+ else
+ [self performSelectorOnMainThread:@selector(vboxReshapePerform) withObject:nil waitUntilDone:NO];
+ }
+
+ DEBUG_FUNC_LEAVE();
+}
+
+- (void)parentWindowChanged:(NSWindow *)pWindow
+{
+ DEBUG_FUNC_ENTER();
+ DEBUG_MSG(("OWIN(%p): parentWindowChanged\n", (void *)self));
+
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+
+ if (pWindow != nil)
+ {
+ /* Ask to get notifications when our parent window frame changes. */
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(parentWindowFrameChanged:)
+ name:NSWindowDidResizeNotification
+ object:pWindow];
+
+ /* Add us self as child window */
+ [pWindow addChildWindow:self ordered:NSWindowAbove];
+
+ /*
+ * Reshape the overlay view after a short waiting time to let the main
+ * window resize itself properly.
+ */
+ /*
+ [m_pOverlayView performSelector:@selector(vboxReshapePerform) withObject:nil afterDelay:0.2];
+ [NSTimer scheduledTimerWithTimeInterval:0.2 target:m_pOverlayView selector:@selector(vboxReshapePerform) userInfo:nil repeats:NO];
+ */
+
+ if ([m_pOverlayView isEverSized])
+ {
+ if ([NSThread isMainThread])
+ [m_pOverlayView vboxReshapePerform];
+ else
+ [self performSelectorOnMainThread:@selector(vboxReshapePerform) withObject:nil waitUntilDone:NO];
+ }
+ }
+
+ DEBUG_FUNC_LEAVE();
+}
+
+@end /* @implementation OverlayWindow */
+
+
+
+/********************************************************************************
+*
+* OverlayView class implementation
+*
+********************************************************************************/
+@implementation OverlayView
+
+- (id)initWithFrame:(NSRect)frame thread:(RTTHREAD)aThread parentView:(NSView *)pParentView winInfo:(WindowInfo *)pWinInfo
+ fVisParams:(GLbitfield) fVisParams
+{
+ COCOA_LOG_FLOW(("%s: self=%p aThread=%p pParentView=%p pWinInfo=%p fVisParams=%#x\n", __PRETTY_FUNCTION__, (void *)self,
+ (void *)aThread, (void *)pParentView, (void *)pWinInfo, fVisParams));
+
+ m_pParentView = pParentView;
+ /* Make some reasonable defaults */
+ m_pGLCtx = nil;
+ m_pSharedGLCtx = nil;
+ m_Thread = aThread;
+ m_FBOId = 0;
+ m_cClipRects = 0;
+ m_paClipRects = NULL;
+ m_Pos = NSZeroPoint;
+ m_Size = NSMakeSize(1, 1);
+ m_RootRect = NSMakeRect(0, 0, m_Size.width, m_Size.height);
+ m_yInvRootOffset = 0;
+#ifndef IN_VMSVGA3D
+ m_pBlitter = nil;
+ m_pWinInfo = pWinInfo;
+#endif
+ m_fNeedViewportUpdate = true;
+ m_fNeedCtxUpdate = true;
+ m_fDataVisible = false;
+ m_fCleanupNeeded = false;
+ m_fEverSized = false;
+
+ self = [super initWithFrame:frame];
+#if defined(VBOX_WITH_CONFIGURABLE_HIDPI_SCALING) && !defined(IN_VMSVGA3D)
+ /* Always allocate HiDPI-ready backing store for NSView, so we will be able change HiDPI scaling option in runtime. */
+ crDebug("HiDPI: Allocate big backing store for NSView. Up-scaling is currently %s.", render_spu.fUnscaledHiDPI ? "OFF" : "ON");
+ [self performSelector:@selector(setWantsBestResolutionOpenGLSurface:) withObject: (id)YES];
+#endif
+
+ COCOA_LOG_FLOW(("%s: returns self=%p\n", __PRETTY_FUNCTION__, (void *)self));
+ return self;
+}
+
+- (void)cleanupData
+{
+ COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
+
+#ifndef IN_VMSVGA3D
+ [self deleteDockTile];
+#endif
+
+ [self setGLCtx:nil];
+
+ if (m_pSharedGLCtx)
+ {
+ if ([m_pSharedGLCtx view] == self)
+ [m_pSharedGLCtx clearDrawable];
+
+ [m_pSharedGLCtx release];
+ m_pSharedGLCtx = nil;
+
+
+#ifndef IN_VMSVGA3D
+ CrBltTerm(m_pBlitter);
+ RTMemFree(m_pBlitter);
+ m_pBlitter = nil;
+#endif
+ }
+
+ [self clearVisibleRegions];
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)dealloc
+{
+ COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
+
+ [self cleanupData];
+ [super dealloc];
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)drawRect:(NSRect)aRect
+{
+ COCOA_LOG_FLOW(("%s: self=%p aRect=%d,%d %d,%d\n", __PRETTY_FUNCTION__, (void *)self, (int)aRect.origin.x, (int)aRect.origin.y,
+ (int)aRect.size.width, (int)aRect.size.height));
+
+ [self vboxTryDrawUI];
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)setGLCtx:(NSOpenGLContext *)pCtx
+{
+ COCOA_LOG_FLOW(("%s: self=%p pCtx=%p (old=%p)\n", __PRETTY_FUNCTION__, (void *)self, (void *)pCtx, m_pGLCtx));
+
+ /*
+ * Only do something if the context changes.
+ */
+ if (m_pGLCtx != pCtx)
+ {
+ /* Ensure the context drawable is cleared to avoid holding a reference to inexistent view. */
+ if (m_pGLCtx)
+ {
+#ifdef IN_VMSVGA3D
+ Assert(!pCtx);
+#endif
+ [m_pGLCtx clearDrawable];
+ [m_pGLCtx release];
+ /*[m_pGLCtx performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO];*/
+ }
+
+ m_pGLCtx = pCtx;
+ if (pCtx)
+ [pCtx retain];
+ }
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (NSOpenGLContext *)glCtx
+{
+ COCOA_LOG_FLOW(("%s: self=%p returns %p\n", __PRETTY_FUNCTION__, (void *)self, (void *)m_pGLCtx));
+ return m_pGLCtx;
+}
+
+- (NSView *)parentView
+{
+ COCOA_LOG_FLOW(("%s: self=%p returns %p\n", __PRETTY_FUNCTION__, (void *)self, (void *)m_pParentView));
+ return m_pParentView;
+}
+
+- (void)setParentView:(NSView *)pView
+{
+ COCOA_LOG_FLOW(("%s: self=%p pView=%p (old=%p)\n", __PRETTY_FUNCTION__, (void *)self, (void *)pView, m_pParentView));
+
+ m_pParentView = pView;
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)setOverlayWin:(NSWindow *)pWin
+{
+ COCOA_LOG_FLOW(("%s: self=%p pWin=%p (old=%p)\n", __PRETTY_FUNCTION__, (void *)self, (void *)pWin, m_pOverlayWin));
+
+ m_pOverlayWin = pWin;
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (NSWindow *)overlayWin
+{
+ COCOA_LOG_FLOW(("%s: self=%p returns %p\n", __PRETTY_FUNCTION__, (void *)self, (void *)m_pOverlayWin));
+ return m_pOverlayWin;
+}
+
+- (void)vboxSetPosUI:(NSPoint)pos
+{
+ COCOA_LOG_FLOW(("%s: self=%p pos=%d,%d (old pos=%d,%d)\n", __PRETTY_FUNCTION__, (void *)self, (int)pos.x, (int)pos.y,
+ (int)m_Pos.x, (int)m_Pos.y));
+
+ DEBUG_MSG(("vboxSetPosUI: [%d, %d].\n", (int)pos.x, (int)pos.y));
+
+ m_Pos = pos;
+
+ if (m_fEverSized)
+ [self vboxReshapePerform];
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)vboxSetPosUIObj:(NSValue *)pPos
+{
+ COCOA_LOG_FLOW(("%s: self=%p pPos=%p (%d,%d) (old pos=%d,%d)\n", __PRETTY_FUNCTION__, (void *)self, pPos,
+ (int)[pPos pointValue].x, (int)[pPos pointValue].y, (int)m_Pos.x, (int)m_Pos.y));
+
+ NSPoint pos = [pPos pointValue];
+ [self vboxSetPosUI:pos];
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)vboxSetPos:(NSPoint)pos
+{
+ COCOA_LOG_FLOW(("%s: self=%p pos=%d,%d (old pos=%d,%d)\n", __PRETTY_FUNCTION__, (void *)self, (int)pos.x, (int)pos.y,
+ (int)m_Pos.x, (int)m_Pos.y));
+
+ VBoxMainThreadTaskRunner *pRunner = [VBoxMainThreadTaskRunner globalInstance];
+ NSValue *pPos = [NSValue valueWithPoint:pos];
+ [pRunner addObj:self selector:@selector(vboxSetPosUIObj:) arg:pPos];
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (NSPoint)pos
+{
+ COCOA_LOG_FLOW(("%s: self=%p returns %d,%d\n", __PRETTY_FUNCTION__, (void *)self, (int)m_Pos.x, (int)m_Pos.y));
+ return m_Pos;
+}
+
+- (bool)isEverSized
+{
+ COCOA_LOG_FLOW(("%s: self=%p returns %d\n", __PRETTY_FUNCTION__, (void *)self, m_fEverSized));
+ return m_fEverSized;
+}
+
+- (void)vboxDestroy
+{
+ COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
+ BOOL fIsMain = [NSThread isMainThread];
+ NSWindow *pWin = nil;
+
+ Assert(fIsMain);
+
+ /* Hide the view early. */
+ [self setHidden: YES];
+
+ pWin = [self window];
+ [[NSNotificationCenter defaultCenter] removeObserver:pWin];
+ [pWin setContentView: nil];
+ [[pWin parentWindow] removeChildWindow: pWin];
+
+ if (fIsMain)
+ [pWin release];
+ else
+ {
+ /* We can NOT run synchronously with the main thread since this may lead to a deadlock,
+ caused by main thread waiting xpcom thread, xpcom thread waiting to main hgcm thread,
+ and main hgcm thread waiting for us, this is why use waitUntilDone:NO,
+ which should cause no harm. */
+ [pWin performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO];
+ }
+
+ [self cleanupData];
+
+ if (fIsMain)
+ [self release];
+ else
+ {
+ /* We can NOT run synchronously with the main thread since this may lead to a deadlock,
+ caused by main thread waiting xpcom thread, xpcom thread waiting to main hgcm thread,
+ and main hgcm thread waiting for us, this is why use waitUntilDone:NO.
+ We need to avoid concurrency though, so we cleanup some data right away via a cleanupData call. */
+ [self performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO];
+ }
+
+#ifndef IN_VMSVGA3D
+ renderspuWinRelease(m_pWinInfo);
+#endif
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)vboxSetSizeUIObj:(NSValue *)pSize
+{
+ COCOA_LOG_FLOW(("%s: self=%p pSize=%p (%d,%d)\n", __PRETTY_FUNCTION__, (void *)self, (void *)pSize,
+ (int)[pSize sizeValue].width, (int)[pSize sizeValue].height));
+
+ NSSize size = [pSize sizeValue];
+ [self vboxSetSizeUI:size];
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)vboxSetSizeUI:(NSSize)size
+{
+ COCOA_LOG_FLOW(("%s: self=%p size=%d,%d\n", __PRETTY_FUNCTION__, (void *)self, (int)size.width, (int)size.height));
+
+ m_Size = size;
+ m_fEverSized = true;
+
+ DEBUG_MSG(("OVIW(%p): vboxSetSize: new size: %dx%d\n", (void *)self, (int)m_Size.width, (int)m_Size.height));
+ [self vboxReshapeOnResizePerform];
+
+ /* ensure window contents is updated after that */
+ [self vboxTryDrawUI];
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)vboxSetSize:(NSSize)size
+{
+ COCOA_LOG_FLOW(("%s: self=%p size=%d,%d\n", __PRETTY_FUNCTION__, (void *)self, (int)size.width, (int)size.height));
+
+ VBoxMainThreadTaskRunner *pRunner = [VBoxMainThreadTaskRunner globalInstance];
+ NSValue *pSize = [NSValue valueWithSize:size];
+ [pRunner addObj:self selector:@selector(vboxSetSizeUIObj:) arg:pSize];
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (NSSize)size
+{
+ COCOA_LOG_FLOW(("%s: self=%p returns %d,%d\n", __PRETTY_FUNCTION__, (void *)self, (int)m_Size.width, (int)m_Size.height));
+ return m_Size;
+}
+
+- (void)updateViewportCS
+{
+ COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
+
+ /* Update the viewport for our OpenGL view. */
+ [m_pSharedGLCtx update];
+
+#ifndef IN_VMSVGA3D
+ [self vboxBlitterSyncWindow];
+#endif
+
+ /* Clear background to transparent. */
+ glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)vboxReshapeOnResizePerform
+{
+ COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
+
+ [self vboxReshapePerform];
+#ifndef IN_VMSVGA3D
+ [self createDockTile];
+#endif
+
+ /* have to rebind GL_TEXTURE_RECTANGLE_ARB as m_FBOTexId could be changed in updateFBO call */
+ m_fNeedViewportUpdate = true;
+#if 0
+ pCurCtx = [NSOpenGLContext currentContext];
+ if (pCurCtx && pCurCtx == m_pGLCtx && (pCurView = [pCurCtx view]) == self)
+ {
+ [m_pGLCtx update];
+ m_fNeedCtxUpdate = false;
+ }
+ else
+ {
+ /* do it in a lazy way */
+ m_fNeedCtxUpdate = true;
+ }
+#endif
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)vboxReshapeOnReparentPerform
+{
+ COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
+ [self vboxReshapePerform];
+#ifndef IN_VMSVGA3D
+ [self createDockTile];
+#endif
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+#ifdef VBOX_WITH_CONFIGURABLE_HIDPI_SCALING
+- (NSRect)safeConvertRectToBacking:(NSRect *)pRect
+{
+ NSRect resultingRect = NSZeroRect;
+
+ NSWindow *pWindow = [m_pParentView window];
+ if (pWindow)
+ {
+ if ([pWindow respondsToSelector:@selector(convertRectToBacking:)])
+ {
+ NSMethodSignature *pSignature = [pWindow methodSignatureForSelector:@selector(convertRectToBacking:)];
+ if (pSignature)
+ {
+ NSInvocation *pInvocation = [NSInvocation invocationWithMethodSignature:pSignature];
+ if (pInvocation)
+ {
+ [pInvocation setSelector:@selector(convertRectToBacking:)];
+ [pInvocation setTarget:pWindow];
+ [pInvocation setArgument:pRect atIndex:2];
+ [pInvocation invoke];
+ [pInvocation getReturnValue:&resultingRect];
+
+ DEBUG_MSG(("safeConvertRectToBacking: convert [X, Y, WxH]: [%d, %d, %dx%d] -> [%d, %d, %dx%d]\n",
+ (int)pRect ->origin.x, (int)pRect ->origin.y, (int)pRect ->size.width, (int)pRect ->size.width,
+ (int)resultingRect.origin.x, (int)resultingRect.origin.y, (int)resultingRect.size.width, (int)resultingRect.size.width));
+
+ return resultingRect;
+ }
+ }
+ }
+ }
+ else
+ /* Should never happen. */
+ DEBUG_WARN(("safeConvertRectToBacking: parent widget has no window.\n"));
+
+ resultingRect = *pRect;
+
+ DEBUG_MSG(("safeConvertRectToBacking (reurn as is): convert [X, Y, WxH]: [%d, %d, %dx%d] -> [%d, %d, %dx%d]\n",
+ (int)pRect ->origin.x, (int)pRect ->origin.y, (int)pRect ->size.width, (int)pRect ->size.width,
+ (int)resultingRect.origin.x, (int)resultingRect.origin.y, (int)resultingRect.size.width, (int)resultingRect.size.width));
+
+ return resultingRect;
+}
+
+
+- (CGFloat)safeGetBackingScaleFactor
+{
+ /* Assume its default value. */
+ CGFloat backingScaleFactor = 1.;
+
+ NSWindow *pWindow = [m_pParentView window];
+ if (pWindow)
+ {
+ NSScreen *pScreen = [pWindow screen];
+ if (pScreen)
+ {
+ if ([pScreen respondsToSelector:@selector(backingScaleFactor)])
+ {
+ NSMethodSignature *pSignature = [pScreen methodSignatureForSelector:@selector(backingScaleFactor)];
+ if (pSignature)
+ {
+ NSInvocation *pInvocation = [NSInvocation invocationWithMethodSignature:pSignature];
+ if (pInvocation)
+ {
+ [pInvocation setSelector:@selector(backingScaleFactor)];
+ [pInvocation setTarget:pScreen];
+ [pInvocation invoke];
+ [pInvocation getReturnValue:&backingScaleFactor];
+
+ DEBUG_MSG(("safeGetBackingScaleFactor: %d\n", (int)backingScaleFactor));
+
+ return backingScaleFactor;
+ }
+ else
+ DEBUG_WARN(("safeGetBackingScaleFactor: unable to create invocation for backingScaleFactor method signature.\n"));
+ }
+ else
+ DEBUG_WARN(("safeGetBackingScaleFactor: unable to create method signature for backingScaleFactor selector.\n"));
+ }
+ else
+ DEBUG_WARN(("safeGetBackingScaleFactor: NSScreen does not respond to backingScaleFactor selector.\n"));
+ }
+ else
+ /* Should never happen. */
+ DEBUG_WARN(("safeGetBackingScaleFactor: parent window has no screen.\n"));
+ }
+ else
+ /* Should never happen. */
+ DEBUG_WARN(("safeGetBackingScaleFactor: parent widget has no window.\n"));
+
+ return backingScaleFactor;
+}
+
+#endif
+
+
+- (NSRect)safeConvertToScreen:(NSRect *)pRect
+{
+ NSRect resultingRect = NSZeroRect;
+
+ NSWindow *pWindow = [m_pParentView window];
+ if (pWindow)
+ {
+ if ([pWindow respondsToSelector:@selector(convertRectToScreen:)])
+ {
+ NSMethodSignature *pSignature = [pWindow methodSignatureForSelector:@selector(convertRectToScreen:)];
+ if (pSignature)
+ {
+ NSInvocation *pInvocation = [NSInvocation invocationWithMethodSignature:pSignature];
+ if (pInvocation)
+ {
+ [pInvocation setSelector:@selector(convertRectToScreen:)];
+ [pInvocation setTarget:pWindow];
+ [pInvocation setArgument:pRect atIndex:2];
+ [pInvocation invoke];
+ [pInvocation getReturnValue:&resultingRect];
+
+ DEBUG_MSG(("safeConvertToScreen: convert [X, Y, WxH]: [%d, %d, %dx%d] -> [%d, %d, %dx%d]\n",
+ (int)pRect ->origin.x, (int)pRect ->origin.y, (int)pRect ->size.width, (int)pRect ->size.width,
+ (int)resultingRect.origin.x, (int)resultingRect.origin.y, (int)resultingRect.size.width, (int)resultingRect.size.width));
+
+ return resultingRect;
+ }
+ }
+ }
+
+ /* If we failed, let's use deprecated @selector(convertBaseToScreen:). It is a bit hacky,
+ * but what to do if we stick to SDK 10.6. */
+ resultingRect.origin = [[m_pParentView window] convertBaseToScreen:pRect->origin];
+ resultingRect.size = pRect->size;
+ }
+ else
+ /* Should never happen. */
+ DEBUG_WARN(("safeConvertToScreen: parent widget has no window.\n"));
+
+ DEBUG_MSG(("safeConvertToScreen (deprecated method): convert [X, Y, WxH]: [%d, %d, %dx%d] -> [%d, %d, %dx%d]\n",
+ (int)pRect ->origin.x, (int)pRect ->origin.y, (int)pRect ->size.width, (int)pRect ->size.width,
+ (int)resultingRect.origin.x, (int)resultingRect.origin.y, (int)resultingRect.size.width, (int)resultingRect.size.width));
+
+ return resultingRect;
+}
+
+- (void)vboxReshapePerform
+{
+#ifndef IN_VMSVGA3D
+ COCOA_LOG_FLOW(("%s: self=%p - m_DockTileView=%p\n", __PRETTY_FUNCTION__, (void *)self, (void *)m_DockTileView));
+#else
+ COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
+#endif
+
+ /* NOTE: Please consider the next naming convention for variables.
+ *
+ * Rectangle variables:
+ *
+ * <object to represent><coordinate system>:
+ * <object to represent>:
+ * parentFrame - a frame of the parent container (NSView) object
+ * childFrame - a frame required to display guest content
+ * windowFrame - resulting window frame constructed as an intersection of parentFrame and childFrame
+ * <coordinate system>:
+ * VCS - View Coordinate System
+ * WCS - Window Coordinate System
+ * SCS - Screen Coordinate System
+ *
+ * The same convention applied to offset variables naming as well which are of format:
+ *
+ * <object to represent><coordinate><coordinate system>.
+ *
+ * https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CocoaDrawingGuide/Transforms/Transforms.html
+ */
+
+ NSRect parentFrameVCS, parentFrameWCS, parentFrameSCS;
+ NSRect childFrameWCS, childFrameSCS;
+ NSRect windowFrameSCS;
+
+ CGFloat childFrameXWCS, childFrameYWCS;
+
+ /* We need to construct a new window frame (windowFrameSCS) for entire NSWindow object in
+ * screen coordinates. In order to make 3D overlay window to do not overlap Cocoa and Qt GUI elements (titlebar,
+ * Qt statusbar, scroll bars etc) let's do the next. Get parent view visible area (parentFrameSCS) in (NS)Screen
+ * coordinates. Then get the area required to diaplay guest content (childFrameSCS) in (NS)Screen coordinates as well.
+ * The intersection of these two areas in screen coordinates will be a new frame for entire NSWindow object. */
+
+ parentFrameVCS = [m_pParentView frame];
+ parentFrameWCS = [m_pParentView convertRect:parentFrameVCS toView:nil];
+ parentFrameSCS = [self safeConvertToScreen:&parentFrameWCS];
+
+ /* Choose childFrame origin in a bit special way. Its pop-left corner should stick to its parent top-left corner. */
+ childFrameXWCS = parentFrameWCS.origin.x + m_Pos.x;
+ childFrameYWCS = parentFrameWCS.origin.y - m_Pos.y - (m_Size.height - parentFrameWCS.size.height);
+ childFrameWCS = NSMakeRect(childFrameXWCS, childFrameYWCS, m_Size.width, m_Size.height);
+ childFrameSCS = [self safeConvertToScreen:&childFrameWCS];
+
+ windowFrameSCS = NSIntersectionRect(parentFrameSCS, childFrameSCS);
+
+ DEBUG_MSG(("vboxReshapePerform: a new overlay frame [%d, %d, %dx%d] has been constructed from intersection of window frame "
+ "[%d, %d, %dx%d] and guest content rectangle [%d, %d, %dx%d]; m_Pos=[%d, %d], m_Size=%dx%d.\n",
+ (int)windowFrameSCS.origin.x, (int)windowFrameSCS.origin.y, (int)windowFrameSCS.size.width, (int)windowFrameSCS.size.width,
+ (int)parentFrameSCS.origin.x, (int)parentFrameSCS.origin.y, (int)parentFrameSCS.size.width, (int)parentFrameSCS.size.width,
+ (int)childFrameSCS .origin.x, (int)childFrameSCS .origin.y, (int)childFrameSCS .size.width, (int)childFrameSCS .size.width,
+ (int)m_Pos.x, (int)m_Pos.y, (int)m_Size.width, (int)m_Size.height));
+
+ /** @todo galitsyn: drop this!
+ * Later we have to correct the texture position in the case the window is
+ * out of the parents window frame. So save the shift values for later use. */
+ m_RootRect.origin.x = windowFrameSCS.origin.x - childFrameSCS.origin.x;
+ m_RootRect.origin.y = childFrameSCS.size.height + childFrameSCS.origin.y - (windowFrameSCS.size.height + windowFrameSCS.origin.y);
+ m_RootRect.size = windowFrameSCS.size;
+ m_yInvRootOffset = windowFrameSCS.origin.y - childFrameSCS.origin.y;
+
+ DEBUG_MSG(("vboxReshapePerform: [%#p]: m_RootRect pos[%d : %d] size[%d : %d]\n",
+ (void *)self, (int)m_RootRect.origin.x, (int)m_RootRect.origin.y, (int)m_RootRect.size.width, (int)m_RootRect.size.height));
+
+ /* Set the new frame. */
+ [[self window] setFrame:windowFrameSCS display:YES];
+
+#ifndef IN_VMSVGA3D
+ /* Inform the dock tile view as well. */
+ [self reshapeDockTile];
+#endif
+
+ /* Make sure the context is updated accordingly. */
+ /* [self updateViewport]; */
+ if (m_pSharedGLCtx)
+ {
+ VBOX_CR_RENDER_CTX_INFO CtxInfo;
+ vboxCtxEnter(m_pSharedGLCtx, &CtxInfo);
+
+ [self updateViewportCS];
+
+ vboxCtxLeave(&CtxInfo);
+ }
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+#ifndef IN_VMSVGA3D
+
+- (void)createDockTile
+{
+ COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
+ NSView *pDockScreen = nil;
+
+ [self deleteDockTile];
+
+ /* Is there a dock tile preview enabled in the GUI? If so setup a
+ * additional thumbnail view for the dock tile. */
+ pDockScreen = [self dockTileScreen];
+ if (pDockScreen)
+ {
+ m_DockTileView = [[DockOverlayView alloc] init];
+ [self reshapeDockTile];
+ [pDockScreen addSubview:m_DockTileView];
+ }
+
+ COCOA_LOG_FLOW(("%s: returns - m_DockTileView\n", __PRETTY_FUNCTION__, (void *)m_DockTileView));
+}
+
+- (void)deleteDockTile
+{
+ COCOA_LOG_FLOW(("%s: self=%p - m_DockTileView=%p\n", __PRETTY_FUNCTION__, (void *)self, (void *)m_DockTileView));
+
+ if (m_DockTileView != nil)
+ {
+ [m_DockTileView removeFromSuperview];
+ [m_DockTileView release];
+ m_DockTileView = nil;
+ }
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+#endif /* !IN_VMSVGA3D */
+
+- (void)makeCurrentFBO
+{
+ COCOA_LOG_FLOW(("%s: self=%p - m_pGLCtx=%p m_fNeedCtxUpdate=%d\n", __PRETTY_FUNCTION__, (void *)self,
+ (void *)m_pGLCtx, m_fNeedCtxUpdate));
+
+ if (m_pGLCtx)
+ {
+ NSOpenGLContext *pPrevCtx = [NSOpenGLContext currentContext];
+
+#ifdef IN_VMSVGA3D
+ /* Always flush before flush. glXMakeCurrent and wglMakeCurrent does this
+ implicitly, seemingly NSOpenGLContext::makeCurrentContext doesn't. */
+ if (pPrevCtx != nil)
+ {
+ DEBUG_CLEAR_GL_ERRORS();
+ glFlush();
+ DEBUG_CHECK_GL_ERROR("glFlush");
+ }
+#endif
+
+ if ([m_pGLCtx view] != self)
+ {
+#ifndef IN_VMSVGA3D
+ /* We change the active view, so flush first */
+ if (pPrevCtx != nil)
+ glFlush();
+#endif
+ DEBUG_CLEAR_GL_ERRORS();
+ [m_pGLCtx setView: self];
+ DEBUG_CHECK_GL_ERROR("setView");
+ }
+
+#if 0
+ if (pPrevCtx != m_pGLCtx)
+#endif
+ {
+ DEBUG_CLEAR_GL_ERRORS();
+ [m_pGLCtx makeCurrentContext];
+ DEBUG_CHECK_GL_ERROR("makeCurrentContext");
+ Assert([NSOpenGLContext currentContext] == m_pGLCtx);
+ Assert([m_pGLCtx view] == self);
+ }
+
+ if (m_fNeedCtxUpdate == true)
+ {
+ [m_pGLCtx update];
+ m_fNeedCtxUpdate = false;
+ }
+
+ if (!m_FBOId)
+ {
+ glGenFramebuffersEXT(1, &m_FBOId);
+ Assert(m_FBOId);
+ }
+ }
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (bool)vboxSharedCtxCreate
+{
+ COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
+
+ if (m_pSharedGLCtx)
+ {
+ COCOA_LOG_FLOW(("%s: returns true (m_pSharedGLCtx=%p)\n", __PRETTY_FUNCTION__, (void *)m_pSharedGLCtx));
+ return true;
+ }
+
+#ifndef IN_VMSVGA3D
+ Assert(!m_pBlitter);
+ m_pBlitter = RTMemAlloc(sizeof(*m_pBlitter));
+ if (RT_UNLIKELY(!m_pBlitter))
+ {
+ DEBUG_WARN(("m_pBlitter allocation failed"));
+ COCOA_LOG_FLOW(("%s: returns false - m_pBlitter allocation failed\n", __PRETTY_FUNCTION__));
+ return false;
+ }
+
+ int rc = CrBltInit(m_pBlitter, NULL, false /*fCreateNewCtx*/, false /*fForceDrawBlt*/,
+ &render_spu.GlobalShaders, &render_spu.blitterDispatch);
+ if (RT_FAILURE(rc))
+ {
+ DEBUG_WARN(("CrBltInit failed, rc %d", rc));
+ RTMemFree(m_pBlitter);
+ m_pBlitter = NULL;
+
+ COCOA_LOG_FLOW(("%s: returns false - CrBltInit failed with rc=%Rrc\n", __PRETTY_FUNCTION__, rc));
+ return false;
+ }
+
+ COCOA_LOG_FLOW(("%s: blitter (%p) created successfully for view 0x%p\n", (void *)m_pBlitter, (void *)self));
+#endif /* !IN_VMSVGA3D */
+
+ /* Create a shared context out of the main context. Use the same pixel format. */
+ NSOpenGLPixelFormat *pPixelFormat = [(OverlayOpenGLContext *)m_pGLCtx openGLPixelFormat];
+ NSOpenGLContext *pSharedGLCtx = [[NSOpenGLContext alloc] initWithFormat:pPixelFormat shareContext:m_pGLCtx];
+
+ /* Set the new context as non opaque */
+ GLint opaque = 0;
+ [pSharedGLCtx setValues:&opaque forParameter:NSOpenGLCPSurfaceOpacity];
+
+ /* Set this view as the drawable for the new context */
+ [pSharedGLCtx setView:self];
+ m_fNeedViewportUpdate = true;
+
+ m_pSharedGLCtx = pSharedGLCtx;
+
+ COCOA_LOG_FLOW(("%s: returns true - new m_pSharedGLCtx=%p\n", __PRETTY_FUNCTION__, (void *)m_pSharedGLCtx));
+ return true;
+}
+
+- (void)vboxTryDraw
+{
+ COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
+
+ glFlush();
+
+ /* Issue to the gui thread. */
+ [self performSelectorOnMainThread:@selector(vboxTryDrawUI) withObject:nil waitUntilDone:NO];
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)vboxSetVisible:(GLboolean)fVisible
+{
+ COCOA_LOG_FLOW(("%s: self=%p fVisible=%d\n", __PRETTY_FUNCTION__, (void *)self, fVisible));
+
+ VBoxMainThreadTaskRunner *pRunner = [VBoxMainThreadTaskRunner globalInstance];
+ NSNumber *pVisObj = [NSNumber numberWithBool:fVisible];
+ [pRunner addObj:self selector:@selector(vboxSetVisibleUIObj:) arg:pVisObj];
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)vboxSetVisibleUI:(GLboolean)fVisible
+{
+ COCOA_LOG_FLOW(("%s: self=%p fVisible=%d\n", __PRETTY_FUNCTION__, (void *)self, fVisible));
+
+ [self setHidden: !fVisible];
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)vboxSetVisibleUIObj:(NSNumber *)pVisibleObj
+{
+ COCOA_LOG_FLOW(("%s: self=%p pVisibleObj=%p(%d)\n", __PRETTY_FUNCTION__,
+ (void *)self, (void *)pVisibleObj, [pVisibleObj boolValue]));
+
+ BOOL fVisible = [pVisibleObj boolValue];
+ [self vboxSetVisibleUI:fVisible];
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)vboxReparent:(NSView *)pParentView
+{
+ COCOA_LOG_FLOW(("%s: self=%p pParentView=%p\n", __PRETTY_FUNCTION__, (void *)self, (void *)pParentView));
+
+ VBoxMainThreadTaskRunner *pRunner = [VBoxMainThreadTaskRunner globalInstance];
+ [pRunner addObj:self selector:@selector(vboxReparentUI:) arg:pParentView];
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)vboxReparentUI:(NSView *)pParentView
+{
+ COCOA_LOG_FLOW(("%s: self=%p pParentView=%p\n", __PRETTY_FUNCTION__, (void *)self, (void *)pParentView));
+
+ /* Make sure the window is removed from any previous parent window. */
+ if ([[self overlayWin] parentWindow] != nil)
+ {
+ [[[self overlayWin] parentWindow] removeChildWindow:[self overlayWin]];
+ }
+
+ /* Set the new parent view */
+ [self setParentView: pParentView];
+
+ /* Add the overlay window as a child to the new parent window */
+ if (pParentView != nil)
+ {
+ [[pParentView window] addChildWindow:[self overlayWin] ordered:NSWindowAbove];
+ if ([self isEverSized])
+ [self vboxReshapeOnReparentPerform];
+ }
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)vboxTryDrawUI
+{
+ COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
+
+ if ([self isHidden])
+ {
+ COCOA_LOG_FLOW(("%s: returns - request to draw on a hidden view\n", __PRETTY_FUNCTION__));
+ return;
+ }
+
+ if ([[self overlayWin] parentWindow] == nil)
+ {
+ COCOA_LOG_FLOW(("%s: returns - request to draw a view w/o a parent\n", __PRETTY_FUNCTION__));
+ return;
+ }
+
+#ifdef IN_VMSVGA3D
+ if (!m_pSharedGLCtx)
+ {
+ Assert(!m_fDataVisible);
+ Assert(!m_fCleanupNeeded);
+ if (![self vboxSharedCtxCreate])
+ {
+ COCOA_LOG_FLOW(("%s: returns - vboxSharedCtxCreate failed\n", __PRETTY_FUNCTION__));
+ return;
+ }
+ Assert(m_pSharedGLCtx);
+ }
+#endif
+
+ const VBOXVR_SCR_COMPOSITOR *pCompositor = NULL;
+#ifndef IN_VMSVGA3D
+ int rc = renderspuVBoxCompositorLock(m_pWinInfo, &pCompositor);
+ if (RT_FAILURE(rc))
+ {
+ COCOA_LOG_FLOW(("%s: returns - renderspuVBoxCompositorLock failed (%Rrc)\n", __PRETTY_FUNCTION__, rc));
+ return;
+ }
+
+ if (!pCompositor && !m_fCleanupNeeded)
+ {
+ renderspuVBoxCompositorUnlock(m_pWinInfo);
+ COCOA_LOG_FLOW(("%s: returns - noCompositorUI\n", __PRETTY_FUNCTION__));
+ return;
+ }
+
+ VBOXVR_SCR_COMPOSITOR TmpCompositor;
+ if (pCompositor)
+ {
+ if (!m_pSharedGLCtx)
+ {
+ Assert(!m_fDataVisible);
+ Assert(!m_fCleanupNeeded);
+ renderspuVBoxCompositorRelease(m_pWinInfo);
+ if (![self vboxSharedCtxCreate])
+ {
+ COCOA_LOG_FLOW(("%s: returns - vboxSharedCtxCreate failed\n", __PRETTY_FUNCTION__));
+ return;
+ }
+
+ Assert(m_pSharedGLCtx);
+
+ pCompositor = renderspuVBoxCompositorAcquire(m_pWinInfo);
+ Assert(!m_fDataVisible);
+ Assert(!m_fCleanupNeeded);
+ if (!pCompositor)
+ {
+ COCOA_LOG_FLOW(("%s: returns - Failed to reacquire compositor\n", __PRETTY_FUNCTION__));
+ return;
+ }
+ }
+ }
+ else
+ {
+ DEBUG_MSG(("%s: NeedCleanup\n", __PRETTY_FUNCTION__));
+ Assert(m_fCleanupNeeded);
+ CrVrScrCompositorInit(&TmpCompositor, NULL);
+ pCompositor = &TmpCompositor;
+ }
+#endif /* !IN_VMSVGA3D */
+
+
+ if ([self lockFocusIfCanDraw])
+ {
+ COCOA_LOG_FLOW(("%s: Calling vboxPresent\n", __PRETTY_FUNCTION__));
+ [self vboxPresent:pCompositor];
+ [self unlockFocus];
+ }
+#ifndef IN_VMSVGA3D /** @todo VMSVGA3 */
+ else if (!m_pWinInfo->visible)
+ {
+ COCOA_LOG_FLOW(("%s: NotVisible\n", __PRETTY_FUNCTION__));
+ m_fCleanupNeeded = false;
+ }
+#endif
+ else
+ {
+ COCOA_LOG_FLOW(("%s: Reschedule\n", __PRETTY_FUNCTION__));
+ [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(vboxTryDrawUI) userInfo:nil repeats:NO];
+ }
+
+#ifndef IN_VMSVGA3D
+ renderspuVBoxCompositorUnlock(m_pWinInfo);
+#endif
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)swapFBO
+{
+ COCOA_LOG_FLOW(("%s: self=%p - m_pGLCtx=%p\n", __PRETTY_FUNCTION__, (void *)self, (void *)m_pGLCtx));
+ [m_pGLCtx flushBuffer];
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)vboxPresent:(PCVBOXVR_SCR_COMPOSITOR)pCompositor
+{
+ COCOA_LOG_FLOW(("%s: self=%p pCompositor=%p\n", __PRETTY_FUNCTION__, (void *)self, (void *)pCompositor));
+ /*DEBUG_MSG(("OVIW(%p): renderFBOToView\n", (void *)self));*/
+#ifndef IN_VMSVGA3D
+ AssertPtr(pCompositor);
+#endif
+
+ VBOX_CR_RENDER_CTX_INFO CtxInfo;
+ vboxCtxEnter(m_pSharedGLCtx, &CtxInfo);
+
+ [self vboxPresentCS:pCompositor];
+
+ vboxCtxLeave(&CtxInfo);
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)vboxPresentCS:(PCVBOXVR_SCR_COMPOSITOR)pCompositor
+{
+ COCOA_LOG_FLOW(("%s: self=%p pCompositor=%p\n", __PRETTY_FUNCTION__, (void *)self, (void *)pCompositor));
+ if ([m_pSharedGLCtx view] != self)
+ {
+ COCOA_LOG_FLOW(("%s: Not current view of shared ctx! Switching... (self=%p, view=%p, m_pSharedGLCtx)\n",
+ __PRETTY_FUNCTION__, (void *)self, (void *)[m_pSharedGLCtx view], (void *)m_pSharedGLCtx));
+ [m_pSharedGLCtx setView: self];
+ m_fNeedViewportUpdate = true;
+ }
+
+ if (m_fNeedViewportUpdate)
+ {
+ [self updateViewportCS];
+ m_fNeedViewportUpdate = false;
+ }
+
+ m_fCleanupNeeded = false;
+
+#ifndef IN_VMSVGA3D
+ /* Render FBO content to the dock tile when necessary. */
+ [self vboxPresentToDockTileCS:pCompositor];
+#endif
+
+ /* change to #if 0 to see thumbnail image */
+#if 1
+ [self vboxPresentToViewCS:pCompositor];
+#else
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ [m_pSharedGLCtx flushBuffer];
+#endif
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+DECLINLINE(void) vboxNSRectToRect(const NSRect *pR, RTRECT *pRect)
+{
+ pRect->xLeft = (int)pR->origin.x;
+ pRect->yTop = (int)pR->origin.y;
+ pRect->xRight = (int)(pR->origin.x + pR->size.width);
+ pRect->yBottom = (int)(pR->origin.y + pR->size.height);
+}
+
+DECLINLINE(void) vboxNSRectToRectUnstretched(const NSRect *pR, RTRECT *pRect, float xStretch, float yStretch)
+{
+ pRect->xLeft = (int)(pR->origin.x / xStretch);
+ pRect->yTop = (int)(pR->origin.y / yStretch);
+ pRect->xRight = (int)((pR->origin.x + pR->size.width) / xStretch);
+ pRect->yBottom = (int)((pR->origin.y + pR->size.height) / yStretch);
+}
+
+DECLINLINE(void) vboxNSRectToRectStretched(const NSRect *pR, RTRECT *pRect, float xStretch, float yStretch)
+{
+ pRect->xLeft = (int)(pR->origin.x * xStretch);
+ pRect->yTop = (int)(pR->origin.y * yStretch);
+ pRect->xRight = (int)((pR->origin.x + pR->size.width) * xStretch);
+ pRect->yBottom = (int)((pR->origin.y + pR->size.height) * yStretch);
+}
+
+- (void)vboxPresentToViewCS:(PCVBOXVR_SCR_COMPOSITOR)pCompositor
+{
+ NSRect r = [self frame];
+ COCOA_LOG_FLOW(("%s: self=%p - r={%d,%d %d,%d}\n", __PRETTY_FUNCTION__, (void *)self,
+ (int)r.origin.x, (int)r.origin.y, (int)r.size.width, (int)r.size.height));
+
+#if 1 /* Set to 0 to see the docktile instead of the real output */
+ float backingStretchFactor = 1.;
+# if defined(VBOX_WITH_CONFIGURABLE_HIDPI_SCALING) && !defined(IN_VMSVGA3D)
+ /* Adjust viewport according to current NSView's backing store parameters. */
+ if (render_spu.fUnscaledHiDPI)
+ {
+ /* Update stretch factor in order to satisfy current NSView's backing store parameters. */
+ backingStretchFactor = [self safeGetBackingScaleFactor];
+ }
+
+ NSRect regularBounds = [self bounds];
+ NSRect backingBounds = [self safeConvertRectToBacking:&regularBounds];
+ glViewport(0, 0, backingBounds.size.width, backingBounds.size.height);
+
+ //crDebug("HiDPI: vboxPresentToViewCS: up-scaling is %s (backingStretchFactor=%d).",
+ // render_spu.fUnscaledHiDPI ? "OFF" : "ON", (int)backingStretchFactor);
+# endif
+
+ glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
+ glDrawBuffer(GL_BACK);
+
+ /* Clear background to transparent */
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ m_fDataVisible = false;
+
+# ifndef IN_VMSVGA3D
+ float xStretch;
+ float yStretch;
+ CrVrScrCompositorGetStretching(pCompositor, &xStretch, &yStretch);
+
+ VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR CIter;
+ const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry;
+ CrVrScrCompositorConstIterInit(pCompositor, &CIter);
+
+ while ((pEntry = CrVrScrCompositorConstIterNext(&CIter)) != NULL)
+ {
+ uint32_t cRegions;
+ const RTRECT *paSrcRegions, *paDstRegions;
+ int rc = CrVrScrCompositorEntryRegionsGet(pCompositor, pEntry, &cRegions, &paSrcRegions, &paDstRegions, NULL);
+ uint32_t fFlags = CrVrScrCompositorEntryFlagsCombinedGet(pCompositor, pEntry);
+ if (RT_SUCCESS(rc))
+ {
+ rc = CrBltEnter(m_pBlitter);
+ if (RT_SUCCESS(rc))
+ {
+ uint32_t i;
+ for (i = 0; i < cRegions; ++i)
+ {
+ const CR_TEXDATA *pTexData;
+ PCRTRECT pSrcRect = &paSrcRegions[i];
+ PCRTRECT pDstRect = &paDstRegions[i];
+ RTRECT DstRect, RestrictDstRect;
+ RTRECT SrcRect, RestrictSrcRect;
+
+ vboxNSRectToRect(&m_RootRect, &RestrictDstRect);
+ VBoxRectIntersected(&RestrictDstRect, pDstRect, &DstRect);
+
+ if (VBoxRectIsZero(&DstRect))
+ continue;
+
+ VBoxRectTranslate(&DstRect, -RestrictDstRect.xLeft, -RestrictDstRect.yTop);
+
+ vboxNSRectToRectUnstretched(&m_RootRect, &RestrictSrcRect, xStretch / backingStretchFactor, yStretch / backingStretchFactor);
+ VBoxRectTranslate(&RestrictSrcRect,
+ -CrVrScrCompositorEntryRectGet(pEntry)->xLeft,
+ -CrVrScrCompositorEntryRectGet(pEntry)->yTop);
+ VBoxRectIntersected(&RestrictSrcRect, pSrcRect, &SrcRect);
+
+ if (VBoxRectIsZero(&SrcRect))
+ continue;
+
+ pSrcRect = &SrcRect;
+ pDstRect = &DstRect;
+
+ pTexData = CrVrScrCompositorEntryTexGet(pEntry);
+
+ CrBltBlitTexMural(m_pBlitter, true, CrTdTexGet(pTexData), pSrcRect, pDstRect, 1, fFlags | CRBLT_F_NOALPHA);
+
+ m_fDataVisible = true;
+ }
+ CrBltLeave(m_pBlitter);
+ }
+ else
+ {
+ DEBUG_WARN(("CrBltEnter failed rc %d", rc));
+# ifndef DEBUG_VERBOSE
+ AssertMsgFailed(("CrBltEnter failed rc %Rrc", rc));
+# endif
+ }
+ }
+ else
+ {
+ AssertMsgFailed(("BlitStretched: CrVrScrCompositorEntryRegionsGet failed rc %Rrc\n", rc));
+ DEBUG_MSG_1(("BlitStretched: CrVrScrCompositorEntryRegionsGet failed rc %d\n", rc));
+ }
+ }
+# endif /* !IN_VMSVGA3D */
+#endif
+
+ /*
+ glFinish();
+ */
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ [m_pSharedGLCtx flushBuffer];
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)presentComposition:(PCVBOXVR_SCR_COMPOSITOR_ENTRY)pChangedEntry
+{
+ COCOA_LOG_FLOW(("%s: self=%p pChangedEntry=%p\n", __PRETTY_FUNCTION__, (void *)self, (void *)pChangedEntry));
+ [self vboxTryDraw];
+}
+
+#ifndef IN_VMSVGA3D
+- (void)vboxBlitterSyncWindow
+{
+ COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
+ CR_BLITTER_WINDOW WinInfo;
+ NSRect r;
+
+ if (!m_pBlitter)
+ return;
+
+ RT_ZERO(WinInfo);
+
+ r = [self frame];
+ WinInfo.width = r.size.width;
+ WinInfo.height = r.size.height;
+
+ Assert(WinInfo.width == m_RootRect.size.width);
+ Assert(WinInfo.height == m_RootRect.size.height);
+
+ /*CrBltMuralSetCurrentInfo(m_pBlitter, NULL);*/
+
+ CrBltMuralSetCurrentInfo(m_pBlitter, &WinInfo);
+ CrBltCheckUpdateViewport(m_pBlitter);
+}
+#endif /* !IN_VMSVGA3D */
+
+#ifndef IN_VMSVGA3D
+# ifdef VBOX_WITH_CRDUMPER_THUMBNAIL
+static int g_cVBoxTgaCtr = 0;
+# endif
+- (void)vboxPresentToDockTileCS:(PCVBOXVR_SCR_COMPOSITOR)pCompositor
+{
+ COCOA_LOG_FLOW(("%s: self=%p pCompositor=%p\n", __PRETTY_FUNCTION__, (void *)self, (void *)pCompositor));
+ NSRect r = [self frame];
+ NSRect rr = NSZeroRect;
+ NSDockTile *pDT = nil;
+ float xStretch;
+ float yStretch;
+
+ if ([m_DockTileView thumbBitmap] != nil)
+ {
+ /*
+ * Only update after at least 200 ms, cause glReadPixels is
+ * heavy performance wise.
+ */
+ uint64_t msTS = RTTimeSystemMilliTS();
+ VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR CIter;
+ const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry;
+
+ if (msTS - m_msDockUpdateTS > 200)
+ {
+ m_msDockUpdateTS = msTS;
+# if 0
+ /** @todo check this for optimization */
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, myTextureName);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_STORAGE_HINT_APPLE,
+ GL_STORAGE_SHARED_APPLE);
+ glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
+ glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA,
+ sizex, sizey, 0, GL_BGRA,
+ GL_UNSIGNED_INT_8_8_8_8_REV, myImagePtr);
+ glCopyTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB,
+ 0, 0, 0, 0, 0, image_width, image_height);
+ glFlush();
+ /* Do other work processing here, using a double or triple buffer */
+ glGetTexImage(GL_TEXTURE_RECTANGLE_ARB, 0, GL_BGRA,
+ GL_UNSIGNED_INT_8_8_8_8_REV, pixels);
+# endif
+ glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
+ glDrawBuffer(GL_BACK);
+
+ /* Clear background to transparent */
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ rr = [m_DockTileView frame];
+
+ CrVrScrCompositorGetStretching(pCompositor, &xStretch, &yStretch);
+
+ CrVrScrCompositorConstIterInit(pCompositor, &CIter);
+ while ((pEntry = CrVrScrCompositorConstIterNext(&CIter)) != NULL)
+ {
+ uint32_t cRegions;
+ PCRTRECT paSrcRegions;
+ PCRTRECT paDstRegions;
+ int rc = CrVrScrCompositorEntryRegionsGet(pCompositor, pEntry, &cRegions, &paSrcRegions, &paDstRegions, NULL);
+ uint32_t fFlags = CrVrScrCompositorEntryFlagsCombinedGet(pCompositor, pEntry);
+ if (RT_SUCCESS(rc))
+ {
+ rc = CrBltEnter(m_pBlitter);
+ if (RT_SUCCESS(rc))
+ {
+ uint32_t i;
+ for (i = 0; i < cRegions; ++i)
+ {
+ const CR_TEXDATA *pTexData;
+ PCRTRECT pSrcRect = &paSrcRegions[i];
+ PCRTRECT pDstRect = &paDstRegions[i];
+ RTRECT DstRect, RestrictDstRect;
+ RTRECT SrcRect, RestrictSrcRect;
+
+ vboxNSRectToRect(&m_RootRect, &RestrictDstRect);
+ VBoxRectIntersected(&RestrictDstRect, pDstRect, &DstRect);
+
+ VBoxRectTranslate(&DstRect, -RestrictDstRect.xLeft, -RestrictDstRect.yTop);
+
+ VBoxRectScale(&DstRect, m_FBOThumbScaleX, m_FBOThumbScaleY);
+
+ if (VBoxRectIsZero(&DstRect))
+ continue;
+
+ vboxNSRectToRectUnstretched(&m_RootRect, &RestrictSrcRect, xStretch, yStretch);
+ VBoxRectTranslate(&RestrictSrcRect,
+ -CrVrScrCompositorEntryRectGet(pEntry)->xLeft,
+ -CrVrScrCompositorEntryRectGet(pEntry)->yTop);
+ VBoxRectIntersected(&RestrictSrcRect, pSrcRect, &SrcRect);
+
+ if (VBoxRectIsZero(&SrcRect))
+ continue;
+
+ pSrcRect = &SrcRect;
+ pDstRect = &DstRect;
+
+ pTexData = CrVrScrCompositorEntryTexGet(pEntry);
+
+ CrBltBlitTexMural(m_pBlitter, true, CrTdTexGet(pTexData), pSrcRect, pDstRect, 1, fFlags);
+ }
+ CrBltLeave(m_pBlitter);
+ }
+ else
+ {
+ DEBUG_WARN(("CrBltEnter failed rc %d", rc));
+# ifndef DEBUG_VERBOSE
+ AssertMsgFailed(("CrBltEnter failed rc %Rrc", rc));
+# endif
+ }
+ }
+ else
+ {
+ DEBUG_MSG_1(("BlitStretched: CrVrScrCompositorEntryRegionsGet failed rc %d\n", rc));
+ AssertMsgFailed(("BlitStretched: CrVrScrCompositorEntryRegionsGet failed rc %Rrc\n", rc));
+ }
+ }
+
+ glFinish();
+
+ glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
+ glReadBuffer(GL_BACK);
+
+ /* Here the magic of reading the FBO content in our own buffer
+ * happens. We have to lock this access, in the case the dock
+ * is updated currently. */
+ [m_DockTileView lock];
+ glReadPixels(0, m_RootRect.size.height - rr.size.height, rr.size.width, rr.size.height,
+ GL_BGRA,
+ GL_UNSIGNED_INT_8_8_8_8,
+ [[m_DockTileView thumbBitmap] bitmapData]);
+ [m_DockTileView unlock];
+
+# ifdef VBOX_WITH_CRDUMPER_THUMBNAIL
+ ++g_cVBoxTgaCtr;
+ crDumpNamedTGAF((GLint)rr.size.width, (GLint)rr.size.height,
+ [[m_DockTileView thumbBitmap] bitmapData], "/Users/leo/vboxdumps/dump%d.tga", g_cVBoxTgaCtr);
+# endif
+
+ pDT = [[NSApplication sharedApplication] dockTile];
+
+ /* Send a display message to the dock tile in the main thread */
+ [[[NSApplication sharedApplication] dockTile] performSelectorOnMainThread:@selector(display) withObject:nil
+ waitUntilDone:NO];
+ }
+ }
+}
+#endif /* !IN_VMSVGA3D */
+
+- (void)clearVisibleRegions
+{
+ if (m_paClipRects)
+ {
+ RTMemFree(m_paClipRects);
+ m_paClipRects = NULL;
+ }
+ m_cClipRects = 0;
+}
+
+- (GLboolean)vboxNeedsEmptyPresent
+{
+ if (m_fDataVisible)
+ {
+ m_fCleanupNeeded = true;
+ return GL_TRUE;
+ }
+
+ return GL_FALSE;
+}
+
+- (void)setVisibleRegions:(GLint)cRects paRects:(const GLint *)paRects
+{
+ COCOA_LOG_FLOW(("%s: self=%p cRects=%d paRects=%p\n", __PRETTY_FUNCTION__, (void *)self, cRects, (void *)paRects));
+ GLint cOldRects = m_cClipRects;
+
+ [self clearVisibleRegions];
+
+ if (cRects > 0)
+ {
+#ifdef DEBUG_poetzsch
+ int i = 0;
+ for (i = 0; i < cRects; ++i)
+ DEBUG_MSG_1(("OVIW(%p): setVisibleRegions: %d - %d %d %d %d\n", (void *)self, i, paRects[i * 4], paRects[i * 4 + 1], paRects[i * 4 + 2], paRects[i * 4 + 3]));
+#endif
+
+ m_paClipRects = (GLint *)RTMemDup(paRects, sizeof(GLint) * 4 * cRects);
+ m_cClipRects = cRects;
+ }
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+#ifndef IN_VMSVGA3D
+
+- (NSView *)dockTileScreen
+{
+ COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
+ NSView *pContentView = [[[NSApplication sharedApplication] dockTile] contentView];
+ NSView *pScreenContent = nil;
+
+ /*
+ * First try the new variant which checks if this window is within the
+ * screen which is previewed in the dock.
+ */
+ if ([pContentView respondsToSelector:@selector(screenContentWithParentView:)])
+ pScreenContent = [pContentView performSelector:@selector(screenContentWithParentView:) withObject:(id)m_pParentView];
+ /*
+ * If it fails, fall back to the old variant (VBox...).
+ */
+ else if ([pContentView respondsToSelector:@selector(screenContent)])
+ pScreenContent = [pContentView performSelector:@selector(screenContent)];
+
+ COCOA_LOG_FLOW(("%s: returns %p (pContentView=%p)\n", __PRETTY_FUNCTION__, (void *)pScreenContent, (void *)pContentView));
+ return pScreenContent;
+}
+
+- (void)reshapeDockTile
+{
+ COCOA_LOG_FLOW(("%s:\n", __PRETTY_FUNCTION__));
+ NSRect newFrame = NSZeroRect;
+ NSView *pView = [self dockTileScreen];
+ if (pView != nil)
+ {
+ NSRect dockFrame = [pView frame];
+ /** @todo This is not correct, we should use framebuffer size here, while
+ * parent view frame size may differ in case of scrolling. */
+ NSRect parentFrame = [m_pParentView frame];
+
+ m_FBOThumbScaleX = (float)dockFrame.size.width / parentFrame.size.width;
+ m_FBOThumbScaleY = (float)dockFrame.size.height / parentFrame.size.height;
+ newFrame = NSMakeRect((int)(m_Pos.x * m_FBOThumbScaleX),
+ (int)(dockFrame.size.height - (m_Pos.y + m_Size.height - m_yInvRootOffset) * m_FBOThumbScaleY),
+ (int)(m_Size.width * m_FBOThumbScaleX),
+ (int)(m_Size.height * m_FBOThumbScaleY));
+ /*
+ NSRect newFrame = NSMakeRect ((int)roundf(m_Pos.x * m_FBOThumbScaleX), (int)roundf(dockFrame.size.height - (m_Pos.y + m_Size.height) * m_FBOThumbScaleY), (int)roundf(m_Size.width * m_FBOThumbScaleX), (int)roundf(m_Size.height * m_FBOThumbScaleY));
+ NSRect newFrame = NSMakeRect ((m_Pos.x * m_FBOThumbScaleX), (dockFrame.size.height - (m_Pos.y + m_Size.height) * m_FBOThumbScaleY), (m_Size.width * m_FBOThumbScaleX), (m_Size.height * m_FBOThumbScaleY));
+ printf ("%f %f %f %f - %f %f\n", newFrame.origin.x, newFrame.origin.y, newFrame.size.width, newFrame.size.height, m_Size.height, m_FBOThumbScaleY);
+ */
+ [m_DockTileView setFrame: newFrame];
+ }
+ COCOA_LOG_FLOW(("%s: returns - newFrame={%d,%d %d,%d} pView=%d\n", __PRETTY_FUNCTION__, (int)newFrame.origin.x,
+ (int)newFrame.origin.y, (int)newFrame.size.width, (int)newFrame.size.height, (void *)pView));
+}
+
+#endif /* !IN_VMSVGA3D */
+
+@end /* @implementation OverlayView */
+
+
+/********************************************************************************
+*
+* OpenGL context management
+*
+********************************************************************************/
+void cocoaGLCtxCreate(NativeNSOpenGLContextRef *ppCtx, GLbitfield fVisParams, NativeNSOpenGLContextRef pSharedCtx)
+{
+ COCOA_LOG_FLOW(("cocoaGLCtxCreate: ppCtx=%p fVisParams=%#x pSharedCtx=%p\n", (void *)ppCtx, fVisParams, (void *)pSharedCtx));
+ NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
+
+ NSOpenGLPixelFormat *pFmt = vboxCreatePixelFormat(fVisParams);
+ if (pFmt)
+ {
+ *ppCtx = [[OverlayOpenGLContext alloc] initWithFormat:pFmt shareContext:pSharedCtx];
+ Assert(*ppCtx);
+
+ /* Enable multi threaded OpenGL engine */
+ /*
+ CGLContextObj cglCtx = [*ppCtx CGLContextObj];
+ CGLError err = CGLEnable(cglCtx, kCGLCEMPEngine);
+ if (err != kCGLNoError)
+ printf ("Couldn't enable MT OpenGL engine!\n");
+ */
+ }
+ else
+ {
+ AssertFailed();
+ *ppCtx = NULL;
+ }
+
+ [pPool release];
+ COCOA_LOG_FLOW(("cocoaGLCtxCreate: returns *ppCtx=%p\n", (void *)*ppCtx));
+}
+
+void cocoaGLCtxDestroy(NativeNSOpenGLContextRef pCtx)
+{
+ COCOA_LOG_FLOW(("cocoaGLCtxDestroy: pCtx=%p\n", (void *)pCtx));
+ NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
+
+ [pCtx release];
+ /*[pCtx performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO];*/
+
+ [pPool release];
+ COCOA_LOG_FLOW(("cocoaGLCtxDestroy: returns\n"));
+}
+
+/********************************************************************************
+*
+* View management
+*
+********************************************************************************/
+static OverlayView *vboxViewCreate(WindowInfo *pWinInfo, NativeNSViewRef pParentView, GLbitfield fVisParams)
+{
+ COCOA_LOG_FLOW(("vboxViewCreate: pWinInfo=%p pParentView=%p fVisParams=%#x\n", pWinInfo, (void *)pParentView, fVisParams));
+
+ /* Create our worker view. */
+ OverlayView *pView = [[OverlayView alloc] initWithFrame:NSZeroRect
+ thread:RTThreadSelf()
+ parentView:pParentView
+ winInfo:pWinInfo
+ fVisParams:fVisParams];
+
+ if (pView)
+ {
+ /* We need a real window as container for the view */
+ [[OverlayWindow alloc] initWithParentView:pParentView overlayView:pView];
+ /* Return the freshly created overlay view */
+ COCOA_LOG_FLOW(("vboxViewCreate: returns %p\n", (void *)pView));
+ return pView;
+ }
+
+ COCOA_LOG_FLOW(("vboxViewCreate: returns NULL\n"));
+ return NULL;
+}
+
+#ifndef IN_VMSVGA3D
+
+typedef struct CR_RCD_CREATEVIEW
+{
+ WindowInfo *pWinInfo;
+ NSView *pParentView;
+ GLbitfield fVisParams;
+ /* out */
+ OverlayView *pView;
+} CR_RCD_CREATEVIEW;
+
+static DECLCALLBACK(void) vboxRcdCreateView(void *pvCb)
+{
+ CR_RCD_CREATEVIEW *pCreateView = (CR_RCD_CREATEVIEW *)pvCb;
+ pCreateView->pView = vboxViewCreate(pCreateView->pWinInfo, pCreateView->pParentView, pCreateView->fVisParams);
+ COCOA_LOG_FLOW(("vboxRcdCreateView: returns pView=%p\n", (void *)pCreateView->pView));
+}
+
+#endif /* !IN_VMSVGA3D */
+
+void cocoaViewCreate(NativeNSViewRef *ppView, WindowInfo *pWinInfo, NativeNSViewRef pParentView, GLbitfield fVisParams)
+{
+ COCOA_LOG_FLOW(("cocoaViewCreate: ppView=%p pWinInfo=%p pParentView=%p fVisParams=%#x\n",
+ (void *)ppView, (void *)pWinInfo, (void *)pParentView, fVisParams));
+ NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
+
+ /* make sure all tasks are run, to preserve the order */
+ VBoxMainThreadTaskRunner *pRunner = [VBoxMainThreadTaskRunner globalInstance];
+ [pRunner runTasksSyncIfPossible];
+
+#ifndef IN_VMSVGA3D
+ renderspuWinRetain(pWinInfo);
+
+ if (renderspuCalloutAvailable())
+ {
+ CR_RCD_CREATEVIEW CreateView;
+ CreateView.pWinInfo = pWinInfo;
+ CreateView.pParentView = pParentView;
+ CreateView.fVisParams = fVisParams;
+ CreateView.pView = NULL;
+ renderspuCalloutClient(vboxRcdCreateView, &CreateView);
+ *ppView = CreateView.pView;
+ }
+ else
+#endif
+ {
+ DEBUG_MSG_NOT_VMSVGA3D(("no callout available on createWindow\n"));
+#if 0
+ dispatch_sync(dispatch_get_main_queue(), ^{
+#endif
+ *ppView = vboxViewCreate(pWinInfo, pParentView, fVisParams);
+#if 0
+ });
+#endif
+ }
+
+#ifndef IN_VMSVGA3D
+ if (!*ppView)
+ renderspuWinRelease(pWinInfo);
+#endif
+
+ [pPool release];
+ COCOA_LOG_FLOW(("cocoaViewCreate: returns *ppView=%p\n", (void *)*ppView));
+}
+
+#ifndef IN_VMSVGA3D
+void cocoaViewReparent(NativeNSViewRef pView, NativeNSViewRef pParentView)
+{
+ COCOA_LOG_FLOW(("cocoaViewReparent: pView=%p pParentView=%p\n", (void *)pView, (void *)pParentView));
+ NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
+
+ OverlayView *pOView = (OverlayView *)pView;
+ if (pOView)
+ [pOView vboxReparent:pParentView];
+
+ [pPool release];
+ COCOA_LOG_FLOW(("cocoaViewReparent: returns\n"));
+}
+#endif /* !IN_VMSVGA3D */
+
+void cocoaViewDestroy(NativeNSViewRef pView)
+{
+ COCOA_LOG_FLOW(("cocoaViewDestroy: pView=%p\n", (void *)pView));
+ NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
+
+ VBoxMainThreadTaskRunner *pRunner = [VBoxMainThreadTaskRunner globalInstance];
+ [pRunner addObj:pView selector:@selector(vboxDestroy) arg:nil];
+
+ [pPool release];
+ COCOA_LOG_FLOW(("cocoaViewDestroy: returns\n"));
+}
+
+#ifndef IN_VMSVGA3D
+void cocoaViewShow(NativeNSViewRef pView, GLboolean fShowIt)
+{
+ COCOA_LOG_FLOW(("cocoaViewShow: pView=%p fShowIt=%d\n", (void *)pView, fShowIt));
+ NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
+
+ [(OverlayView *)pView vboxSetVisible:fShowIt];
+
+ [pPool release];
+ COCOA_LOG_FLOW(("cocoaViewShow: returns\n"));
+}
+#endif /* IN_VMSVGA3D */
+
+void cocoaViewDisplay(NativeNSViewRef pView)
+{
+ COCOA_LOG_FLOW(("cocoaViewDisplay: pView=%p\n", (void *)pView));
+ NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
+
+#ifndef IN_VMSVGA3D
+ DEBUG_WARN(("cocoaViewDisplay should never happen!\n"));
+ DEBUG_MSG_1(("cocoaViewDisplay %p\n", (void *)pView));
+#endif
+ [(OverlayView *)pView swapFBO];
+
+ [pPool release];
+ COCOA_LOG_FLOW(("cocoaViewDisplay: returns\n"));
+}
+
+void cocoaViewSetPosition(NativeNSViewRef pView, NativeNSViewRef pParentView, int x, int y)
+{
+ COCOA_LOG_FLOW(("cocoaViewSetPosition: pView=%p pParentView=%p x=%d y=%d\n", (void *)pView, (void *)pParentView, x, y));
+ NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
+
+ [(OverlayView *)pView vboxSetPos:NSMakePoint(x, y)];
+
+ [pPool release];
+ COCOA_LOG_FLOW(("cocoaViewSetPosition: returns\n"));
+}
+
+void cocoaViewSetSize(NativeNSViewRef pView, int cx, int cy)
+{
+ COCOA_LOG_FLOW(("cocoaViewSetSize: pView=%p cx=%d cy=%d\n", (void *)pView, cx, cy));
+ NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
+ OverlayView *pOverlayView = (OverlayView *)pView;
+
+ [pOverlayView vboxSetSize:NSMakeSize(cx, cy)];
+
+ [pPool release];
+ COCOA_LOG_FLOW(("cocoaViewSetSize: returns\n"));
+}
+
+#ifndef IN_VMSVGA3D
+
+typedef struct CR_RCD_GETGEOMETRY
+{
+ OverlayView *pView;
+ NSRect rect;
+} CR_RCD_GETGEOMETRY;
+
+static DECLCALLBACK(void) vboxRcdGetGeomerty(void *pvUser)
+{
+ CR_RCD_GETGEOMETRY *pGetGeometry = (CR_RCD_GETGEOMETRY *)pvUser;
+ pGetGeometry->rect = [[pGetGeometry->pView window] frame];
+ COCOA_LOG_FLOW(("vboxRcdGetGeomerty: (x,y)=(%d,%d) (cx,cy)=(%d,%d)\n", pGetGeometry->rect.origin.x, pGetGeometry->rect.origin.y,
+ pGetGeometry->rect.size.width, pGetGeometry->rect.size.height));
+}
+
+void cocoaViewGetGeometry(NativeNSViewRef pView, int *px, int *py, int *pcx, int *pcy)
+{
+ COCOA_LOG_FLOW(("cocoaViewGetGeometry: pView=%p px=%p py=%p pcx=%p pcy=%p\n",
+ (void *)pView, (void *)px, (void *)py, (void *)pcx, (void *)pcy));
+ NSAutoreleasePool *pPool;
+ pPool = [[NSAutoreleasePool alloc] init];
+
+ /* make sure all tasks are run, to preserve the order */
+ VBoxMainThreadTaskRunner *pRunner = [VBoxMainThreadTaskRunner globalInstance];
+ [pRunner runTasksSyncIfPossible];
+
+ NSRect frame;
+#ifndef IN_VMSVGA3D
+ if (renderspuCalloutAvailable())
+ {
+ CR_RCD_GETGEOMETRY GetGeometry;
+ GetGeometry.pView = (OverlayView *)pView;
+ renderspuCalloutClient(vboxRcdGetGeomerty, &GetGeometry);
+ frame = GetGeometry.rect;
+ }
+ else
+#endif
+ {
+ DEBUG_MSG_NOT_VMSVGA3D(("no callout available on getGeometry\n"));
+ frame = [[pView window] frame];
+ }
+
+ *px = frame.origin.x;
+ *py = frame.origin.y;
+ *pcx = frame.size.width;
+ *pcy = frame.size.height;
+
+ [pPool release];
+ COCOA_LOG_FLOW(("cocoaViewGetGeometry: returns *px=%d, *py=%d, *pcx=%d, *pcy=%d\n", *px, *py, *pcx, *pcy));
+}
+
+void cocoaViewPresentComposition(NativeNSViewRef pView, PCVBOXVR_SCR_COMPOSITOR_ENTRY pChangedEntry)
+{
+ COCOA_LOG_FLOW(("cocoaViewPresentComposition: pView=%p pChangedEntry=%p\n", (void *)pView, (void *)pChangedEntry));
+ NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
+ NSOpenGLContext *pCtx;
+
+# ifdef IN_VMSVGA3D
+ Assert([(OverlayView *)pView glCtx]);
+
+# else
+ /* The view may not necesserily have a GL context set. */
+ pCtx = [(OverlayView *)pView glCtx];
+ if (!pCtx)
+ {
+ ContextInfo *pCtxInfo = renderspuDefaultSharedContextAcquire();
+ if (!pCtxInfo)
+ {
+ DEBUG_WARN(("renderspuDefaultSharedContextAcquire returned NULL"));
+
+ [pPool release];
+ DEBUG_FUNC_LEAVE();
+ return;
+ }
+
+ pCtx = pCtxInfo->context;
+
+ [(OverlayView *)pView setGLCtx:pCtx];
+ }
+# endif
+
+ [(OverlayView *)pView presentComposition:pChangedEntry];
+
+ [pPool release];
+ COCOA_LOG_FLOW(("cocoaViewPresentComposition: returns\n"));
+}
+
+#endif /* !IN_VMSVGA3D */
+
+void cocoaViewMakeCurrentContext(NativeNSViewRef pView, NativeNSOpenGLContextRef pCtx)
+{
+ COCOA_LOG_FLOW(("cocoaViewMakeCurrentContext: pView=%p pCtx=%p\n", (void *)pView, (void *)pCtx));
+ NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
+
+ if (pView)
+ {
+ [(OverlayView *)pView setGLCtx:pCtx];
+ [(OverlayView *)pView makeCurrentFBO];
+ }
+ else
+ {
+#ifdef IN_VMSVGA3D
+ /* Always flush before flush. glXMakeCurrent and wglMakeCurrent does this
+ implicitly, seemingly NSOpenGLContext::makeCurrentContext doesn't. */
+ if ([NSOpenGLContext currentContext] != nil)
+ {
+ DEBUG_CLEAR_GL_ERRORS();
+ glFlush();
+ DEBUG_CHECK_GL_ERROR("glFlush");
+ }
+#endif
+ [NSOpenGLContext clearCurrentContext];
+ }
+
+ [pPool release];
+ COCOA_LOG_FLOW(("cocoaViewMakeCurrentContext: returns\n"));
+}
+
+#ifndef IN_VMSVGA3D
+
+GLboolean cocoaViewNeedsEmptyPresent(NativeNSViewRef pView)
+{
+ COCOA_LOG_FLOW(("cocoaViewNeedsEmptyPresent: pView=%p\n", (void *)pView));
+ NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
+
+ GLboolean fNeedsPresent = [(OverlayView *)pView vboxNeedsEmptyPresent];
+
+ [pPool release];
+ COCOA_LOG_FLOW(("cocoaViewNeedsEmptyPresent: returns %d\n", fNeedsPresent));
+ return fNeedsPresent;
+}
+
+void cocoaViewSetVisibleRegion(NativeNSViewRef pView, GLint cRects, const GLint *paRects)
+{
+ COCOA_LOG_FLOW(("cocoaViewSetVisibleRegion: pView=%p cRects=%d paRects=%p)\n", (void *)pView, cRects, (void const *)paRects));
+ NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
+
+ [(OverlayView *)pView setVisibleRegions:cRects paRects:paRects];
+
+ [pPool release];
+ COCOA_LOG_FLOW(("cocoaViewSetVisibleRegion: returns\n"));
+}
+
+#endif /* IN_VMSVGA3D */
+
+#ifdef IN_VMSVGA3D
+/*
+ * VMSVGA3D interface.
+ */
+
+VMSVGA3DCOCOA_DECL(bool) vmsvga3dCocoaCreateViewAndContext(NativeNSViewRef *ppView, NativeNSOpenGLContextRef *ppCtx,
+ NativeNSViewRef pParentView, uint32_t cx, uint32_t cy,
+ NativeNSOpenGLContextRef pSharedCtx, bool fOtherProfile)
+{
+ NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
+ GLbitfield fVisParams = CR_ALPHA_BIT | CR_DEPTH_BIT | CR_DOUBLE_BIT | (fOtherProfile ? VMSVGA3D_NON_DEFAULT_PROFILE_BIT : 0);
+ bool fRc = false;
+
+ cocoaGLCtxCreate(ppCtx, fVisParams, pSharedCtx);
+ if (*ppCtx)
+ {
+ cocoaViewCreate(ppView, NULL, pParentView, fVisParams);
+ if (*ppView)
+ {
+ cocoaViewSetSize(*ppView, cx, cy);
+ [(OverlayView *)*ppView setGLCtx: *ppCtx];
+ fRc = true;
+ }
+ else
+ [*ppCtx release];
+ }
+
+ [pPool release];
+ return fRc;
+}
+
+VMSVGA3DCOCOA_DECL(void) vmsvga3dCocoaDestroyViewAndContext(NativeNSViewRef pView, NativeNSOpenGLContextRef pCtx)
+{
+ cocoaGLCtxDestroy(pCtx);
+ cocoaViewDestroy(pView);
+}
+
+VMSVGA3DCOCOA_DECL(void) vmsvga3dCocoaViewSetPosition(NativeNSViewRef pView, NativeNSViewRef pParentView, int x, int y)
+{
+ cocoaViewSetPosition(pView, pParentView, x, y);
+}
+
+VMSVGA3DCOCOA_DECL(void) vmsvga3dCocoaViewSetSize(NativeNSViewRef pView, int w, int h)
+{
+ cocoaViewSetSize(pView, w, h);
+}
+
+VMSVGA3DCOCOA_DECL(void) vmsvga3dCocoaViewMakeCurrentContext(NativeNSViewRef pView, NativeNSOpenGLContextRef pCtx)
+{
+ Assert(!pView || [(OverlayView *)pView glCtx] == pCtx || [(OverlayView *)pView glCtx] == nil);
+ cocoaViewMakeCurrentContext(pView, pCtx);
+}
+
+VMSVGA3DCOCOA_DECL(void) vmsvga3dCocoaSwapBuffers(NativeNSViewRef pView, NativeNSOpenGLContextRef pCtx)
+{
+# if 1
+ Assert([(OverlayView *)pView glCtx] == pCtx);
+ Assert([pCtx view] == pView);
+ cocoaViewDisplay(pView);
+# else
+ DEBUG_FUNC_ENTER();
+ NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
+
+ Assert([(OverlayView *)pView glCtx] == pCtx);
+ Assert([pCtx view] == pView);
+
+ [pCtx flushBuffer];
+
+ [pPool release];
+ DEBUG_FUNC_LEAVE();
+# endif
+}
+
+#endif /* IN_VMSVGA3D */
diff --git a/src/VBox/HostServices/SharedOpenGL/render/renderspu_config.c b/src/VBox/HostServices/SharedOpenGL/render/renderspu_config.c
new file mode 100644
index 00000000..624a051f
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/render/renderspu_config.c
@@ -0,0 +1,392 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "renderspu.h"
+
+#include "cr_string.h"
+#include "cr_mem.h"
+#include "cr_error.h"
+#include "cr_environment.h"
+#include "cr_url.h"
+
+
+static void set_window_geometry( RenderSPU *render_spu, const char *response )
+{
+ int x, y, w, h;
+ CRASSERT(response[0] == '[');
+ sscanf( response, "[ %d, %d, %d, %d ]", &x, &y, &w, &h );
+ render_spu->defaultX = (int) x;
+ render_spu->defaultY = (int) y;
+ render_spu->defaultWidth = (unsigned int) w;
+ render_spu->defaultHeight = (unsigned int) h;
+}
+
+static void set_default_visual( RenderSPU *render_spu, const char *response )
+{
+ if (crStrlen(response) > 0) {
+ if (crStrstr(response, "rgb"))
+ render_spu->default_visual |= CR_RGB_BIT;
+ if (crStrstr(response, "alpha"))
+ render_spu->default_visual |= CR_ALPHA_BIT;
+ if (crStrstr(response, "z") || crStrstr(response, "depth"))
+ render_spu->default_visual |= CR_DEPTH_BIT;
+ if (crStrstr(response, "stencil"))
+ render_spu->default_visual |= CR_STENCIL_BIT;
+ if (crStrstr(response, "accum"))
+ render_spu->default_visual |= CR_ACCUM_BIT;
+ if (crStrstr(response, "stereo"))
+ render_spu->default_visual |= CR_STEREO_BIT;
+ if (crStrstr(response, "multisample"))
+ render_spu->default_visual |= CR_MULTISAMPLE_BIT;
+ if (crStrstr(response, "double"))
+ render_spu->default_visual |= CR_DOUBLE_BIT;
+ if (crStrstr(response, "pbuffer"))
+ render_spu->default_visual |= CR_PBUFFER_BIT;
+ }
+}
+
+static void set_display_string( RenderSPU *render_spu, const char *response )
+{
+ if (!crStrcmp(response, "DEFAULT")) {
+ const char *display = crGetenv("DISPLAY");
+ if (display)
+ crStrncpy(render_spu->display_string,
+ display,
+ sizeof(render_spu->display_string));
+ else
+ crStrcpy(render_spu->display_string, ""); /* empty string */
+ }
+ else {
+ crStrncpy(render_spu->display_string,
+ response,
+ sizeof(render_spu->display_string));
+ }
+}
+
+static void set_fullscreen( RenderSPU *render_spu, const char *response )
+{
+ sscanf( response, "%d", &(render_spu->fullscreen) );
+}
+
+static void set_on_top( RenderSPU *render_spu, const char *response )
+{
+ sscanf( response, "%d", &(render_spu->ontop) );
+}
+
+static void set_system_gl_path( RenderSPU *render_spu, const char *response )
+{
+ if (crStrlen(response) > 0)
+ crSetenv( "CR_SYSTEM_GL_PATH", response );
+}
+
+static void set_title( RenderSPU *render_spu, const char *response )
+{
+ crFree( render_spu->window_title );
+ render_spu->window_title = crStrdup( response );
+}
+
+#if defined(GLX)
+static void set_try_direct( RenderSPU *render_spu, const char *response )
+{
+ sscanf( response, "%d", &(render_spu->try_direct) );
+}
+
+static void set_force_direct( RenderSPU *render_spu, const char *response )
+{
+ sscanf( response, "%d", &(render_spu->force_direct) );
+}
+#endif /* GLX */
+
+static void render_to_app_window( RenderSPU *render_spu, const char *response )
+{
+ sscanf( response, "%d", &(render_spu->render_to_app_window) );
+}
+
+static void render_to_crut_window( RenderSPU *render_spu, const char *response )
+{
+ sscanf( response, "%d", &(render_spu->render_to_crut_window) );
+}
+
+static void resizable( RenderSPU *render_spu, const char *response )
+{
+ sscanf( response, "%d", &(render_spu->resizable) );
+}
+
+static void set_borderless( RenderSPU *render_spu, const char *response )
+{
+ sscanf( response, "%d", &(render_spu->borderless) );
+}
+
+static void set_cursor( RenderSPU *render_spu, const char *response )
+{
+ sscanf( response, "%d", &(render_spu->drawCursor) );
+}
+
+static void gather_url( RenderSPU *render_spu, const char *response )
+{
+ char protocol[4096], hostname[4096];
+ unsigned short port;
+
+ if (!crParseURL(response, protocol, hostname, &port, 0))
+ {
+ crError( "Malformed URL: \"%s\"", response );
+ }
+
+ render_spu->gather_port = port;
+}
+
+static void gather_userbuf( RenderSPU *render_spu, const char *response )
+{
+ sscanf( response, "%d", &(render_spu->gather_userbuf_size) );
+}
+
+static void set_lut8( RenderSPU *render_spu, const char *response )
+{
+ int a;
+ char **lut;
+
+ if (!response[0]) return;
+
+ lut = crStrSplit(response, ",");
+ if (!lut) return;
+
+ for (a=0; a<256; a++)
+ {
+ render_spu->lut8[0][a] = crStrToInt(lut[a]);
+ render_spu->lut8[1][a] = crStrToInt(lut[256+a]);
+ render_spu->lut8[2][a] = crStrToInt(lut[512+a]);
+ }
+
+ crFreeStrings(lut);
+
+ render_spu->use_lut8 = 1;
+}
+
+static void set_master_url ( RenderSPU *render_spu, char *response )
+{
+ if (response[0])
+ render_spu->swap_master_url = crStrdup( response );
+ else
+ render_spu->swap_master_url = NULL;
+}
+
+static void set_is_master ( RenderSPU *render_spu, char *response )
+{
+ render_spu->is_swap_master = crStrToInt( response );
+}
+
+static void set_num_clients ( RenderSPU *render_spu, char *response )
+{
+ render_spu->num_swap_clients = crStrToInt( response );
+}
+
+static void set_use_osmesa ( RenderSPU *render_spu, char *response )
+{
+ int val = crStrToInt( response );
+#ifdef USE_OSMESA
+ render_spu->use_osmesa = val;
+#else
+ if (val != 0)
+ crError( "renderspu with Conf(use_osmesa, 1) but not compiled with -DUSE_OSMESA");
+#endif
+}
+
+static void set_nv_swap_group( RenderSPU *render_spu, char *response )
+{
+ render_spu->nvSwapGroup = crStrToInt( response );
+ if (render_spu->nvSwapGroup < 0)
+ render_spu->nvSwapGroup = 0;
+}
+
+static void set_ignore_papi( RenderSPU *render_spu, char *response )
+{
+ render_spu->ignore_papi = crStrToInt( response );
+}
+
+static void set_ignore_window_moves( RenderSPU *render_spu, char *response )
+{
+ render_spu->ignore_window_moves = crStrToInt( response );
+}
+
+static void set_pbuffer_size( RenderSPU *render_spu, const char *response )
+{
+ CRASSERT(response[0] == '[');
+ sscanf( response, "[ %d, %d ]",
+ &render_spu->pbufferWidth, &render_spu->pbufferHeight);
+}
+
+static void set_use_glxchoosevisual( RenderSPU *render_spu, char *response )
+{
+ render_spu->use_glxchoosevisual = crStrToInt( response );
+}
+
+static void set_draw_bbox( RenderSPU *render_spu, char *response )
+{
+ render_spu->draw_bbox = crStrToInt( response );
+}
+
+
+
+/* option, type, nr, default, min, max, title, callback
+ */
+SPUOptions renderSPUOptions[] = {
+ { "title", CR_STRING, 1, "Chromium Render SPU", NULL, NULL,
+ "Window Title", (SPUOptionCB)set_title },
+
+ { "window_geometry", CR_INT, 4, "[0, 0, 256, 256]", "[0, 0, 1, 1]", NULL,
+ "Default Window Geometry (x,y,w,h)", (SPUOptionCB)set_window_geometry },
+
+ { "fullscreen", CR_BOOL, 1, "0", NULL, NULL,
+ "Full-screen Window", (SPUOptionCB)set_fullscreen },
+
+ { "resizable", CR_BOOL, 1, "0", NULL, NULL,
+ "Resizable Window", (SPUOptionCB)resizable },
+
+ { "on_top", CR_BOOL, 1, "0", NULL, NULL,
+ "Display on Top", (SPUOptionCB)set_on_top },
+
+ { "borderless", CR_BOOL, 1, "0", NULL, NULL,
+ "Borderless Window", (SPUOptionCB) set_borderless },
+
+ { "default_visual", CR_STRING, 1, "rgb, double, depth", NULL, NULL,
+ "Default GL Visual", (SPUOptionCB) set_default_visual },
+
+#if defined(GLX)
+ { "try_direct", CR_BOOL, 1, "1", NULL, NULL,
+ "Try Direct Rendering", (SPUOptionCB)set_try_direct },
+
+ { "force_direct", CR_BOOL, 1, "0", NULL, NULL,
+ "Force Direct Rendering", (SPUOptionCB)set_force_direct },
+#endif
+
+ { "render_to_app_window", CR_BOOL, 1, "0", NULL, NULL,
+ "Render to Application window", (SPUOptionCB)render_to_app_window },
+
+ { "render_to_crut_window", CR_BOOL, 1, "0", NULL, NULL,
+ "Render to CRUT window", (SPUOptionCB)render_to_crut_window },
+
+ { "show_cursor", CR_BOOL, 1, "0", NULL, NULL,
+ "Show Software Cursor", (SPUOptionCB) set_cursor },
+
+ { "system_gl_path", CR_STRING, 1, "", NULL, NULL,
+ "System GL Path", (SPUOptionCB)set_system_gl_path },
+
+ { "display_string", CR_STRING, 1, "DEFAULT", NULL, NULL,
+ "X Display String", (SPUOptionCB)set_display_string },
+
+ { "gather_url", CR_STRING, 1, "", NULL, NULL,
+ "Gatherer URL", (SPUOptionCB)gather_url},
+
+ { "gather_userbuf_size", CR_INT, 1, "0", NULL, NULL,
+ "Size of Buffer to Allocate for Gathering", (SPUOptionCB)gather_userbuf},
+
+ { "lut8", CR_STRING, 1, "", NULL, NULL,
+ "8 bit RGB LUT", (SPUOptionCB)set_lut8},
+
+ { "swap_master_url", CR_STRING, 1, "", NULL, NULL,
+ "The URL to the master swapper", (SPUOptionCB)set_master_url },
+
+ { "is_swap_master", CR_BOOL, 1, "0", NULL, NULL,
+ "Is this the swap master", (SPUOptionCB)set_is_master },
+
+ { "num_swap_clients", CR_INT, 1, "1", NULL, NULL,
+ "How many swaps to wait on", (SPUOptionCB)set_num_clients },
+
+ { "use_osmesa", CR_BOOL, 1, "0", NULL, NULL,
+ "Use offscreen rendering with Mesa", (SPUOptionCB)set_use_osmesa },
+
+ { "nv_swap_group", CR_INT, 1, "0", NULL, NULL,
+ "NVIDIA Swap Group Number", (SPUOptionCB) set_nv_swap_group },
+
+ { "ignore_papi", CR_BOOL, 1, "0", NULL, NULL,
+ "Ignore Barrier and Semaphore calls", (SPUOptionCB) set_ignore_papi },
+
+ { "ignore_window_moves", CR_BOOL, 1, "0", NULL, NULL,
+ "Ignore crWindowPosition calls", (SPUOptionCB) set_ignore_window_moves },
+
+ { "pbuffer_size", CR_INT, 2, "[0, 0]", "[0, 0]", NULL,
+ "Maximum PBuffer Size", (SPUOptionCB) set_pbuffer_size },
+
+ { "use_glxchoosevisual", CR_BOOL, 1, "1", NULL, NULL,
+ "Use glXChooseVisual", (SPUOptionCB) set_use_glxchoosevisual },
+
+ { "draw_bbox", CR_BOOL, 1, "0", NULL, NULL,
+ "Draw Bounding Boxes", (SPUOptionCB) set_draw_bbox },
+ { NULL, CR_BOOL, 0, NULL, NULL, NULL, NULL, NULL },
+};
+
+
+void renderspuSetVBoxConfiguration( RenderSPU *render_spu )
+{
+ int a;
+
+ for (a=0; a<256; a++)
+ {
+ render_spu->lut8[0][a] =
+ render_spu->lut8[1][a] =
+ render_spu->lut8[2][a] = a;
+ }
+ render_spu->use_lut8 = 0;
+
+ set_title(render_spu, "Chromium Render SPU");
+ set_window_geometry(render_spu, "[0, 0, 0, 0]");
+ set_fullscreen(render_spu, "0");
+ resizable(render_spu, "0");
+ set_on_top(render_spu, "1");
+ set_borderless(render_spu, "1");
+ set_default_visual(render_spu, "rgb, double, depth");
+#if defined(GLX)
+ set_try_direct(render_spu, "1");
+ set_force_direct(render_spu, "0");
+#endif
+ render_to_app_window(render_spu, "0");
+ render_to_crut_window(render_spu, "0");
+ set_cursor(render_spu, "0");
+ set_system_gl_path(render_spu, "");
+ set_display_string(render_spu, "DEFAULT");
+ gather_url(render_spu, "");
+ gather_userbuf(render_spu, "0");
+ set_lut8(render_spu, "");
+ set_master_url(render_spu, "");
+ set_is_master(render_spu, "0");
+ set_num_clients(render_spu, "1");
+ set_use_osmesa(render_spu, "0");
+ set_nv_swap_group(render_spu, "0");
+ set_ignore_papi(render_spu, "0");
+ set_ignore_window_moves(render_spu, "0");
+ set_pbuffer_size(render_spu, "[0, 0]");
+ set_use_glxchoosevisual(render_spu, "1");
+ set_draw_bbox(render_spu, "0");
+
+ render_spu->swap_mtu = 1024 * 500;
+
+ /* Some initialization that doesn't really have anything to do
+ * with configuration but which was done here before:
+ */
+ render_spu->use_L2 = 0;
+ render_spu->cursorX = 0;
+ render_spu->cursorY = 0;
+#if defined(GLX)
+ render_spu->sync = 0;
+#endif
+
+ /* Config of "render force present main thread" (currently implemented by glx and wgl). */
+ {
+ const char *forcePresent = crGetenv("CR_RENDER_FORCE_PRESENT_MAIN_THREAD");
+ if (forcePresent)
+ render_spu->force_present_main_thread = crStrToInt(forcePresent) ? 1 : 0;
+ else
+ {
+#if defined(GLX)
+ /* Customer needed this for avoiding system 3D driver bugs. */
+ render_spu->force_present_main_thread = 1;
+#else
+ render_spu->force_present_main_thread = 0;
+#endif
+ }
+ }
+}
+
diff --git a/src/VBox/HostServices/SharedOpenGL/render/renderspu_glx.c b/src/VBox/HostServices/SharedOpenGL/render/renderspu_glx.c
new file mode 100644
index 00000000..8a1a61ff
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/render/renderspu_glx.c
@@ -0,0 +1,2042 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+#if 00 /*TEMPORARY*/
+#include <unistd.h>
+#include "cr_rand.h"
+#endif
+
+#include <GL/glx.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xmu/StdCmap.h>
+#include <X11/Xatom.h>
+#include <X11/extensions/shape.h>
+#include <sys/time.h>
+#include <stdio.h>
+
+#include "cr_environment.h"
+#include "cr_error.h"
+#include "cr_string.h"
+#include "cr_mem.h"
+#include "cr_process.h"
+#include "renderspu.h"
+
+
+/*
+ * Stuff from MwmUtils.h
+ */
+typedef struct
+{
+ unsigned long flags;
+ unsigned long functions;
+ unsigned long decorations;
+ long inputMode;
+ unsigned long status;
+} PropMotifWmHints;
+
+#define PROP_MOTIF_WM_HINTS_ELEMENTS 5
+#define MWM_HINTS_DECORATIONS (1L << 1)
+
+
+#define WINDOW_NAME window->title
+
+static Bool WindowExistsFlag;
+
+static int
+WindowExistsErrorHandler( Display *dpy, XErrorEvent *xerr )
+{
+ if (xerr->error_code == BadWindow)
+ {
+ WindowExistsFlag = GL_FALSE;
+ }
+ return 0;
+}
+
+static GLboolean
+WindowExists( Display *dpy, Window w )
+{
+ XWindowAttributes xwa;
+ int (*oldXErrorHandler)(Display *, XErrorEvent *);
+
+ WindowExistsFlag = GL_TRUE;
+ oldXErrorHandler = XSetErrorHandler(WindowExistsErrorHandler);
+ XGetWindowAttributes(dpy, w, &xwa); /* dummy request */
+ XSetErrorHandler(oldXErrorHandler);
+ return WindowExistsFlag;
+}
+
+static Colormap
+GetLUTColormap( Display *dpy, XVisualInfo *vi )
+{
+ int a;
+ XColor col;
+ Colormap cmap;
+
+#if defined(__cplusplus) || defined(c_plusplus)
+ int localclass = vi->c_class; /* C++ */
+#else
+ int localclass = vi->class; /* C */
+#endif
+
+ if ( localclass != DirectColor )
+ {
+ crError( "No support for non-DirectColor visuals with LUTs" );
+ }
+
+ cmap = XCreateColormap( dpy, RootWindow(dpy, vi->screen),
+ vi->visual, AllocAll );
+
+ for (a=0; a<256; a++)
+ {
+ col.red = render_spu.lut8[0][a]<<8;
+ col.green = col.blue = 0;
+ col.pixel = a<<16;
+ col.flags = DoRed;
+ XStoreColor(dpy, cmap, &col);
+ }
+
+ for (a=0; a<256; a++)
+ {
+ col.green = render_spu.lut8[1][a]<<8;
+ col.red = col.blue = 0;
+ col.pixel = a<<8;
+ col.flags = DoGreen;
+ XStoreColor(dpy, cmap, &col);
+ }
+
+ for (a=0; a<256; a++)
+ {
+ col.blue = render_spu.lut8[2][a]<<8;
+ col.red = col.green= 0;
+ col.pixel = a;
+ col.flags = DoBlue;
+ XStoreColor(dpy, cmap, &col);
+ }
+
+ return cmap;
+}
+
+static Colormap
+GetShareableColormap( Display *dpy, XVisualInfo *vi )
+{
+ Status status;
+ XStandardColormap *standardCmaps;
+ Colormap cmap;
+ int i, numCmaps;
+
+#if defined(__cplusplus) || defined(c_plusplus)
+ int localclass = vi->c_class; /* C++ */
+#else
+ int localclass = vi->class; /* C */
+#endif
+
+ if ( localclass != TrueColor )
+ {
+ crError( "No support for non-TrueColor visuals." );
+ }
+
+ status = XmuLookupStandardColormap( dpy, vi->screen, vi->visualid,
+ vi->depth, XA_RGB_DEFAULT_MAP,
+ False, True );
+
+ if ( status == 1 )
+ {
+ status = XGetRGBColormaps( dpy, RootWindow( dpy, vi->screen),
+ &standardCmaps, &numCmaps,
+ XA_RGB_DEFAULT_MAP );
+ if ( status == 1 )
+ {
+ for (i = 0 ; i < numCmaps ; i++)
+ {
+ if (standardCmaps[i].visualid == vi->visualid)
+ {
+ cmap = standardCmaps[i].colormap;
+ XFree( standardCmaps);
+ return cmap;
+ }
+ }
+ }
+ }
+
+ cmap = XCreateColormap( dpy, RootWindow(dpy, vi->screen),
+ vi->visual, AllocNone );
+ return cmap;
+}
+
+
+static int
+WaitForMapNotify( Display *display, XEvent *event, char *arg )
+{
+ (void)display;
+ return ( event->type == MapNotify && event->xmap.window == (Window)arg );
+}
+
+
+/**
+ * Return the X Visual ID of the given window
+ */
+static int
+GetWindowVisualID( Display *dpy, Window w )
+{
+ XWindowAttributes attr;
+ int k = XGetWindowAttributes(dpy, w, &attr);
+ if (!k)
+ return -1;
+ return attr.visual->visualid;
+}
+
+
+/**
+ * Wrapper for glXGetConfig().
+ */
+static int
+Attrib( const VisualInfo *visual, int attrib )
+{
+ int value = 0;
+ render_spu.ws.glXGetConfig( visual->dpy, visual->visual, attrib, &value );
+ return value;
+}
+
+
+
+/**
+ * Find a visual with the specified attributes. If we fail, turn off an
+ * attribute (like multisample or stereo) and try again.
+ */
+static XVisualInfo *
+chooseVisualRetry( Display *dpy, int screen, GLbitfield visAttribs )
+{
+ while (1) {
+ XVisualInfo *vis = crChooseVisual(&render_spu.ws, dpy, screen,
+ (GLboolean) render_spu.use_lut8,
+ visAttribs);
+ if (vis)
+ return vis;
+
+ if (visAttribs & CR_MULTISAMPLE_BIT)
+ visAttribs &= ~CR_MULTISAMPLE_BIT;
+ else if (visAttribs & CR_OVERLAY_BIT)
+ visAttribs &= ~CR_OVERLAY_BIT;
+ else if (visAttribs & CR_STEREO_BIT)
+ visAttribs &= ~CR_STEREO_BIT;
+ else if (visAttribs & CR_ACCUM_BIT)
+ visAttribs &= ~CR_ACCUM_BIT;
+ else if (visAttribs & CR_ALPHA_BIT)
+ visAttribs &= ~CR_ALPHA_BIT;
+ else
+ return NULL;
+ }
+}
+
+
+/**
+ * Get an FBconfig for the specified attributes
+ */
+#ifdef GLX_VERSION_1_3
+static GLXFBConfig
+chooseFBConfig( Display *dpy, int screen, GLbitfield visAttribs )
+{
+ GLXFBConfig *fbconfig;
+ int attribs[1000], attrCount = 0, numConfigs;
+ int major, minor;
+
+ CRASSERT(visAttribs & CR_PBUFFER_BIT);
+
+ /* Make sure pbuffers are supported */
+ render_spu.ws.glXQueryVersion(dpy, &major, &minor);
+ if (major * 100 + minor < 103) {
+ crWarning("Render SPU: GLX %d.%d doesn't support pbuffers", major, minor);
+ return 0;
+ }
+
+ attribs[attrCount++] = GLX_DRAWABLE_TYPE;
+ attribs[attrCount++] = GLX_PBUFFER_BIT;
+
+ if (visAttribs & CR_RGB_BIT) {
+ attribs[attrCount++] = GLX_RENDER_TYPE;
+ attribs[attrCount++] = GLX_RGBA_BIT;
+ attribs[attrCount++] = GLX_RED_SIZE;
+ attribs[attrCount++] = 1;
+ attribs[attrCount++] = GLX_GREEN_SIZE;
+ attribs[attrCount++] = 1;
+ attribs[attrCount++] = GLX_BLUE_SIZE;
+ attribs[attrCount++] = 1;
+ if (visAttribs & CR_ALPHA_BIT) {
+ attribs[attrCount++] = GLX_ALPHA_SIZE;
+ attribs[attrCount++] = 1;
+ }
+ }
+
+ if (visAttribs & CR_DEPTH_BIT) {
+ attribs[attrCount++] = GLX_DEPTH_SIZE;
+ attribs[attrCount++] = 1;
+ }
+
+ if (visAttribs & CR_DOUBLE_BIT) {
+ attribs[attrCount++] = GLX_DOUBLEBUFFER;
+ attribs[attrCount++] = True;
+ }
+ else {
+ /* don't care */
+ }
+
+ if (visAttribs & CR_STENCIL_BIT) {
+ attribs[attrCount++] = GLX_STENCIL_SIZE;
+ attribs[attrCount++] = 1;
+ }
+
+ if (visAttribs & CR_ACCUM_BIT) {
+ attribs[attrCount++] = GLX_ACCUM_RED_SIZE;
+ attribs[attrCount++] = 1;
+ attribs[attrCount++] = GLX_ACCUM_GREEN_SIZE;
+ attribs[attrCount++] = 1;
+ attribs[attrCount++] = GLX_ACCUM_BLUE_SIZE;
+ attribs[attrCount++] = 1;
+ if (visAttribs & CR_ALPHA_BIT) {
+ attribs[attrCount++] = GLX_ACCUM_ALPHA_SIZE;
+ attribs[attrCount++] = 1;
+ }
+ }
+
+ if (visAttribs & CR_MULTISAMPLE_BIT) {
+ attribs[attrCount++] = GLX_SAMPLE_BUFFERS_SGIS;
+ attribs[attrCount++] = 1;
+ attribs[attrCount++] = GLX_SAMPLES_SGIS;
+ attribs[attrCount++] = 4;
+ }
+
+ if (visAttribs & CR_STEREO_BIT) {
+ attribs[attrCount++] = GLX_STEREO;
+ attribs[attrCount++] = 1;
+ }
+
+ /* terminate */
+ attribs[attrCount++] = 0;
+
+ fbconfig = render_spu.ws.glXChooseFBConfig(dpy, screen, attribs, &numConfigs);
+ if (!fbconfig || numConfigs == 0) {
+ /* no matches! */
+ return 0;
+ }
+ if (numConfigs == 1) {
+ /* one match */
+ return fbconfig[0];
+ }
+ else {
+ /* found several matches - try to find best one */
+ int i;
+
+ crDebug("Render SPU: glXChooseFBConfig found %d matches for visBits 0x%x",
+ numConfigs, visAttribs);
+ /* Skip/omit configs that have unneeded Z buffer or unneeded double
+ * buffering. Possible add other tests in the future.
+ */
+ for (i = 0; i < numConfigs; i++) {
+ int zBits, db;
+ render_spu.ws.glXGetFBConfigAttrib(dpy, fbconfig[i],
+ GLX_DEPTH_SIZE, &zBits);
+ if ((visAttribs & CR_DEPTH_BIT) == 0 && zBits > 0) {
+ /* omit fbconfig with unneeded Z */
+ continue;
+ }
+ render_spu.ws.glXGetFBConfigAttrib(dpy, fbconfig[i],
+ GLX_DOUBLEBUFFER, &db);
+ if ((visAttribs & CR_DOUBLE_BIT) == 0 && db) {
+ /* omit fbconfig with unneeded DB */
+ continue;
+ }
+
+ /* if we get here, use this config */
+ return fbconfig[i];
+ }
+
+ /* if we get here, we didn't find a better fbconfig */
+ return fbconfig[0];
+ }
+}
+#endif /* GLX_VERSION_1_3 */
+
+static const char * renderspuGetDisplayName()
+{
+ const char *dpyName;
+
+ if (render_spu.display_string[0])
+ dpyName = render_spu.display_string;
+ else
+ {
+ crWarning("Render SPU: no display..");
+ dpyName = NULL;
+ }
+ return dpyName;
+}
+
+static int renderspuWinCmdWinCreate(WindowInfo *pWindow)
+{
+ return VERR_NOT_IMPLEMENTED;
+}
+
+static int renderspuWinCmdWinDestroy(WindowInfo *pWindow)
+{
+ return VERR_NOT_IMPLEMENTED;
+}
+
+static int renderspuWinCmdInit()
+{
+ const char * dpyName;
+ int rc = VERR_GENERAL_FAILURE;
+
+ if (!crHashtableAllocRegisterKey(render_spu.windowTable, CR_RENDER_WINCMD_ID))
+ {
+ crError("CR_RENDER_WINCMD_ID %d is occupied already", CR_RENDER_WINCMD_ID);
+ return VERR_INVALID_STATE;
+ }
+
+ render_spu.pWinToInfoTable = crAllocHashtable();
+ if (render_spu.pWinToInfoTable)
+ {
+ dpyName = renderspuGetDisplayName();
+ if (dpyName)
+ {
+ GLboolean bRc = renderspuInitVisual(&render_spu.WinCmdVisual, dpyName, render_spu.default_visual);
+ if (bRc)
+ {
+ bRc = renderspuWinInitWithVisual(&render_spu.WinCmdWindow, &render_spu.WinCmdVisual, GL_FALSE, CR_RENDER_WINCMD_ID);
+ if (bRc)
+ {
+ XSelectInput(render_spu.WinCmdVisual.dpy, render_spu.WinCmdWindow.window, StructureNotifyMask);
+ render_spu.WinCmdAtom = XInternAtom(render_spu.WinCmdVisual.dpy, "VBoxWinCmd", False);
+ CRASSERT(render_spu.WinCmdAtom != None);
+ return VINF_SUCCESS;
+ }
+ else
+ {
+ crError("renderspuWinInitWithVisual failed");
+ }
+ /* there is no visual destroy impl currently
+ * @todo: implement */
+ }
+ else
+ {
+ crError("renderspuInitVisual failed");
+ }
+ }
+ else
+ {
+ crError("Render SPU: no display, aborting");
+ }
+ crFreeHashtable(render_spu.pWinToInfoTable, NULL);
+ render_spu.pWinToInfoTable = NULL;
+ }
+ else
+ {
+ crError("crAllocHashtable failed");
+ }
+ return rc;
+}
+
+static void renderspuWinCmdTerm()
+{
+ /* the window is not in the table, this will just ensure the key is freed */
+ crHashtableDelete(render_spu.windowTable, CR_RENDER_WINCMD_ID, NULL);
+ renderspuWinCleanup(&render_spu.WinCmdWindow);
+ crFreeHashtable(render_spu.pWinToInfoTable, NULL);
+ /* we do not have visual destroy functionality
+ * @todo implement */
+}
+
+
+static bool renderspuWinCmdProcess(CR_RENDER_WINCMD* pWinCmd)
+{
+ bool fExit = false;
+ /* process commands */
+ switch (pWinCmd->enmCmd)
+ {
+ case CR_RENDER_WINCMD_TYPE_WIN_ON_CREATE:
+ crHashtableAdd(render_spu.pWinToInfoTable, pWinCmd->pWindow->window, pWinCmd->pWindow);
+ XSelectInput(render_spu.WinCmdVisual.dpy, pWinCmd->pWindow->window, ExposureMask);
+ pWinCmd->rc = VINF_SUCCESS;
+ break;
+ case CR_RENDER_WINCMD_TYPE_WIN_ON_DESTROY:
+ crHashtableDelete(render_spu.pWinToInfoTable, pWinCmd->pWindow->window, NULL);
+ pWinCmd->rc = VINF_SUCCESS;
+ break;
+ case CR_RENDER_WINCMD_TYPE_NOP:
+ pWinCmd->rc = VINF_SUCCESS;
+ break;
+ case CR_RENDER_WINCMD_TYPE_EXIT:
+ renderspuWinCmdTerm();
+ pWinCmd->rc = VINF_SUCCESS;
+ fExit = true;
+ pWinCmd->rc = VINF_SUCCESS;
+ break;
+ case CR_RENDER_WINCMD_TYPE_WIN_CREATE:
+ pWinCmd->rc = renderspuWinCmdWinCreate(pWinCmd->pWindow);
+ break;
+ case CR_RENDER_WINCMD_TYPE_WIN_DESTROY:
+ pWinCmd->rc = renderspuWinCmdWinDestroy(pWinCmd->pWindow);
+ break;
+ default:
+ crError("unknown WinCmd command! %d", pWinCmd->enmCmd);
+ pWinCmd->rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ RTSemEventSignal(render_spu.hWinCmdCompleteEvent);
+ return fExit;
+}
+
+static DECLCALLBACK(int) renderspuWinCmdThreadProc(RTTHREAD ThreadSelf, void *pvUser)
+{
+ int rc;
+ bool fExit = false;
+ crDebug("RenderSPU: Window thread started (%x)", crThreadID());
+
+ rc = renderspuWinCmdInit();
+
+ /* notify the main cmd thread that we have started */
+ RTSemEventSignal(render_spu.hWinCmdCompleteEvent);
+
+ if (!RT_SUCCESS(rc))
+ {
+ CRASSERT(!render_spu.pWinToInfoTable);
+ return rc;
+ }
+
+ do
+ {
+ XEvent event;
+ XNextEvent(render_spu.WinCmdVisual.dpy, &event);
+
+ switch (event.type)
+ {
+ case ClientMessage:
+ {
+ CRASSERT(event.xclient.window == render_spu.WinCmdWindow.window);
+ if (event.xclient.window == render_spu.WinCmdWindow.window)
+ {
+ if (render_spu.WinCmdAtom == event.xclient.message_type)
+ {
+ CR_RENDER_WINCMD *pWinCmd;
+ memcpy(&pWinCmd, event.xclient.data.b, sizeof (pWinCmd));
+ fExit = renderspuWinCmdProcess(pWinCmd);
+ }
+ }
+
+ break;
+ }
+ case Expose:
+ {
+ if (!event.xexpose.count)
+ {
+ WindowInfo *pWindow = (WindowInfo*)crHashtableSearch(render_spu.pWinToInfoTable, event.xexpose.window);
+ if (pWindow)
+ {
+ const struct VBOXVR_SCR_COMPOSITOR * pCompositor;
+
+ pCompositor = renderspuVBoxCompositorAcquire(pWindow);
+ if (pCompositor)
+ {
+ renderspuVBoxPresentCompositionGeneric(pWindow, pCompositor, NULL, 0, false);
+ renderspuVBoxCompositorRelease(pWindow);
+ }
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ } while (!fExit);
+
+ return 0;
+}
+
+static int renderspuWinCmdSubmit(CR_RENDER_WINCMD_TYPE enmCmd, WindowInfo *pWindow)
+{
+ Status status;
+ XEvent event;
+ CR_RENDER_WINCMD WinCmd, *pWinCmd;
+ int rc;
+
+ pWinCmd = &WinCmd;
+ pWinCmd->enmCmd = enmCmd;
+ pWinCmd->rc = VERR_GENERAL_FAILURE;
+ pWinCmd->pWindow = pWindow;
+
+ memset(&event, 0, sizeof (event));
+ event.type = ClientMessage;
+ event.xclient.window = render_spu.WinCmdWindow.window;
+ event.xclient.message_type = render_spu.WinCmdAtom;
+ event.xclient.format = 8;
+ memcpy(event.xclient.data.b, &pWinCmd, sizeof (pWinCmd));
+
+ status = XSendEvent(render_spu.pCommunicationDisplay, render_spu.WinCmdWindow.window, False, StructureNotifyMask, &event);
+ if (!status)
+ {
+ Assert(0);
+ crWarning("XSendEvent returned null");
+ return VERR_GENERAL_FAILURE;
+ }
+
+ XFlush(render_spu.pCommunicationDisplay);
+ rc = RTSemEventWaitNoResume(render_spu.hWinCmdCompleteEvent, RT_INDEFINITE_WAIT);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("RTSemEventWaitNoResume failed rc %d", rc);
+ return rc;
+ }
+ return pWinCmd->rc;
+}
+
+int renderspu_SystemInit()
+{
+ const char * dpyName;
+ int rc = VERR_GENERAL_FAILURE;
+
+ if (!render_spu.use_glxchoosevisual) {
+ /* sometimes want to set this option with ATI drivers */
+ render_spu.ws.glXChooseVisual = NULL;
+ }
+
+ /* setup communication display connection */
+ dpyName = renderspuGetDisplayName();
+ if (!dpyName)
+ {
+ crWarning("no display name, aborting");
+ return VERR_GENERAL_FAILURE;
+ }
+
+ render_spu.pCommunicationDisplay = XOpenDisplay(dpyName);
+ if (!render_spu.pCommunicationDisplay)
+ {
+ crWarning( "Couldn't open X display named '%s'", dpyName );
+ return VERR_GENERAL_FAILURE;
+ }
+
+ if ( !render_spu.ws.glXQueryExtension( render_spu.pCommunicationDisplay, NULL, NULL ) )
+ {
+ crWarning( "Render SPU: Display %s doesn't support GLX", dpyName );
+ return VERR_GENERAL_FAILURE;
+ }
+
+ rc = RTSemEventCreate(&render_spu.hWinCmdCompleteEvent);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTThreadCreate(&render_spu.hWinCmdThread, renderspuWinCmdThreadProc, NULL, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "VBoxCrWinCmd");
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTSemEventWait(render_spu.hWinCmdCompleteEvent, RT_INDEFINITE_WAIT);
+ if (RT_SUCCESS(rc))
+ {
+ return VINF_SUCCESS;
+ }
+ else
+ {
+ crWarning("RTSemEventWait failed rc %d", rc);
+ }
+
+ RTThreadWait(render_spu.hWinCmdThread, RT_INDEFINITE_WAIT, NULL);
+ }
+ else
+ {
+ crWarning("RTThreadCreate failed rc %d", rc);
+ }
+ RTSemEventDestroy(render_spu.hWinCmdCompleteEvent);
+ }
+ else
+ {
+ crWarning("RTSemEventCreate failed rc %d", rc);
+ }
+
+ return rc;
+}
+
+int renderspu_SystemTerm()
+{
+ int rc = renderspuWinCmdSubmit(CR_RENDER_WINCMD_TYPE_EXIT, NULL);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("renderspuWinCmdSubmit EXIT failed rc %d", rc);
+ return rc;
+ }
+
+ RTThreadWait(render_spu.hWinCmdThread, RT_INDEFINITE_WAIT, NULL);
+ RTSemEventDestroy(render_spu.hWinCmdCompleteEvent);
+ return VINF_SUCCESS;
+}
+
+GLboolean
+renderspu_SystemInitVisual( VisualInfo *visual )
+{
+ const char *dpyName;
+ int screen;
+
+ CRASSERT(visual);
+
+#ifdef USE_OSMESA
+ if (render_spu.use_osmesa) {
+ /* A dummy visual - being non null is enough. */
+ visual->visual =(XVisualInfo *) "os";
+ return GL_TRUE;
+ }
+#endif
+
+ dpyName = renderspuGetDisplayName();
+ if (!dpyName)
+ {
+ crWarning("Render SPU: no display, aborting");
+ return GL_FALSE;
+ }
+
+
+ crInfo("Render SPU: Opening display %s", dpyName);
+
+ if (dpyName &&
+ (crStrncmp(dpyName, "localhost:11", 12) == 0 ||
+ crStrncmp(dpyName, "localhost:12", 12) == 0 ||
+ crStrncmp(dpyName, "localhost:13", 12) == 0)) {
+ /* Issue both debug and warning messages to make sure the
+ * message gets noticed!
+ */
+ crDebug("Render SPU: display string looks like a proxy X server!");
+ crDebug("Render SPU: This is usually a problem!");
+ crWarning("Render SPU: display string looks like a proxy X server!");
+ crWarning("Render SPU: This is usually a problem!");
+ }
+
+ visual->dpy = XOpenDisplay(dpyName);
+ if (!visual->dpy)
+ {
+ crWarning( "Couldn't open X display named '%s'", dpyName );
+ return GL_FALSE;
+ }
+
+ if ( !render_spu.ws.glXQueryExtension( visual->dpy, NULL, NULL ) )
+ {
+ crWarning( "Render SPU: Display %s doesn't support GLX", visual->displayName );
+ return GL_FALSE;
+ }
+
+ screen = DefaultScreen(visual->dpy);
+
+#ifdef GLX_VERSION_1_3
+ if (visual->visAttribs & CR_PBUFFER_BIT)
+ {
+ visual->fbconfig = chooseFBConfig(visual->dpy, screen, visual->visAttribs);
+ if (!visual->fbconfig) {
+ char s[1000];
+ renderspuMakeVisString( visual->visAttribs, s );
+ crWarning( "Render SPU: Display %s doesn't have the necessary fbconfig: %s",
+ dpyName, s );
+ XCloseDisplay(visual->dpy);
+ return GL_FALSE;
+ }
+ }
+ else
+#endif /* GLX_VERSION_1_3 */
+ {
+ visual->visual = chooseVisualRetry(visual->dpy, screen, visual->visAttribs);
+ if (!visual->visual) {
+ char s[1000];
+ renderspuMakeVisString( visual->visAttribs, s );
+ crWarning("Render SPU: Display %s doesn't have the necessary visual: %s",
+ dpyName, s );
+ XCloseDisplay(visual->dpy);
+ return GL_FALSE;
+ }
+ }
+
+ if ( render_spu.sync )
+ {
+ crDebug( "Render SPU: Turning on XSynchronize" );
+ XSynchronize( visual->dpy, True );
+ }
+
+ if (visual->visual) {
+ crDebug( "Render SPU: Choose visual id=0x%x: RGBA=(%d,%d,%d,%d) Z=%d"
+ " stencil=%d double=%d stereo=%d accum=(%d,%d,%d,%d)",
+ (int) visual->visual->visualid,
+ Attrib( visual, GLX_RED_SIZE ),
+ Attrib( visual, GLX_GREEN_SIZE ),
+ Attrib( visual, GLX_BLUE_SIZE ),
+ Attrib( visual, GLX_ALPHA_SIZE ),
+ Attrib( visual, GLX_DEPTH_SIZE ),
+ Attrib( visual, GLX_STENCIL_SIZE ),
+ Attrib( visual, GLX_DOUBLEBUFFER ),
+ Attrib( visual, GLX_STEREO ),
+ Attrib( visual, GLX_ACCUM_RED_SIZE ),
+ Attrib( visual, GLX_ACCUM_GREEN_SIZE ),
+ Attrib( visual, GLX_ACCUM_BLUE_SIZE ),
+ Attrib( visual, GLX_ACCUM_ALPHA_SIZE )
+ );
+ }
+ else if (visual->fbconfig) {
+ int id;
+ render_spu.ws.glXGetFBConfigAttrib(visual->dpy, visual->fbconfig,
+ GLX_FBCONFIG_ID, &id);
+ crDebug("Render SPU: Chose FBConfig 0x%x, visBits=0x%x",
+ id, visual->visAttribs);
+ }
+
+ return GL_TRUE;
+}
+
+
+/*
+ * Add a GLX window to a swap group for inter-machine SwapBuffer
+ * synchronization.
+ * Only supported on NVIDIA Quadro 3000G hardware.
+ */
+static void
+JoinSwapGroup(Display *dpy, int screen, Window window,
+ GLuint group, GLuint barrier)
+{
+ GLuint maxGroups, maxBarriers;
+ const char *ext;
+ Bool b;
+
+ /*
+ * XXX maybe query glXGetClientString() instead???
+ */
+ ext = render_spu.ws.glXQueryExtensionsString(dpy, screen);
+
+ if (!crStrstr(ext, "GLX_NV_swap_group") ||
+ !render_spu.ws.glXQueryMaxSwapGroupsNV ||
+ !render_spu.ws.glXJoinSwapGroupNV ||
+ !render_spu.ws.glXBindSwapBarrierNV) {
+ crWarning("Render SPU: nv_swap_group is set but GLX_NV_swap_group is not supported on this system!");
+ return;
+ }
+
+ b = render_spu.ws.glXQueryMaxSwapGroupsNV(dpy, screen,
+ &maxGroups, &maxBarriers);
+ if (!b)
+ crWarning("Render SPU: call to glXQueryMaxSwapGroupsNV() failed!");
+
+ if (group >= maxGroups) {
+ crWarning("Render SPU: nv_swap_group too large (%d > %d)",
+ group, (int) maxGroups);
+ return;
+ }
+ crDebug("Render SPU: max swap groups = %d, max barriers = %d",
+ maxGroups, maxBarriers);
+
+ /* add this window to the swap group */
+ b = render_spu.ws.glXJoinSwapGroupNV(dpy, window, group);
+ if (!b) {
+ crWarning("Render SPU: call to glXJoinSwapGroupNV() failed!");
+ return;
+ }
+ else {
+ crDebug("Render SPU: call to glXJoinSwapGroupNV() worked!");
+ }
+
+ /* ... and bind window to barrier of same ID */
+ b = render_spu.ws.glXBindSwapBarrierNV(dpy, group, barrier);
+ if (!b) {
+ crWarning("Render SPU: call to glXBindSwapBarrierNV(group=%d barrier=%d) failed!", group, barrier);
+ return;
+ }
+ else {
+ crDebug("Render SPU: call to glXBindSwapBarrierNV(group=%d barrier=%d) worked!", group, barrier);
+ }
+
+ crDebug("Render SPU: window has joined swap group %d", group);
+}
+
+
+
+static GLboolean
+createWindow( VisualInfo *visual, GLboolean showIt, WindowInfo *window )
+{
+ Display *dpy;
+ Colormap cmap;
+ XSetWindowAttributes swa;
+ XSizeHints hints = {0};
+ XEvent event;
+ XTextProperty text_prop;
+ XClassHint *class_hints = NULL;
+ Window parent;
+ char *name;
+ unsigned long flags;
+ unsigned int vncWin;
+
+ CRASSERT(visual);
+ window->visual = visual;
+ window->nativeWindow = 0;
+
+#ifdef USE_OSMESA
+ if (render_spu.use_osmesa)
+ return GL_TRUE;
+#endif
+
+ dpy = visual->dpy;
+
+ if ( render_spu.use_L2 )
+ {
+ crWarning( "Render SPU: Going fullscreen because we think we're using Lightning-2." );
+ render_spu.fullscreen = 1;
+ }
+
+ /*
+ * Query screen size if we're going full-screen
+ */
+ if ( render_spu.fullscreen )
+ {
+ XWindowAttributes xwa;
+ Window root_window;
+
+ /* disable the screensaver */
+ XSetScreenSaver( dpy, 0, 0, PreferBlanking, AllowExposures );
+ crDebug( "Render SPU: Just turned off the screensaver" );
+
+ /* Figure out how big the screen is, and make the window that size */
+ root_window = DefaultRootWindow( dpy );
+ XGetWindowAttributes( dpy, root_window, &xwa );
+
+ crDebug( "Render SPU: root window size: %d x %d", xwa.width, xwa.height );
+
+ window->x = 0;
+ window->y = 0;
+ window->BltInfo.width = xwa.width;
+ window->BltInfo.height = xwa.height;
+ }
+
+ /* i've changed default window size to be 0,0 but X doesn't like it */
+ /*CRASSERT(window->BltInfo.width >= 1);
+ CRASSERT(window->BltInfo.height >= 1);*/
+ if (window->BltInfo.width < 1) window->BltInfo.width = 1;
+ if (window->BltInfo.height < 1) window->BltInfo.height = 1;
+
+ /*
+ * Get a colormap.
+ */
+ if (render_spu.use_lut8)
+ cmap = GetLUTColormap( dpy, visual->visual );
+ else
+ cmap = GetShareableColormap( dpy, visual->visual );
+ if ( !cmap ) {
+ crError( "Render SPU: Unable to get a colormap!" );
+ return GL_FALSE;
+ }
+
+ /* destroy existing window if there is one */
+ if (window->window) {
+ XDestroyWindow(dpy, window->window);
+ }
+
+ /*
+ * Create the window
+ *
+ * POSSIBLE OPTIMIZATION:
+ * If we're using the render_to_app_window or render_to_crut_window option
+ * (or DMX) we may never actually use this X window. So we could perhaps
+ * delay its creation until glXMakeCurrent is called. With NVIDIA's OpenGL
+ * driver, creating a lot of GLX windows can eat up a lot of VRAM and lead
+ * to slow, software-fallback rendering. Apps that use render_to_app_window,
+ * etc should set the default window size very small to avoid this.
+ * See dmx.conf for example.
+ */
+ swa.colormap = cmap;
+ swa.border_pixel = 0;
+ swa.event_mask = ExposureMask | StructureNotifyMask;
+ swa.override_redirect = 1;
+
+ flags = CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect;
+
+ /*
+ * We pass the VNC's desktop windowID via an environment variable.
+ * If we don't find one, we're not on a 3D-capable vncviewer, or
+ * if we do find one, then create the renderspu subwindow as a
+ * child of the vncviewer's desktop window.
+ *
+ * This is purely for the replicateSPU.
+ *
+ * NOTE: This is crufty, and will do for now. FIXME.
+ */
+ vncWin = crStrToInt( crGetenv("CRVNCWINDOW") );
+ if (vncWin)
+ parent = (Window) vncWin;
+ else
+ parent = RootWindow(dpy, visual->visual->screen);
+
+ if (render_spu_parent_window_id>0)
+ {
+ crDebug("Render SPU: VBox parent window_id is: %x", render_spu_parent_window_id);
+ window->window = XCreateWindow(dpy, render_spu_parent_window_id,
+ window->x, window->y,
+ window->BltInfo.width, window->BltInfo.height,
+ 0, visual->visual->depth, InputOutput,
+ visual->visual->visual, flags, &swa);
+ }
+ else
+ {
+ /* This should happen only at the call from crVBoxServerInit. At this point we don't
+ * know render_spu_parent_window_id yet, nor we need it for default window which is hidden.
+ */
+
+ crDebug("Render SPU: Creating global window, parent: %x", RootWindow(dpy, visual->visual->screen));
+ window->window = XCreateWindow(dpy, RootWindow(dpy, visual->visual->screen),
+ window->x, window->y,
+ window->BltInfo.width, window->BltInfo.height,
+ 0, visual->visual->depth, InputOutput,
+ visual->visual->visual, flags, &swa);
+ }
+
+ if (!window->window) {
+ crWarning( "Render SPU: unable to create window" );
+ return GL_FALSE;
+ }
+
+ crDebug( "Render SPU: Created window 0x%x on display %s, Xvisual 0x%x",
+ (int) window->window,
+ DisplayString(visual->dpy),
+ (int) visual->visual->visual->visualid /* yikes */
+ );
+
+ if (render_spu.fullscreen || render_spu.borderless)
+ {
+ /* Disable border/decorations with an MWM property (observed by most
+ * modern window managers.
+ */
+ PropMotifWmHints motif_hints;
+ Atom prop, proptype;
+
+ /* setup the property */
+ motif_hints.flags = MWM_HINTS_DECORATIONS;
+ motif_hints.decorations = 0; /* Turn off all decorations */
+
+ /* get the atom for the property */
+ prop = XInternAtom( dpy, "_MOTIF_WM_HINTS", True );
+ if (prop) {
+ /* not sure this is correct, seems to work, XA_WM_HINTS didn't work */
+ proptype = prop;
+ XChangeProperty( dpy, window->window, /* display, window */
+ prop, proptype, /* property, type */
+ 32, /* format: 32-bit datums */
+ PropModeReplace, /* mode */
+ (unsigned char *) &motif_hints, /* data */
+ PROP_MOTIF_WM_HINTS_ELEMENTS /* nelements */
+ );
+ }
+ }
+
+ /* Make a clear cursor to get rid of the monitor cursor */
+ if ( render_spu.fullscreen )
+ {
+ Pixmap pixmap;
+ Cursor cursor;
+ XColor colour;
+ char clearByte = 0;
+
+ /* AdB - Only bother to create a 1x1 cursor (byte) */
+ pixmap = XCreatePixmapFromBitmapData(dpy, window->window, &clearByte,
+ 1, 1, 1, 0, 1);
+ if(!pixmap){
+ crWarning("Unable to create clear cursor pixmap");
+ return GL_FALSE;
+ }
+
+ cursor = XCreatePixmapCursor(dpy, pixmap, pixmap, &colour, &colour, 0, 0);
+ if(!cursor){
+ crWarning("Unable to create clear cursor from zero byte pixmap");
+ return GL_FALSE;
+ }
+ XDefineCursor(dpy, window->window, cursor);
+ XFreePixmap(dpy, pixmap);
+ }
+
+ hints.x = window->x;
+ hints.y = window->y;
+ hints.width = window->BltInfo.width;
+ hints.height = window->BltInfo.height;
+ hints.min_width = hints.width;
+ hints.min_height = hints.height;
+ hints.max_width = hints.width;
+ hints.max_height = hints.height;
+ if (render_spu.resizable)
+ hints.flags = USPosition | USSize;
+ else
+ hints.flags = USPosition | USSize | PMinSize | PMaxSize;
+ XSetStandardProperties( dpy, window->window,
+ WINDOW_NAME, WINDOW_NAME,
+ None, NULL, 0, &hints );
+
+ /* New item! This is needed so that the sgimouse server can find
+ * the crDebug window.
+ */
+ name = WINDOW_NAME;
+ XStringListToTextProperty( &name, 1, &text_prop );
+ XSetWMName( dpy, window->window, &text_prop );
+
+ /* Set window name, resource class */
+ class_hints = XAllocClassHint( );
+ class_hints->res_name = crStrdup( "foo" );
+ class_hints->res_class = crStrdup( "Chromium" );
+ XSetClassHint( dpy, window->window, class_hints );
+ crFree( class_hints->res_name );
+ crFree( class_hints->res_class );
+ XFree( class_hints );
+
+ if (showIt) {
+ XMapWindow( dpy, window->window );
+ XIfEvent( dpy, &event, WaitForMapNotify,
+ (char *) window->window );
+ }
+
+ if ((window->visual->visAttribs & CR_DOUBLE_BIT) && render_spu.nvSwapGroup) {
+ /* NOTE:
+ * If this SPU creates N windows we don't want to gang the N windows
+ * together!
+ * By adding the window ID to the nvSwapGroup ID we can be sure each
+ * app window is in a separate swap group while all the back-end windows
+ * which form a mural are in the same swap group.
+ */
+ GLuint group = 0; /*render_spu.nvSwapGroup + window->BltInfo.Base.id;*/
+ GLuint barrier = 0;
+ JoinSwapGroup(dpy, visual->visual->screen, window->window, group, barrier);
+ }
+
+ /*
+ * End GLX code
+ */
+ crDebug( "Render SPU: actual window x, y, width, height: %d, %d, %d, %d",
+ window->x, window->y, window->BltInfo.width, window->BltInfo.height );
+
+ XSync(dpy, 0);
+
+ if (window->BltInfo.Base.id != CR_RENDER_WINCMD_ID)
+ {
+ int rc = renderspuWinCmdSubmit(CR_RENDER_WINCMD_TYPE_WIN_ON_CREATE, window);
+ AssertRC(rc);
+ }
+
+ return GL_TRUE;
+}
+
+
+static GLboolean
+createPBuffer( VisualInfo *visual, WindowInfo *window )
+{
+ window->visual = visual;
+ window->x = 0;
+ window->y = 0;
+ window->nativeWindow = 0;
+
+ CRASSERT(window->BltInfo.width > 0);
+ CRASSERT(window->BltInfo.height > 0);
+
+#ifdef GLX_VERSION_1_3
+ {
+ int attribs[100], i = 0, w, h;
+ CRASSERT(visual->fbconfig);
+ w = window->BltInfo.width;
+ h = window->BltInfo.height;
+ attribs[i++] = GLX_PRESERVED_CONTENTS;
+ attribs[i++] = True;
+ attribs[i++] = GLX_PBUFFER_WIDTH;
+ attribs[i++] = w;
+ attribs[i++] = GLX_PBUFFER_HEIGHT;
+ attribs[i++] = h;
+ attribs[i++] = 0; /* terminator */
+ window->window = render_spu.ws.glXCreatePbuffer(visual->dpy,
+ visual->fbconfig, attribs);
+ if (window->window) {
+ crDebug("Render SPU: Allocated %d x %d pbuffer", w, h);
+ return GL_TRUE;
+ }
+ else {
+ crWarning("Render SPU: Failed to allocate %d x %d pbuffer", w, h);
+ return GL_FALSE;
+ }
+ }
+#endif /* GLX_VERSION_1_3 */
+ return GL_FALSE;
+}
+
+
+GLboolean
+renderspu_SystemCreateWindow( VisualInfo *visual, GLboolean showIt, WindowInfo *window )
+{
+ if (visual->visAttribs & CR_PBUFFER_BIT) {
+ window->BltInfo.width = render_spu.defaultWidth;
+ window->BltInfo.height = render_spu.defaultHeight;
+ return createPBuffer(visual, window);
+ }
+ else {
+ return createWindow(visual, showIt, window);
+ }
+}
+
+GLboolean
+renderspu_SystemVBoxCreateWindow( VisualInfo *visual, GLboolean showIt, WindowInfo *window )
+{
+ return renderspu_SystemCreateWindow(visual, showIt, window);
+}
+
+void
+renderspu_SystemDestroyWindow( WindowInfo *window )
+{
+ CRASSERT(window);
+ CRASSERT(window->visual);
+
+#ifdef USE_OSMESA
+ if (render_spu.use_osmesa)
+ {
+ crFree(window->buffer);
+ window->buffer = NULL;
+ }
+ else
+#endif
+ {
+ if (window->visual->visAttribs & CR_PBUFFER_BIT) {
+#ifdef GLX_VERSION_1_3
+ render_spu.ws.glXDestroyPbuffer(window->visual->dpy, window->window);
+#endif
+ }
+ else {
+ /* The value window->nativeWindow will only be non-NULL if the
+ * render_to_app_window option is set to true. In this case, we
+ * don't want to do anything, since we're not responsible for this
+ * window. I know...personal responsibility and all...
+ */
+ if (!window->nativeWindow) {
+ if (window->BltInfo.Base.id != CR_RENDER_WINCMD_ID)
+ {
+ int rc = renderspuWinCmdSubmit(CR_RENDER_WINCMD_TYPE_WIN_ON_DESTROY, window);
+ AssertRC(rc);
+ }
+ XDestroyWindow(window->visual->dpy, window->window);
+ XSync(window->visual->dpy, 0);
+ }
+ }
+ }
+ window->visual = NULL;
+ window->window = 0;
+}
+
+
+GLboolean
+renderspu_SystemCreateContext( VisualInfo *visual, ContextInfo *context, ContextInfo *sharedContext )
+{
+ Bool is_direct;
+ GLXContext sharedSystemContext = NULL;
+
+ CRASSERT(visual);
+ CRASSERT(context);
+
+ context->visual = visual;
+
+ if (sharedContext != NULL) {
+ sharedSystemContext = sharedContext->context;
+ }
+
+
+
+#ifdef USE_OSMESA
+ if (render_spu.use_osmesa) {
+ context->context = (GLXContext) render_spu.OSMesaCreateContext(OSMESA_RGB, 0);
+ if (context->context)
+ return GL_TRUE;
+ else
+ return GL_FALSE;
+ }
+#endif
+
+#ifdef GLX_VERSION_1_3
+ if (visual->visAttribs & CR_PBUFFER_BIT) {
+ context->context = render_spu.ws.glXCreateNewContext( visual->dpy,
+ visual->fbconfig,
+ GLX_RGBA_TYPE,
+ sharedSystemContext,
+ render_spu.try_direct);
+ }
+ else
+#endif
+ {
+ context->context = render_spu.ws.glXCreateContext( visual->dpy,
+ visual->visual,
+ sharedSystemContext,
+ render_spu.try_direct);
+ }
+ if (!context->context) {
+ crError( "Render SPU: Couldn't create rendering context" );
+ return GL_FALSE;
+ }
+
+ is_direct = render_spu.ws.glXIsDirect( visual->dpy, context->context );
+ if (visual->visual)
+ crDebug("Render SPU: Created %s context (%d) on display %s for visAttribs 0x%x",
+ is_direct ? "DIRECT" : "INDIRECT",
+ context->BltInfo.Base.id,
+ DisplayString(visual->dpy),
+ visual->visAttribs);
+
+ if ( render_spu.force_direct && !is_direct )
+ {
+ crError( "Render SPU: Direct rendering not possible." );
+ return GL_FALSE;
+ }
+
+ return GL_TRUE;
+}
+
+
+#define USE_GLX_COPYCONTEXT 0
+
+#if !USE_GLX_COPYCONTEXT
+
+/**
+ * Unfortunately, glXCopyContext() is broken sometimes (NVIDIA 76.76 driver).
+ * This bit of code gets and sets GL state we need to copy between contexts.
+ */
+struct saved_state
+{
+ /* XXX depending on the app, more state may be needed here */
+ GLboolean Lighting;
+ GLboolean LightEnabled[8];
+ GLfloat LightPos[8][4];
+ GLfloat LightAmbient[8][4];
+ GLfloat LightDiffuse[8][4];
+ GLfloat LightSpecular[8][4];
+ GLboolean DepthTest;
+};
+
+static struct saved_state SavedState;
+
+static void
+get_state(struct saved_state *s)
+{
+ int i;
+
+ s->Lighting = render_spu.self.IsEnabled(GL_LIGHTING);
+ for (i = 0; i < 8; i++) {
+ s->LightEnabled[i] = render_spu.self.IsEnabled(GL_LIGHT0 + i);
+ render_spu.self.GetLightfv(GL_LIGHT0 + i, GL_POSITION, s->LightPos[i]);
+ render_spu.self.GetLightfv(GL_LIGHT0 + i, GL_AMBIENT, s->LightAmbient[i]);
+ render_spu.self.GetLightfv(GL_LIGHT0 + i, GL_DIFFUSE, s->LightDiffuse[i]);
+ render_spu.self.GetLightfv(GL_LIGHT0 + i, GL_SPECULAR, s->LightSpecular[i]);
+ }
+
+ s->DepthTest = render_spu.self.IsEnabled(GL_DEPTH_TEST);
+}
+
+static void
+set_state(const struct saved_state *s)
+{
+ int i;
+
+ if (s->Lighting) {
+ render_spu.self.Enable(GL_LIGHTING);
+ }
+ else {
+ render_spu.self.Disable(GL_LIGHTING);
+ }
+
+ for (i = 0; i < 8; i++) {
+ if (s->LightEnabled[i]) {
+ render_spu.self.Enable(GL_LIGHT0 + i);
+ }
+ else {
+ render_spu.self.Disable(GL_LIGHT0 + i);
+ }
+ render_spu.self.Lightfv(GL_LIGHT0 + i, GL_POSITION, s->LightPos[i]);
+ render_spu.self.Lightfv(GL_LIGHT0 + i, GL_AMBIENT, s->LightAmbient[i]);
+ render_spu.self.Lightfv(GL_LIGHT0 + i, GL_DIFFUSE, s->LightDiffuse[i]);
+ render_spu.self.Lightfv(GL_LIGHT0 + i, GL_SPECULAR, s->LightSpecular[i]);
+ }
+
+ if (s->DepthTest)
+ render_spu.self.Enable(GL_DEPTH_TEST);
+ else
+ render_spu.self.Disable(GL_DEPTH_TEST);
+}
+
+#endif /* !USE_GLX_COPYCONTEXT */
+
+/**
+ * Recreate the GLX context for ContextInfo. The new context will use the
+ * visual specified by newVisualID.
+ */
+static void
+renderspu_RecreateContext( ContextInfo *context, int newVisualID )
+{
+ XVisualInfo templateVis, *vis;
+ long templateFlags;
+ int screen = 0, count;
+ GLXContext oldContext = context->context;
+
+ templateFlags = VisualScreenMask | VisualIDMask;
+ templateVis.screen = screen;
+ templateVis.visualid = newVisualID;
+ vis = XGetVisualInfo(context->visual->dpy, templateFlags, &templateVis, &count);
+ CRASSERT(vis);
+ if (!vis)
+ return;
+
+ /* create new context */
+ crDebug("Render SPU: Creating new GLX context with visual 0x%x", newVisualID);
+ context->context = render_spu.ws.glXCreateContext(context->visual->dpy,
+ vis, NULL,
+ render_spu.try_direct);
+ CRASSERT(context->context);
+
+#if USE_GLX_COPYCONTEXT
+ /* copy old context state to new context */
+ render_spu.ws.glXCopyContext(context->visual->dpy,
+ oldContext, context->context, ~0);
+ crDebug("Render SPU: Done copying context state");
+#endif
+
+ /* destroy old context */
+ render_spu.ws.glXDestroyContext(context->visual->dpy, oldContext);
+
+ context->visual->visual = vis;
+}
+
+
+void
+renderspu_SystemDestroyContext( ContextInfo *context )
+{
+#ifdef USE_OSMESA
+ if (render_spu.use_osmesa)
+ {
+ render_spu.OSMesaDestroyContext( (OSMesaContext) context->context );
+ }
+ else
+#endif
+ {
+#if 0
+ /* XXX disable for now - causes segfaults w/ NVIDIA's driver */
+ render_spu.ws.glXDestroyContext( context->visual->dpy, context->context );
+#endif
+ }
+ context->visual = NULL;
+ context->context = 0;
+}
+
+
+#ifdef USE_OSMESA
+static void
+check_buffer_size( WindowInfo *window )
+{
+ if (window->BltInfo.width != window->in_buffer_width
+ || window->BltInfo.height != window->in_buffer_height
+ || ! window->buffer) {
+ crFree(window->buffer);
+
+ window->buffer = crCalloc(window->BltInfo.width * window->BltInfo.height
+ * 4 * sizeof (GLubyte));
+
+ window->in_buffer_width = window->BltInfo.width;
+ window->in_buffer_height = window->BltInfo.height;
+
+ crDebug("Render SPU: dimensions changed to %d x %d", window->BltInfo.width, window->BltInfo.height);
+ }
+}
+#endif
+
+
+void
+renderspu_SystemMakeCurrent( WindowInfo *window, GLint nativeWindow,
+ ContextInfo *context )
+{
+ Bool b;
+
+ CRASSERT(render_spu.ws.glXMakeCurrent);
+
+ /*crDebug("%s nativeWindow=0x%x", __FUNCTION__, (int) nativeWindow);*/
+
+#ifdef USE_OSMESA
+ if (render_spu.use_osmesa) {
+ check_buffer_size(window);
+ render_spu.OSMesaMakeCurrent( (OSMesaContext) context->context,
+ window->buffer, GL_UNSIGNED_BYTE,
+ window->BltInfo.width, window->BltInfo.height);
+ return;
+ }
+#endif
+
+ nativeWindow = 0;
+
+ if (window && context) {
+ window->appWindow = nativeWindow;
+
+ if (window->visual != context->visual) {
+ crDebug("Render SPU: MakeCurrent visual mismatch (win(%d) bits:0x%x != ctx(%d) bits:0x%x); remaking window.",
+ window->BltInfo.Base.id, window->visual->visAttribs,
+ context->BltInfo.Base.id, context->visual->visAttribs);
+ /*
+ * XXX have to revisit this issue!!!
+ *
+ * But for now we destroy the current window
+ * and re-create it with the context's visual abilities
+ */
+#ifndef SOLARIS_9_X_BUG
+ /*
+ I'm having some really weird issues if I destroy this window
+ when I'm using the version of sunX that comes with Solaris 9.
+ Subsiquent glX calls return GLXBadCurrentWindow error.
+
+ This is an issue even when running Linux version and using
+ the Solaris 9 sunX as a display.
+ -- jw
+
+ jw: we might have to call glXMakeCurrent(dpy, 0, 0) to unbind
+ the context from the window before destroying it. -Brian
+ */
+ render_spu.ws.glXMakeCurrent(window->visual->dpy, 0, 0);
+ renderspu_SystemDestroyWindow( window );
+#endif
+ renderspu_SystemCreateWindow( context->visual, window->visible, window );
+ /*
+ crError("In renderspu_SystemMakeCurrent() window and context"
+ " weren't created with same visual!");
+ */
+ }
+
+ CRASSERT(context->context);
+
+#if 0
+ if (render_spu.render_to_crut_window) {
+ if (render_spu.crut_drawable == 0) {
+ /* We don't know the X drawable ID yet. Ask mothership for it. */
+ char response[8096];
+ CRConnection *conn = crMothershipConnect();
+ if (!conn)
+ {
+ crError("Couldn't connect to the mothership to get CRUT drawable-- "
+ "I have no idea what to do!");
+ }
+ crMothershipGetParam( conn, "crut_drawable", response );
+ render_spu.crut_drawable = crStrToInt(response);
+ crMothershipDisconnect(conn);
+
+ crDebug("Render SPU: using CRUT drawable: 0x%x",
+ render_spu.crut_drawable);
+ if (!render_spu.crut_drawable) {
+ crDebug("Render SPU: Crut drawable 0 is invalid");
+ /* Continue with nativeWindow = 0; we'll render to the window that
+ * we (the Render SPU) previously created.
+ */
+ }
+ }
+
+ nativeWindow = render_spu.crut_drawable;
+ }
+#endif
+
+ if ((render_spu.render_to_crut_window || render_spu.render_to_app_window)
+ && nativeWindow)
+ {
+ /* We're about to bind the rendering context to a window that we
+ * (the Render SPU) did not create. The window was created by the
+ * application or the CRUT server.
+ * Make sure the window ID is valid and that the window's X visual is
+ * the same as the rendering context's.
+ */
+ if (WindowExists(window->visual->dpy, nativeWindow))
+ {
+ int vid = GetWindowVisualID(window->visual->dpy, nativeWindow);
+ GLboolean recreated = GL_FALSE;
+
+ /* check that the window's visual and context's visual match */
+ if (vid != (int) context->visual->visual->visualid) {
+ crWarning("Render SPU: Can't bind context %d to CRUT/native window "
+ "0x%x because of different X visuals (0x%x != 0x%x)!",
+ context->BltInfo.Base.id, (int) nativeWindow,
+ vid, (int) context->visual->visual->visualid);
+ crWarning("Render SPU: Trying to recreate GLX context to match.");
+ /* Try to recreate the GLX context so that it uses the same
+ * GLX visual as the window.
+ */
+#if !USE_GLX_COPYCONTEXT
+ if (context->everCurrent) {
+ get_state(&SavedState);
+ }
+#endif
+ renderspu_RecreateContext(context, vid);
+ recreated = GL_TRUE;
+ }
+
+ /* OK, this should work */
+ window->nativeWindow = (Window) nativeWindow;
+ b = render_spu.ws.glXMakeCurrent( window->visual->dpy,
+ window->nativeWindow,
+ context->context );
+ CRASSERT(b);
+#if !USE_GLX_COPYCONTEXT
+ if (recreated) {
+ set_state(&SavedState);
+ }
+#endif
+ }
+ else
+ {
+ crWarning("Render SPU: render_to_app/crut_window option is set but "
+ "the window ID 0x%x is invalid on the display named %s",
+ (unsigned int) nativeWindow,
+ DisplayString(window->visual->dpy));
+ CRASSERT(window->window);
+ b = render_spu.ws.glXMakeCurrent( window->visual->dpy,
+ window->window, context->context );
+ CRASSERT(b);
+ }
+ }
+ else
+ {
+ /* This is the normal case - rendering to the render SPU's own window */
+ CRASSERT(window->window);
+#if 0
+ crDebug("calling glXMakecurrent(%p, 0x%x, 0x%x)",
+ window->visual->dpy,
+ (int) window->window, (int) context->context );
+#endif
+ b = render_spu.ws.glXMakeCurrent( window->visual->dpy,
+ window->window, context->context );
+ if (!b) {
+ crWarning("glXMakeCurrent(%p, 0x%x, %p) failed! (winId %d, ctxId %d)",
+ window->visual->dpy,
+ (int) window->window, (void *) context->context,
+ window->BltInfo.Base.id, context->BltInfo.Base.id );
+ }
+ /*CRASSERT(b);*/
+ }
+
+ /* XXX this is a total hack to work around an NVIDIA driver bug */
+#if 0
+ if (render_spu.self.GetFloatv && context->haveWindowPosARB) {
+ GLfloat f[4];
+ render_spu.self.GetFloatv(GL_CURRENT_RASTER_POSITION, f);
+ if (!window->everCurrent || f[1] < 0.0) {
+ crDebug("Render SPU: Resetting raster pos");
+ render_spu.self.WindowPos2iARB(0, 0);
+ }
+ }
+#endif
+ }
+ else
+ {
+ GET_CONTEXT(pCurCtx);
+ if (pCurCtx)
+ {
+ b = render_spu.ws.glXMakeCurrent( pCurCtx->currentWindow->visual->dpy, None, NULL);
+ if (!b) {
+ crWarning("glXMakeCurrent(%p, None, NULL) failed!", pCurCtx->currentWindow->visual->dpy);
+ }
+ }
+
+ }
+}
+
+
+/**
+ * Set window (or pbuffer) size.
+ */
+void
+renderspu_SystemWindowSize( WindowInfo *window, GLint w, GLint h )
+{
+#ifdef USE_OSMESA
+ if (render_spu.use_osmesa) {
+ window->BltInfo.width = w;
+ window->BltInfo.height = h;
+ check_buffer_size(window);
+ return;
+ }
+#endif
+
+ CRASSERT(window);
+ CRASSERT(window->visual);
+ if (window->visual->visAttribs & CR_PBUFFER_BIT)
+ {
+ /* resizing a pbuffer */
+ if (render_spu.pbufferWidth != 0 || render_spu.pbufferHeight != 0) {
+ /* size limit check */
+ if (w > render_spu.pbufferWidth || h > render_spu.pbufferHeight) {
+ crWarning("Render SPU: Request for %d x %d pbuffer is larger than "
+ "the configured size of %d x %d. ('pbuffer_size')",
+ w, h, render_spu.pbufferWidth, render_spu.pbufferHeight);
+ return;
+ }
+ /*
+ * If the requested new pbuffer size is greater than 1/2 the size of
+ * the max pbuffer, just use the max pbuffer size. This helps avoid
+ * problems with VRAM memory fragmentation. If we run out of VRAM
+ * for pbuffers, some drivers revert to software rendering. We want
+ * to avoid that!
+ */
+ if (w * h >= render_spu.pbufferWidth * render_spu.pbufferHeight / 2) {
+ /* increase the dimensions to the max pbuffer size now */
+ w = render_spu.pbufferWidth;
+ h = render_spu.pbufferHeight;
+ }
+ }
+
+ if (window->BltInfo.width != w || window->BltInfo.height != h) {
+ /* Only resize if the new dimensions really are different */
+#ifdef CHROMIUM_THREADSAFE
+ ContextInfo *currentContext = (ContextInfo *) crGetTSD(&_RenderTSD);
+#else
+ ContextInfo *currentContext = render_spu.currentContext;
+#endif
+ /* Can't resize pbuffers, so destroy it and make a new one */
+ render_spu.ws.glXDestroyPbuffer(window->visual->dpy, window->window);
+ window->BltInfo.width = w;
+ window->BltInfo.height = h;
+ crDebug("Render SPU: Creating new %d x %d PBuffer (id=%d)",
+ w, h, window->BltInfo.Base.id);
+ if (!createPBuffer(window->visual, window)) {
+ crWarning("Render SPU: Unable to create PBuffer (out of VRAM?)!");
+ }
+ else if (currentContext && currentContext->currentWindow == window) {
+ /* Determine if we need to bind the current context to new pbuffer */
+ render_spu.ws.glXMakeCurrent(window->visual->dpy,
+ window->window,
+ currentContext->context );
+ }
+ }
+ }
+ else {
+ if (!w || !h)
+ {
+ /* X can not handle zero sizes */
+ if (window->visible)
+ {
+ renderspu_SystemShowWindow( window, GL_FALSE );
+ }
+ return;
+ }
+ /* Resize ordinary X window */
+ /*
+ * This is ugly, but it seems to be the only thing that works.
+ * Basically, XResizeWindow() doesn't seem to always take effect
+ * immediately.
+ * Even after an XSync(), the GetWindowAttributes() call will sometimes
+ * return the old window size. So, we use a loop to repeat the window
+ * resize until it seems to take effect.
+ */
+ int attempt;
+ crDebug("Render SPU: XResizeWindow (%x, %x, %d, %d)", window->visual->dpy, window->window, w, h);
+ XResizeWindow(window->visual->dpy, window->window, w, h);
+ XSync(window->visual->dpy, 0);
+
+ if (!window->BltInfo.width || !window->BltInfo.height)
+ {
+ /* we have hidden the window instead of sizing it to (0;0) since X is unable to handle zero sizes */
+ if (window->visible)
+ {
+ renderspu_SystemShowWindow( window, GL_TRUE );
+ return;
+ }
+ }
+#if 0
+ for (attempt = 0; attempt < 3; attempt++) { /* try three times max */
+ XWindowAttributes attribs;
+ /* Now, query the window size */
+ XGetWindowAttributes(window->visual->dpy, window->window, &attribs);
+ if (attribs.width == w && attribs.height == h)
+ break;
+ /* sleep for a millisecond and try again */
+ crMsleep(1);
+ }
+#endif
+ }
+}
+
+
+void
+renderspu_SystemGetWindowGeometry( WindowInfo *window,
+ GLint *x, GLint *y, GLint *w, GLint *h )
+{
+#ifdef USE_OSMESA
+ if (render_spu.use_osmesa) {
+ *w = window->BltInfo.width;
+ *h = window->BltInfo.height;
+ return;
+ }
+#endif
+
+ CRASSERT(window);
+ CRASSERT(window->visual);
+ CRASSERT(window->window);
+ if (window->visual->visAttribs & CR_PBUFFER_BIT)
+ {
+ *x = 0;
+ *y = 0;
+ *w = window->BltInfo.width;
+ *h = window->BltInfo.height;
+ }
+ else
+ {
+ Window xw, child, root;
+ unsigned int width, height, bw, d;
+ int rx, ry;
+
+ if ((render_spu.render_to_app_window || render_spu.render_to_crut_window)
+ && window->nativeWindow) {
+ xw = window->nativeWindow;
+ }
+ else {
+ xw = window->window;
+ }
+
+ XGetGeometry(window->visual->dpy, xw, &root,
+ x, y, &width, &height, &bw, &d);
+
+ /* translate x/y to screen coords */
+ if (!XTranslateCoordinates(window->visual->dpy, xw, root,
+ 0, 0, &rx, &ry, &child)) {
+ rx = ry = 0;
+ }
+ *x = rx;
+ *y = ry;
+ *w = (int) width;
+ *h = (int) height;
+ }
+}
+
+
+void
+renderspu_SystemGetMaxWindowSize( WindowInfo *window, GLint *w, GLint *h )
+{
+ int scrn;
+#ifdef USE_OSMESA
+ if (render_spu.use_osmesa) {
+ *w = 2048;
+ *h = 2048;
+ return;
+ }
+#endif
+
+ CRASSERT(window);
+ CRASSERT(window->visual);
+ CRASSERT(window->window);
+
+ scrn = DefaultScreen(window->visual->dpy);
+ *w = DisplayWidth(window->visual->dpy, scrn);
+ *h = DisplayHeight(window->visual->dpy, scrn);
+}
+
+
+void
+renderspu_SystemWindowPosition( WindowInfo *window, GLint x, GLint y )
+{
+#ifdef USE_OSMESA
+ if (render_spu.use_osmesa)
+ return;
+#endif
+
+ CRASSERT(window);
+ CRASSERT(window->visual);
+ if ((window->visual->visAttribs & CR_PBUFFER_BIT) == 0)
+ {
+ crDebug("Render SPU: XMoveWindow (%x, %x, %d, %d)", window->visual->dpy, window->window, x, y);
+ XMoveWindow(window->visual->dpy, window->window, x, y);
+ XSync(window->visual->dpy, 0);
+ }
+}
+
+GLboolean renderspu_SystemWindowNeedEmptyPresent(WindowInfo *window)
+{
+ return GL_FALSE;
+}
+
+void
+renderspu_SystemWindowVisibleRegion( WindowInfo *window, GLint cRects, const GLint *pRects )
+{
+#ifdef USE_OSMESA
+ if (render_spu.use_osmesa)
+ return;
+#endif
+
+ CRASSERT(window);
+ CRASSERT(window->visual);
+ if ((window->visual->visAttribs & CR_PBUFFER_BIT) == 0)
+ {
+ int evb, erb, i;
+ XRectangle *pXRects;
+
+ if (!XShapeQueryExtension(window->visual->dpy, &evb, &erb))
+ {
+ crWarning("Render SPU: Display %s doesn't support SHAPE extension", window->visual->displayName);
+ return;
+ }
+
+ if (cRects>0)
+ {
+ pXRects = (XRectangle *) crAlloc(cRects * sizeof(XRectangle));
+
+ for (i=0; i<cRects; ++i)
+ {
+ pXRects[i].x = (short) pRects[4*i];
+ pXRects[i].y = (short) pRects[4*i+1];
+ pXRects[i].width = (unsigned short) (pRects[4*i+2]-pRects[4*i]);
+ pXRects[i].height = (unsigned short) (pRects[4*i+3]-pRects[4*i+1]);
+ }
+ }
+ else
+ {
+ pXRects = (XRectangle *) crAlloc(sizeof(XRectangle));
+ pXRects[0].x = 0;
+ pXRects[0].y = 0;
+ pXRects[0].width = 0;
+ pXRects[0].height = 0;
+ cRects = 1;
+ }
+
+ crDebug("Render SPU: XShapeCombineRectangles (%x, %x, cRects=%i)", window->visual->dpy, window->window, cRects);
+
+ XShapeCombineRectangles(window->visual->dpy, window->window, ShapeBounding, 0, 0,
+ pXRects, cRects, ShapeSet, YXBanded);
+ XSync(window->visual->dpy, 0);
+ crFree(pXRects);
+ }
+}
+
+/* Either show or hide the render SPU's window. */
+void
+renderspu_SystemShowWindow( WindowInfo *window, GLboolean showIt )
+{
+#ifdef USE_OSMESA
+ if (render_spu.use_osmesa)
+ return;
+#endif
+
+ if (window->visual->dpy && window->window &&
+ (window->visual->visAttribs & CR_PBUFFER_BIT) == 0)
+ {
+ if (showIt)
+ {
+ if (window->BltInfo.width && window->BltInfo.height)
+ {
+ XMapWindow( window->visual->dpy, window->window );
+ XSync(window->visual->dpy, 0);
+ }
+ }
+ else
+ {
+ XUnmapWindow( window->visual->dpy, window->window );
+ XSync(window->visual->dpy, 0);
+ }
+ }
+}
+
+void renderspu_SystemVBoxPresentComposition( WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pChangedEntry )
+{
+ /* The !render_spu.force_present_main_thread code flow is actually inspired
+ * by cocoa backend impl, here it forces rendering in WinCmd thread rather
+ * than a Main thread. It defaults to 1, because otherwise there were
+ * 3D driver incompatibilities on some systems. Elsewhere it causes flicker
+ * on NVidia GPUs. In principle would need root cause investigation. */
+ if (!render_spu.force_present_main_thread)
+ {
+ const struct VBOXVR_SCR_COMPOSITOR *pCompositor;
+ /* we do not want to be blocked with the GUI thread here, so only draw here if we are really able to do that w/o blocking */
+ int rc = renderspuVBoxCompositorTryAcquire(window, &pCompositor);
+ if (RT_SUCCESS(rc))
+ {
+ renderspuVBoxPresentCompositionGeneric(window, pCompositor, pChangedEntry, 0, false);
+ renderspuVBoxCompositorRelease(window);
+ }
+ else if (rc != VERR_SEM_BUSY)
+ {
+ /* this is somewhat we do not expect */
+ WARN(("renderspuVBoxCompositorTryAcquire failed rc %d", rc));
+ return;
+ }
+ }
+
+ {
+ Status status;
+ XEvent event;
+ render_spu.self.Flush();
+// renderspuVBoxPresentBlitterEnsureCreated(window, 0);
+
+ crMemset(&event, 0, sizeof (event));
+ event.type = Expose;
+ event.xexpose.window = window->window;
+ event.xexpose.width = window->BltInfo.width;
+ event.xexpose.height = window->BltInfo.height;
+ status = XSendEvent(render_spu.pCommunicationDisplay, render_spu.WinCmdWindow.window, False, 0, &event);
+ if (!status)
+ {
+ WARN(("XSendEvent returned null"));
+ }
+ XFlush(render_spu.pCommunicationDisplay);
+ }
+}
+
+static void
+MarkWindow(WindowInfo *w)
+{
+ static GC gc = 0; /* XXX per-window??? */
+ if (!gc) {
+ /* Create a GC for drawing invisible lines */
+ XGCValues gcValues;
+ gcValues.function = GXnoop;
+ gc = XCreateGC(w->visual->dpy, w->nativeWindow, GCFunction, &gcValues);
+ }
+ XDrawLine(w->visual->dpy, w->nativeWindow, gc, 0, 0, w->BltInfo.width, w->BltInfo.height);
+}
+
+
+void
+renderspu_SystemSwapBuffers( WindowInfo *w, GLint flags )
+{
+ CRASSERT(w);
+
+#if 00 /*TEMPORARY - FOR TESTING SWAP LOCK*/
+ if (1) {
+ /* random delay */
+ int k = crRandInt(1000 * 100, 750*1000);
+ static int first = 1;
+ if (first) {
+ crRandAutoSeed();
+ first = 0;
+ }
+ usleep(k);
+ }
+#endif
+
+ /* 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 (w->nativeWindow) {
+ render_spu.ws.glXSwapBuffers( w->visual->dpy, w->nativeWindow );
+#if 0
+ MarkWindow(w);
+#else
+ (void) MarkWindow;
+#endif
+ }
+ else {
+ render_spu.ws.glXSwapBuffers( w->visual->dpy, w->window );
+ }
+}
+
+void renderspu_SystemReparentWindow(WindowInfo *window)
+{
+ Window parent;
+
+ parent = render_spu_parent_window_id>0 ? render_spu_parent_window_id :
+ RootWindow(window->visual->dpy, window->visual->visual->screen);
+
+ XReparentWindow(window->visual->dpy, window->window, parent, window->x, window->y);
+ XSync(window->visual->dpy, False);
+}
+
+void renderspu_SystemDefaultSharedContextChanged(ContextInfo *fromContext, ContextInfo *toContext)
+{
+
+}
+
+uint32_t renderspu_SystemPostprocessFunctions(SPUNamedFunctionTable *aFunctions, uint32_t cFunctions, uint32_t cTable)
+{
+ return cFunctions;
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/render/renderspu_init.c b/src/VBox/HostServices/SharedOpenGL/render/renderspu_init.c
new file mode 100644
index 00000000..ec494a1f
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/render/renderspu_init.c
@@ -0,0 +1,623 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "cr_mem.h"
+#include "cr_spu.h"
+#include "cr_error.h"
+#include "cr_string.h"
+#include "cr_url.h"
+#include "cr_environment.h"
+#include "renderspu.h"
+#include <stdio.h>
+
+#ifdef RT_OS_DARWIN
+# include <iprt/semaphore.h>
+#endif /* RT_OS_DARWIN */
+
+static SPUNamedFunctionTable _cr_render_table[1000];
+
+SPUFunctions render_functions = {
+ NULL, /* CHILD COPY */
+ NULL, /* DATA */
+ _cr_render_table /* THE ACTUAL FUNCTIONS */
+};
+
+RenderSPU render_spu;
+uint64_t render_spu_parent_window_id = 0;
+
+#ifdef CHROMIUM_THREADSAFE
+CRtsd _RenderTSD;
+#endif
+
+static void swapsyncConnect(void)
+{
+ char hostname[4096], protocol[4096];
+ unsigned short port;
+
+ crNetInit(NULL, NULL);
+
+ if (!crParseURL( render_spu.swap_master_url, protocol, hostname,
+ &port, 9876))
+ crError( "Bad URL: %s", render_spu.swap_master_url );
+
+ if (render_spu.is_swap_master)
+ {
+ int a;
+
+ render_spu.swap_conns = (CRConnection **)crAlloc(
+ render_spu.num_swap_clients*sizeof(CRConnection *));
+ for (a=0; a<render_spu.num_swap_clients; a++)
+ {
+ render_spu.swap_conns[a] = crNetAcceptClient( protocol, hostname, port,
+ render_spu.swap_mtu, 1);
+ }
+ }
+ else
+ {
+ render_spu.swap_conns = (CRConnection **)crAlloc(sizeof(CRConnection *));
+
+ render_spu.swap_conns[0] = crNetConnectToServer(render_spu.swap_master_url,
+ port, render_spu.swap_mtu, 1);
+ if (!render_spu.swap_conns[0])
+ crError("Failed connection");
+ }
+}
+
+#ifdef RT_OS_WINDOWS
+static DWORD WINAPI renderSPUWindowThreadProc(void* unused)
+{
+ MSG msg;
+ BOOL bRet;
+
+ (void) unused;
+
+ /* Force system to create the message queue.
+ * Else, there's a chance that render spu will issue PostThreadMessage
+ * before this thread calls GetMessage for first time.
+ */
+ PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
+
+ crDebug("RenderSPU: Window thread started (%x)", crThreadID());
+ SetEvent(render_spu.hWinThreadReadyEvent);
+
+ while( (bRet = GetMessage( &msg, 0, 0, 0 )) != 0)
+ {
+ if (bRet == -1)
+ {
+ crError("RenderSPU: Window thread GetMessage failed (%x)", GetLastError());
+ break;
+ }
+ else
+ {
+ if (msg.message == WM_VBOX_RENDERSPU_CREATE_WINDOW)
+ {
+ LPCREATESTRUCT pCS = (LPCREATESTRUCT) msg.lParam;
+ HWND hWnd;
+ WindowInfo *pWindow = (WindowInfo *)pCS->lpCreateParams;
+
+ CRASSERT(msg.lParam && !msg.wParam && pCS->lpCreateParams);
+
+ hWnd = CreateWindowEx(pCS->dwExStyle, pCS->lpszName, pCS->lpszClass, pCS->style,
+ pCS->x, pCS->y, pCS->cx, pCS->cy,
+ pCS->hwndParent, pCS->hMenu, pCS->hInstance, &render_spu);
+
+ pWindow->hWnd = hWnd;
+
+ SetEvent(render_spu.hWinThreadReadyEvent);
+ }
+ else if (msg.message == WM_VBOX_RENDERSPU_DESTROY_WINDOW)
+ {
+ CRASSERT(msg.lParam && !msg.wParam);
+
+ DestroyWindow(((VBOX_RENDERSPU_DESTROY_WINDOW*) msg.lParam)->hWnd);
+
+ SetEvent(render_spu.hWinThreadReadyEvent);
+ }
+ else
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+ }
+
+ render_spu.dwWinThreadId = 0;
+
+ crDebug("RenderSPU: Window thread stopped (%x)", crThreadID());
+ SetEvent(render_spu.hWinThreadReadyEvent);
+
+ return 0;
+}
+#endif
+
+int renderspuDefaultCtxInit()
+{
+ GLint defaultWin, defaultCtx;
+ WindowInfo *windowInfo;
+
+ /*
+ * Create the default window and context. Their indexes are zero and
+ * a client can use them without calling CreateContext or WindowCreate.
+ */
+ crDebug("Render SPU: Creating default window (visBits=0x%x, id=0)",
+ render_spu.default_visual);
+ defaultWin = renderspuWindowCreateEx( NULL, render_spu.default_visual, CR_RENDER_DEFAULT_WINDOW_ID );
+ if (defaultWin != CR_RENDER_DEFAULT_WINDOW_ID) {
+ crError("Render SPU: Couldn't get a double-buffered, RGB visual with Z!");
+ return VERR_GENERAL_FAILURE;
+ }
+ crDebug( "Render SPU: WindowCreate returned %d (0=normal)", defaultWin );
+
+ crDebug("Render SPU: Creating default context, visBits=0x%x",
+ render_spu.default_visual );
+ defaultCtx = renderspuCreateContextEx( NULL, render_spu.default_visual, CR_RENDER_DEFAULT_CONTEXT_ID, 0 );
+ if (defaultCtx != CR_RENDER_DEFAULT_CONTEXT_ID) {
+ crError("Render SPU: failed to create default context!");
+ return VERR_GENERAL_FAILURE;
+ }
+
+ renderspuMakeCurrent( defaultWin, 0, defaultCtx );
+
+ /* Get windowInfo for the default window */
+ windowInfo = (WindowInfo *) crHashtableSearch(render_spu.windowTable, CR_RENDER_DEFAULT_WINDOW_ID);
+ CRASSERT(windowInfo);
+ windowInfo->mapPending = GL_TRUE;
+
+ return VINF_SUCCESS;
+}
+
+static SPUFunctions *
+renderSPUInit( int id, SPU *child, SPU *self,
+ unsigned int context_id, unsigned int num_contexts )
+{
+ int numFuncs, numSpecial;
+
+ const char * pcpwSetting;
+ int rc;
+
+ (void) child;
+ (void) context_id;
+ (void) num_contexts;
+
+ self->privatePtr = (void *) &render_spu;
+
+#ifdef CHROMIUM_THREADSAFE
+ crDebug("Render SPU: thread-safe");
+ crInitTSD(&_RenderTSD);
+#endif
+
+ crMemZero(&render_spu, sizeof(render_spu));
+
+ render_spu.id = id;
+ renderspuSetVBoxConfiguration(&render_spu);
+
+ if (render_spu.swap_master_url)
+ swapsyncConnect();
+
+
+ /* Get our special functions. */
+ numSpecial = renderspuCreateFunctions( _cr_render_table );
+
+#ifdef RT_OS_WINDOWS
+ /* Start thread to create windows and process window messages */
+ crDebug("RenderSPU: Starting windows serving thread");
+ render_spu.hWinThreadReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (!render_spu.hWinThreadReadyEvent)
+ {
+ crError("RenderSPU: Failed to create WinThreadReadyEvent! (%x)", GetLastError());
+ return NULL;
+ }
+
+ if (!CreateThread(NULL, 0, renderSPUWindowThreadProc, 0, 0, &render_spu.dwWinThreadId))
+ {
+ crError("RenderSPU: Failed to start windows thread! (%x)", GetLastError());
+ return NULL;
+ }
+ WaitForSingleObject(render_spu.hWinThreadReadyEvent, INFINITE);
+#endif
+
+ /* Get the OpenGL functions. */
+ numFuncs = crLoadOpenGL( &render_spu.ws, _cr_render_table + numSpecial );
+ if (numFuncs == 0) {
+ crError("The render SPU was unable to load the native OpenGL library");
+ return NULL;
+ }
+
+ numFuncs += numSpecial;
+
+ render_spu.contextTable = crAllocHashtableEx(1, INT32_MAX);
+ render_spu.windowTable = crAllocHashtableEx(1, INT32_MAX);
+
+ render_spu.dummyWindowTable = crAllocHashtable();
+
+ pcpwSetting = crGetenv("CR_RENDER_ENABLE_SINGLE_PRESENT_CONTEXT");
+ if (pcpwSetting)
+ {
+ if (pcpwSetting[0] == '0')
+ pcpwSetting = NULL;
+ }
+
+ if (pcpwSetting)
+ {
+ /** @todo need proper blitter synchronization, do not use so far!
+ * the problem is that rendering can be done in multiple thread: the main command (hgcm) thread and the redraw thread
+ * we currently use per-window synchronization, while we'll need a per-blitter synchronization if one blitter is used for multiple windows
+ * this is not done currently */
+ crWarning("TODO: need proper blitter synchronization, do not use so far!");
+ render_spu.blitterTable = crAllocHashtable();
+ CRASSERT(render_spu.blitterTable);
+ }
+ else
+ render_spu.blitterTable = NULL;
+
+ CRASSERT(render_spu.default_visual & CR_RGB_BIT);
+
+ rc = renderspu_SystemInit();
+ if (!RT_SUCCESS(rc))
+ {
+ crError("renderspu_SystemInit failed rc %d", rc);
+ return NULL;
+ }
+#ifdef USE_OSMESA
+ if (render_spu.use_osmesa) {
+ if (!crLoadOSMesa(&render_spu.OSMesaCreateContext,
+ &render_spu.OSMesaMakeCurrent,
+ &render_spu.OSMesaDestroyContext)) {
+ crError("Unable to load OSMesa library");
+ }
+ }
+#endif
+
+#ifdef DARWIN
+# ifdef VBOX_WITH_COCOA_QT
+# else /* VBOX_WITH_COCOA_QT */
+ render_spu.hRootVisibleRegion = 0;
+ render_spu.currentBufferName = 1;
+ render_spu.uiDockUpdateTS = 0;
+ /* Create a mutex for synchronizing events from the main Qt thread & this
+ thread */
+ RTSemFastMutexCreate(&render_spu.syncMutex);
+ /* Create our window groups */
+ CreateWindowGroup(kWindowGroupAttrMoveTogether | kWindowGroupAttrLayerTogether | kWindowGroupAttrSharedActivation | kWindowGroupAttrHideOnCollapse | kWindowGroupAttrFixedLevel, &render_spu.pMasterGroup);
+ CreateWindowGroup(kWindowGroupAttrMoveTogether | kWindowGroupAttrLayerTogether | kWindowGroupAttrSharedActivation | kWindowGroupAttrHideOnCollapse | kWindowGroupAttrFixedLevel, &render_spu.pParentGroup);
+ /* Make the correct z-layering */
+ SendWindowGroupBehind (render_spu.pParentGroup, render_spu.pMasterGroup);
+ /* and set the gParentGroup as parent for gMasterGroup. */
+ SetWindowGroupParent (render_spu.pMasterGroup, render_spu.pParentGroup);
+ /* Install the event handlers */
+ EventTypeSpec eventList[] =
+ {
+ {kEventClassVBox, kEventVBoxUpdateContext}, /* Update the context after show/size/move events */
+ {kEventClassVBox, kEventVBoxBoundsChanged} /* Clip/Pos the OpenGL windows when the main window is changed in pos/size */
+ };
+ /* We need to process events from our main window */
+ render_spu.hParentEventHandler = NewEventHandlerUPP(windowEvtHndlr);
+ InstallApplicationEventHandler (render_spu.hParentEventHandler,
+ GetEventTypeCount(eventList), eventList,
+ NULL, NULL);
+ render_spu.fInit = true;
+# endif /* VBOX_WITH_COCOA_QT */
+#endif /* DARWIN */
+
+ rc = renderspuDefaultCtxInit();
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("renderspuDefaultCtxInit failed %d", rc));
+ return NULL;
+ }
+
+ /*
+ * Get the OpenGL extension functions.
+ * SIGH -- we have to wait until the very bitter end to load the
+ * extensions, because the context has to be bound before
+ * wglGetProcAddress will work correctly. No such issue with GLX though.
+ */
+ numFuncs += crLoadOpenGLExtensions( &render_spu.ws, _cr_render_table + numFuncs );
+ CRASSERT(numFuncs < 1000);
+
+#ifdef WINDOWS
+ /*
+ * Same problem as above, these are extensions so we need to
+ * load them after a context has been bound. As they're WGL
+ * extensions too, we can't simply tag them into the spu_loader.
+ * So we do them here for now.
+ * Grrr, NVIDIA driver uses EXT for GetExtensionsStringEXT,
+ * but ARB for others. Need further testing here....
+ */
+ render_spu.ws.wglGetExtensionsStringEXT =
+ (wglGetExtensionsStringEXTFunc_t)
+ render_spu.ws.wglGetProcAddress( "wglGetExtensionsStringEXT" );
+ render_spu.ws.wglChoosePixelFormatEXT =
+ (wglChoosePixelFormatEXTFunc_t)
+ render_spu.ws.wglGetProcAddress( "wglChoosePixelFormatARB" );
+ render_spu.ws.wglGetPixelFormatAttribivEXT =
+ (wglGetPixelFormatAttribivEXTFunc_t)
+ render_spu.ws.wglGetProcAddress( "wglGetPixelFormatAttribivARB" );
+ render_spu.ws.wglGetPixelFormatAttribfvEXT =
+ (wglGetPixelFormatAttribfvEXTFunc_t)
+ render_spu.ws.wglGetProcAddress( "wglGetPixelFormatAttribfvARB" );
+
+ if (render_spu.ws.wglGetProcAddress("glCopyTexSubImage3D"))
+ {
+ _cr_render_table[numFuncs].name = crStrdup("CopyTexSubImage3D");
+ _cr_render_table[numFuncs].fn = (SPUGenericFunction) render_spu.ws.wglGetProcAddress("glCopyTexSubImage3D");
+ ++numFuncs;
+ crDebug("Render SPU: Found glCopyTexSubImage3D function");
+ }
+
+ if (render_spu.ws.wglGetProcAddress("glDrawRangeElements"))
+ {
+ _cr_render_table[numFuncs].name = crStrdup("DrawRangeElements");
+ _cr_render_table[numFuncs].fn = (SPUGenericFunction) render_spu.ws.wglGetProcAddress("glDrawRangeElements");
+ ++numFuncs;
+ crDebug("Render SPU: Found glDrawRangeElements function");
+ }
+
+ if (render_spu.ws.wglGetProcAddress("glTexSubImage3D"))
+ {
+ _cr_render_table[numFuncs].name = crStrdup("TexSubImage3D");
+ _cr_render_table[numFuncs].fn = (SPUGenericFunction) render_spu.ws.wglGetProcAddress("glTexSubImage3D");
+ ++numFuncs;
+ crDebug("Render SPU: Found glTexSubImage3D function");
+ }
+
+ if (render_spu.ws.wglGetProcAddress("glTexImage3D"))
+ {
+ _cr_render_table[numFuncs].name = crStrdup("TexImage3D");
+ _cr_render_table[numFuncs].fn = (SPUGenericFunction) render_spu.ws.wglGetProcAddress("glTexImage3D");
+ ++numFuncs;
+ crDebug("Render SPU: Found glTexImage3D function");
+ }
+
+ if (render_spu.ws.wglGetExtensionsStringEXT) {
+ crDebug("WGL - found wglGetExtensionsStringEXT\n");
+ }
+ if (render_spu.ws.wglChoosePixelFormatEXT) {
+ crDebug("WGL - found wglChoosePixelFormatEXT\n");
+ }
+#endif
+
+ render_spu.barrierHash = crAllocHashtable();
+
+ render_spu.cursorX = 0;
+ render_spu.cursorY = 0;
+ render_spu.use_L2 = 0;
+
+ render_spu.gather_conns = NULL;
+
+ numFuncs = renderspu_SystemPostprocessFunctions(_cr_render_table, numFuncs, RT_ELEMENTS(_cr_render_table));
+
+ crDebug("Render SPU: ---------- End of Init -------------");
+
+ return &render_functions;
+}
+
+static void renderSPUSelfDispatch(SPUDispatchTable *self)
+{
+ crSPUInitDispatchTable( &(render_spu.self) );
+ crSPUCopyDispatchTable( &(render_spu.self), self );
+
+ crSPUInitDispatchTable( &(render_spu.blitterDispatch) );
+ crSPUCopyDispatchTable( &(render_spu.blitterDispatch), self );
+
+ render_spu.server = (CRServer *)(self->server);
+
+ {
+ GLfloat version;
+ version = crStrToFloat((const char *) render_spu.ws.glGetString(GL_VERSION));
+
+ if (version>=2.f || crStrstr((const char*)render_spu.ws.glGetString(GL_EXTENSIONS), "GL_ARB_vertex_shader"))
+ {
+ GLint mu=0;
+ render_spu.self.GetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, &mu);
+ crInfo("Render SPU: GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB=%i", mu);
+ }
+ }
+}
+
+
+static void DeleteContextCallback( void *data )
+{
+ ContextInfo *context = (ContextInfo *) data;
+ renderspuContextMarkDeletedAndRelease(context);
+}
+
+static void DeleteWindowCallback( void *data )
+{
+ WindowInfo *window = (WindowInfo *) data;
+ renderspuWinTermOnShutdown(window);
+ renderspuWinRelease(window);
+}
+
+static void DeleteBlitterCallback( void *data )
+{
+ PCR_BLITTER pBlitter = (PCR_BLITTER) data;
+ CrBltTerm(pBlitter);
+ crFree(pBlitter);
+}
+
+static void renderspuBlitterCleanupCB(unsigned long key, void *data1, void *data2)
+{
+ WindowInfo *window = (WindowInfo *) data1;
+ CRASSERT(window);
+
+ renderspuVBoxPresentBlitterCleanup( window );
+}
+
+
+static void renderspuDeleteBlitterCB(unsigned long key, void *data1, void *data2)
+{
+ CRHashTable *pTbl = (CRHashTable*)data2;
+
+ crHashtableDelete( pTbl, key, NULL );
+
+ DeleteBlitterCallback(data1);
+}
+
+
+static void renderspuDeleteWindowCB(unsigned long key, void *data1, void *data2)
+{
+ CRHashTable *pTbl = (CRHashTable*)data2;
+
+ crHashtableDelete( pTbl, key, NULL );
+
+ DeleteWindowCallback(data1);
+}
+
+static void renderspuDeleteBarierCB(unsigned long key, void *data1, void *data2)
+{
+ CRHashTable *pTbl = (CRHashTable*)data2;
+
+ crHashtableDelete( pTbl, key, NULL );
+
+ crFree(data1);
+}
+
+
+static void renderspuDeleteContextCB(unsigned long key, void *data1, void *data2)
+{
+ CRHashTable *pTbl = (CRHashTable*)data2;
+
+ crHashtableDelete( pTbl, key, NULL );
+
+ DeleteContextCallback(data1);
+}
+
+void renderspuCleanupBase(bool fDeleteTables)
+{
+ renderspuVBoxCompositorClearAll();
+
+ if (render_spu.blitterTable)
+ {
+ if (fDeleteTables)
+ {
+ crFreeHashtable(render_spu.blitterTable, DeleteBlitterCallback);
+ render_spu.blitterTable = NULL;
+ }
+ else
+ {
+ crHashtableWalk(render_spu.blitterTable, renderspuDeleteBlitterCB, render_spu.contextTable);
+ }
+ }
+ else
+ {
+ crHashtableWalk(render_spu.windowTable, renderspuBlitterCleanupCB, NULL);
+
+ crHashtableWalk(render_spu.dummyWindowTable, renderspuBlitterCleanupCB, NULL);
+ }
+
+ renderspuSetDefaultSharedContext(NULL);
+
+ if (fDeleteTables)
+ {
+ crFreeHashtable(render_spu.contextTable, DeleteContextCallback);
+ render_spu.contextTable = NULL;
+ crFreeHashtable(render_spu.windowTable, DeleteWindowCallback);
+ render_spu.windowTable = NULL;
+ crFreeHashtable(render_spu.dummyWindowTable, DeleteWindowCallback);
+ render_spu.dummyWindowTable = NULL;
+ crFreeHashtable(render_spu.barrierHash, crFree);
+ render_spu.barrierHash = NULL;
+ }
+ else
+ {
+ crHashtableWalk(render_spu.contextTable, renderspuDeleteContextCB, render_spu.contextTable);
+ crHashtableWalk(render_spu.windowTable, renderspuDeleteWindowCB, render_spu.windowTable);
+ crHashtableWalk(render_spu.dummyWindowTable, renderspuDeleteWindowCB, render_spu.dummyWindowTable);
+ crHashtableWalk(render_spu.barrierHash, renderspuDeleteBarierCB, render_spu.barrierHash);
+ }
+}
+
+static int renderSPUCleanup(void)
+{
+ renderspuCleanupBase(true);
+
+#ifdef RT_OS_DARWIN
+# ifndef VBOX_WITH_COCOA_QT
+ render_spu.fInit = false;
+ DisposeEventHandlerUPP(render_spu.hParentEventHandler);
+ ReleaseWindowGroup(render_spu.pMasterGroup);
+ ReleaseWindowGroup(render_spu.pParentGroup);
+ if (render_spu.hRootVisibleRegion)
+ {
+ DisposeRgn(render_spu.hRootVisibleRegion);
+ render_spu.hRootVisibleRegion = 0;
+ }
+ render_spu.currentBufferName = 1;
+ render_spu.uiDockUpdateTS = 0;
+ RTSemFastMutexDestroy(render_spu.syncMutex);
+# else /* VBOX_WITH_COCOA_QT */
+# endif /* VBOX_WITH_COCOA_QT */
+#endif /* RT_OS_DARWIN */
+
+#ifdef RT_OS_WINDOWS
+ if (render_spu.dwWinThreadId)
+ {
+ HANDLE hNative;
+
+ hNative = OpenThread(SYNCHRONIZE|THREAD_QUERY_INFORMATION|THREAD_TERMINATE,
+ false, render_spu.dwWinThreadId);
+ if (!hNative)
+ {
+ crWarning("Failed to get handle for window thread(%#x)", GetLastError());
+ }
+
+ if (PostThreadMessage(render_spu.dwWinThreadId, WM_QUIT, 0, 0))
+ {
+ WaitForSingleObject(render_spu.hWinThreadReadyEvent, INFINITE);
+
+ /*wait for os thread to actually finish*/
+ if (hNative && WaitForSingleObject(hNative, 3000)==WAIT_TIMEOUT)
+ {
+ crDebug("Wait failed, terminating");
+ if (!TerminateThread(hNative, 1))
+ {
+ crWarning("TerminateThread failed");
+ }
+ }
+ }
+
+ if (hNative)
+ {
+ CloseHandle(hNative);
+ }
+ }
+ CloseHandle(render_spu.hWinThreadReadyEvent);
+ render_spu.hWinThreadReadyEvent = NULL;
+#endif
+
+ crUnloadOpenGL();
+
+#ifdef CHROMIUM_THREADSAFE
+ crFreeTSD(&_RenderTSD);
+#endif
+
+ return 1;
+}
+
+
+extern SPUOptions renderSPUOptions[];
+
+int SPULoad( char **name, char **super, SPUInitFuncPtr *init,
+ SPUSelfDispatchFuncPtr *self, SPUCleanupFuncPtr *cleanup,
+ SPUOptionsPtr *options, int *flags )
+{
+ *name = "render";
+ *super = NULL;
+ *init = renderSPUInit;
+ *self = renderSPUSelfDispatch;
+ *cleanup = renderSPUCleanup;
+ *options = renderSPUOptions;
+ *flags = (SPU_NO_PACKER|SPU_IS_TERMINAL|SPU_MAX_SERVERS_ZERO);
+
+ return 1;
+}
+
+DECLEXPORT(void) renderspuSetWindowId(uint64_t winId)
+{
+ render_spu_parent_window_id = winId;
+ crDebug("Set new parent window %p (no actual reparent performed)", winId);
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/render/renderspu_wgl.c b/src/VBox/HostServices/SharedOpenGL/render/renderspu_wgl.c
new file mode 100644
index 00000000..5df60410
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/render/renderspu_wgl.c
@@ -0,0 +1,1741 @@
+/* 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 <iprt/win/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 quirk patch 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)
+ {
+ const 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, true);
+
+ bRc = EndPaint(pWindow->hWnd, &Paint);
+
+ pWindow->redraw_device_context = NULL;
+
+ renderspuVBoxCompositorRelease(pWindow);
+
+ if (!bRc)
+ {
+ DWORD winEr = GetLastError();
+ crWarning("EndPaint failed, winEr %d", winEr);
+ }
+ }
+ 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
+ {
+#ifdef DEBUG_misha
+ crWarning( "Render SPU: Showing the window" );
+#else
+ crDebug( "Render SPU: Showing the window" );
+#endif
+ 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 != CR_RENDER_DEFAULT_WINDOW_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 */
+#ifdef RT_STRICT
+ SetLastError(NO_ERROR);
+#endif
+ {
+ LONG_PTR oldVal = SetWindowLongPtr(window->hWnd, GWLP_USERDATA, (LONG_PTR)window);
+ Assert(!oldVal && GetLastError() == NO_ERROR); RT_NOREF_PV(oldVal);
+ }
+
+ return GL_TRUE;
+}
+
+static void renderspuWindowRgnApply(WindowInfo *window)
+{
+ HRGN hRgn = window->hRgn;
+ if (hRgn)
+ {
+ /* note: according to the docs, SetWindowRgn owns the regions after it is called,
+ * and the regions will be freed automatically when needed,
+ * i.e. the caller should not do that.
+ * this is why we need to make a copy of the regions to be passed in */
+
+ int result;
+ hRgn = CreateRectRgn(0, 0, 0, 0);
+ if (!hRgn)
+ {
+ WARN(("CreateRectRgn failed"));
+ return;
+ }
+
+ result = CombineRgn(hRgn, window->hRgn, NULL, RGN_COPY);
+ if (result == ERROR)
+ {
+ WARN(("CombineRgn failed"));
+ return;
+ }
+ }
+
+ SetWindowRgn(window->hWnd, hRgn, 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);
+ renderspuWindowRgnApply(window);
+ }
+ else
+ {
+ HRGN hRgn;
+ crDebug("HIDE renderspu_SystemShowWindow: %x", window->hWnd);
+ hRgn = CreateRectRgn(0, 0, 0, 0);
+ SetWindowRgn(window->hWnd, hRgn, true);
+ /* note: according to the docs, SetWindowRgn owns the regions after it is called,
+ * and the regions will be freed automatically when needed,
+ * i.e. the caller should not do that */
+ }
+ window->visible = showIt;
+}
+
+void renderspu_SystemVBoxPresentComposition( WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pChangedEntry )
+{
+ /* The !render_spu.force_present_main_thread code flow is actually inspired
+ * by cocoa backend impl, here it forces rendering in WndProc, i.e. main
+ * thread. It defaults to 0, because it is for debugging and working around
+ * bugs. In principle would need root cause investigation. */
+ if (!render_spu.force_present_main_thread)
+ {
+ const struct VBOXVR_SCR_COMPOSITOR *pCompositor;
+ /* we do not want to be blocked with the GUI thread here, so only draw here if we are really able to do that w/o blocking */
+ int rc = renderspuVBoxCompositorTryAcquire(window, &pCompositor);
+ if (RT_SUCCESS(rc))
+ {
+ renderspuVBoxPresentCompositionGeneric(window, pCompositor, pChangedEntry, 0, false);
+ renderspuVBoxCompositorRelease(window);
+ }
+ else if (rc != VERR_SEM_BUSY)
+ {
+ /* this is somewhat we do not expect */
+ crWarning("renderspuVBoxCompositorTryAcquire failed rc %d", rc);
+ }
+ }
+
+ {
+ render_spu.self.Flush();
+ renderspuVBoxPresentBlitterEnsureCreated(window, 0);
+ RedrawWindow(window->hWnd, NULL, NULL, RDW_INTERNALPAINT);
+ }
+}
+
+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)
+{
+ WindowInfo *window;
+
+ if (sharedContext->hRC)
+ return GL_TRUE;
+
+ CRASSERT(sharedContext->BltInfo.Base.id);
+
+ if (sharedContext->shared)
+ renderspuChkActivateSharedContext(sharedContext->shared);
+
+ window = renderspuGetDummyWindow(sharedContext->visual->visAttribs);
+ if (!window)
+ {
+ crError("renderspuChkActivateSharedContext: renderspuGetDummyWindow failed!");
+ 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() );
+ 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;
+}
+
+GLboolean renderspu_SystemWindowNeedEmptyPresent(WindowInfo *window)
+{
+ return GL_FALSE;
+}
+
+void renderspu_SystemWindowVisibleRegion(WindowInfo *window, GLint cRects, const GLint* pRects)
+{
+ GLint i;
+ HRGN hRgn, hTmpRgn;
+ RECT rectRgnBound;
+
+ 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++)
+ {
+ crDebug("Render SPU: CreateRectRgn #%d: (%d, %d)-(%d, %d)", i,
+ pRects[4 * i], pRects[4 * i + 1], pRects[4 * i + 2], pRects[4 * i + 3]);
+
+ 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 (GetRgnBox(hRgn, &rectRgnBound))
+ {
+ crDebug("Render SPU: Rgn bounding box (%d, %d)-(%d, %d)",
+ rectRgnBound.left, rectRgnBound.top, rectRgnBound.right, rectRgnBound.bottom);
+ }
+
+ window->hRgn = hRgn;
+
+ if (window->visible)
+ renderspuWindowRgnApply(window);
+
+ crDebug("Render SPU: SetWindowRgn (%x, cRects=%i)", window->hWnd, cRects);
+}
+
+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);
+}
+
+int renderspu_SystemInit()
+{
+ return VINF_SUCCESS;
+}
+
+int renderspu_SystemTerm()
+{
+ return VINF_SUCCESS;
+}
+
+void renderspu_SystemDefaultSharedContextChanged(ContextInfo *fromContext, ContextInfo *toContext)
+{
+
+}
+
+uint32_t renderspu_SystemPostprocessFunctions(SPUNamedFunctionTable *aFunctions, uint32_t cFunctions, uint32_t cTable)
+{
+ return cFunctions;
+}