/* $Id$ */
/** @file
* VBox crOpenGL: Host service entry points.
*/
/*
* 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;
* 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 <iprt/critsect.h>
#include <iprt/semaphore.h>
#include "cr_mem.h"
#include "cr_server.h"
#ifndef RT_OS_WINDOWS
# define DWORD int
# define WINAPI
#endif
/* Used to process guest calls exceeding maximum allowed HGCM call size in a sequence of smaller calls */
typedef struct _CRVBOXSVCBUFFER_t {
void* pData;
/* svcPresentFBO related data */
typedef struct _CRVBOXSVCPRESENTFBOCMD_t {
void *pData;
static DECLCALLBACK(void) svcNotifyEventCB(int32_t screenId, uint32_t uEvent, void* pvData, uint32_t cbData)
{
if (!g_pConsole)
{
crWarning("Console not defined!");
return;
}
if (!pFramebuffer)
return;
if (cbData)
}
{
Log(("SHARED_CROPENGL svcUnload\n"));
return rc;
}
{
if (g_u32fCrHgcmDisabled)
{
WARN(("connect not expected"));
return VERR_INVALID_STATE;
}
return rc;
}
{
if (g_u32fCrHgcmDisabled)
{
WARN(("disconnect not expected"));
return VINF_SUCCESS;
}
return rc;
}
static DECLCALLBACK(int) svcSaveState(void *, uint32_t u32ClientID, void *pvClient, PSSMHANDLE pSSM)
{
/* Start*/
/* Version */
/* The state itself */
/* Save svc buffers info */
{
while (pBuffer)
{
}
}
/* End */
return VINF_SUCCESS;
}
static DECLCALLBACK(int) svcLoadState(void *, uint32_t u32ClientID, void *pvClient, PSSMHANDLE pSSM)
{
/* Start of data */
return VERR_SSM_UNEXPECTED_DATA;
/* Version */
/* The state itself */
{
/*@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*/
{
char current;
while (*pMatch)
{
{
pMatch++;
}
else
{
pMatch = &gszVBoxOGLSSMMagic[0];
}
}
}
return VINF_SUCCESS;
}
/* Load svc buffers info */
if (ui32>=24)
{
while (uiId)
{
if (!pBuffer)
{
return VERR_NO_MEMORY;
}
{
return VERR_NO_MEMORY;
}
if (g_pCRVBoxSVCBuffers)
{
}
}
}
/* End of data */
return VERR_SSM_UNEXPECTED_DATA;
return VINF_SUCCESS;
}
{
/*MS's opengl32 tries to load our ICD around 30 times on failure...this is to prevent unnecessary spam*/
static int shown = 0;
{
"An attempt by the virtual machine to use hardware 3D acceleration failed. "
"The version of the Guest Additions installed in the virtual machine does not match the "
"version of VirtualBox on the host. Please install appropriate Guest Additions to fix this issue");
shown = 1;
}
}
{
if (iBuffer)
{
while (pBuffer)
{
{
{
static int shown=0;
if (shown<20)
{
shown++;
LogRel(("SHARED_CROPENGL svcGetBuffer: invalid buffer(%i) size %i instead of %i\n",
}
return NULL;
}
return pBuffer;
}
}
return NULL;
}
else /*allocate new buffer*/
{
if (pBuffer)
{
{
return NULL;
}
{
}
if (g_pCRVBoxSVCBuffers)
{
}
}
else
{
}
return pBuffer;
}
}
{
{
}
else
{
}
{
}
}
static DECLCALLBACK(void) svcCall (void *, VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID, void *pvClient, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
{
if (g_u32fCrHgcmDisabled)
{
WARN(("cr hgcm disabled!"));
return;
}
Log(("SHARED_CROPENGL svcCall: u32ClientID = %d, fn = %d, cParms = %d, pparms = %d\n", u32ClientID, u32Function, cParms, paParms));
#ifdef DEBUG
uint32_t i;
for (i = 0; i < cParms; i++)
{
/** @todo parameters other than 32 bit */
}
#endif
switch (u32Function)
{
case SHCRGL_GUEST_FN_WRITE:
{
Log(("svcCall: SHCRGL_GUEST_FN_WRITE\n"));
/* Verify parameter count and types. */
if (cParms != SHCRGL_CPARMS_WRITE)
{
}
else
)
{
}
else
{
/* Fetch parameters. */
/* Execute the function. */
if (!RT_SUCCESS(rc))
{
svcClientVersionUnsupported(0, 0);
}
}
break;
}
case SHCRGL_GUEST_FN_INJECT:
{
Log(("svcCall: SHCRGL_GUEST_FN_INJECT\n"));
/* Verify parameter count and types. */
if (cParms != SHCRGL_CPARMS_INJECT)
{
}
else
)
{
}
else
{
/* Fetch parameters. */
/* Execute the function. */
if (!RT_SUCCESS(rc))
{
if (VERR_NOT_SUPPORTED==rc)
{
svcClientVersionUnsupported(0, 0);
}
else
{
crWarning("SHCRGL_GUEST_FN_INJECT failed to inject for %i from %i", u32InjectClientID, u32ClientID);
}
}
}
break;
}
case SHCRGL_GUEST_FN_READ:
{
Log(("svcCall: SHCRGL_GUEST_FN_READ\n"));
/* Verify parameter count and types. */
if (cParms != SHCRGL_CPARMS_READ)
{
}
else
)
{
}
/* Fetch parameters. */
/* Execute the function. */
if (RT_SUCCESS(rc))
{
/* Update parameters.*/
} else if (VERR_NOT_SUPPORTED==rc)
{
svcClientVersionUnsupported(0, 0);
}
/* Return the required buffer size always */
break;
}
{
Log(("svcCall: SHCRGL_GUEST_FN_WRITE_READ\n"));
/* Verify parameter count and types. */
if (cParms != SHCRGL_CPARMS_WRITE_READ)
{
}
else
)
{
}
else
{
/* Fetch parameters. */
/* Execute the function. */
if (!RT_SUCCESS(rc))
{
svcClientVersionUnsupported(0, 0);
}
if (RT_SUCCESS(rc))
{
/* Update parameters.*/
}
/* Return the required buffer size always */
}
break;
}
{
Log(("svcCall: SHCRGL_GUEST_FN_SET_VERSION\n"));
/* Verify parameter count and types. */
if (cParms != SHCRGL_CPARMS_SET_VERSION)
{
}
else
)
{
}
else
{
/* Fetch parameters. */
/* Execute the function. */
if (!RT_SUCCESS(rc))
{
}
}
break;
}
case SHCRGL_GUEST_FN_SET_PID:
{
Log(("svcCall: SHCRGL_GUEST_FN_SET_PID\n"));
/* Verify parameter count and types. */
if (cParms != SHCRGL_CPARMS_SET_PID)
{
}
else
{
}
else
{
/* Fetch parameters. */
/* Execute the function. */
}
break;
}
{
Log(("svcCall: SHCRGL_GUEST_FN_WRITE_BUFFER\n"));
/* Verify parameter count and types. */
if (cParms != SHCRGL_CPARMS_WRITE_BUFFER)
{
}
else
)
{
}
else
{
/* Fetch parameters. */
/* Execute the function. */
{
}
else
{
/* Return the buffer id */
}
}
break;
}
{
Log(("svcCall: SHCRGL_GUEST_FN_WRITE_READ_BUFFERED\n"));
/* Verify parameter count and types. */
{
}
else
)
{
}
else
{
/* Fetch parameters. */
if (!pSvcBuffer)
{
break;
}
/* Execute the function. */
if (!RT_SUCCESS(rc))
{
svcClientVersionUnsupported(0, 0);
}
if (RT_SUCCESS(rc))
{
/* Update parameters.*/
}
/* Return the required buffer size always */
}
break;
}
{
Log(("svcCall: SHCRGL_GUEST_FN_GET_CAPS_NEW\n"));
/* Verify parameter count and types. */
if (cParms != SHCRGL_CPARMS_GET_CAPS_NEW)
{
WARN(("invalid parameter count"));
break;
}
{
WARN(("invalid parameter"));
break;
}
{
WARN(("invalid buffer size"));
break;
}
break;
}
{
Log(("svcCall: SHCRGL_GUEST_FN_GET_CAPS_LEGACY\n"));
/* Verify parameter count and types. */
if (cParms != SHCRGL_CPARMS_GET_CAPS_LEGACY)
{
}
{
}
else
{
/* Execute the function. */
}
break;
}
default:
{
}
}
}
static void crScreenshotHandle(CRVBOXHGCMTAKESCREENSHOT *pScreenshot, uint32_t idScreen, uint64_t u64Now)
{
if (!pScreenshot->pfnScreenshotBegin || pScreenshot->pfnScreenshotBegin(pScreenshot->pvContext, idScreen, u64Now))
{
int rc = crServerVBoxScreenshotGet(idScreen, pScreenshot->u32Width, pScreenshot->u32Height, pScreenshot->u32Pitch, pScreenshot->pvBuffer, &Screenshot);
if (RT_SUCCESS(rc))
{
0, 0, 32,
}
else
{
}
if (pScreenshot->pfnScreenshotEnd)
}
}
/*
* We differentiate between a function handler for the guest and one for the host.
*/
{
Log(("SHARED_CROPENGL svcHostCall: fn = %d, cParms = %d, pparms = %d\n", u32Function, cParms, paParms));
#ifdef DEBUG
uint32_t i;
for (i = 0; i < cParms; i++)
{
/** @todo parameters other than 32 bit */
}
#endif
switch (u32Function)
{
#ifdef VBOX_WITH_CRHGSMI
{
{
rc = crVBoxServerCrHgsmiCmd((PVBOXVDMACMD_CHROMIUM_CMD)paParms[0].u.pointer.addr, paParms[0].u.pointer.size);
if (VERR_NOT_SUPPORTED == rc)
{
svcClientVersionUnsupported(0, 0);
}
}
else
} break;
{
rc = crVBoxServerCrHgsmiCtl((PVBOXVDMACMD_CHROMIUM_CTL)paParms[0].u.pointer.addr, paParms[0].u.pointer.size);
else
} break;
#endif
{
Log(("svcCall: SHCRGL_HOST_FN_SET_DISPLAY\n"));
/* Verify parameter count and types. */
if (cParms != SHCRGL_CPARMS_SET_CONSOLE)
{
}
{
}
else
{
/* Fetch parameters. */
/* Verify parameters values. */
{
}
else if (!pConsole)
{
}
else /* Execute the function. */
{
#if 1
for (i=0; i<monitorCount; ++i)
{
if (!pFramebuffer)
{
rc = crVBoxServerUnmapScreen(i);
}
else
{
CHECK_ERROR_RET(pDisplay, GetScreenResolution(i, &dummy, &dummy, &dummy, &xo, &yo, &monitorStatus), rc);
}
}
#endif
rc = VINF_SUCCESS;
}
}
break;
}
case SHCRGL_HOST_FN_SET_VM:
{
Log(("svcCall: SHCRGL_HOST_FN_SET_VM\n"));
/* Verify parameter count and types. */
if (cParms != SHCRGL_CPARMS_SET_VM)
{
}
{
}
else
{
/* Fetch parameters. */
/* Verify parameters values. */
{
}
else
{
/* Execute the function. */
rc = VINF_SUCCESS;
}
}
break;
}
{
Log(("svcCall: SHCRGL_HOST_FN_SET_VISIBLE_REGION\n"));
{
break;
}
)
{
break;
}
rc = crVBoxServerSetRootVisibleRegion(paParms[0].u.pointer.size / sizeof (RTRECT), (const RTRECT*)paParms[0].u.pointer.addr);
break;
}
{
Log(("svcCall: SHCRGL_HOST_FN_SCREEN_CHANGED\n"));
/* Verify parameter count and types. */
if (cParms != SHCRGL_CPARMS_SCREEN_CHANGED)
{
}
{
}
else
{
/* Fetch parameters. */
/* Execute the function. */
ULONG w, h;
if (!pFramebuffer)
{
}
else
{
do {
/* determine if the framebuffer is functional */
rc = pFramebuffer->Notify3DEvent(VBOX3D_NOTIFY_EVENT_TYPE_TEST_FUNCTIONAL, ComSafeArrayAsInParam(data));
if (!winId)
{
/* View associated with framebuffer is destroyed, happens with 2d accel enabled */
}
else
{
CHECK_ERROR_BREAK(pDisplay, GetScreenResolution(screenId, &dummy, &dummy, &dummy, &xo, &yo, &monitorStatus));
}
} while (0);
}
rc = VINF_SUCCESS;
}
break;
}
{
if (cParms != 1)
{
break;
}
{
AssertMsgFailed(("invalid param\n"));
break;
}
{
AssertMsgFailed(("invalid param\n"));
break;
}
{
AssertMsgFailed(("invalid param\n"));
break;
}
{
for (uint32_t i = 0; i < g_u32ScreenCount; ++i)
{
}
}
{
}
else
{
AssertMsgFailed(("invalid screen id\n"));
break;
}
break;
}
{
Log(("svcCall: SHCRGL_HOST_FN_DEV_RESIZE\n"));
/* Verify parameter count and types. */
if (cParms != SHCRGL_CPARMS_DEV_RESIZE)
{
break;
}
{
AssertMsgFailed(("invalid param\n"));
return VERR_INVALID_PARAMETER;
}
{
AssertMsgFailed(("invalid param\n"));
return VERR_INVALID_PARAMETER;
}
{
AssertMsgFailed(("invalid param\n"));
return VERR_INVALID_PARAMETER;
}
break;
}
{
Log(("svcCall: SHCRGL_HOST_FN_VIEWPORT_CHANGED\n"));
/* Verify parameter count and types. */
if (cParms != SHCRGL_CPARMS_VIEWPORT_CHANGED)
{
break;
}
for (int i = 0; i < SHCRGL_CPARMS_VIEWPORT_CHANGED; ++i)
{
{
break;
}
}
if (!RT_SUCCESS(rc))
{
LogRel(("SHCRGL_HOST_FN_VIEWPORT_CHANGED: param validation failed, returning.."));
break;
}
if (!RT_SUCCESS(rc))
{
}
break;
}
{
Log(("svcCall: SHCRGL_HOST_FN_VIEWPORT_CHANGED\n"));
/* Verify parameter count and types. */
if (cParms != SHCRGL_CPARMS_VIEWPORT_CHANGED)
{
break;
}
{
LogRel(("SHCRGL_HOST_FN_VIEWPORT_CHANGED: param invalid - %d, %#x, %d",
break;
}
pViewportInfo->x, /* x */
pViewportInfo->y, /* y */
if (!RT_SUCCESS(rc))
{
}
break;
}
{
/*
* OutputRedirect.
* Note: the service calls OutputRedirect callbacks directly
* and they must not block. If asynchronous processing is needed,
* the callback provider must organize this.
*/
Log(("svcCall: SHCRGL_HOST_FN_SET_OUTPUT_REDIRECT\n"));
/* Verify parameter count and types. */
{
}
{
}
else
{
/* Fetch parameters. */
/* Verify parameters values. */
if (cbData != sizeof (H3DOUTPUTREDIRECT))
{
}
else /* Execute the function. */
{
{
if (RT_SUCCESS(rc))
{
}
}
else
{
/* Redirection is disabled. */
}
}
}
break;
}
{
/* Verify parameter count and types. */
if (cParms != 1)
{
WARN(("invalid parameter"));
break;
}
{
WARN(("invalid parameter"));
break;
}
if (!RT_SUCCESS(rc))
break;
}
{
/* Verify parameter count and types. */
if (cParms != 1
{
WARN(("invalid parameter"));
break;
}
double dScaleFactorW = (double)(pData->u32ScaleFactorWMultiplied) / VBOX_OGL_SCALE_FACTOR_MULTIPLIER;
double dScaleFactorH = (double)(pData->u32ScaleFactorHMultiplied) / VBOX_OGL_SCALE_FACTOR_MULTIPLIER;
/* Log scaling factor rounded to nearest 'int' value (not so precise). */
LogRel(("OpenGL: Set 3D content scale factor to (%u, %u), multiplier %d (rc=%Rrc).\n",
rc));
break;
}
{
/* Verify parameter count and types. */
if (cParms != 1
{
WARN(("invalid parameter"));
break;
}
CRVBOXHGCMSETUNSCALEDHIDPIOUTPUT *pData = (CRVBOXHGCMSETUNSCALEDHIDPIOUTPUT *)paParms[0].u.pointer.addr;
LogRel(("OpenGL: Set OpenGL scale policy on HiDPI displays (fUnscaledHiDPI=%d).\n", pData->fUnscaledHiDPI));
break;
}
default:
break;
}
return rc;
}
{
{
WARN(("invalid param size"));
return VERR_INVALID_PARAMETER;
}
if (fHasCallout)
if (fHasCallout)
return rc;
}
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;
}
{
WARN(("invalid param type"));
return VERR_INVALID_PARAMETER;
}
{
WARN(("invalid param size"));
return VERR_INVALID_PARAMETER;
}
{
case VBOXCRCMDCTL_TYPE_HGCM:
{
}
{
WARN(("invalid param size"));
if (RT_SUCCESS(rc))
g_u32fCrHgcmDisabled = 1;
else
return rc;
}
case VBOXCRCMDCTL_TYPE_ENABLE:
{
WARN(("invalid param size"));
if (RT_SUCCESS(rc))
g_u32fCrHgcmDisabled = 0;
else
return rc;
}
default:
return VERR_INVALID_PARAMETER;
}
WARN(("should not be here!"));
return VERR_INTERNAL_ERROR;
}
default:
if (g_u32fCrHgcmDisabled)
{
WARN(("cr hgcm disabled!"));
return VERR_INVALID_STATE;
}
}
}
{
if (!ptable)
{
}
else
{
Log(("VBoxHGCMSvcLoad: ptable->cbSize = %d, ptable->u32Version = 0x%08X\n", ptable->cbSize, ptable->u32Version));
{
}
else
{
g_u32fCrHgcmDisabled = 0;
if (!crVBoxServerInit())
return VERR_NOT_SUPPORTED;
}
}
return rc;
}
#ifdef RT_OS_WINDOWS
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
{
(void) lpvReserved;
switch (fdwReason)
{
case DLL_THREAD_ATTACH:
{
break;
}
case DLL_PROCESS_DETACH:
/* do exactly the same thing as for DLL_THREAD_DETACH since
* DLL_THREAD_DETACH is not called for the thread doing DLL_PROCESS_DETACH according to msdn docs */
case DLL_THREAD_DETACH:
{
break;
}
case DLL_PROCESS_ATTACH:
default:
break;
}
return TRUE;
}
#endif