summaryrefslogtreecommitdiff
path: root/src/VBox/HostServices/SharedOpenGL/crserver/crservice.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/HostServices/SharedOpenGL/crserver/crservice.cpp')
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserver/crservice.cpp429
1 files changed, 368 insertions, 61 deletions
diff --git a/src/VBox/HostServices/SharedOpenGL/crserver/crservice.cpp b/src/VBox/HostServices/SharedOpenGL/crserver/crservice.cpp
index b63f788a..77ddf197 100644
--- a/src/VBox/HostServices/SharedOpenGL/crserver/crservice.cpp
+++ b/src/VBox/HostServices/SharedOpenGL/crserver/crservice.cpp
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (C) 2006-2008 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -18,50 +18,31 @@
#define __STDC_CONSTANT_MACROS /* needed for a definition in iprt/string.h */
-#ifdef RT_OS_WINDOWS
-# include <iprt/alloc.h>
-# include <iprt/string.h>
-# include <iprt/assert.h>
-# include <iprt/stream.h>
-# include <VBox/vmm/ssm.h>
-# include <VBox/hgcmsvc.h>
-# include <VBox/HostServices/VBoxCrOpenGLSvc.h>
-# include "cr_server.h"
-# define LOG_GROUP LOG_GROUP_SHARED_CROPENGL
-# include <VBox/log.h>
-
-# include <VBox/com/com.h>
-# include <VBox/com/string.h>
-# include <VBox/com/array.h>
-# include <VBox/com/Guid.h>
-# include <VBox/com/ErrorInfo.h>
-# include <VBox/com/EventQueue.h>
-# include <VBox/com/VirtualBox.h>
-# include <VBox/com/assert.h>
-
-#else
-# include <VBox/com/VirtualBox.h>
-# include <iprt/assert.h>
-# include <VBox/vmm/ssm.h>
-# include <VBox/hgcmsvc.h>
-# include <VBox/HostServices/VBoxCrOpenGLSvc.h>
-
-# include "cr_server.h"
-# define LOG_GROUP LOG_GROUP_SHARED_CROPENGL
-# include <VBox/log.h>
-# include <VBox/com/ErrorInfo.h>
-#endif /* RT_OS_WINDOWS */
+#define LOG_GROUP LOG_GROUP_SHARED_CROPENGL
-#include <VBox/com/errorprint.h>
-#include <iprt/thread.h>
+#include <iprt/assert.h>
+#include <iprt/asm.h>
#include <iprt/critsect.h>
+#include <iprt/mem.h>
#include <iprt/semaphore.h>
-#include <iprt/asm.h>
+#include <iprt/stream.h>
+#include <iprt/string.h>
+#include <iprt/thread.h>
+
+#include <VBox/hgcmsvc.h>
+#include <VBox/log.h>
+#include <VBox/com/ErrorInfo.h>
+#include <VBox/com/VirtualBox.h>
+#include <VBox/com/errorprint.h>
+#include <VBox/HostServices/VBoxCrOpenGLSvc.h>
+#include <VBox/vmm/ssm.h>
#include "cr_mem.h"
+#include "cr_server.h"
PVBOXHGCMSVCHELPERS g_pHelpers;
static IConsole* g_pConsole = NULL;
+static uint32_t g_u32ScreenCount = 0;
static PVM g_pVM = NULL;
#ifndef RT_OS_WINDOWS
@@ -244,6 +225,29 @@ static int svcPresentFBOTearDown(void)
return rc;
}
+static DECLCALLBACK(void) svcNotifyEventCB(int32_t screenId, uint32_t uEvent, void*pvData)
+{
+ ComPtr<IDisplay> pDisplay;
+ ComPtr<IFramebuffer> pFramebuffer;
+ LONG xo, yo;
+
+ if (!g_pConsole)
+ {
+ crWarning("Console not defined!");
+ return;
+ }
+
+ CHECK_ERROR2_STMT(g_pConsole, COMGETTER(Display)(pDisplay.asOutParam()), return);
+
+ CHECK_ERROR2_STMT(pDisplay, GetFramebuffer(screenId, pFramebuffer.asOutParam(), &xo, &yo), return);
+
+ if (!pFramebuffer)
+ return;
+
+ pFramebuffer->Notify3DEvent(uEvent, (BYTE*)pvData);
+}
+
+
static DECLCALLBACK(int) svcUnload (void *)
{
int rc = VINF_SUCCESS;
@@ -364,7 +368,7 @@ static DECLCALLBACK(int) svcLoadState(void *, uint32_t u32ClientID, void *pvClie
LogRel(("SHARED_CROPENGL svcLoadState: unsupported save state version %d\n", ui32));
/*@todo ugly hack, as we don't know size of stored opengl data try to read untill end of opengl data marker*/
- /*VboxSharedCrOpenGL isn't last hgcm service now, so can't use SSMR3SkipToEndOfUnit*/
+ /*VBoxSharedCrOpenGL isn't last hgcm service now, so can't use SSMR3SkipToEndOfUnit*/
{
const char *pMatch = &gszVBoxOGLSSMMagic[0];
char current;
@@ -472,7 +476,7 @@ static CRVBOXSVCBUFFER_t* svcGetBuffer(uint32_t iBuffer, uint32_t cbBufferSize)
{
if (pBuffer->uiId == iBuffer)
{
- if (pBuffer->uiSize!=cbBufferSize)
+ if (cbBufferSize && pBuffer->uiSize!=cbBufferSize)
{
static int shown=0;
@@ -892,6 +896,30 @@ static DECLCALLBACK(void) svcCall (void *, VBOXHGCMCALLHANDLE callHandle, uint32
break;
}
+ case SHCRGL_GUEST_FN_GET_CAPS:
+ {
+ Log(("svcCall: SHCRGL_GUEST_FN_GET_CAPS\n"));
+
+ /* Verify parameter count and types. */
+ if (cParms != SHCRGL_CPARMS_GET_CAPS)
+ {
+ rc = VERR_INVALID_PARAMETER;
+ }
+ else
+ if (paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT)
+ {
+ rc = VERR_INVALID_PARAMETER;
+ }
+ else
+ {
+ /* Execute the function. */
+ rc = crVBoxServerClientGetCaps(u32ClientID, &paParms[0].u.uint32);
+ AssertRC(rc);
+ }
+
+ break;
+ }
+
default:
{
rc = VERR_NOT_IMPLEMENTED;
@@ -904,10 +932,36 @@ static DECLCALLBACK(void) svcCall (void *, VBOXHGCMCALLHANDLE callHandle, uint32
g_pHelpers->pfnCallComplete (callHandle, rc);
}
+static void crScreenshotHandle(CRVBOXHGCMTAKESCREENSHOT *pScreenshot, uint32_t idScreen, uint64_t u64Now)
+{
+ if (!pScreenshot->pfnScreenshotBegin || pScreenshot->pfnScreenshotBegin(pScreenshot->pvContext, idScreen, u64Now))
+ {
+ CR_SCREENSHOT Screenshot;
+
+ int rc = crServerVBoxScreenshotGet(idScreen, pScreenshot->u32Width, pScreenshot->u32Height, pScreenshot->u32Pitch, pScreenshot->pvBuffer, &Screenshot);
+ if (RT_SUCCESS(rc))
+ {
+ if (pScreenshot->pfnScreenshotPerform)
+ pScreenshot->pfnScreenshotPerform(pScreenshot->pvContext, idScreen,
+ 0, 0, 32,
+ Screenshot.Img.pitch, Screenshot.Img.width, Screenshot.Img.height,
+ (uint8_t*)Screenshot.Img.pvData, u64Now);
+ crServerVBoxScreenshotRelease(&Screenshot);
+ }
+ else
+ {
+ Assert(rc == VERR_INVALID_STATE);
+ }
+
+ if (pScreenshot->pfnScreenshotEnd)
+ pScreenshot->pfnScreenshotEnd(pScreenshot->pvContext, idScreen, u64Now);
+ }
+}
+
/*
* We differentiate between a function handler for the guest and one for the host.
*/
-static DECLCALLBACK(int) svcHostCall (void *, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
+static int svcHostCallPerform(uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
{
int rc = VINF_SUCCESS;
@@ -990,6 +1044,11 @@ static DECLCALLBACK(int) svcHostCall (void *, uint32_t u32Function, uint32_t cPa
CHECK_ERROR_BREAK(pMachine, COMGETTER(MonitorCount)(&monitorCount));
CHECK_ERROR_BREAK(pConsole, COMGETTER(Display)(pDisplay.asOutParam()));
+ crServerVBoxCompositionSetEnableStateGlobal(GL_FALSE);
+
+ g_pConsole = pConsole;
+ g_u32ScreenCount = monitorCount;
+
rc = crVBoxServerSetScreenCount(monitorCount);
AssertRCReturn(rc, rc);
@@ -1013,7 +1072,7 @@ static DECLCALLBACK(int) svcHostCall (void *, uint32_t u32Function, uint32_t cPa
}
}
- g_pConsole = pConsole;
+ crServerVBoxCompositionSetEnableStateGlobal(GL_TRUE);
rc = VINF_SUCCESS;
}
@@ -1064,16 +1123,15 @@ static DECLCALLBACK(int) svcHostCall (void *, uint32_t u32Function, uint32_t cPa
}
if ( paParms[0].type != VBOX_HGCM_SVC_PARM_PTR /* pRects */
- || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* cRects */
)
{
rc = VERR_INVALID_PARAMETER;
break;
}
- Assert(sizeof(RTRECT)==4*sizeof(GLint));
+ Assert(sizeof (RTRECT) == 4 * sizeof (GLint));
- rc = crVBoxServerSetRootVisibleRegion(paParms[1].u.uint32, (GLint*)paParms[0].u.pointer.addr);
+ rc = crVBoxServerSetRootVisibleRegion(paParms[0].u.pointer.size / sizeof (RTRECT), (const RTRECT*)paParms[0].u.pointer.addr);
break;
}
case SHCRGL_HOST_FN_SCREEN_CHANGED:
@@ -1105,6 +1163,8 @@ static DECLCALLBACK(int) svcHostCall (void *, uint32_t u32Function, uint32_t cPa
CHECK_ERROR_RET(g_pConsole, COMGETTER(Display)(pDisplay.asOutParam()), rc);
CHECK_ERROR_RET(pDisplay, GetFramebuffer(screenId, pFramebuffer.asOutParam(), &xo, &yo), rc);
+ crServerVBoxCompositionSetEnableStateGlobal(GL_FALSE);
+
if (!pFramebuffer)
{
rc = crVBoxServerUnmapScreen(screenId);
@@ -1112,28 +1172,130 @@ static DECLCALLBACK(int) svcHostCall (void *, uint32_t u32Function, uint32_t cPa
}
else
{
- CHECK_ERROR_RET(pFramebuffer, COMGETTER(WinId)(&winId), rc);
+#if 0
+ CHECK_ERROR_RET(pFramebuffer, Lock(), rc);
+#endif
- if (!winId)
- {
- /* View associated with framebuffer is destroyed, happens with 2d accel enabled */
- rc = crVBoxServerUnmapScreen(screenId);
- AssertRCReturn(rc, rc);
- }
- else
- {
- CHECK_ERROR_RET(pFramebuffer, COMGETTER(Width)(&w), rc);
- CHECK_ERROR_RET(pFramebuffer, COMGETTER(Height)(&h), rc);
+ do {
+ /* determine if the framebuffer is functional */
+ rc = pFramebuffer->Notify3DEvent(VBOX3D_NOTIFY_EVENT_TYPE_TEST_FUNCTIONAL, NULL);
- rc = crVBoxServerMapScreen(screenId, xo, yo, w, h, winId);
- AssertRCReturn(rc, rc);
- }
+ if (rc == S_OK)
+ CHECK_ERROR_BREAK(pFramebuffer, COMGETTER(WinId)(&winId));
+
+ if (!winId)
+ {
+ /* View associated with framebuffer is destroyed, happens with 2d accel enabled */
+ rc = crVBoxServerUnmapScreen(screenId);
+ AssertRCReturn(rc, rc);
+ }
+ else
+ {
+ CHECK_ERROR_BREAK(pFramebuffer, COMGETTER(Width)(&w));
+ CHECK_ERROR_BREAK(pFramebuffer, COMGETTER(Height)(&h));
+
+ rc = crVBoxServerMapScreen(screenId, xo, yo, w, h, winId);
+ AssertRCReturn(rc, rc);
+ }
+ } while (0);
+#if 0
+ CHECK_ERROR_RET(pFramebuffer, Unlock(), rc);
+#endif
}
+ crServerVBoxCompositionSetEnableStateGlobal(GL_TRUE);
+
rc = VINF_SUCCESS;
}
break;
}
+ case SHCRGL_HOST_FN_TAKE_SCREENSHOT:
+ {
+ if (cParms != 1)
+ {
+ LogRel(("SHCRGL_HOST_FN_TAKE_SCREENSHOT: cParms invalid - %d", cParms));
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ if (paParms->type != VBOX_HGCM_SVC_PARM_PTR)
+ {
+ AssertMsgFailed(("invalid param\n"));
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ if (!paParms->u.pointer.addr)
+ {
+ AssertMsgFailed(("invalid param\n"));
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ if (paParms->u.pointer.size != sizeof (CRVBOXHGCMTAKESCREENSHOT))
+ {
+ AssertMsgFailed(("invalid param\n"));
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ CRVBOXHGCMTAKESCREENSHOT *pScreenshot = (CRVBOXHGCMTAKESCREENSHOT*)paParms->u.pointer.addr;
+ uint64_t u64Now = RTTimeProgramMilliTS();
+
+ if (pScreenshot->u32Screen == CRSCREEN_ALL)
+ {
+ for (uint32_t i = 0; i < g_u32ScreenCount; ++i)
+ {
+ crScreenshotHandle(pScreenshot, i, u64Now);
+ }
+ }
+ else if (pScreenshot->u32Screen < g_u32ScreenCount)
+ {
+ crScreenshotHandle(pScreenshot, pScreenshot->u32Screen, u64Now);
+ }
+ else
+ {
+ AssertMsgFailed(("invalid screen id\n"));
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+ break;
+ }
+ case SHCRGL_HOST_FN_DEV_RESIZE:
+ {
+ Log(("svcCall: SHCRGL_HOST_FN_DEV_RESIZE\n"));
+
+ /* Verify parameter count and types. */
+ if (cParms != SHCRGL_CPARMS_DEV_RESIZE)
+ {
+ LogRel(("SHCRGL_HOST_FN_DEV_RESIZE: cParms invalid - %d", cParms));
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ if (paParms->type != VBOX_HGCM_SVC_PARM_PTR)
+ {
+ AssertMsgFailed(("invalid param\n"));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ if (!paParms->u.pointer.addr)
+ {
+ AssertMsgFailed(("invalid param\n"));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ if (paParms->u.pointer.size != sizeof (CRVBOXHGCMDEVRESIZE))
+ {
+ AssertMsgFailed(("invalid param\n"));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ CRVBOXHGCMDEVRESIZE *pResize = (CRVBOXHGCMDEVRESIZE*)paParms->u.pointer.addr;
+
+ rc = crVBoxServerNotifyResize(&pResize->Screen, pResize->pvVRAM);
+ break;
+ }
case SHCRGL_HOST_FN_VIEWPORT_CHANGED:
{
Log(("svcCall: SHCRGL_HOST_FN_VIEWPORT_CHANGED\n"));
@@ -1162,6 +1324,8 @@ static DECLCALLBACK(int) svcHostCall (void *, uint32_t u32Function, uint32_t cPa
break;
}
+ crServerVBoxCompositionSetEnableStateGlobal(GL_FALSE);
+
rc = crVBoxServerSetScreenViewport((int)paParms[0].u.uint32,
paParms[1].u.uint32, /* x */
paParms[2].u.uint32, /* y */
@@ -1170,9 +1334,52 @@ static DECLCALLBACK(int) svcHostCall (void *, uint32_t u32Function, uint32_t cPa
if (!RT_SUCCESS(rc))
{
LogRel(("SHCRGL_HOST_FN_VIEWPORT_CHANGED: crVBoxServerSetScreenViewport failed, rc %d", rc));
+ }
+
+ crServerVBoxCompositionSetEnableStateGlobal(GL_TRUE);
+
+ break;
+ }
+ case SHCRGL_HOST_FN_VIEWPORT_CHANGED2:
+ {
+ Log(("svcCall: SHCRGL_HOST_FN_VIEWPORT_CHANGED\n"));
+
+ /* Verify parameter count and types. */
+ if (cParms != SHCRGL_CPARMS_VIEWPORT_CHANGED)
+ {
+ LogRel(("SHCRGL_HOST_FN_VIEWPORT_CHANGED: cParms invalid - %d", cParms));
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ if (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR
+ || !paParms[0].u.pointer.addr
+ || paParms[0].u.pointer.size != sizeof (CRVBOXHGCMVIEWPORT))
+ {
+ LogRel(("SHCRGL_HOST_FN_VIEWPORT_CHANGED: param invalid - %d, %#x, %d",
+ paParms[0].type,
+ paParms[0].u.pointer.addr,
+ paParms[0].u.pointer.size));
+ rc = VERR_INVALID_PARAMETER;
break;
}
+ crServerVBoxCompositionSetEnableStateGlobal(GL_FALSE);
+
+ CRVBOXHGCMVIEWPORT *pViewportInfo = (CRVBOXHGCMVIEWPORT*)paParms[0].u.pointer.addr;
+
+ rc = crVBoxServerSetScreenViewport(pViewportInfo->u32Screen,
+ pViewportInfo->x, /* x */
+ pViewportInfo->y, /* y */
+ pViewportInfo->width, /* w */
+ pViewportInfo->height /* h */);
+ if (!RT_SUCCESS(rc))
+ {
+ LogRel(("SHCRGL_HOST_FN_VIEWPORT_CHANGED: crVBoxServerSetScreenViewport failed, rc %d", rc));
+ }
+
+ crServerVBoxCompositionSetEnableStateGlobal(GL_TRUE);
+
break;
}
case SHCRGL_HOST_FN_SET_OUTPUT_REDIRECT:
@@ -1207,9 +1414,7 @@ static DECLCALLBACK(int) svcHostCall (void *, uint32_t u32Function, uint32_t cPa
}
else /* Execute the function. */
{
- rc = crVBoxServerSetOffscreenRendering(GL_TRUE);
-
- if (RT_SUCCESS(rc))
+ if (pOutputRedirect->H3DORBegin != NULL)
{
CROutputRedirect outputRedirect;
outputRedirect.pvContext = pOutputRedirect->pvContext;
@@ -1220,11 +1425,44 @@ static DECLCALLBACK(int) svcHostCall (void *, uint32_t u32Function, uint32_t cPa
outputRedirect.CROREnd = pOutputRedirect->H3DOREnd;
outputRedirect.CRORContextProperty = pOutputRedirect->H3DORContextProperty;
rc = crVBoxServerOutputRedirectSet(&outputRedirect);
+ if (RT_SUCCESS(rc))
+ {
+ rc = crVBoxServerSetOffscreenRendering(GL_TRUE);
+ }
+ }
+ else
+ {
+ /* Redirection is disabled. */
+ crVBoxServerSetOffscreenRendering(GL_FALSE);
+ crVBoxServerOutputRedirectSet(NULL);
}
}
}
break;
}
+ case SHCRGL_HOST_FN_WINDOWS_SHOW:
+ {
+ /* Verify parameter count and types. */
+ if (cParms != 1)
+ {
+ WARN(("invalid parameter"));
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ if (paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT)
+ {
+ WARN(("invalid parameter"));
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ rc = crServerVBoxWindowsShow(paParms[0].u.uint32);
+ if (!RT_SUCCESS(rc))
+ WARN(("crServerVBoxWindowsShow failed rc %d", rc));
+
+ break;
+ }
default:
rc = VERR_NOT_IMPLEMENTED;
break;
@@ -1234,6 +1472,73 @@ static DECLCALLBACK(int) svcHostCall (void *, uint32_t u32Function, uint32_t cPa
return rc;
}
+int crVBoxServerHostCtl(VBOXCRCMDCTL *pCtl, uint32_t cbCtl)
+{
+ if ((cbCtl - sizeof (VBOXCRCMDCTL)) % sizeof(VBOXHGCMSVCPARM))
+ {
+ WARN(("invalid param size"));
+ return VERR_INVALID_PARAMETER;
+ }
+ uint32_t cParams = (cbCtl - sizeof (VBOXCRCMDCTL)) / sizeof (VBOXHGCMSVCPARM);
+ return svcHostCallPerform(pCtl->u32Function, cParams, (VBOXHGCMSVCPARM*)(pCtl + 1));
+}
+
+static DECLCALLBACK(int) svcHostCall(void *, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
+{
+ switch (u32Function)
+ {
+ case SHCRGL_HOST_FN_CTL:
+ {
+ if (cParms != 1)
+ {
+ WARN(("cParams != 1"));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ if (paParms->type != VBOX_HGCM_SVC_PARM_PTR)
+ {
+ WARN(("invalid param type"));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ if (paParms->u.pointer.size < sizeof (VBOXCRCMDCTL))
+ {
+ WARN(("invalid param size"));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ VBOXCRCMDCTL *pCtl = (VBOXCRCMDCTL*)paParms->u.pointer.addr;
+ switch (pCtl->enmType)
+ {
+ case VBOXCRCMDCTL_TYPE_HGCM:
+ {
+ return crVBoxServerHostCtl(pCtl, paParms->u.pointer.size);
+ }
+ case VBOXCRCMDCTL_TYPE_DISABLE:
+ {
+ if (paParms->u.pointer.size != sizeof (VBOXCRCMDCTL))
+ WARN(("invalid param size"));
+ return crVBoxServerHgcmDisable();
+ }
+ case VBOXCRCMDCTL_TYPE_ENABLE:
+ {
+ if (paParms->u.pointer.size != sizeof (VBOXCRCMDCTL_ENABLE))
+ WARN(("invalid param size"));
+ VBOXCRCMDCTL_ENABLE *pEnable = (VBOXCRCMDCTL_ENABLE*)pCtl;
+ return crVBoxServerHgcmEnable(pEnable->hRHCmd, pEnable->pfnRHCmd);
+ }
+ default:
+ WARN(("invalid function"));
+ return VERR_INVALID_PARAMETER;
+ }
+ WARN(("should not be here!"));
+ return VERR_INTERNAL_ERROR;
+ }
+ default:
+ return svcHostCallPerform(u32Function, cParms, paParms);
+ }
+}
+
extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad (VBOXHGCMSVCFNTABLE *ptable)
{
int rc = VINF_SUCCESS;
@@ -1272,6 +1577,8 @@ extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad (VBOXHGCMSVCFNTABLE *pt
return VERR_NOT_SUPPORTED;
rc = svcPresentFBOInit();
+
+ crServerVBoxSetNotifyEventCB(svcNotifyEventCB);
}
}