crservice.cpp revision e5970f9ca60805a4507171d4d88da38e61ca5004
/* $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.
*/
#define __STDC_CONSTANT_MACROS /* needed for a definition in iprt/string.h */
#define LOG_GROUP LOG_GROUP_SHARED_CROPENGL
#include <iprt/critsect.h>
#include <iprt/semaphore.h>
#include "cr_mem.h"
#include "cr_server.h"
static uint32_t g_u32ScreenCount = 0;
static uint32_t g_u32fCrHgcmDisabled = 0;
#ifndef RT_OS_WINDOWS
# define DWORD int
# define WINAPI
#endif
static const char* gszVBoxOGLSSMMagic = "***OpenGL state data***";
/* Used to process guest calls exceeding maximum allowed HGCM call size in a sequence of smaller calls */
typedef struct _CRVBOXSVCBUFFER_t {
void* pData;
static uint32_t g_CRVBoxSVCBufferID = 0;
/* svcPresentFBO related data */
typedef struct _CRVBOXSVCPRESENTFBOCMD_t {
void *pData;
typedef struct _CRVBOXSVCPRESENTFBO_t {
bool volatile bShutdownWorker; /* Shutdown flag */
static CRVBOXSVCPRESENTFBO_t g_SvcPresentFBO;
/* Schedule a call to a separate worker thread to avoid deadlock on EMT thread when the screen configuration changes
and we're processing crServerPresentFBO caused by guest application command.
To avoid unnecessary memcpy, worker thread frees the data passed.
*/
static DECLCALLBACK(void) svcPresentFBO(void *data, int32_t screenId, int32_t x, int32_t y, uint32_t w, uint32_t h)
{
if (!pCmd)
{
LogRel(("SHARED_CROPENGL svcPresentFBO: not enough memory (%d)\n", sizeof(CRVBOXSVCPRESENTFBOCMD_t)));
return;
}
pCmd->x = x;
pCmd->y = y;
pCmd->w = w;
pCmd->h = h;
{
}
else
{
}
}
{
int rc = VINF_SUCCESS;
Log(("SHARED_CROPENGL svcPresentFBOWorkerThreadProc started\n"));
for (;;)
{
{
break;
}
// @todo use critsect only to fetch the list and update the g_SvcPresentFBO's pQueueHead and pQueueTail.
while (pCmd)
{
/*remove from queue*/
if (!g_SvcPresentFBO.pQueueHead)
{
}
CHECK_ERROR_RET(pDisplay, DrawToScreen(pCmd->screenId, (BYTE*)pCmd->pData, pCmd->x, pCmd->y, pCmd->w, pCmd->h), rc);
}
}
Log(("SHARED_CROPENGL svcPresentFBOWorkerThreadProc finished\n"));
return rc;
}
static int svcPresentFBOInit(void)
{
int rc = VINF_SUCCESS;
g_SvcPresentFBO.bShutdownWorker = false;
return rc;
}
static int svcPresentFBOTearDown(void)
{
int rc = VINF_SUCCESS;
while (pQueue)
{
}
return rc;
}
{
if (!g_pConsole)
{
crWarning("Console not defined!");
return;
}
if (!pFramebuffer)
return;
}
static DECLCALLBACK(int) svcUnload (void *)
{
int rc = VINF_SUCCESS;
Log(("SHARED_CROPENGL svcUnload\n"));
return rc;
}
{
int rc = VINF_SUCCESS;
return rc;
}
{
int rc = VINF_SUCCESS;
return rc;
}
static DECLCALLBACK(int) svcSaveState(void *, uint32_t u32ClientID, void *pvClient, PSSMHANDLE pSSM)
{
int rc = VINF_SUCCESS;
/* 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)
{
int rc = VINF_SUCCESS;
char psz[2000];
/* 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*/
{
const char *pMatch = &gszVBoxOGLSSMMagic[0];
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[])
{
int rc = VINF_SUCCESS;
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.
*/
{
int rc = VINF_SUCCESS;
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. */
{
ULONG monitorCount, i, w, h;
for (i=0; i<monitorCount; ++i)
{
if (!pFramebuffer)
{
rc = crVBoxServerUnmapScreen(i);
}
else
{
}
}
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
{
#if 0
#endif
do {
/* determine if the framebuffer is functional */
if (!winId)
{
/* View associated with framebuffer is destroyed, happens with 2d accel enabled */
}
else
{
}
} while (0);
#if 0
#endif
}
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;
}
default:
break;
}
return rc;
}
{
{
WARN(("invalid param size"));
return VERR_INVALID_PARAMETER;
}
}
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:
WARN(("invalid function"));
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;
}
}
}
{
int rc = VINF_SUCCESS;
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;
rc = svcPresentFBOInit();
}
}
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