diff options
author | Felix Geyer <debfx-pkg@fobos.de> | 2010-05-13 18:18:03 +0200 |
---|---|---|
committer | Felix Geyer <debfx-pkg@fobos.de> | 2010-05-13 18:18:03 +0200 |
commit | 0c7f2a3d122182fe8890ea1f8178d1955c5a04dc (patch) | |
tree | 8cba8ec40170496c6511fb9016d157df568258cb /src/VBox/HostServices | |
parent | 33961db1e2718be932cefe0b32aae173ae760cea (diff) | |
download | virtualbox-0c7f2a3d122182fe8890ea1f8178d1955c5a04dc.tar.gz |
Imported Upstream version 3.1.53-dfsgupstream/3.1.53-dfsg
Diffstat (limited to 'src/VBox/HostServices')
6 files changed, 245 insertions, 131 deletions
diff --git a/src/VBox/HostServices/GuestControl/service.cpp b/src/VBox/HostServices/GuestControl/service.cpp index 74b002523..d3cdb093a 100644 --- a/src/VBox/HostServices/GuestControl/service.cpp +++ b/src/VBox/HostServices/GuestControl/service.cpp @@ -1,4 +1,4 @@ -/* $Id: service.cpp 29003 2010-05-04 11:26:52Z vboxsync $ */ +/* $Id: service.cpp 29220 2010-05-07 15:09:53Z vboxsync $ */ /** @file * Guest Control Service: Controlling the guest. */ @@ -27,7 +27,7 @@ #include <VBox/HostServices/GuestControlSvc.h> #include <VBox/log.h> -#include <iprt/asm.h> +#include <iprt/asm.h> /* For ASMBreakpoint(). */ #include <iprt/assert.h> #include <iprt/cpp/autores.h> #include <iprt/cpp/utils.h> @@ -64,6 +64,8 @@ typedef std::list< HostCmd >::const_iterator HostCmdListIterConst; */ struct GuestCall { + /** Client ID; a client can have multiple handles! */ + uint32_t mClientID; /** The call handle */ VBOXHGCMCALLHANDLE mHandle; /** The call parameters */ @@ -72,13 +74,16 @@ struct GuestCall uint32_t mNumParms; /** The standard constructor */ - GuestCall() : mHandle(0), mParms(NULL), mNumParms(0) {} + GuestCall() : mClientID(0), mHandle(0), mParms(NULL), mNumParms(0) {} /** The normal contructor */ - GuestCall(VBOXHGCMCALLHANDLE aHandle, VBOXHGCMSVCPARM aParms[], int cParms) - : mHandle(aHandle), mParms(aParms), mNumParms(cParms) {} + GuestCall(uint32_t aClientID, VBOXHGCMCALLHANDLE aHandle, + VBOXHGCMSVCPARM aParms[], uint32_t cParms) + : mClientID(aClientID), mHandle(aHandle), mParms(aParms), mNumParms(cParms) {} }; /** The guest call list type */ -typedef std::list <GuestCall> CallList; +typedef std::list< GuestCall > CallList; +typedef std::list< GuestCall >::iterator CallListIter; +typedef std::list< GuestCall >::const_iterator CallListIterConst; /** * Class containing the shared information service functionality. @@ -90,15 +95,6 @@ private: typedef Service SELF; /** HGCM helper functions. */ PVBOXHGCMSVCHELPERS mpHelpers; - /** @todo we should have classes for thread and request handler thread */ - /** Queue of outstanding property change notifications */ - RTREQQUEUE *mReqQueue; - /** Request that we've left pending in a call to flushNotifications. */ - PRTREQ mPendingDummyReq; - /** Thread for processing the request queue */ - RTTHREAD mReqThread; - /** Tell the thread that it should exit */ - bool volatile mfExitThread; /** Callback function supplied by the host for notification of updates * to properties */ PFNHGCMSVCEXT mpfnHostCallback; @@ -112,20 +108,9 @@ private: public: explicit Service(PVBOXHGCMSVCHELPERS pHelpers) : mpHelpers(pHelpers) - , mPendingDummyReq(NULL) - , mfExitThread(false) , mpfnHostCallback(NULL) , mpvHostData(NULL) { - int rc = RTReqCreateQueue(&mReqQueue); -#ifndef VBOX_GUEST_CTRL_TEST_NOTHREAD - if (RT_SUCCESS(rc)) - rc = RTThreadCreate(&mReqThread, reqThreadFn, this, 0, - RTTHREADTYPE_MSG_PUMP, RTTHREADFLAGS_WAITABLE, - "GuestCtrlReq"); -#endif - if (RT_FAILURE(rc)) - throw rc; } /** @@ -230,11 +215,10 @@ private: void paramBufferFree(PVBOXGUESTCTRPARAMBUFFER pBuf); int paramBufferAssign(PVBOXGUESTCTRPARAMBUFFER pBuf, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); int prepareExecute(uint32_t cParms, VBOXHGCMSVCPARM paParms[]); - static DECLCALLBACK(int) reqThreadFn(RTTHREAD ThreadSelf, void *pvUser); int clientConnect(uint32_t u32ClientID, void *pvClient); int clientDisconnect(uint32_t u32ClientID, void *pvClient); int sendHostCmdToGuest(HostCmd *pCmd, VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); - int retrieveNextHostCmd(VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); + int retrieveNextHostCmd(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); int notifyHost(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); int processHostCmd(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); void call(VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID, @@ -245,19 +229,6 @@ private: }; -/** - * Thread function for processing the request queue - * @copydoc FNRTTHREAD - */ -/* static */ -DECLCALLBACK(int) Service::reqThreadFn(RTTHREAD ThreadSelf, void *pvUser) -{ - SELF *pSelf = reinterpret_cast<SELF *>(pvUser); - while (!pSelf->mfExitThread) - RTReqProcess(pSelf->mReqQueue, RT_INDEFINITE_WAIT); - return VINF_SUCCESS; -} - /** @todo Write some nice doc headers! */ /* Stores a HGCM request in an internal buffer (pEx). Needs to be freed later using execBufferFree(). */ int Service::paramBufferAllocate(PVBOXGUESTCTRPARAMBUFFER pBuf, uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) @@ -265,6 +236,10 @@ int Service::paramBufferAllocate(PVBOXGUESTCTRPARAMBUFFER pBuf, uint32_t uMsg, u AssertPtr(pBuf); int rc = VINF_SUCCESS; + /* Paranoia. */ + if (cParms > 256) + cParms = 256; + /* * Don't verify anything here (yet), because this function only buffers * the HGCM data into an internal structure and reaches it back to the guest (client) @@ -391,6 +366,17 @@ int Service::clientConnect(uint32_t u32ClientID, void *pvClient) int Service::clientDisconnect(uint32_t u32ClientID, void *pvClient) { LogFlowFunc(("Client (%ld) disconnected\n", u32ClientID)); + /* + * Throw out all stale clients. + */ + CallListIter it = mClientList.begin(); + while (it != mClientList.end()) + { + if (it->mClientID == u32ClientID) + it = mClientList.erase(it); + else + it++; + } return VINF_SUCCESS; } @@ -423,7 +409,8 @@ int Service::sendHostCmdToGuest(HostCmd *pCmd, VBOXHGCMCALLHANDLE callHandle, ui * Either fills in parameters from a pending host command into our guest context or * defer the guest call until we have something from the host. */ -int Service::retrieveNextHostCmd(VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) +int Service::retrieveNextHostCmd(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle, + uint32_t cParms, VBOXHGCMSVCPARM paParms[]) { int rc = VINF_SUCCESS; @@ -434,7 +421,7 @@ int Service::retrieveNextHostCmd(VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, */ if (mHostCmds.empty()) /* If command list is empty, defer ... */ { - mClientList.push_back(GuestCall(callHandle, paParms, cParms)); + mClientList.push_back(GuestCall(u32ClientID, callHandle, paParms, cParms)); rc = VINF_HGCM_ASYNC_EXECUTE; } else @@ -534,11 +521,12 @@ int Service::processHostCmd(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM /* If not processed, buffer it ... */ if (!fProcessed) { - mHostCmds.push_back(newCmd); - + mHostCmds.push_back(newCmd); +#if 0 /* Limit list size by deleting oldest element. */ if (mHostCmds.size() > 256) /** @todo Use a define! */ mHostCmds.pop_front(); +#endif } } return rc; @@ -567,7 +555,7 @@ void Service::call(VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID, /* The guest asks the host for the next messsage to process. */ case GUEST_GET_HOST_MSG: LogFlowFunc(("GUEST_GET_HOST_MSG\n")); - rc = retrieveNextHostCmd(callHandle, cParms, paParms); + rc = retrieveNextHostCmd(u32ClientID, callHandle, cParms, paParms); break; /* The guest notifies the host that some output at stdout/stderr is available. */ diff --git a/src/VBox/HostServices/GuestProperties/service.cpp b/src/VBox/HostServices/GuestProperties/service.cpp index bb443a1fb..7b97a96c3 100644 --- a/src/VBox/HostServices/GuestProperties/service.cpp +++ b/src/VBox/HostServices/GuestProperties/service.cpp @@ -1,4 +1,4 @@ -/* $Id: service.cpp 28800 2010-04-27 08:22:32Z vboxsync $ */ +/* $Id: service.cpp 29394 2010-05-12 01:27:04Z vboxsync $ */ /** @file * Guest Property Service: Host service entry points. */ @@ -96,13 +96,17 @@ struct Property } /** Are two properties equal? */ - bool operator== (const Property &prop) + bool operator==(const Property &prop) { - return ( mName == prop.mName - && mValue == prop.mValue - && mTimestamp == prop.mTimestamp - && mFlags == prop.mFlags - ); + if (mTimestamp != prop.mTimestamp) + return false; + if (mFlags != prop.mFlags) + return false; + if (mName != prop.mName) + return false; + if (mValue != prop.mValue) + return false; + return true; } /* Is the property nil? */ @@ -163,6 +167,14 @@ private: PFNHGCMSVCEXT mpfnHostCallback; /** User data pointer to be supplied to the host callback function */ void *mpvHostData; + /** The previous timestamp. + * This is used by getCurrentTimestamp() to decrease the chance of + * generating duplicate timestamps. */ + uint64_t mPrevTimestamp; + /** The number of consecutive timestamp adjustments that we've made. + * Together with mPrevTimestamp, this defines a set of obsolete timestamp + * values: {(mPrevTimestamp - mcTimestampAdjustments), ..., mPrevTimestamp} */ + uint64_t mcTimestampAdjustments; /** * Get the next property change notification from the queue of saved @@ -192,9 +204,12 @@ private: * - Appears later than u64Timestamp * - Matches the pszPatterns */ + /** @todo r=bird: This incorrectly ASSUMES that mTimestamp is unique. + * The timestamp resolution can be very coarse on windows for instance. */ PropertyList::const_iterator it = mGuestNotifications.begin(); for (; it != mGuestNotifications.end() - && it->mTimestamp != u64Timestamp; ++it) {} + && it->mTimestamp != u64Timestamp; ++it) + {} if (it == mGuestNotifications.end()) /* Not found */ it = mGuestNotifications.begin(); else @@ -238,6 +253,8 @@ public: , meGlobalFlags(NILFLAG) , mpfnHostCallback(NULL) , mpvHostData(NULL) + , mPrevTimestamp(0) + , mcTimestampAdjustments(0) { } /** @@ -318,6 +335,7 @@ public: } private: static DECLCALLBACK(int) reqThreadFn(RTTHREAD ThreadSelf, void *pvUser); + uint64_t getCurrentTimestamp(void); int validateName(const char *pszName, uint32_t cbName); int validateValue(const char *pszValue, uint32_t cbValue); int setPropertyBlock(uint32_t cParms, VBOXHGCMSVCPARM paParms[]); @@ -343,6 +361,31 @@ private: /** + * Gets the current timestamp. + * + * Since the RTTimeNow resolution can be very coarse, this method takes some + * simple steps to try avoid returning the same timestamp for two consecutive + * calls. Code like getOldNotification() more or less assumes unique + * timestamps. + * + * @returns Nanosecond timestamp. + */ +uint64_t Service::getCurrentTimestamp(void) +{ + RTTIMESPEC time; + uint64_t u64NanoTS = RTTimeSpecGetNano(RTTimeNow(&time)); + if (mPrevTimestamp - u64NanoTS > mcTimestampAdjustments) + mcTimestampAdjustments = 0; + else + { + mcTimestampAdjustments++; + u64NanoTS = mPrevTimestamp + 1; + } + this->mPrevTimestamp = u64NanoTS; + return u64NanoTS; +} + +/** * Check that a string fits our criteria for a property name. * * @returns IPRT status code @@ -571,8 +614,7 @@ int Service::setProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool isGues uint32_t cchValue = 0; /* ditto */ uint32_t cchFlags = 0; uint32_t fFlags = NILFLAG; - RTTIMESPEC time; - uint64_t u64TimeNano = RTTimeSpecGetNano(RTTimeNow(&time)); + uint64_t u64TimeNano = getCurrentTimestamp(); LogFlowThisFunc(("\n")); /* @@ -701,8 +743,7 @@ int Service::delProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool isGues */ if (rc == VINF_SUCCESS && found) { - RTTIMESPEC time; - uint64_t u64Timestamp = RTTimeSpecGetNano(RTTimeNow(&time)); + uint64_t u64Timestamp = getCurrentTimestamp(); mProperties.erase(it); // if (isGuest) /* Notify the host even for properties that the host // * changed. Less efficient, but ensures consistency. */ @@ -807,28 +848,27 @@ int Service::getOldNotificationInternal(const char *pszPatterns, uint64_t u64Timestamp, Property *pProp) { - int rc = VINF_SUCCESS; - bool warn = false; - /* We count backwards, as the guest should normally be querying the * most recent events. */ + int rc = VWRN_NOT_FOUND; PropertyList::reverse_iterator it = mGuestNotifications.rbegin(); - for (; it->mTimestamp != u64Timestamp && it != mGuestNotifications.rend(); - ++it) {} - /* Warn if the timestamp was not found. */ - if (it->mTimestamp != u64Timestamp) - warn = true; + for (; it != mGuestNotifications.rend(); ++it) + if (it->mTimestamp == u64Timestamp) + { + rc = VINF_SUCCESS; + break; + } + /* Now look for an event matching the patterns supplied. The base() * member conveniently points to the following element. */ PropertyList::iterator base = it.base(); - for (; !base->Matches(pszPatterns) && base != mGuestNotifications.end(); - ++base) {} - if (RT_SUCCESS(rc) && base != mGuestNotifications.end()) - *pProp = *base; - else if (RT_SUCCESS(rc)) - *pProp = Property(); - if (warn) - rc = VWRN_NOT_FOUND; + for (; base != mGuestNotifications.end(); ++base) + if (base->Matches(pszPatterns)) + { + *pProp = *base; + return rc; + } + *pProp = Property(); return rc; } diff --git a/src/VBox/HostServices/GuestProperties/testcase/tstGuestPropSvc.cpp b/src/VBox/HostServices/GuestProperties/testcase/tstGuestPropSvc.cpp index b76cf5821..6433ff5ea 100644 --- a/src/VBox/HostServices/GuestProperties/testcase/tstGuestPropSvc.cpp +++ b/src/VBox/HostServices/GuestProperties/testcase/tstGuestPropSvc.cpp @@ -1,4 +1,4 @@ -/* $Id: tstGuestPropSvc.cpp 28800 2010-04-27 08:22:32Z vboxsync $ */ +/* $Id: tstGuestPropSvc.cpp 29394 2010-05-12 01:27:04Z vboxsync $ */ /** @file * * Testcase for the guest property service. @@ -726,7 +726,7 @@ int testGetNotification(VBOXHGCMSVCFNTABLE *pTable) { int rc = VINF_SUCCESS; VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS }; - char chBuffer[MAX_NAME_LEN + MAX_VALUE_LEN + MAX_FLAGS_LEN]; + char achBuffer[MAX_NAME_LEN + MAX_VALUE_LEN + MAX_FLAGS_LEN]; static char szPattern[] = ""; RTPrintf("Testing the GET_NOTIFICATION call.\n"); @@ -738,7 +738,7 @@ int testGetNotification(VBOXHGCMSVCFNTABLE *pTable) u64Timestamp = 1; paParms[0].setPointer ((void *) szPattern, sizeof(szPattern)); paParms[1].setUInt64 (u64Timestamp); - paParms[2].setPointer ((void *) chBuffer, getNotifications[0].cchBuffer - 1); + paParms[2].setPointer ((void *) achBuffer, getNotifications[0].cchBuffer - 1); pTable->pfnCall(pTable->pvService, &callHandle, 0, NULL, GET_NOTIFICATION, 4, paParms); if ( callHandle.rc != VERR_BUFFER_OVERFLOW @@ -759,7 +759,7 @@ int testGetNotification(VBOXHGCMSVCFNTABLE *pTable) { paParms[0].setPointer ((void *) szPattern, sizeof(szPattern)); paParms[1].setUInt64 (u64Timestamp); - paParms[2].setPointer ((void *) chBuffer, sizeof(chBuffer)); + paParms[2].setPointer ((void *) achBuffer, sizeof(achBuffer)); pTable->pfnCall(pTable->pvService, &callHandle, 0, NULL, GET_NOTIFICATION, 4, paParms); if ( RT_FAILURE(callHandle.rc) @@ -767,11 +767,11 @@ int testGetNotification(VBOXHGCMSVCFNTABLE *pTable) || RT_FAILURE(paParms[1].getUInt64 (&u64Timestamp)) || RT_FAILURE(paParms[3].getUInt32 (&u32Size)) || u32Size != getNotifications[i].cchBuffer - || memcmp(chBuffer, getNotifications[i].pchBuffer, u32Size) != 0 + || memcmp(achBuffer, getNotifications[i].pchBuffer, u32Size) != 0 ) { - RTPrintf("Failed to get notification for property '%s'.\n", - getNotifications[i].pchBuffer); + RTPrintf("Failed to get notification for property '%s' (rc=%Rrc).\n", + getNotifications[i].pchBuffer, rc); rc = VERR_UNRESOLVED_ERROR; } } diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_main.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_main.c index 695a6f7fc..41e4f74ae 100644 --- a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_main.c +++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_main.c @@ -25,7 +25,7 @@ #include <iprt/assert.h> /** - * \mainpage CrServerLib + * \mainpage CrServerLib * * \section CrServerLibIntroduction Introduction * @@ -90,7 +90,7 @@ static void crServerTearDown( void ) /* Deallocate all semaphores */ crFreeHashtable(cr_server.semaphores, crFree); cr_server.semaphores = NULL; - + /* Deallocate all barriers */ crFreeHashtable(cr_server.barriers, DeleteBarrierCallback); cr_server.barriers = NULL; @@ -328,7 +328,7 @@ int32_t crVBoxServerAddClient(uint32_t u32ClientID) return VERR_MAX_THRDS_REACHED; } - newClient = (CRClient *) crCalloc(sizeof(CRClient)); + newClient = (CRClient *) crCalloc(sizeof(CRClient)); crDebug("crServer: AddClient u32ClientID=%d", u32ClientID); newClient->spu_id = 0; @@ -355,8 +355,8 @@ void crVBoxServerRemoveClient(uint32_t u32ClientID) for (i = 0; i < cr_server.numClients; i++) { - if (cr_server.clients[i] && cr_server.clients[i]->conn - && cr_server.clients[i]->conn->u32ClientID==u32ClientID) + if (cr_server.clients[i] && cr_server.clients[i]->conn + && cr_server.clients[i]->conn->u32ClientID==u32ClientID) { break; } @@ -380,8 +380,8 @@ int32_t crVBoxServerClientWrite(uint32_t u32ClientID, uint8_t *pBuffer, uint32_t for (i = 0; i < cr_server.numClients; i++) { - if (cr_server.clients[i] && cr_server.clients[i]->conn - && cr_server.clients[i]->conn->u32ClientID==u32ClientID) + if (cr_server.clients[i] && cr_server.clients[i]->conn + && cr_server.clients[i]->conn->u32ClientID==u32ClientID) { break; } @@ -403,11 +403,11 @@ int32_t crVBoxServerClientWrite(uint32_t u32ClientID, uint8_t *pBuffer, uint32_t crDebug("crServer: client %d blocked, allow_redir_ptr = 0", u32ClientID); pClient->conn->allow_redir_ptr = 0; } - else + else { pClient->conn->allow_redir_ptr = 1; } - + pClient->conn->pBuffer = pBuffer; pClient->conn->cbBuffer = cbBuffer; @@ -459,8 +459,8 @@ int32_t crVBoxServerClientRead(uint32_t u32ClientID, uint8_t *pBuffer, uint32_t for (i = 0; i < cr_server.numClients; i++) { - if (cr_server.clients[i] && cr_server.clients[i]->conn - && cr_server.clients[i]->conn->u32ClientID==u32ClientID) + if (cr_server.clients[i] && cr_server.clients[i]->conn + && cr_server.clients[i]->conn->u32ClientID==u32ClientID) { break; } @@ -490,7 +490,7 @@ int32_t crVBoxServerClientRead(uint32_t u32ClientID, uint8_t *pBuffer, uint32_t crMemcpy(pBuffer, pClient->conn->pHostBuffer, *pcbBuffer); pClient->conn->cbHostBuffer = 0; } - + return VINF_SUCCESS; } @@ -501,8 +501,8 @@ int32_t crVBoxServerClientSetVersion(uint32_t u32ClientID, uint32_t vMajor, uint for (i = 0; i < cr_server.numClients; i++) { - if (cr_server.clients[i] && cr_server.clients[i]->conn - && cr_server.clients[i]->conn->u32ClientID==u32ClientID) + if (cr_server.clients[i] && cr_server.clients[i]->conn + && cr_server.clients[i]->conn->u32ClientID==u32ClientID) { break; } @@ -602,7 +602,7 @@ static void crVBoxServerSaveContextStateCB(unsigned long key, void *data1, void */ rc = SSMR3PutMem(pSSM, &key, sizeof(key)); CRASSERT(rc == VINF_SUCCESS); - + #ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE if (cr_server.curClient) { @@ -676,9 +676,9 @@ DECLEXPORT(int32_t) crVBoxServerSaveState(PSSMHANDLE pSSM) #endif /* Save contexts state tracker data */ - /* @todo For now just some blind data dumps, + /* @todo For now just some blind data dumps, * but I've a feeling those should be saved/restored in a very strict sequence to - * allow diff_api to work correctly. + * allow diff_api to work correctly. * Should be tested more with multiply guest opengl apps working when saving VM snapshot. */ crHashtableWalk(cr_server.contextTable, crVBoxServerSaveContextStateCB, pSSM); @@ -699,7 +699,7 @@ DECLEXPORT(int32_t) crVBoxServerSaveState(PSSMHANDLE pSSM) /* Save cr_server.muralTable * @todo we don't need it all, just geometry info actually - * @todo store visible regions as well + * @todo store visible regions as well */ ui32 = crHashtableNumElements(cr_server.muralTable); /* There should be default mural always */ @@ -715,7 +715,7 @@ DECLEXPORT(int32_t) crVBoxServerSaveState(PSSMHANDLE pSSM) /* Save clients info */ for (i = 0; i < cr_server.numClients; i++) { - if (cr_server.clients[i] && cr_server.clients[i]->conn) + if (cr_server.clients[i] && cr_server.clients[i]->conn) { CRClient *pClient = cr_server.clients[i]; @@ -816,7 +816,7 @@ DECLEXPORT(int32_t) crVBoxServerLoadState(PSSMHANDLE pSSM, uint32_t version) rc = crStateLoadContext(pContext, pSSM); AssertRCReturn(rc, rc); - } + } /* Load windows */ rc = SSMR3GetU32(pSSM, &uiNumElems); @@ -891,7 +891,7 @@ DECLEXPORT(int32_t) crVBoxServerLoadState(PSSMHANDLE pSSM, uint32_t version) /* Load clients info */ for (i = 0; i < cr_server.numClients; i++) { - if (cr_server.clients[i] && cr_server.clients[i]->conn) + if (cr_server.clients[i] && cr_server.clients[i]->conn) { CRClient *pClient = cr_server.clients[i]; CRClient client; @@ -982,7 +982,7 @@ DECLEXPORT(int32_t) crVBoxServerLoadState(PSSMHANDLE pSSM, uint32_t version) cr_server.head_spu->dispatch_table.Enable(GL_CULL_FACE); cr_server.head_spu->dispatch_table.Enable(GL_TEXTURE_2D);*/ - + //crStateViewport( 0, 0, 600, 600 ); //pClient->currentMural->viewportValidated = GL_FALSE; //cr_server.head_spu->dispatch_table.Viewport( 0, 0, 600, 600 ); @@ -1102,9 +1102,6 @@ DECLEXPORT(int32_t) crVBoxServerMapScreen(int sIndex, int32_t x, int32_t y, uint if (sIndex<0 || sIndex>=cr_server.screenCount) return VERR_INVALID_PARAMETER; - if (winID==0) - return VERR_INVALID_PARAMETER; - if (MAPPED(SCREEN(sIndex)) && SCREEN(sIndex).winID!=winID) { crWarning("Mapped screen[%i] is being remapped.", sIndex); @@ -1122,7 +1119,37 @@ DECLEXPORT(int32_t) crVBoxServerMapScreen(int sIndex, int32_t x, int32_t y, uint renderspuSetWindowId(SCREEN(0).winID); crHashtableWalk(cr_server.muralTable, crVBoxServerCheckMuralCB, NULL); - + +#ifndef WINDOWS + /*Restore FB content for clients, which have current window on a screen being remapped*/ + { + GLint i; + + for (i = 0; i < cr_server.numClients; i++) + { + cr_server.curClient = cr_server.clients[i]; + if (cr_server.curClient->currentCtx + && cr_server.curClient->currentCtx->pImage + && cr_server.curClient->currentMural + && cr_server.curClient->currentMural->screenId == sIndex + && cr_server.curClient->currentCtx->viewport.viewportH == h + && cr_server.curClient->currentCtx->viewport.viewportW == w) + { + int clientWindow = cr_server.curClient->currentWindow; + int clientContext = cr_server.curClient->currentContextNumber; + + if (clientWindow && clientWindow != cr_server.currentWindow) + { + crServerDispatchMakeCurrent(clientWindow, 0, clientContext); + } + + crStateApplyFBImage(cr_server.curClient->currentCtx); + } + } + cr_server.curClient = NULL; + } +#endif + return VINF_SUCCESS; } diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_window.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_window.c index 2d04295b5..bf9af42fd 100644 --- a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_window.c +++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_window.c @@ -212,10 +212,7 @@ crServerDispatchWindowSize( GLint window, GLint width, GLint height ) crServerCheckMuralGeometry(mural); - if (!mural->bUseFBO) - { - cr_server.head_spu->dispatch_table.WindowSize(mural->spuWindow, width, height); - } + cr_server.head_spu->dispatch_table.WindowSize(mural->spuWindow, width, height); } diff --git a/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa_helper.m b/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa_helper.m index 32a5ac654..50ce881c1 100644 --- a/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa_helper.m +++ b/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa_helper.m @@ -21,11 +21,14 @@ #include <iprt/thread.h> #include <iprt/string.h> +#include <iprt/mem.h> +#include <iprt/time.h> /* Debug macros */ #define FBO 1 /* Disable this to see how the output is without the FBO in the middle of the processing chain. */ //#define SHOW_WINDOW_BACKGROUND 1 /* Define this to see the window background even if the window is clipped */ //#define DEBUG_VERBOSE /* Define this could get some debug info about the messages flow. */ +//#define DEBUG_poetzsch 1 #ifdef DEBUG_poetzsch #define DEBUG_MSG(text) \ @@ -53,7 +56,7 @@ static void checkGLError(char *file, int line) { GLenum g = glGetError(); - if (g != GL_NO_ERROR) + if (g != GL_NO_ERROR) { char *errStr; switch (g) @@ -506,12 +509,14 @@ while(0); /* Reposition this window with the help of the OverlayView. Perform the * call in the OpenGL thread. */ // [m_pOverlayView performSelector:@selector(reshape) onThread:m_Thread withObject:nil waitUntilDone:YES]; + DEBUG_MSG(("parentWindowFrameChanged\n")); [m_pOverlayView reshape]; } - (void)parentWindowChanged:(NSWindow*)pWindow { [[NSNotificationCenter defaultCenter] removeObserver:self]; + DEBUG_MSG(("parentWindowChanged\n")); if(pWindow != nil) { /* Ask to get notifications when our parent window frame changes. */ @@ -527,7 +532,6 @@ while(0); // [m_pOverlayView performSelector:@selector(reshape) withObject:nil afterDelay:0.2]; // [NSTimer scheduledTimerWithTimeInterval:0.2 target:m_pOverlayView selector:@selector(reshape) userInfo:nil repeats:NO]; [m_pOverlayView reshape]; - } } @@ -551,6 +555,8 @@ while(0); m_FBOTexId = 0; m_FBOTexSize = NSZeroSize; m_FBODepthStencilPackedId = 0; + m_FBOThumbId = 0; + m_FBOThumbTexId = 0; m_cClipRects = 0; m_paClipRects = NULL; m_Pos = NSZeroPoint; @@ -647,8 +653,21 @@ while(0); - (void)setSize:(NSSize)size { m_Size = size; - [self reshape]; - [self updateFBO]; + + if (!m_FBOId) + { + DEBUG_MSG(("Set size (no fbo) %p\n", self)); + [self reshape]; + [self updateFBO]; + } + else + { + DEBUG_MSG(("Set size FBO %p\n", self)); + [self reshape]; + [self updateFBO]; + /* have to rebind GL_TEXTURE_RECTANGLE_ARB as m_FBOTexId could be changed in updateFBO call */ + [self updateViewport]; + } } - (NSSize)size @@ -658,9 +677,11 @@ while(0); - (void)updateViewport { + DEBUG_MSG(("updateViewport %p\n", self)); if (m_pSharedGLCtx) { /* Update the viewport for our OpenGL view */ + DEBUG_MSG(("MakeCurrent (shared) %X\n", m_pSharedGLCtx)); [m_pSharedGLCtx makeCurrentContext]; [m_pSharedGLCtx update]; @@ -683,12 +704,14 @@ while(0); glEnable(GL_TEXTURE_RECTANGLE_ARB); glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_FBOTexId); + DEBUG_MSG(("MakeCurrent %X\n", m_pGLCtx)); [m_pGLCtx makeCurrentContext]; } } - (void)reshape { + DEBUG_MSG(("(%p)reshape %p\n", RTThreadSelf(), self)); /* Getting the right screen coordinates of the parents frame is a little bit * complicated. */ NSRect parentFrame = [m_pParentView frame]; @@ -742,9 +765,13 @@ while(0); } - (void)createFBO -{ +{ + GLuint fboid = m_FBOId; + + DEBUG_MSG(("createFBO %p\n", self)); [self deleteFBO]; +if (0&&!fboid) GL_SAVE_STATE; /* If not previously setup generate IDs for FBO and its associated texture. */ @@ -766,7 +793,7 @@ while(0); glGenFramebuffersEXT(1, &m_FBOId); /* & the texture as well the depth/stencil render buffer */ glGenTextures(1, &m_FBOTexId); - DEBUG_MSG_1(("Create FBO %d %d\n", m_FBOId, m_FBOTexId)); + DEBUG_MSG(("Create FBO %d %d\n", m_FBOId, m_FBOTexId)); glGenRenderbuffersEXT(1, &m_FBODepthStencilPackedId); } @@ -787,7 +814,7 @@ while(0); GLint filter = GL_NEAREST; if (m_FBOTexSize.width > maxTexSize || m_FBOTexSize.height > maxTexSize) { - filter = GL_NICEST; + filter = GL_LINEAR; if (imageAspectRatio > 1) { m_FBOTexSize.width = maxTexSize; @@ -825,6 +852,7 @@ while(0); glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + glDisable(GL_TEXTURE_RECTANGLE_ARB); /* Is there a dock tile preview enabled in the GUI? If so setup a * additional thumbnail view for the dock tile. */ @@ -840,8 +868,8 @@ while(0); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FBOThumbId); /* Initialize FBO Texture */ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_FBOThumbTexId); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NICEST); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NICEST); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP); @@ -872,15 +900,28 @@ while(0); m_paClipRects[1] = 0; m_paClipRects[2] = m_FBOTexSize.width; m_paClipRects[3] = m_FBOTexSize.height; - + +if (0&&!fboid) GL_RESTORE_STATE; } - (void)deleteFBO { - if ([NSOpenGLContext currentContext] != nil) + DEBUG_MSG(("deleteFBO %p\n", self)); + if (m_pSharedGLCtx) { - GL_SAVE_STATE; + DEBUG_MSG(("MakeCurrent (shared) %X\n", m_pSharedGLCtx)); + [m_pSharedGLCtx makeCurrentContext]; + [m_pSharedGLCtx update]; + + glEnable(GL_TEXTURE_RECTANGLE_ARB); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); + } + + if (m_pGLCtx) + { + DEBUG_MSG(("MakeCurrent %X\n", m_pGLCtx)); + [m_pGLCtx makeCurrentContext]; if (m_FBODepthStencilPackedId > 0) { @@ -896,14 +937,19 @@ while(0); } if (m_FBOId > 0) { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + GLint tmpFB; + glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &tmpFB); + if (tmpFB == m_FBOId) + { + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + } + glDeleteFramebuffersEXT(1, &m_FBOId); m_FBOId = 0; } - - GL_RESTORE_STATE; } + if (m_DockTileView != nil) { [m_DockTileView removeFromSuperview]; @@ -914,6 +960,7 @@ while(0); - (void)updateFBO { + DEBUG_MSG(("updateFBO %p\n", self)); [self makeCurrentFBO]; if (m_pGLCtx) @@ -947,6 +994,7 @@ while(0); } // if ([NSOpenGLContext currentContext] != m_pGLCtx) { + DEBUG_MSG(("MakeCurrent %X\n", m_pGLCtx)); [m_pGLCtx makeCurrentContext]; CHECK_GL_ERROR(); // [m_pGLCtx update]; @@ -969,7 +1017,7 @@ while(0); // [m_pGLCtx flushBuffer]; glFlush(); // glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - if (tmpFB == m_FBOId) + if (tmpFB == m_FBOId) { if ([self lockFocusIfCanDraw]) { @@ -990,7 +1038,7 @@ while(0); glFlush(); // glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); DEBUG_MSG_1 (("Flush GetINT %d\n", tmpFB)); - if (tmpFB == m_FBOId) + if (tmpFB == m_FBOId) { if ([self lockFocusIfCanDraw]) { @@ -1008,7 +1056,7 @@ while(0); glFinish(); // glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); DEBUG_MSG_1 (("Finish GetINT %d\n", tmpFB)); - if (tmpFB == m_FBOId) + if (tmpFB == m_FBOId) { if ([self lockFocusIfCanDraw]) { @@ -1048,8 +1096,16 @@ while(0); if (m_FBOTexId > 0) { + if ([m_pSharedGLCtx view] != self) + { + DEBUG_MSG(("renderFBOToView: not currect view of shared ctx!")); + [m_pSharedGLCtx setView: self]; + [self updateViewport]; + } + + //DEBUG_MSG(("MakeCurrent (shared) %X\n", m_pSharedGLCtx)); [m_pSharedGLCtx makeCurrentContext]; - + if (m_FBOThumbTexId > 0 && [m_DockTileView thumbBitmap] != nil) { @@ -1143,6 +1199,9 @@ while(0); /* Clear background to transparent */ glClear(GL_COLOR_BUFFER_BIT); + glEnable(GL_TEXTURE_RECTANGLE_ARB); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_FBOTexId); + /* Blit the content of the FBO to the screen. todo: check for * optimization with display lists. */ GLint i; @@ -1163,6 +1222,7 @@ while(0); } glFinish(); [m_pSharedGLCtx flushBuffer]; + //DEBUG_MSG(("MakeCurrent %X\n", m_pGLCtx)); [m_pGLCtx makeCurrentContext]; } } @@ -1454,6 +1514,8 @@ void cocoaViewMakeCurrentContext(NativeViewRef pView, NativeGLCtxRef pCtx) { NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init]; + DEBUG_MSG(("cocoaViewMakeCurrentContext(%p, %p)\n", pView, pCtx)); + [(OverlayView*)pView setGLCtx:pCtx]; [(OverlayView*)pView makeCurrentFBO]; @@ -1529,7 +1591,7 @@ void cocoaBindFramebufferEXT(GLenum target, GLuint framebuffer) { NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init]; - DEBUG_MSG_1(("glRenderspuBindFramebufferEXT called %d\n", framebuffer)); + DEBUG_MSG(("glRenderspuBindFramebufferEXT called %d\n", framebuffer)); #ifdef FBO if (framebuffer != 0) |