diff options
Diffstat (limited to '')
-rw-r--r-- | src/VBox/HostServices/SharedOpenGL/crserver/crservice.cpp | 1603 |
1 files changed, 1603 insertions, 0 deletions
diff --git a/src/VBox/HostServices/SharedOpenGL/crserver/crservice.cpp b/src/VBox/HostServices/SharedOpenGL/crserver/crservice.cpp new file mode 100644 index 00000000..770b5847 --- /dev/null +++ b/src/VBox/HostServices/SharedOpenGL/crserver/crservice.cpp @@ -0,0 +1,1603 @@ +/* $Id: crservice.cpp $ */ +/** @file + * VBox crOpenGL - Host service entry points. + */ + +/* + * Copyright (C) 2006-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. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#define LOG_GROUP LOG_GROUP_SHARED_CROPENGL + +#define __STDC_CONSTANT_MACROS /* needed for a definition in iprt/string.h */ + +#include <iprt/assert.h> +#include <iprt/asm.h> +#include <iprt/critsect.h> +#include <iprt/mem.h> +#include <iprt/semaphore.h> +#include <iprt/stream.h> +#include <iprt/string.h> +#include <iprt/thread.h> + +#include <VBox/err.h> +#include <VBox/hgcmsvc.h> +#include <VBox/log.h> +#include <VBox/com/array.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 <VBox/VBoxOGL.h> + +#include "cr_mem.h" +#include "cr_server.h" + +#ifndef RT_OS_WINDOWS +# define DWORD int +# define WINAPI +#endif + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +PVBOXHGCMSVCHELPERS g_pHelpers; +static IConsole* g_pConsole = NULL; +static uint32_t g_u32ScreenCount = 0; +static PVM g_pVM = NULL; +static uint32_t g_u32fCrHgcmDisabled = 0; + +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 { + uint32_t uiId; + uint32_t uiSize; + void* pData; + _CRVBOXSVCBUFFER_t *pNext, *pPrev; +} CRVBOXSVCBUFFER_t; + +static CRVBOXSVCBUFFER_t *g_pCRVBoxSVCBuffers = NULL; +static uint32_t g_CRVBoxSVCBufferID = 0; + +/* svcPresentFBO related data */ +typedef struct _CRVBOXSVCPRESENTFBOCMD_t { + void *pData; + int32_t screenId, x, y, w, h; + _CRVBOXSVCPRESENTFBOCMD_t *pNext; +} CRVBOXSVCPRESENTFBOCMD_t, *PCRVBOXSVCPRESENTFBOCMD_t; + + +static DECLCALLBACK(void) svcNotifyEventCB(int32_t screenId, uint32_t uEvent, void* pvData, uint32_t cbData) +{ + ComPtr<IDisplay> pDisplay; + ComPtr<IFramebuffer> pFramebuffer; + + if (!g_pConsole) + { + crWarning("Console not defined!"); + return; + } + + CHECK_ERROR2I_STMT(g_pConsole, COMGETTER(Display)(pDisplay.asOutParam()), return); + + CHECK_ERROR2I_STMT(pDisplay, QueryFramebuffer(screenId, pFramebuffer.asOutParam()), return); + + if (!pFramebuffer) + return; + + com::SafeArray<BYTE> data(cbData); + if (cbData) + memcpy(data.raw(), pvData, cbData); + + pFramebuffer->Notify3DEvent(uEvent, ComSafeArrayAsInParam(data)); +} + + +static DECLCALLBACK(int) svcUnload (void *) +{ + int rc = VINF_SUCCESS; + + Log(("SHARED_CROPENGL svcUnload\n")); + + crVBoxServerTearDown(); + + return rc; +} + +static DECLCALLBACK(int) svcConnect (void *, uint32_t u32ClientID, void *pvClient, uint32_t fRequestor, bool fRestoring) +{ + RT_NOREF(pvClient, fRequestor, fRestoring); + + if (g_u32fCrHgcmDisabled) + { + WARN(("connect not expected")); + return VERR_INVALID_STATE; + } + + Log(("SHARED_CROPENGL svcConnect: u32ClientID = %d\n", u32ClientID)); + + int rc = crVBoxServerAddClient(u32ClientID); + + return rc; +} + +static DECLCALLBACK(int) svcDisconnect (void *, uint32_t u32ClientID, void *pvClient) +{ + int rc = VINF_SUCCESS; + + NOREF(pvClient); + + if (g_u32fCrHgcmDisabled) + { + WARN(("disconnect not expected")); + return VINF_SUCCESS; + } + + Log(("SHARED_CROPENGL svcDisconnect: u32ClientID = %d\n", u32ClientID)); + + crVBoxServerRemoveClient(u32ClientID); + + return rc; +} + +static DECLCALLBACK(int) svcSaveState(void *, uint32_t u32ClientID, void *pvClient, PSSMHANDLE pSSM) +{ + int rc = VINF_SUCCESS; + + NOREF(pvClient); + + Log(("SHARED_CROPENGL svcSaveState: u32ClientID = %d\n", u32ClientID)); + + /* Start*/ + rc = SSMR3PutStrZ(pSSM, gszVBoxOGLSSMMagic); + AssertRCReturn(rc, rc); + + /* Version */ + rc = SSMR3PutU32(pSSM, (uint32_t) SHCROGL_SSM_VERSION); + AssertRCReturn(rc, rc); + + /* The state itself */ + rc = crVBoxServerSaveState(pSSM); + AssertRCReturn(rc, rc); + + /* Save svc buffers info */ + { + CRVBOXSVCBUFFER_t *pBuffer = g_pCRVBoxSVCBuffers; + + rc = SSMR3PutU32(pSSM, g_CRVBoxSVCBufferID); + AssertRCReturn(rc, rc); + + while (pBuffer) + { + rc = SSMR3PutU32(pSSM, pBuffer->uiId); + AssertRCReturn(rc, rc); + + rc = SSMR3PutU32(pSSM, pBuffer->uiSize); + AssertRCReturn(rc, rc); + + rc = SSMR3PutMem(pSSM, pBuffer->pData, pBuffer->uiSize); + AssertRCReturn(rc, rc); + + pBuffer = pBuffer->pNext; + } + + rc = SSMR3PutU32(pSSM, 0); + AssertRCReturn(rc, rc); + } + + /* End */ + rc = SSMR3PutStrZ(pSSM, gszVBoxOGLSSMMagic); + AssertRCReturn(rc, rc); + + return VINF_SUCCESS; +} + +static DECLCALLBACK(int) svcLoadState(void *, uint32_t u32ClientID, void *pvClient, PSSMHANDLE pSSM, uint32_t uVersion) +{ + RT_NOREF(pvClient, uVersion); + int rc = VINF_SUCCESS; + + Log(("SHARED_CROPENGL svcLoadState: u32ClientID = %d\n", u32ClientID)); + + char psz[2000]; + uint32_t ui32; + + /* Start of data */ + rc = SSMR3GetStrZEx(pSSM, psz, 2000, NULL); + AssertRCReturn(rc, rc); + if (strcmp(gszVBoxOGLSSMMagic, psz)) + return VERR_SSM_UNEXPECTED_DATA; + + /* Version */ + rc = SSMR3GetU32(pSSM, &ui32); + AssertRCReturn(rc, rc); + + /* The state itself */ + rc = crVBoxServerLoadState(pSSM, ui32); + + if (rc==VERR_SSM_DATA_UNIT_FORMAT_CHANGED && ui32!=SHCROGL_SSM_VERSION) + { + LogRel(("OpenGL: 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*/ + { + const char *pMatch = &gszVBoxOGLSSMMagic[0]; + char current; + + while (*pMatch) + { + rc = SSMR3GetS8(pSSM, (int8_t*)¤t); + AssertRCReturn(rc, rc); + + if (current==*pMatch) + { + pMatch++; + } + else + { + pMatch = &gszVBoxOGLSSMMagic[0]; + } + } + } + + return VINF_SUCCESS; + } + AssertRCReturn(rc, rc); + + /* Load svc buffers info */ + if (ui32>=24) + { + uint32_t uiId; + + rc = SSMR3GetU32(pSSM, &g_CRVBoxSVCBufferID); + AssertRCReturn(rc, rc); + + rc = SSMR3GetU32(pSSM, &uiId); + AssertRCReturn(rc, rc); + + while (uiId) + { + CRVBOXSVCBUFFER_t *pBuffer = (CRVBOXSVCBUFFER_t *) RTMemAlloc(sizeof(CRVBOXSVCBUFFER_t)); + if (!pBuffer) + { + return VERR_NO_MEMORY; + } + pBuffer->uiId = uiId; + + rc = SSMR3GetU32(pSSM, &pBuffer->uiSize); + AssertRCReturn(rc, rc); + + pBuffer->pData = RTMemAlloc(pBuffer->uiSize); + if (!pBuffer->pData) + { + RTMemFree(pBuffer); + return VERR_NO_MEMORY; + } + + rc = SSMR3GetMem(pSSM, pBuffer->pData, pBuffer->uiSize); + AssertRCReturn(rc, rc); + + pBuffer->pNext = g_pCRVBoxSVCBuffers; + pBuffer->pPrev = NULL; + if (g_pCRVBoxSVCBuffers) + { + g_pCRVBoxSVCBuffers->pPrev = pBuffer; + } + g_pCRVBoxSVCBuffers = pBuffer; + + rc = SSMR3GetU32(pSSM, &uiId); + AssertRCReturn(rc, rc); + } + } + + /* End of data */ + rc = SSMR3GetStrZEx(pSSM, psz, 2000, NULL); + AssertRCReturn(rc, rc); + if (strcmp(gszVBoxOGLSSMMagic, psz)) + return VERR_SSM_UNEXPECTED_DATA; + + return VINF_SUCCESS; +} + +static void svcClientVersionUnsupported(uint32_t minor, uint32_t major) +{ + LogRel(("OpenGL: Unsupported client version %d.%d\n", minor, major)); + + /*MS's opengl32 tries to load our ICD around 30 times on failure...this is to prevent unnecessary spam*/ + static int shown = 0; + + if (g_pVM && !shown) + { + VMSetRuntimeError(g_pVM, VMSETRTERR_FLAGS_NO_WAIT, "3DSupportIncompatibleAdditions", + "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; + } +} + +static CRVBOXSVCBUFFER_t* svcGetBuffer(uint32_t iBuffer, uint32_t cbBufferSize) +{ + CRVBOXSVCBUFFER_t* pBuffer; + + if (iBuffer) + { + pBuffer = g_pCRVBoxSVCBuffers; + while (pBuffer) + { + if (pBuffer->uiId == iBuffer) + { + if (cbBufferSize && pBuffer->uiSize!=cbBufferSize) + { + static int shown=0; + + if (shown<20) + { + shown++; + LogRel(("OpenGL: svcGetBuffer: Invalid buffer(%i) size %i instead of %i\n", + iBuffer, pBuffer->uiSize, cbBufferSize)); + } + return NULL; + } + return pBuffer; + } + pBuffer = pBuffer->pNext; + } + return NULL; + } + else /*allocate new buffer*/ + { + pBuffer = (CRVBOXSVCBUFFER_t*) RTMemAlloc(sizeof(CRVBOXSVCBUFFER_t)); + if (pBuffer) + { + /* Filling host buffer with zeroes to prevent possible host->guest memory disclosure */ + pBuffer->pData = RTMemAllocZ(cbBufferSize); + if (!pBuffer->pData) + { + LogRel(("OpenGL: svcGetBuffer: Not enough memory (%d)\n", cbBufferSize)); + RTMemFree(pBuffer); + return NULL; + } + pBuffer->uiId = ++g_CRVBoxSVCBufferID; + if (!pBuffer->uiId) + { + pBuffer->uiId = ++g_CRVBoxSVCBufferID; + } + Assert(pBuffer->uiId); + pBuffer->uiSize = cbBufferSize; + pBuffer->pPrev = NULL; + pBuffer->pNext = g_pCRVBoxSVCBuffers; + if (g_pCRVBoxSVCBuffers) + { + g_pCRVBoxSVCBuffers->pPrev = pBuffer; + } + g_pCRVBoxSVCBuffers = pBuffer; + } + else + { + LogRel(("OpenGL: svcGetBuffer: Not enough memory (%d)\n", sizeof(CRVBOXSVCBUFFER_t))); + } + return pBuffer; + } +} + +static void svcFreeBuffer(CRVBOXSVCBUFFER_t* pBuffer) +{ + Assert(pBuffer); + + if (pBuffer->pPrev) + { + pBuffer->pPrev->pNext = pBuffer->pNext; + } + else + { + Assert(pBuffer==g_pCRVBoxSVCBuffers); + g_pCRVBoxSVCBuffers = pBuffer->pNext; + } + + if (pBuffer->pNext) + { + pBuffer->pNext->pPrev = pBuffer->pPrev; + } + + RTMemFree(pBuffer->pData); + RTMemFree(pBuffer); +} + +static DECLCALLBACK(void) svcCall (void *, VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID, void *pvClient, + uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[], uint64_t tsArrival) +{ + RT_NOREF(pvClient, tsArrival); + 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 */ + Log((" pparms[%d]: type %d value %d\n", i, paParms[i].type, paParms[i].u.uint32)); + } +#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) + { + rc = VERR_INVALID_PARAMETER; + } + else + if ( paParms[0].type != VBOX_HGCM_SVC_PARM_PTR /* pBuffer */ + ) + { + rc = VERR_INVALID_PARAMETER; + } + else + { + /* Fetch parameters. */ + uint8_t *pBuffer = (uint8_t *)paParms[0].u.pointer.addr; + uint32_t cbBuffer = paParms[0].u.pointer.size; + + /* Execute the function. */ + rc = crVBoxServerClientWrite(u32ClientID, pBuffer, cbBuffer); + if (!RT_SUCCESS(rc)) + { + Assert(VERR_NOT_SUPPORTED==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) + { + rc = VERR_INVALID_PARAMETER; + } + else + if ( paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* u32ClientID */ + || paParms[1].type != VBOX_HGCM_SVC_PARM_PTR /* pBuffer */ + ) + { + rc = VERR_INVALID_PARAMETER; + } + else + { + /* Fetch parameters. */ + uint32_t u32InjectClientID = paParms[0].u.uint32; + uint8_t *pBuffer = (uint8_t *)paParms[1].u.pointer.addr; + uint32_t cbBuffer = paParms[1].u.pointer.size; + + /* Execute the function. */ + rc = crVBoxServerClientWrite(u32InjectClientID, pBuffer, cbBuffer); + 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) + { + rc = VERR_INVALID_PARAMETER; + } + else + if ( paParms[0].type != VBOX_HGCM_SVC_PARM_PTR /* pBuffer */ + || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* cbBuffer */ + ) + { + rc = VERR_INVALID_PARAMETER; + } + + /* Fetch parameters. */ + uint8_t *pBuffer = (uint8_t *)paParms[0].u.pointer.addr; + uint32_t cbBuffer = paParms[0].u.pointer.size; + + /* Execute the function. */ + rc = crVBoxServerClientRead(u32ClientID, pBuffer, &cbBuffer); + + if (RT_SUCCESS(rc)) + { + /* Update parameters.*/ + paParms[0].u.pointer.size = cbBuffer; /// @todo guest doesn't see this change somehow? + } else if (VERR_NOT_SUPPORTED==rc) + { + svcClientVersionUnsupported(0, 0); + } + + /* Return the required buffer size always */ + paParms[1].u.uint32 = cbBuffer; + + break; + } + + case SHCRGL_GUEST_FN_WRITE_READ: + { + Log(("svcCall: SHCRGL_GUEST_FN_WRITE_READ\n")); + + /* Verify parameter count and types. */ + if (cParms != SHCRGL_CPARMS_WRITE_READ) + { + rc = VERR_INVALID_PARAMETER; + } + else + if ( paParms[0].type != VBOX_HGCM_SVC_PARM_PTR /* pBuffer */ + || paParms[1].type != VBOX_HGCM_SVC_PARM_PTR /* pWriteback */ + || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* cbWriteback */ + ) + { + rc = VERR_INVALID_PARAMETER; + } + else + { + /* Fetch parameters. */ + uint8_t *pBuffer = (uint8_t *)paParms[0].u.pointer.addr; + uint32_t cbBuffer = paParms[0].u.pointer.size; + + uint8_t *pWriteback = (uint8_t *)paParms[1].u.pointer.addr; + uint32_t cbWriteback = paParms[1].u.pointer.size; + + /* Execute the function. */ + rc = crVBoxServerClientWrite(u32ClientID, pBuffer, cbBuffer); + if (!RT_SUCCESS(rc)) + { + Assert(VERR_NOT_SUPPORTED==rc); + svcClientVersionUnsupported(0, 0); + } + + rc = crVBoxServerClientRead(u32ClientID, pWriteback, &cbWriteback); + + if (RT_SUCCESS(rc)) + { + /* Update parameters.*/ + paParms[1].u.pointer.size = cbWriteback; + } + /* Return the required buffer size always */ + paParms[2].u.uint32 = cbWriteback; + } + + break; + } + + case SHCRGL_GUEST_FN_SET_VERSION: + { + Log(("svcCall: SHCRGL_GUEST_FN_SET_VERSION\n")); + + /* Verify parameter count and types. */ + if (cParms != SHCRGL_CPARMS_SET_VERSION) + { + rc = VERR_INVALID_PARAMETER; + } + else + if ( paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* vMajor */ + || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* vMinor */ + ) + { + rc = VERR_INVALID_PARAMETER; + } + else + { + /* Fetch parameters. */ + uint32_t vMajor = paParms[0].u.uint32; + uint32_t vMinor = paParms[1].u.uint32; + + /* Execute the function. */ + rc = crVBoxServerClientSetVersion(u32ClientID, vMajor, vMinor); + + if (!RT_SUCCESS(rc)) + { + svcClientVersionUnsupported(vMajor, vMinor); + } + } + + 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) + { + rc = VERR_INVALID_PARAMETER; + } + else + if (paParms[0].type != VBOX_HGCM_SVC_PARM_64BIT) + { + rc = VERR_INVALID_PARAMETER; + } + else + { + /* Fetch parameters. */ + uint64_t pid = paParms[0].u.uint64; + + /* Execute the function. */ + rc = crVBoxServerClientSetPID(u32ClientID, pid); + } + + break; + } + + case SHCRGL_GUEST_FN_WRITE_BUFFER: + { + Log(("svcCall: SHCRGL_GUEST_FN_WRITE_BUFFER\n")); + /* Verify parameter count and types. */ + if (cParms != SHCRGL_CPARMS_WRITE_BUFFER) + { + rc = VERR_INVALID_PARAMETER; + } + else + if ( paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /*iBufferID*/ + || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /*cbBufferSize*/ + || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /*ui32Offset*/ + || paParms[3].type != VBOX_HGCM_SVC_PARM_PTR /*pBuffer*/ + ) + { + rc = VERR_INVALID_PARAMETER; + } + else + { + /* Fetch parameters. */ + uint32_t iBuffer = paParms[0].u.uint32; + uint32_t cbBufferSize = paParms[1].u.uint32; + uint32_t ui32Offset = paParms[2].u.uint32; + uint8_t *pBuffer = (uint8_t *)paParms[3].u.pointer.addr; + uint32_t cbBuffer = paParms[3].u.pointer.size; + + /* Execute the function. */ + CRVBOXSVCBUFFER_t *pSvcBuffer = svcGetBuffer(iBuffer, cbBufferSize); + if (!pSvcBuffer || ((uint64_t)ui32Offset+cbBuffer)>cbBufferSize) + { + rc = VERR_INVALID_PARAMETER; + } + else + { + memcpy((void*)((uintptr_t)pSvcBuffer->pData+ui32Offset), pBuffer, cbBuffer); + + /* Return the buffer id */ + paParms[0].u.uint32 = pSvcBuffer->uiId; + } + } + + break; + } + + case SHCRGL_GUEST_FN_WRITE_READ_BUFFERED: + { + Log(("svcCall: SHCRGL_GUEST_FN_WRITE_READ_BUFFERED\n")); + + /* Verify parameter count and types. */ + if (cParms != SHCRGL_CPARMS_WRITE_READ_BUFFERED) + { + rc = VERR_INVALID_PARAMETER; + } + else + if ( paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* iBufferID */ + || paParms[1].type != VBOX_HGCM_SVC_PARM_PTR /* pWriteback */ + || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* cbWriteback */ + || !paParms[0].u.uint32 /*iBufferID can't be 0 here*/ + ) + { + rc = VERR_INVALID_PARAMETER; + } + else + { + /* Fetch parameters. */ + uint32_t iBuffer = paParms[0].u.uint32; + uint8_t *pWriteback = (uint8_t *)paParms[1].u.pointer.addr; + uint32_t cbWriteback = paParms[1].u.pointer.size; + + CRVBOXSVCBUFFER_t *pSvcBuffer = svcGetBuffer(iBuffer, 0); + if (!pSvcBuffer) + { + LogRel(("OpenGL: svcCall(WRITE_READ_BUFFERED): Invalid buffer (%d)\n", iBuffer)); + rc = VERR_INVALID_PARAMETER; + break; + } + + uint8_t *pBuffer = (uint8_t *)pSvcBuffer->pData; + uint32_t cbBuffer = pSvcBuffer->uiSize; + + /* Execute the function. */ + rc = crVBoxServerClientWrite(u32ClientID, pBuffer, cbBuffer); + if (!RT_SUCCESS(rc)) + { + Assert(VERR_NOT_SUPPORTED==rc); + svcClientVersionUnsupported(0, 0); + } + + rc = crVBoxServerClientRead(u32ClientID, pWriteback, &cbWriteback); + + if (RT_SUCCESS(rc)) + { + /* Update parameters.*/ + paParms[1].u.pointer.size = cbWriteback; + } + /* Return the required buffer size always */ + paParms[2].u.uint32 = cbWriteback; + + svcFreeBuffer(pSvcBuffer); + } + + break; + } + + case SHCRGL_GUEST_FN_GET_CAPS_NEW: + { + 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")); + rc = VERR_INVALID_PARAMETER; + break; + } + + if (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR) + { + WARN(("invalid parameter")); + rc = VERR_INVALID_PARAMETER; + break; + } + + if (paParms[0].u.pointer.size < sizeof (CR_CAPS_INFO)) + { + WARN(("invalid buffer size")); + rc = VERR_INVALID_PARAMETER; + break; + } + + CR_CAPS_INFO *pInfo = (CR_CAPS_INFO*)paParms[0].u.pointer.addr; + rc = crVBoxServerClientGetCapsNew(u32ClientID, pInfo); + AssertRC(rc); + + break; + } + + case SHCRGL_GUEST_FN_GET_CAPS_LEGACY: + { + Log(("svcCall: SHCRGL_GUEST_FN_GET_CAPS_LEGACY\n")); + + /* Verify parameter count and types. */ + if (cParms != SHCRGL_CPARMS_GET_CAPS_LEGACY) + { + rc = VERR_INVALID_PARAMETER; + } + else if (paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT) + { + rc = VERR_INVALID_PARAMETER; + } + else + { + /* Execute the function. */ + rc = crVBoxServerClientGetCapsLegacy(u32ClientID, &paParms[0].u.uint32); + AssertRC(rc); + } + + break; + } + + default: + { + WARN(("svcCall: unexpected u32Function %d", u32Function)); + rc = VERR_NOT_IMPLEMENTED; + } + } + + + LogFlow(("svcCall: rc = %Rrc\n", rc)); + + 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 int svcHostCallPerform(uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) +{ + 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 */ + Log((" pparms[%d]: type %d value %d\n", i, paParms[i].type, paParms[i].u.uint32)); + } +#endif + + switch (u32Function) + { +#ifdef VBOX_WITH_CRHGSMI + case SHCRGL_HOST_FN_CRHGSMI_CMD: + { + Assert(cParms == 1 && paParms[0].type == VBOX_HGCM_SVC_PARM_PTR); + if (cParms == 1 && paParms[0].type == VBOX_HGCM_SVC_PARM_PTR) + { + rc = crVBoxServerCrHgsmiCmd((PVBOXVDMACMD_CHROMIUM_CMD)paParms[0].u.pointer.addr, paParms[0].u.pointer.size); + if (VERR_NOT_SUPPORTED == rc) + { + svcClientVersionUnsupported(0, 0); + } + } + else + rc = VERR_INVALID_PARAMETER; + } break; + case SHCRGL_HOST_FN_CRHGSMI_CTL: + { + Assert(cParms == 1 && paParms[0].type == VBOX_HGCM_SVC_PARM_PTR); + if (cParms == 1 && paParms[0].type == VBOX_HGCM_SVC_PARM_PTR) + rc = crVBoxServerCrHgsmiCtl((PVBOXVDMACMD_CHROMIUM_CTL)paParms[0].u.pointer.addr, paParms[0].u.pointer.size); + else + rc = VERR_INVALID_PARAMETER; + } break; +#endif + case SHCRGL_HOST_FN_SET_CONSOLE: + { + Log(("svcCall: SHCRGL_HOST_FN_SET_DISPLAY\n")); + + /* Verify parameter count and types. */ + if (cParms != SHCRGL_CPARMS_SET_CONSOLE) + { + rc = VERR_INVALID_PARAMETER; + } + else if (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR) + { + rc = VERR_INVALID_PARAMETER; + } + else + { + /* Fetch parameters. */ + IConsole* pConsole = (IConsole*)paParms[0].u.pointer.addr; + uint32_t cbData = paParms[0].u.pointer.size; + + /* Verify parameters values. */ + if (cbData != sizeof (IConsole*)) + { + rc = VERR_INVALID_PARAMETER; + } + else if (!pConsole) + { + rc = VERR_INVALID_PARAMETER; + } + else /* Execute the function. */ + { + ComPtr<IMachine> pMachine; + ComPtr<IDisplay> pDisplay; + ComPtr<IFramebuffer> pFramebuffer; + LONG xo, yo; + LONG64 winId = 0; + ULONG monitorCount, i, w, h; + + CHECK_ERROR_BREAK(pConsole, COMGETTER(Machine)(pMachine.asOutParam())); + CHECK_ERROR_BREAK(pMachine, COMGETTER(MonitorCount)(&monitorCount)); + CHECK_ERROR_BREAK(pConsole, COMGETTER(Display)(pDisplay.asOutParam())); + + g_pConsole = pConsole; + g_u32ScreenCount = monitorCount; + + rc = crVBoxServerSetScreenCount(monitorCount); + AssertRCReturn(rc, rc); + +#if 1 + crServerVBoxCompositionSetEnableStateGlobal(GL_FALSE); + + for (i=0; i<monitorCount; ++i) + { + CHECK_ERROR_RET(pDisplay, QueryFramebuffer(i, pFramebuffer.asOutParam()), rc); + + if (!pFramebuffer) + { + rc = crVBoxServerUnmapScreen(i); + AssertRCReturn(rc, rc); + } + else + { + CHECK_ERROR_RET(pFramebuffer, COMGETTER(WinId)(&winId), rc); + CHECK_ERROR_RET(pFramebuffer, COMGETTER(Width)(&w), rc); + CHECK_ERROR_RET(pFramebuffer, COMGETTER(Height)(&h), rc); + ULONG dummy; + GuestMonitorStatus_T monitorStatus; + CHECK_ERROR_RET(pDisplay, GetScreenResolution(i, &dummy, &dummy, &dummy, &xo, &yo, &monitorStatus), rc); + + rc = crVBoxServerMapScreen(i, xo, yo, w, h, winId); + AssertRCReturn(rc, rc); + } + } + + crServerVBoxCompositionSetEnableStateGlobal(GL_TRUE); +#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) + { + rc = VERR_INVALID_PARAMETER; + } + else if (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR) + { + rc = VERR_INVALID_PARAMETER; + } + else + { + /* Fetch parameters. */ + PVM pVM = (PVM)paParms[0].u.pointer.addr; + uint32_t cbData = paParms[0].u.pointer.size; + + /* Verify parameters values. */ + if (cbData != sizeof (PVM)) + { + rc = VERR_INVALID_PARAMETER; + } + else + { + /* Execute the function. */ + g_pVM = pVM; + rc = VINF_SUCCESS; + } + } + break; + } + case SHCRGL_HOST_FN_SET_VISIBLE_REGION: + { + Log(("svcCall: SHCRGL_HOST_FN_SET_VISIBLE_REGION\n")); + + if (cParms != SHCRGL_CPARMS_SET_VISIBLE_REGION) + { + rc = VERR_INVALID_PARAMETER; + break; + } + + if ( paParms[0].type != VBOX_HGCM_SVC_PARM_PTR /* pRects */ + ) + { + rc = VERR_INVALID_PARAMETER; + break; + } + + Assert(sizeof (RTRECT) == 4 * sizeof (GLint)); + + rc = crVBoxServerSetRootVisibleRegion(paParms[0].u.pointer.size / sizeof (RTRECT), (const RTRECT*)paParms[0].u.pointer.addr); + break; + } + case SHCRGL_HOST_FN_SCREEN_CHANGED: + { + Log(("svcCall: SHCRGL_HOST_FN_SCREEN_CHANGED\n")); + + /* Verify parameter count and types. */ + if (cParms != SHCRGL_CPARMS_SCREEN_CHANGED) + { + rc = VERR_INVALID_PARAMETER; + } + else if (paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT) + { + rc = VERR_INVALID_PARAMETER; + } + else + { + /* Fetch parameters. */ + uint32_t screenId = paParms[0].u.uint32; + + /* Execute the function. */ + ComPtr<IDisplay> pDisplay; + ComPtr<IFramebuffer> pFramebuffer; + LONG xo, yo; + LONG64 winId = 0; + ULONG w, h; + + Assert(g_pConsole); + CHECK_ERROR_RET(g_pConsole, COMGETTER(Display)(pDisplay.asOutParam()), rc); + CHECK_ERROR_RET(pDisplay, QueryFramebuffer(screenId, pFramebuffer.asOutParam()), rc); + + crServerVBoxCompositionSetEnableStateGlobal(GL_FALSE); + + if (!pFramebuffer) + { + rc = crVBoxServerUnmapScreen(screenId); + AssertRCReturn(rc, rc); + } + else + { + do { + /* determine if the framebuffer is functional */ + com::SafeArray<BYTE> data; + rc = pFramebuffer->Notify3DEvent(VBOX3D_NOTIFY_EVENT_TYPE_TEST_FUNCTIONAL, ComSafeArrayAsInParam(data)); + + 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)); + ULONG dummy; + GuestMonitorStatus_T monitorStatus; + CHECK_ERROR_BREAK(pDisplay, GetScreenResolution(screenId, &dummy, &dummy, &dummy, &xo, &yo, &monitorStatus)); + + rc = crVBoxServerMapScreen(screenId, xo, yo, w, h, winId); + AssertRCReturn(rc, rc); + } + } while (0); + } + + crServerVBoxCompositionSetEnableStateGlobal(GL_TRUE); + + rc = VINF_SUCCESS; + } + break; + } + case SHCRGL_HOST_FN_TAKE_SCREENSHOT: + { + if (cParms != 1) + { + LogRel(("OpenGL: 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(("OpenGL: 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")); + + /* Verify parameter count and types. */ + if (cParms != SHCRGL_CPARMS_VIEWPORT_CHANGED) + { + LogRel(("OpenGL: SHCRGL_HOST_FN_VIEWPORT_CHANGED: cParms invalid - %d", cParms)); + rc = VERR_INVALID_PARAMETER; + break; + } + + for (int i = 0; i < SHCRGL_CPARMS_VIEWPORT_CHANGED; ++i) + { + if (paParms[i].type != VBOX_HGCM_SVC_PARM_32BIT) + { + LogRel(("OpenGL: SHCRGL_HOST_FN_VIEWPORT_CHANGED: param[%d] type invalid - %d", i, paParms[i].type)); + rc = VERR_INVALID_PARAMETER; + break; + } + } + + if (!RT_SUCCESS(rc)) + { + LogRel(("OpenGL: SHCRGL_HOST_FN_VIEWPORT_CHANGED: param validation failed, returning..")); + break; + } + + crServerVBoxCompositionSetEnableStateGlobal(GL_FALSE); + + rc = crVBoxServerSetScreenViewport((int)paParms[0].u.uint32, + paParms[1].u.uint32, /* x */ + paParms[2].u.uint32, /* y */ + paParms[3].u.uint32, /* w */ + paParms[4].u.uint32 /* h */); + if (!RT_SUCCESS(rc)) + { + LogRel(("OpenGL: 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(("OpenGL: 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(("OpenGL: 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(("OpenGL: SHCRGL_HOST_FN_VIEWPORT_CHANGED: crVBoxServerSetScreenViewport failed, rc %d", rc)); + } + + crServerVBoxCompositionSetEnableStateGlobal(GL_TRUE); + + break; + } + case SHCRGL_HOST_FN_SET_OUTPUT_REDIRECT: + { + /* + * 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. */ + if (cParms != SHCRGL_CPARMS_SET_OUTPUT_REDIRECT) + { + rc = VERR_INVALID_PARAMETER; + } + else if (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR) + { + rc = VERR_INVALID_PARAMETER; + } + else + { + /* Fetch parameters. */ + H3DOUTPUTREDIRECT *pOutputRedirect = (H3DOUTPUTREDIRECT *)paParms[0].u.pointer.addr; + uint32_t cbData = paParms[0].u.pointer.size; + + /* Verify parameters values. */ + if (cbData != sizeof (H3DOUTPUTREDIRECT)) + { + rc = VERR_INVALID_PARAMETER; + } + else /* Execute the function. */ + { + if (pOutputRedirect->H3DORBegin != NULL) + { + CROutputRedirect outputRedirect; + outputRedirect.pvContext = pOutputRedirect->pvContext; + outputRedirect.CRORBegin = pOutputRedirect->H3DORBegin; + outputRedirect.CRORGeometry = pOutputRedirect->H3DORGeometry; + outputRedirect.CRORVisibleRegion = pOutputRedirect->H3DORVisibleRegion; + outputRedirect.CRORFrame = pOutputRedirect->H3DORFrame; + 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; + } + case SHCRGL_HOST_FN_SET_SCALE_FACTOR: + { + /* Verify parameter count and types. */ + if (cParms != 1 + || paParms[0].type != VBOX_HGCM_SVC_PARM_PTR + || paParms[0].u.pointer.size != sizeof(CRVBOXHGCMSETSCALEFACTOR) + || !paParms[0].u.pointer.addr) + { + WARN(("invalid parameter")); + rc = VERR_INVALID_PARAMETER; + break; + } + + CRVBOXHGCMSETSCALEFACTOR *pData = (CRVBOXHGCMSETSCALEFACTOR *)paParms[0].u.pointer.addr; + double dScaleFactorW = (double)(pData->u32ScaleFactorWMultiplied) / VBOX_OGL_SCALE_FACTOR_MULTIPLIER; + double dScaleFactorH = (double)(pData->u32ScaleFactorHMultiplied) / VBOX_OGL_SCALE_FACTOR_MULTIPLIER; + + rc = VBoxOglSetScaleFactor(pData->u32Screen, dScaleFactorW, dScaleFactorH); + + /* 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", + pData->u32ScaleFactorWMultiplied, + pData->u32ScaleFactorHMultiplied, + (int)VBOX_OGL_SCALE_FACTOR_MULTIPLIER, + rc)); + + break; + } + + case SHCRGL_HOST_FN_SET_UNSCALED_HIDPI: + { + /* Verify parameter count and types. */ + if (cParms != 1 + || paParms[0].type != VBOX_HGCM_SVC_PARM_PTR + || paParms[0].u.pointer.size != sizeof(CRVBOXHGCMSETUNSCALEDHIDPIOUTPUT) + || !paParms[0].u.pointer.addr) + { + WARN(("invalid parameter")); + rc = VERR_INVALID_PARAMETER; + break; + } + + CRVBOXHGCMSETUNSCALEDHIDPIOUTPUT *pData = (CRVBOXHGCMSETUNSCALEDHIDPIOUTPUT *)paParms[0].u.pointer.addr; + crServerSetUnscaledHiDPI(pData->fUnscaledHiDPI); + LogRel(("OpenGL: Set OpenGL scale policy on HiDPI displays (fUnscaledHiDPI=%d)\n", pData->fUnscaledHiDPI)); + break; + } + + default: + WARN(("svcHostCallPerform: unexpected u32Function %d", u32Function)); + rc = VERR_NOT_IMPLEMENTED; + break; + } + + LogFlow(("svcHostCall: rc = %Rrc\n", rc)); + 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); + bool fHasCallout = VBOXCRCMDCTL_IS_CALLOUT_AVAILABLE(pCtl); + if (fHasCallout) + crVBoxServerCalloutEnable(pCtl); + + int rc = svcHostCallPerform(pCtl->u32Function, cParams, (VBOXHGCMSVCPARM*)(pCtl + 1)); + + if (fHasCallout) + crVBoxServerCalloutDisable(); + + 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; + } + + 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_DISABLE)) + WARN(("invalid param size")); + VBOXCRCMDCTL_DISABLE *pDisable = (VBOXCRCMDCTL_DISABLE*)pCtl; + int rc = crVBoxServerHgcmDisable(&pDisable->Data); + if (RT_SUCCESS(rc)) + g_u32fCrHgcmDisabled = 1; + else + WARN(("crVBoxServerHgcmDisable failed %d", rc)); + return rc; + } + case VBOXCRCMDCTL_TYPE_ENABLE: + { + if (paParms->u.pointer.size != sizeof (VBOXCRCMDCTL_ENABLE)) + WARN(("invalid param size")); + VBOXCRCMDCTL_ENABLE *pEnable = (VBOXCRCMDCTL_ENABLE*)pCtl; + int rc = crVBoxServerHgcmEnable(&pEnable->Data); + if (RT_SUCCESS(rc)) + g_u32fCrHgcmDisabled = 0; + else + WARN(("crVBoxServerHgcmEnable failed %d", rc)); + return rc; + } + default: + WARN(("svcHostCall: invalid function %d", pCtl->enmType)); + return VERR_INVALID_PARAMETER; + } + /* not reached. */ + } + + default: + if (g_u32fCrHgcmDisabled) + { + WARN(("cr hgcm disabled!")); + return VERR_INVALID_STATE; + } + return svcHostCallPerform(u32Function, cParms, paParms); + } +} + +extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad (VBOXHGCMSVCFNTABLE *ptable) +{ + int rc = VINF_SUCCESS; + + Log(("SHARED_CROPENGL VBoxHGCMSvcLoad: ptable = %p\n", ptable)); + + if (!ptable) + { + rc = VERR_INVALID_PARAMETER; + } + else + { + Log(("VBoxHGCMSvcLoad: ptable->cbSize = %d, ptable->u32Version = 0x%08X\n", ptable->cbSize, ptable->u32Version)); + + if ( ptable->cbSize != sizeof (VBOXHGCMSVCFNTABLE) + || ptable->u32Version != VBOX_HGCM_SVC_VERSION) + { + rc = VERR_INVALID_PARAMETER; + } + else + { + g_pHelpers = ptable->pHelpers; + + g_u32fCrHgcmDisabled = 0; + + ptable->cbClient = sizeof (void*); + + ptable->pfnUnload = svcUnload; + ptable->pfnConnect = svcConnect; + ptable->pfnDisconnect = svcDisconnect; + ptable->pfnCall = svcCall; + ptable->pfnHostCall = svcHostCall; + ptable->pfnSaveState = svcSaveState; + ptable->pfnLoadState = svcLoadState; + ptable->pfnNotify = NULL; + ptable->pvService = NULL; + + if (!crVBoxServerInit()) + return VERR_NOT_SUPPORTED; + + crServerVBoxSetNotifyEventCB(svcNotifyEventCB); + } + } + + return rc; +} + +#ifdef RT_OS_WINDOWS +#define WIN32_LEAN_AND_MEAN +#include <iprt/win/windows.h> +BOOL WINAPI DllMain(HINSTANCE hDLLInst, DWORD fdwReason, LPVOID lpvReserved) +{ + (void) lpvReserved; + + switch (fdwReason) + { + case DLL_THREAD_ATTACH: + { + crStateVBoxAttachThread(); + 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: + { + crStateVBoxDetachThread(); + break; + } + + case DLL_PROCESS_ATTACH: + default: + break; + } + + return TRUE; +} +#endif |