summaryrefslogtreecommitdiff
path: root/src/VBox/HostServices/SharedOpenGL/crserverlib/server_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/HostServices/SharedOpenGL/crserverlib/server_main.c')
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_main.c2411
1 files changed, 2211 insertions, 200 deletions
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_main.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_main.c
index f914569e..1a7e360c 100644
--- a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_main.c
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_main.c
@@ -12,7 +12,9 @@
#include "cr_string.h"
#include "cr_mem.h"
#include "cr_hash.h"
+#include "cr_vreg.h"
#include "cr_environment.h"
+#include "cr_pixeldata.h"
#include "server_dispatch.h"
#include "state/cr_texture.h"
#include "render/renderspu.h"
@@ -25,6 +27,7 @@
#endif
#include <iprt/assert.h>
#include <VBox/err.h>
+#include <VBox/log.h>
#ifdef VBOXCR_LOGFPS
#include <iprt/timer.h>
@@ -56,6 +59,8 @@ CRServer cr_server;
int tearingdown = 0; /* can't be static */
+static DECLCALLBACK(int) crVBoxCrCmdCmd(HVBOXCRCMDSVR hSvr, PVBOXCMDVBVA_HDR pCmd, uint32_t cbCmd);
+
DECLINLINE(int32_t) crVBoxServerClientGet(uint32_t u32ClientID, CRClient **ppClient)
{
CRClient *pClient = NULL;
@@ -118,11 +123,22 @@ static void deleteContextInfoCallback( void *data )
crFree(c);
}
+static void deleteMuralInfoCallback( void *data )
+{
+ CRMuralInfo *m = (CRMuralInfo *) data;
+ if (m->spuWindow != CR_RENDER_DEFAULT_WINDOW_ID) /* <- do not do term for default mural as it does not contain any info to be freed,
+ * and renderspu will destroy it up itself*/
+ {
+ crServerMuralTerm(m);
+ }
+ crFree(m);
+}
static void crServerTearDown( void )
{
GLint i;
CRClientNode *pNode, *pNext;
+ GLboolean fOldEnableDiff;
/* avoid a race condition */
if (tearingdown)
@@ -138,6 +154,17 @@ static void crServerTearDown( void )
crFree( cr_server.overlap_intens );
cr_server.overlap_intens = NULL;
+ /* needed to make sure window dummy mural not get created on mural destruction
+ * and generally this should be zeroed up */
+ cr_server.currentCtxInfo = NULL;
+ cr_server.currentWindow = -1;
+ cr_server.currentNativeWindow = 0;
+ cr_server.currentMural = NULL;
+
+ /* sync our state with renderspu,
+ * do it before mural & context deletion to avoid deleting currently set murals/contexts*/
+ cr_server.head_spu->dispatch_table.MakeCurrent(CR_RENDER_DEFAULT_WINDOW_ID, 0, CR_RENDER_DEFAULT_CONTEXT_ID);
+
/* Deallocate all semaphores */
crFreeHashtable(cr_server.semaphores, crFree);
cr_server.semaphores = NULL;
@@ -149,12 +176,28 @@ static void crServerTearDown( void )
/* Free all context info */
crFreeHashtable(cr_server.contextTable, deleteContextInfoCallback);
- /* Free context/window creation info */
- crFreeHashtable(cr_server.pWindowCreateInfoTable, crServerCreateInfoDeleteCB);
+ /* synchronize with reality */
+ fOldEnableDiff = crStateEnableDiffOnMakeCurrent(GL_FALSE);
+ if(cr_server.MainContextInfo.pContext)
+ crStateMakeCurrent(cr_server.MainContextInfo.pContext);
+ crStateEnableDiffOnMakeCurrent(fOldEnableDiff);
/* Free vertex programs */
crFreeHashtable(cr_server.programTable, crFree);
+ /* Free murals */
+ crFreeHashtable(cr_server.muralTable, deleteMuralInfoCallback);
+
+ CrPMgrTerm();
+
+ if (CrBltIsInitialized(&cr_server.Blitter))
+ {
+ CrBltTerm(&cr_server.Blitter);
+ }
+
+ /* Free dummy murals */
+ crFreeHashtable(cr_server.dummyMuralTable, deleteMuralInfoCallback);
+
for (i = 0; i < cr_server.numClients; i++) {
if (cr_server.clients[i]) {
CRConnection *conn = cr_server.clients[i]->conn;
@@ -174,6 +217,11 @@ static void crServerTearDown( void )
}
cr_server.pCleanupClient = NULL;
+ if (crServerRpwIsInitialized(&cr_server.RpwWorker))
+ {
+ crServerRpwTerm(&cr_server.RpwWorker);
+ }
+
#if 1
/* disable these two lines if trying to get stack traces with valgrind */
crSPUUnloadChain(cr_server.head_spu);
@@ -183,6 +231,10 @@ static void crServerTearDown( void )
crStateDestroy();
crNetTearDown();
+
+ VBoxVrListClear(&cr_server.RootVr);
+
+ VBoxVrTerm();
}
static void crServerClose( unsigned int id )
@@ -226,8 +278,15 @@ void
crServerInit(int argc, char *argv[])
{
int i;
+ const char*env;
char *mothership = NULL;
CRMuralInfo *defaultMural;
+ int rc = VBoxVrInit();
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("VBoxVrInit failed, rc %d", rc);
+ return;
+ }
for (i = 1 ; i < argc ; i++)
{
@@ -294,6 +353,7 @@ crServerInit(int argc, char *argv[])
*/
cr_server.muralTable = crAllocHashtable();
defaultMural = (CRMuralInfo *) crCalloc(sizeof(CRMuralInfo));
+ defaultMural->spuWindow = CR_RENDER_DEFAULT_WINDOW_ID;
crHashtableAdd(cr_server.muralTable, 0, defaultMural);
cr_server.programTable = crAllocHashtable();
@@ -311,9 +371,39 @@ crServerInit(int argc, char *argv[])
cr_server.contextTable = crAllocHashtable();
cr_server.curClient->currentCtxInfo = &cr_server.MainContextInfo;
+ cr_server.dummyMuralTable = crAllocHashtable();
+
+ CrPMgrInit();
+
+ cr_server.fRootVrOn = GL_FALSE;
+ VBoxVrListInit(&cr_server.RootVr);
+ crMemset(&cr_server.RootVrCurPoint, 0, sizeof (cr_server.RootVrCurPoint));
+
+ crMemset(&cr_server.RpwWorker, 0, sizeof (cr_server.RpwWorker));
+
+ env = crGetenv("CR_SERVER_BFB");
+ if (env)
+ {
+ cr_server.fBlitterMode = env[0] - '0';
+ }
+ else
+ {
+ cr_server.fBlitterMode = CR_SERVER_BFB_DISABLED;
+ }
+ crMemset(&cr_server.Blitter, 0, sizeof (cr_server.Blitter));
+
crServerInitDispatch();
+ crServerInitTmpCtxDispatch();
crStateDiffAPI( &(cr_server.head_spu->dispatch_table) );
+#ifdef VBOX_WITH_CRSERVER_DUMPER
+ crMemset(&cr_server.Recorder, 0, sizeof (cr_server.Recorder));
+ crMemset(&cr_server.RecorderBlitter, 0, sizeof (cr_server.RecorderBlitter));
+ crMemset(&cr_server.DbgPrintDumper, 0, sizeof (cr_server.DbgPrintDumper));
+ crMemset(&cr_server.HtmlDumper, 0, sizeof (cr_server.HtmlDumper));
+ cr_server.pDumper = NULL;
+#endif
+
crUnpackSetReturnPointer( &(cr_server.return_ptr) );
crUnpackSetWritebackPointer( &(cr_server.writeback_ptr) );
@@ -332,6 +422,13 @@ void crVBoxServerTearDown(void)
GLboolean crVBoxServerInit(void)
{
CRMuralInfo *defaultMural;
+ const char*env;
+ int rc = VBoxVrInit();
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("VBoxVrInit failed, rc %d", rc);
+ return GL_FALSE;
+ }
#if DEBUG_FP_EXCEPTIONS
{
@@ -367,6 +464,7 @@ GLboolean crVBoxServerInit(void)
*/
cr_server.muralTable = crAllocHashtable();
defaultMural = (CRMuralInfo *) crCalloc(sizeof(CRMuralInfo));
+ defaultMural->spuWindow = CR_RENDER_DEFAULT_WINDOW_ID;
crHashtableAdd(cr_server.muralTable, 0, defaultMural);
cr_server.programTable = crAllocHashtable();
@@ -385,8 +483,27 @@ GLboolean crVBoxServerInit(void)
* Default context
*/
cr_server.contextTable = crAllocHashtable();
-// cr_server.pContextCreateInfoTable = crAllocHashtable();
- cr_server.pWindowCreateInfoTable = crAllocHashtable();
+
+ cr_server.dummyMuralTable = crAllocHashtable();
+
+ CrPMgrInit();
+
+ cr_server.fRootVrOn = GL_FALSE;
+ VBoxVrListInit(&cr_server.RootVr);
+ crMemset(&cr_server.RootVrCurPoint, 0, sizeof (cr_server.RootVrCurPoint));
+
+ crMemset(&cr_server.RpwWorker, 0, sizeof (cr_server.RpwWorker));
+
+ env = crGetenv("CR_SERVER_BFB");
+ if (env)
+ {
+ cr_server.fBlitterMode = env[0] - '0';
+ }
+ else
+ {
+ cr_server.fBlitterMode = CR_SERVER_BFB_DISABLED;
+ }
+ crMemset(&cr_server.Blitter, 0, sizeof (cr_server.Blitter));
crServerSetVBoxConfigurationHGCM();
@@ -394,8 +511,17 @@ GLboolean crVBoxServerInit(void)
return GL_FALSE;
crServerInitDispatch();
+ crServerInitTmpCtxDispatch();
crStateDiffAPI( &(cr_server.head_spu->dispatch_table) );
+#ifdef VBOX_WITH_CRSERVER_DUMPER
+ crMemset(&cr_server.Recorder, 0, sizeof (cr_server.Recorder));
+ crMemset(&cr_server.RecorderBlitter, 0, sizeof (cr_server.RecorderBlitter));
+ crMemset(&cr_server.DbgPrintDumper, 0, sizeof (cr_server.DbgPrintDumper));
+ crMemset(&cr_server.HtmlDumper, 0, sizeof (cr_server.HtmlDumper));
+ cr_server.pDumper = NULL;
+#endif
+
/*Check for PBO support*/
if (crStateGetCurrent()->extensions.ARB_pixel_buffer_object)
{
@@ -405,6 +531,38 @@ GLboolean crVBoxServerInit(void)
return GL_TRUE;
}
+static int32_t crVBoxServerAddClientObj(uint32_t u32ClientID, CRClient **ppNewClient)
+{
+ CRClient *newClient;
+
+ if (cr_server.numClients>=CR_MAX_CLIENTS)
+ {
+ if (ppNewClient)
+ *ppNewClient = NULL;
+ return VERR_MAX_THRDS_REACHED;
+ }
+
+ newClient = (CRClient *) crCalloc(sizeof(CRClient));
+ crDebug("crServer: AddClient u32ClientID=%d", u32ClientID);
+
+ newClient->spu_id = 0;
+ newClient->currentCtxInfo = &cr_server.MainContextInfo;
+ newClient->currentContextNumber = -1;
+ newClient->conn = crNetAcceptClient(cr_server.protocol, NULL,
+ cr_server.tcpip_port,
+ cr_server.mtu, 0);
+ newClient->conn->u32ClientID = u32ClientID;
+
+ cr_server.clients[cr_server.numClients++] = newClient;
+
+ crServerAddToRunQueue(newClient);
+
+ if (ppNewClient)
+ *ppNewClient = newClient;
+
+ return VINF_SUCCESS;
+}
+
int32_t crVBoxServerAddClient(uint32_t u32ClientID)
{
CRClient *newClient;
@@ -614,6 +772,23 @@ int32_t crVBoxServerClientRead(uint32_t u32ClientID, uint8_t *pBuffer, uint32_t
return crVBoxServerInternalClientRead(pClient, pBuffer, pcbBuffer);
}
+extern DECLEXPORT(int32_t) crVBoxServerClientGetCaps(uint32_t u32ClientID, uint32_t *pu32Caps)
+{
+ *pu32Caps = cr_server.u32Caps;
+ return VINF_SUCCESS;
+}
+
+static int32_t crVBoxServerClientObjSetVersion(CRClient *pClient, uint32_t vMajor, uint32_t vMinor)
+{
+ pClient->conn->vMajor = vMajor;
+ pClient->conn->vMinor = vMinor;
+
+ if (vMajor != CR_PROTOCOL_VERSION_MAJOR
+ || vMinor != CR_PROTOCOL_VERSION_MINOR)
+ return VERR_NOT_SUPPORTED;
+ return VINF_SUCCESS;
+}
+
int32_t crVBoxServerClientSetVersion(uint32_t u32ClientID, uint32_t vMajor, uint32_t vMinor)
{
CRClient *pClient=NULL;
@@ -630,15 +805,14 @@ int32_t crVBoxServerClientSetVersion(uint32_t u32ClientID, uint32_t vMajor, uint
}
if (!pClient) return VERR_INVALID_PARAMETER;
- pClient->conn->vMajor = vMajor;
- pClient->conn->vMinor = vMinor;
+ return crVBoxServerClientObjSetVersion(pClient, vMajor, vMinor);
+}
- if (vMajor != CR_PROTOCOL_VERSION_MAJOR
- || vMinor != CR_PROTOCOL_VERSION_MINOR)
- {
- return VERR_NOT_SUPPORTED;
- }
- else return VINF_SUCCESS;
+static int32_t crVBoxServerClientObjSetPID(CRClient *pClient, uint64_t pid)
+{
+ pClient->pid = pid;
+
+ return VINF_SUCCESS;
}
int32_t crVBoxServerClientSetPID(uint32_t u32ClientID, uint64_t pid)
@@ -657,9 +831,7 @@ int32_t crVBoxServerClientSetPID(uint32_t u32ClientID, uint64_t pid)
}
if (!pClient) return VERR_INVALID_PARAMETER;
- pClient->pid = pid;
-
- return VINF_SUCCESS;
+ return crVBoxServerClientObjSetPID(pClient, pid);
}
int
@@ -690,13 +862,16 @@ static void crVBoxServerSaveMuralCB(unsigned long key, void *data1, void *data2)
rc = SSMR3PutMem(pSSM, &key, sizeof(key));
CRASSERT(rc == VINF_SUCCESS);
- rc = SSMR3PutMem(pSSM, pMI, sizeof(*pMI));
+ rc = SSMR3PutMem(pSSM, pMI, RT_OFFSETOF(CRMuralInfo, CreateInfo));
CRASSERT(rc == VINF_SUCCESS);
if (pMI->pVisibleRects)
{
rc = SSMR3PutMem(pSSM, pMI->pVisibleRects, 4*sizeof(GLint)*pMI->cVisibleRects);
}
+
+ rc = SSMR3PutMem(pSSM, pMI->ctxUsage, sizeof (pMI->ctxUsage));
+ CRASSERT(rc == VINF_SUCCESS);
}
/* @todo add hashtable walker with result info and intermediate abort */
@@ -708,6 +883,9 @@ static void crVBoxServerSaveCreateInfoCB(unsigned long key, void *data1, void *d
CRASSERT(pCreateInfo && pSSM);
+ /* Don't store default mural create info */
+ if (!key) return;
+
rc = SSMR3PutMem(pSSM, &key, sizeof(key));
CRASSERT(rc == VINF_SUCCESS);
@@ -721,10 +899,22 @@ static void crVBoxServerSaveCreateInfoCB(unsigned long key, void *data1, void *d
}
}
+static void crVBoxServerSaveCreateInfoFromMuralInfoCB(unsigned long key, void *data1, void *data2)
+{
+ CRMuralInfo *pMural = (CRMuralInfo *)data1;
+ CRCreateInfo_t CreateInfo;
+ CreateInfo.pszDpyName = pMural->CreateInfo.pszDpyName;
+ CreateInfo.visualBits = pMural->CreateInfo.requestedVisualBits;
+ CreateInfo.externalID = pMural->CreateInfo.externalID;
+ crVBoxServerSaveCreateInfoCB(key, &CreateInfo, data2);
+}
+
static void crVBoxServerSaveCreateInfoFromCtxInfoCB(unsigned long key, void *data1, void *data2)
{
CRContextInfo *pContextInfo = (CRContextInfo *)data1;
- CRCreateInfo_t CreateInfo = pContextInfo->CreateInfo;
+ CRCreateInfo_t CreateInfo;
+ CreateInfo.pszDpyName = pContextInfo->CreateInfo.pszDpyName;
+ CreateInfo.visualBits = pContextInfo->CreateInfo.requestedVisualBits;
/* saved state contains internal id */
CreateInfo.externalID = pContextInfo->pContext->id;
crVBoxServerSaveCreateInfoCB(key, &CreateInfo, data2);
@@ -739,40 +929,672 @@ static void crVBoxServerSyncTextureCB(unsigned long key, void *data1, void *data
crStateTextureObjectDiff(pContext, NULL, NULL, pTexture, GL_TRUE);
}
+typedef struct CRVBOX_SAVE_STATE_GLOBAL
+{
+ /* context id -> mural association
+ * on context data save, each context will be made current with the corresponding mural from this table
+ * thus saving the mural front & back buffer data */
+ CRHashTable *contextMuralTable;
+ /* mural id -> context info
+ * for murals that do not have associated context in contextMuralTable
+ * we still need to save*/
+ CRHashTable *additionalMuralContextTable;
+
+ PSSMHANDLE pSSM;
+
+ int rc;
+} CRVBOX_SAVE_STATE_GLOBAL, *PCRVBOX_SAVE_STATE_GLOBAL;
+
+
+typedef struct CRVBOX_CTXWND_CTXWALKER_CB
+{
+ PCRVBOX_SAVE_STATE_GLOBAL pGlobal;
+ CRHashTable *usedMuralTable;
+ GLuint cAdditionalMurals;
+} CRVBOX_CTXWND_CTXWALKER_CB, *PCRVBOX_CTXWND_CTXWALKER_CB;
+
+static void crVBoxServerBuildAdditionalWindowContextMapCB(unsigned long key, void *data1, void *data2)
+{
+ CRMuralInfo * pMural = (CRMuralInfo *) data1;
+ PCRVBOX_CTXWND_CTXWALKER_CB pData = (PCRVBOX_CTXWND_CTXWALKER_CB)data2;
+ CRContextInfo *pContextInfo = NULL;
+
+ if (!pMural->CreateInfo.externalID)
+ {
+ CRASSERT(!key);
+ return;
+ }
+
+ if (crHashtableSearch(pData->usedMuralTable, pMural->CreateInfo.externalID))
+ {
+ Assert(crHashtableGetDataKey(pData->pGlobal->contextMuralTable, pMural, NULL));
+ return;
+ }
+
+ Assert(!crHashtableGetDataKey(pData->pGlobal->contextMuralTable, pMural, NULL));
+
+ if (cr_server.MainContextInfo.CreateInfo.realVisualBits == pMural->CreateInfo.realVisualBits)
+ {
+ pContextInfo = &cr_server.MainContextInfo;
+ }
+ else
+ {
+ crWarning("different visual bits not implemented!");
+ pContextInfo = &cr_server.MainContextInfo;
+ }
+
+ crHashtableAdd(pData->pGlobal->additionalMuralContextTable, pMural->CreateInfo.externalID, pContextInfo);
+}
+
+
+typedef struct CRVBOX_CTXWND_WNDWALKER_CB
+{
+ PCRVBOX_SAVE_STATE_GLOBAL pGlobal;
+ CRHashTable *usedMuralTable;
+ CRContextInfo *pContextInfo;
+ CRMuralInfo * pMural;
+} CRVBOX_CTXWND_WNDWALKER_CB, *PCRVBOX_CTXWND_WNDWALKER_CB;
+
+static void crVBoxServerBuildContextWindowMapWindowWalkerCB(unsigned long key, void *data1, void *data2)
+{
+ CRMuralInfo * pMural = (CRMuralInfo *) data1;
+ PCRVBOX_CTXWND_WNDWALKER_CB pData = (PCRVBOX_CTXWND_WNDWALKER_CB)data2;
+
+ Assert(pData->pMural != pMural);
+ Assert(pData->pContextInfo);
+
+ if (pData->pMural)
+ return;
+
+ if (!pMural->CreateInfo.externalID)
+ {
+ CRASSERT(!key);
+ return;
+ }
+
+ if (!CR_STATE_SHAREDOBJ_USAGE_IS_SET(pMural, pData->pContextInfo->pContext))
+ return;
+
+ if (crHashtableSearch(pData->usedMuralTable, pMural->CreateInfo.externalID))
+ return;
+
+ CRASSERT(pMural->CreateInfo.realVisualBits == pData->pContextInfo->CreateInfo.realVisualBits);
+ pData->pMural = pMural;
+}
+
+static void crVBoxServerBuildContextUsedWindowMapCB(unsigned long key, void *data1, void *data2)
+{
+ CRContextInfo *pContextInfo = (CRContextInfo *)data1;
+ PCRVBOX_CTXWND_CTXWALKER_CB pData = (PCRVBOX_CTXWND_CTXWALKER_CB)data2;
+
+ if (!pContextInfo->currentMural)
+ return;
+
+ crHashtableAdd(pData->pGlobal->contextMuralTable, pContextInfo->CreateInfo.externalID, pContextInfo->currentMural);
+ crHashtableAdd(pData->usedMuralTable, pContextInfo->currentMural->CreateInfo.externalID, pContextInfo->currentMural);
+}
+
+CRMuralInfo * crServerGetDummyMural(GLint visualBits)
+{
+ CRMuralInfo * pMural = (CRMuralInfo *)crHashtableSearch(cr_server.dummyMuralTable, visualBits);
+ if (!pMural)
+ {
+ GLint id;
+ pMural = (CRMuralInfo *) crCalloc(sizeof(CRMuralInfo));
+ if (!pMural)
+ {
+ crWarning("crCalloc failed!");
+ return NULL;
+ }
+ id = crServerMuralInit(pMural, GL_FALSE, visualBits, 0);
+ if (id < 0)
+ {
+ crWarning("crServerMuralInit failed!");
+ crFree(pMural);
+ return NULL;
+ }
+
+ crHashtableAdd(cr_server.dummyMuralTable, visualBits, pMural);
+ }
+
+ return pMural;
+}
+
+static void crVBoxServerBuildContextUnusedWindowMapCB(unsigned long key, void *data1, void *data2)
+{
+ CRContextInfo *pContextInfo = (CRContextInfo *)data1;
+ PCRVBOX_CTXWND_CTXWALKER_CB pData = (PCRVBOX_CTXWND_CTXWALKER_CB)data2;
+ CRMuralInfo * pMural = NULL;
+
+ if (pContextInfo->currentMural)
+ return;
+
+ Assert(crHashtableNumElements(pData->pGlobal->contextMuralTable) <= crHashtableNumElements(cr_server.muralTable) - 1);
+ if (crHashtableNumElements(pData->pGlobal->contextMuralTable) < crHashtableNumElements(cr_server.muralTable) - 1)
+ {
+ CRVBOX_CTXWND_WNDWALKER_CB MuralData;
+ MuralData.pGlobal = pData->pGlobal;
+ MuralData.usedMuralTable = pData->usedMuralTable;
+ MuralData.pContextInfo = pContextInfo;
+ MuralData.pMural = NULL;
+
+ crHashtableWalk(cr_server.muralTable, crVBoxServerBuildContextWindowMapWindowWalkerCB, &MuralData);
+
+ pMural = MuralData.pMural;
+
+ }
+
+ if (!pMural)
+ {
+ pMural = crServerGetDummyMural(pContextInfo->CreateInfo.realVisualBits);
+ if (!pMural)
+ {
+ crWarning("crServerGetDummyMural failed");
+ return;
+ }
+ }
+ else
+ {
+ crHashtableAdd(pData->usedMuralTable, pMural->CreateInfo.externalID, pMural);
+ ++pData->cAdditionalMurals;
+ }
+
+ crHashtableAdd(pData->pGlobal->contextMuralTable, pContextInfo->CreateInfo.externalID, pMural);
+}
+
+static void crVBoxServerBuildSaveStateGlobal(PCRVBOX_SAVE_STATE_GLOBAL pGlobal)
+{
+ CRVBOX_CTXWND_CTXWALKER_CB Data;
+ GLuint cMurals;
+ pGlobal->contextMuralTable = crAllocHashtable();
+ pGlobal->additionalMuralContextTable = crAllocHashtable();
+ /* 1. go through all contexts and match all having currentMural set */
+ Data.pGlobal = pGlobal;
+ Data.usedMuralTable = crAllocHashtable();
+ Data.cAdditionalMurals = 0;
+ crHashtableWalk(cr_server.contextTable, crVBoxServerBuildContextUsedWindowMapCB, &Data);
+
+ cMurals = crHashtableNumElements(pGlobal->contextMuralTable);
+ CRASSERT(cMurals <= crHashtableNumElements(cr_server.contextTable));
+ CRASSERT(cMurals <= crHashtableNumElements(cr_server.muralTable) - 1);
+ CRASSERT(cMurals == crHashtableNumElements(Data.usedMuralTable));
+ if (cMurals < crHashtableNumElements(cr_server.contextTable))
+ {
+ Data.cAdditionalMurals = 0;
+ crHashtableWalk(cr_server.contextTable, crVBoxServerBuildContextUnusedWindowMapCB, &Data);
+ }
+
+ CRASSERT(crHashtableNumElements(pGlobal->contextMuralTable) == crHashtableNumElements(cr_server.contextTable));
+ CRASSERT(cMurals + Data.cAdditionalMurals <= crHashtableNumElements(cr_server.muralTable) - 1);
+ if (cMurals + Data.cAdditionalMurals < crHashtableNumElements(cr_server.muralTable) - 1)
+ {
+ crHashtableWalk(cr_server.muralTable, crVBoxServerBuildAdditionalWindowContextMapCB, &Data);
+ CRASSERT(cMurals + Data.cAdditionalMurals + crHashtableNumElements(pGlobal->additionalMuralContextTable) == crHashtableNumElements(cr_server.muralTable) - 1);
+ }
+
+ crFreeHashtable(Data.usedMuralTable, NULL);
+}
+
+static void crVBoxServerFBImageDataTerm(CRFBData *pData)
+{
+ GLuint i;
+ for (i = 0; i < pData->cElements; ++i)
+ {
+ CRFBDataElement * pEl = &pData->aElements[i];
+ if (pEl->pvData)
+ {
+ crFree(pEl->pvData);
+ /* sanity */
+ pEl->pvData = NULL;
+ }
+ }
+ pData->cElements = 0;
+}
+
+static int crVBoxServerFBImageDataInitEx(CRFBData *pData, CRContextInfo *pCtxInfo, CRMuralInfo *pMural, GLboolean fWrite, uint32_t version, GLuint overrideWidth, GLuint overrideHeight)
+{
+ CRContext *pContext;
+ GLuint i;
+ GLfloat *pF;
+ CRFBDataElement *pEl;
+ GLuint width;
+ GLuint height;
+
+ crMemset(pData, 0, sizeof (*pData));
+
+ pContext = pCtxInfo->pContext;
+
+ /* the version should be always actual when we do reads,
+ * i.e. it could differ on writes when snapshot is getting loaded */
+ CRASSERT(fWrite || version == SHCROGL_SSM_VERSION);
+
+ width = overrideWidth ? overrideWidth : pMural->width;
+ height = overrideHeight ? overrideHeight : pMural->height;
+
+ if (!width || !height)
+ return VINF_SUCCESS;
+
+ if (pMural)
+ {
+ if (fWrite)
+ {
+ if (!pContext->framebufferobject.drawFB)
+ pData->idOverrrideFBO = CR_SERVER_FBO_FOR_IDX(pMural, pMural->iCurDrawBuffer);
+ }
+ else
+ {
+ if (!pContext->framebufferobject.readFB)
+ pData->idOverrrideFBO = CR_SERVER_FBO_FOR_IDX(pMural, pMural->iCurReadBuffer);
+ }
+ }
+ pData->cElements = 0;
+
+ pEl = &pData->aElements[pData->cElements];
+ pEl->idFBO = pMural && pMural->fRedirected ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0;
+ pEl->enmBuffer = pData->aElements[1].idFBO ? GL_COLOR_ATTACHMENT0 : GL_FRONT;
+ pEl->posX = 0;
+ pEl->posY = 0;
+ pEl->width = width;
+ pEl->height = height;
+ pEl->enmFormat = GL_RGBA;
+ pEl->enmType = GL_UNSIGNED_BYTE;
+ pEl->cbData = width * height * 4;
+ pEl->pvData = crCalloc(pEl->cbData);
+ if (!pEl->pvData)
+ {
+ crVBoxServerFBImageDataTerm(pData);
+ crWarning("crVBoxServerFBImageDataInit: crCalloc failed");
+ return VERR_NO_MEMORY;
+ }
+ ++pData->cElements;
+
+ /* there is a lot of code that assumes we have double buffering, just assert here to print a warning in the log
+ * so that we know that something irregular is going on */
+ CRASSERT(pCtxInfo->CreateInfo.requestedVisualBits & CR_DOUBLE_BIT);
+ if ((pCtxInfo->CreateInfo.requestedVisualBits & CR_DOUBLE_BIT)
+ || version < SHCROGL_SSM_VERSION_WITH_SINGLE_DEPTH_STENCIL /* <- older version had a typo which lead to back always being used,
+ * no matter what the visual bits are */
+ )
+ {
+ pEl = &pData->aElements[pData->cElements];
+ pEl->idFBO = pMural && pMural->fRedirected ? pMural->aidFBOs[CR_SERVER_FBO_BB_IDX(pMural)] : 0;
+ pEl->enmBuffer = pData->aElements[1].idFBO ? GL_COLOR_ATTACHMENT0 : GL_BACK;
+ pEl->posX = 0;
+ pEl->posY = 0;
+ pEl->width = width;
+ pEl->height = height;
+ pEl->enmFormat = GL_RGBA;
+ pEl->enmType = GL_UNSIGNED_BYTE;
+ pEl->cbData = width * height * 4;
+ pEl->pvData = crCalloc(pEl->cbData);
+ if (!pEl->pvData)
+ {
+ crVBoxServerFBImageDataTerm(pData);
+ crWarning("crVBoxServerFBImageDataInit: crCalloc failed");
+ return VERR_NO_MEMORY;
+ }
+ ++pData->cElements;
+ }
+
+ if (version < SHCROGL_SSM_VERSION_WITH_SAVED_DEPTH_STENCIL_BUFFER)
+ return VINF_SUCCESS;
+
+
+ if (version < SHCROGL_SSM_VERSION_WITH_SINGLE_DEPTH_STENCIL)
+ {
+/* if (pCtxInfo->CreateInfo.requestedVisualBits & CR_DEPTH_BIT) */ /* <- older version had a typo which lead to back always being used,
+ * no matter what the visual bits are */
+ {
+ AssertCompile(sizeof (GLfloat) == 4);
+ pEl = &pData->aElements[pData->cElements];
+ pEl->idFBO = pMural && pMural->fRedirected ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0;
+ pEl->enmBuffer = 0; /* we do not care */
+ pEl->posX = 0;
+ pEl->posY = 0;
+ pEl->width = width;
+ pEl->height = height;
+ pEl->enmFormat = GL_DEPTH_COMPONENT;
+ pEl->enmType = GL_FLOAT;
+ pEl->cbData = width * height * 4;
+ pEl->pvData = crCalloc(pEl->cbData);
+ if (!pEl->pvData)
+ {
+ crVBoxServerFBImageDataTerm(pData);
+ crWarning("crVBoxServerFBImageDataInit: crCalloc failed");
+ return VERR_NO_MEMORY;
+ }
+
+ /* init to default depth value, just in case */
+ pF = (GLfloat*)pEl->pvData;
+ for (i = 0; i < width * height; ++i)
+ {
+ pF[i] = 1.;
+ }
+ ++pData->cElements;
+ }
+
+ /* if (pCtxInfo->CreateInfo.requestedVisualBits & CR_STENCIL_BIT) */ /* <- older version had a typo which lead to back always being used,
+ * no matter what the visual bits are */
+ {
+ AssertCompile(sizeof (GLuint) == 4);
+ pEl = &pData->aElements[pData->cElements];
+ pEl->idFBO = pMural && pMural->fRedirected ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0;
+ pEl->enmBuffer = 0; /* we do not care */
+ pEl->posX = 0;
+ pEl->posY = 0;
+ pEl->width = width;
+ pEl->height = height;
+ pEl->enmFormat = GL_STENCIL_INDEX;
+ pEl->enmType = GL_UNSIGNED_INT;
+ pEl->cbData = width * height * 4;
+ pEl->pvData = crCalloc(pEl->cbData);
+ if (!pEl->pvData)
+ {
+ crVBoxServerFBImageDataTerm(pData);
+ crWarning("crVBoxServerFBImageDataInit: crCalloc failed");
+ return VERR_NO_MEMORY;
+ }
+ ++pData->cElements;
+ }
+ return VINF_SUCCESS;
+ }
+
+ if ((pCtxInfo->CreateInfo.requestedVisualBits & CR_STENCIL_BIT)
+ || (pCtxInfo->CreateInfo.requestedVisualBits & CR_DEPTH_BIT))
+ {
+ pEl = &pData->aElements[pData->cElements];
+ pEl->idFBO = pMural && pMural->fRedirected ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0;
+ pEl->enmBuffer = 0; /* we do not care */
+ pEl->posX = 0;
+ pEl->posY = 0;
+ pEl->width = width;
+ pEl->height = height;
+ pEl->enmFormat = GL_DEPTH_STENCIL;
+ pEl->enmType = GL_UNSIGNED_INT_24_8;
+ pEl->cbData = width * height * 4;
+ pEl->pvData = crCalloc(pEl->cbData);
+ if (!pEl->pvData)
+ {
+ crVBoxServerFBImageDataTerm(pData);
+ crWarning("crVBoxServerFBImageDataInit: crCalloc failed");
+ return VERR_NO_MEMORY;
+ }
+ ++pData->cElements;
+ }
+ return VINF_SUCCESS;
+}
+
+static int crVBoxServerFBImageDataInit(CRFBData *pData, CRContextInfo *pCtxInfo, CRMuralInfo *pMural, GLboolean fWrite)
+{
+ return crVBoxServerFBImageDataInitEx(pData, pCtxInfo, pMural, fWrite, SHCROGL_SSM_VERSION, 0, 0);
+}
+
+static int crVBoxServerSaveFBImage(PSSMHANDLE pSSM)
+{
+ CRContextInfo *pCtxInfo;
+ CRContext *pContext;
+ CRMuralInfo *pMural;
+ int32_t rc;
+ GLuint i;
+ struct
+ {
+ CRFBData data;
+ CRFBDataElement buffer[3]; /* CRFBData::aElements[1] + buffer[3] gives 4: back, front, depth and stencil */
+ } Data;
+
+ Assert(sizeof (Data) >= RT_OFFSETOF(CRFBData, aElements[4]));
+
+ pCtxInfo = cr_server.currentCtxInfo;
+ pContext = pCtxInfo->pContext;
+ pMural = pCtxInfo->currentMural;
+
+ rc = crVBoxServerFBImageDataInit(&Data.data, pCtxInfo, pMural, GL_FALSE);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("crVBoxServerFBImageDataInit failed rc %d", rc);
+ return rc;
+ }
+
+ rc = crStateAcquireFBImage(pContext, &Data.data);
+ AssertRCReturn(rc, rc);
+
+ for (i = 0; i < Data.data.cElements; ++i)
+ {
+ CRFBDataElement * pEl = &Data.data.aElements[i];
+ rc = SSMR3PutMem(pSSM, pEl->pvData, pEl->cbData);
+ AssertRCReturn(rc, rc);
+ }
+
+ crVBoxServerFBImageDataTerm(&Data.data);
+
+ return VINF_SUCCESS;
+}
+
+#define CRSERVER_ASSERTRC_RETURN_VOID(_rc) do { \
+ if(!RT_SUCCESS((_rc))) { \
+ AssertFailed(); \
+ return; \
+ } \
+ } while (0)
+
+static void crVBoxServerSaveAdditionalMuralsCB(unsigned long key, void *data1, void *data2)
+{
+ CRContextInfo *pContextInfo = (CRContextInfo *) data1;
+ PCRVBOX_SAVE_STATE_GLOBAL pData = (PCRVBOX_SAVE_STATE_GLOBAL)data2;
+ CRMuralInfo *pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, key);
+ PSSMHANDLE pSSM = pData->pSSM;
+ CRbitvalue initialCtxUsage[CR_MAX_BITARRAY];
+ CRMuralInfo *pInitialCurMural = pContextInfo->currentMural;
+
+ crMemcpy(initialCtxUsage, pMural->ctxUsage, sizeof (initialCtxUsage));
+
+ CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
+
+ pData->rc = SSMR3PutMem(pSSM, &key, sizeof(key));
+ CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
+
+ pData->rc = SSMR3PutMem(pSSM, &pContextInfo->CreateInfo.externalID, sizeof(pContextInfo->CreateInfo.externalID));
+ CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
+
+ crServerPerformMakeCurrent(pMural, pContextInfo);
+
+ pData->rc = crVBoxServerSaveFBImage(pSSM);
+
+ /* restore the reference data, we synchronize it with the HW state in a later crServerPerformMakeCurrent call */
+ crMemcpy(pMural->ctxUsage, initialCtxUsage, sizeof (initialCtxUsage));
+ pContextInfo->currentMural = pInitialCurMural;
+
+ CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
+}
+
static void crVBoxServerSaveContextStateCB(unsigned long key, void *data1, void *data2)
{
CRContextInfo *pContextInfo = (CRContextInfo *) data1;
CRContext *pContext = pContextInfo->pContext;
- PSSMHANDLE pSSM = (PSSMHANDLE) data2;
- int32_t rc;
+ PCRVBOX_SAVE_STATE_GLOBAL pData = (PCRVBOX_SAVE_STATE_GLOBAL)data2;
+ PSSMHANDLE pSSM = pData->pSSM;
+ CRMuralInfo *pMural = (CRMuralInfo*)crHashtableSearch(pData->contextMuralTable, key);
+ CRMuralInfo *pContextCurrentMural = pContextInfo->currentMural;
+ const int32_t i32Dummy = 0;
+
+ AssertCompile(sizeof (i32Dummy) == sizeof (pMural->CreateInfo.externalID));
+ CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
CRASSERT(pContext && pSSM);
+ CRASSERT(pMural);
+ CRASSERT(pMural->CreateInfo.externalID);
/* We could have skipped saving the key and use similar callback to load context states back,
* but there's no guarantee we'd traverse hashtable in same order after loading.
*/
- rc = SSMR3PutMem(pSSM, &key, sizeof(key));
- CRASSERT(rc == VINF_SUCCESS);
+ pData->rc = SSMR3PutMem(pSSM, &key, sizeof(key));
+ CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
+
+#ifdef DEBUG_misha
+ {
+ unsigned long id;
+ if (!crHashtableGetDataKey(cr_server.contextTable, pContextInfo, &id))
+ crWarning("No client id for server ctx %d", pContextInfo->CreateInfo.externalID);
+ else
+ CRASSERT(id == key);
+ }
+#endif
#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
- if (cr_server.curClient)
+ if (pContextInfo->currentMural
+ || crHashtableSearch(cr_server.muralTable, pMural->CreateInfo.externalID) /* <- this is not a dummy mural */
+ )
+ {
+ CRASSERT(pMural->CreateInfo.externalID);
+ CRASSERT(!crHashtableSearch(cr_server.dummyMuralTable, pMural->CreateInfo.externalID));
+ pData->rc = SSMR3PutMem(pSSM, &pMural->CreateInfo.externalID, sizeof(pMural->CreateInfo.externalID));
+ }
+ else
+ {
+ /* this is a dummy mural */
+ CRASSERT(!pMural->width);
+ CRASSERT(!pMural->height);
+ CRASSERT(crHashtableSearch(cr_server.dummyMuralTable, pMural->CreateInfo.externalID));
+ pData->rc = SSMR3PutMem(pSSM, &i32Dummy, sizeof(pMural->CreateInfo.externalID));
+ }
+ CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
+
+ CRASSERT(CR_STATE_SHAREDOBJ_USAGE_IS_SET(pMural, pContext));
+ CRASSERT(pContextInfo->currentMural == pMural || !pContextInfo->currentMural);
+ CRASSERT(cr_server.curClient);
+
+ crServerPerformMakeCurrent(pMural, pContextInfo);
+#endif
+
+ pData->rc = crStateSaveContext(pContext, pSSM);
+ CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
+
+ pData->rc = crVBoxServerSaveFBImage(pSSM);
+ CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
+
+ /* restore the initial current mural */
+ pContextInfo->currentMural = pContextCurrentMural;
+}
+
+#if 0
+typedef struct CR_SERVER_CHECK_BUFFERS
+{
+ CRBufferObject *obj;
+ CRContext *ctx;
+}CR_SERVER_CHECK_BUFFERS, *PCR_SERVER_CHECK_BUFFERS;
+
+static void crVBoxServerCheckConsistencyContextBuffersCB(unsigned long key, void *data1, void *data2)
+{
+ CRContextInfo* pContextInfo = (CRContextInfo*)data1;
+ CRContext *ctx = pContextInfo->pContext;
+ PCR_SERVER_CHECK_BUFFERS pBuffers = (PCR_SERVER_CHECK_BUFFERS)data2;
+ CRBufferObject *obj = pBuffers->obj;
+ CRBufferObjectState *b = &(ctx->bufferobject);
+ int j, k;
+
+ if (obj == b->arrayBuffer)
+ {
+ Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
+ pBuffers->ctx = ctx;
+ }
+ if (obj == b->elementsBuffer)
+ {
+ Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
+ pBuffers->ctx = ctx;
+ }
+#ifdef CR_ARB_pixel_buffer_object
+ if (obj == b->packBuffer)
+ {
+ Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
+ pBuffers->ctx = ctx;
+ }
+ if (obj == b->unpackBuffer)
+ {
+ Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
+ pBuffers->ctx = ctx;
+ }
+#endif
+
+#ifdef CR_ARB_vertex_buffer_object
+ for (j=0; j<CRSTATECLIENT_MAX_VERTEXARRAYS; ++j)
{
- unsigned long id;
- if (!crHashtableGetDataKey(cr_server.contextTable, pContextInfo, &id))
+ CRClientPointer *cp = crStateGetClientPointerByIndex(j, &ctx->client.array);
+ if (obj == cp->buffer)
{
- crWarning("No client id for server ctx %d", pContext->id);
+ Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
+ pBuffers->ctx = ctx;
}
- else
+ }
+
+ for (k=0; k<ctx->client.vertexArrayStackDepth; ++k)
+ {
+ CRVertexArrays *pArray = &ctx->client.vertexArrayStack[k];
+ for (j=0; j<CRSTATECLIENT_MAX_VERTEXARRAYS; ++j)
{
- crServerDispatchMakeCurrent(cr_server.curClient->currentWindow, 0, id);
+ CRClientPointer *cp = crStateGetClientPointerByIndex(j, pArray);
+ if (obj == cp->buffer)
+ {
+ Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
+ pBuffers->ctx = ctx;
+ }
}
}
#endif
+}
- rc = crStateSaveContext(pContext, pSSM);
- CRASSERT(rc == VINF_SUCCESS);
+static void crVBoxServerCheckConsistencyBuffersCB(unsigned long key, void *data1, void *data2)
+{
+ CRBufferObject *obj = (CRBufferObject *)data1;
+ CR_SERVER_CHECK_BUFFERS Buffers = {0};
+ Buffers.obj = obj;
+ crHashtableWalk(cr_server.contextTable, crVBoxServerCheckConsistencyContextBuffersCB, (void*)&Buffers);
}
+//static void crVBoxServerCheckConsistency2CB(unsigned long key, void *data1, void *data2)
+//{
+// CRContextInfo* pContextInfo1 = (CRContextInfo*)data1;
+// CRContextInfo* pContextInfo2 = (CRContextInfo*)data2;
+//
+// CRASSERT(pContextInfo1->pContext);
+// CRASSERT(pContextInfo2->pContext);
+//
+// if (pContextInfo1 == pContextInfo2)
+// {
+// CRASSERT(pContextInfo1->pContext == pContextInfo2->pContext);
+// return;
+// }
+//
+// CRASSERT(pContextInfo1->pContext != pContextInfo2->pContext);
+// CRASSERT(pContextInfo1->pContext->shared);
+// CRASSERT(pContextInfo2->pContext->shared);
+// CRASSERT(pContextInfo1->pContext->shared == pContextInfo2->pContext->shared);
+// if (pContextInfo1->pContext->shared != pContextInfo2->pContext->shared)
+// return;
+//
+// crHashtableWalk(pContextInfo1->pContext->shared->buffersTable, crVBoxServerCheckConsistencyBuffersCB, pContextInfo2);
+//}
+static void crVBoxServerCheckSharedCB(unsigned long key, void *data1, void *data2)
+{
+ CRContextInfo* pContextInfo = (CRContextInfo*)data1;
+ void **ppShared = (void**)data2;
+ if (!*ppShared)
+ *ppShared = pContextInfo->pContext->shared;
+ else
+ Assert(pContextInfo->pContext->shared == *ppShared);
+}
+
+static void crVBoxServerCheckConsistency()
+{
+ CRSharedState *pShared = NULL;
+ crHashtableWalk(cr_server.contextTable, crVBoxServerCheckSharedCB, (void*)&pShared);
+ Assert(pShared);
+ if (pShared)
+ {
+ crHashtableWalk(pShared->buffersTable, crVBoxServerCheckConsistencyBuffersCB, NULL);
+ }
+}
+#endif
+
static uint32_t g_hackVBoxServerSaveLoadCallsLeft = 0;
DECLEXPORT(int32_t) crVBoxServerSaveState(PSSMHANDLE pSSM)
@@ -781,8 +1603,18 @@ DECLEXPORT(int32_t) crVBoxServerSaveState(PSSMHANDLE pSSM)
uint32_t ui32;
GLboolean b;
unsigned long key;
+ GLenum err;
#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
- unsigned long ctxID=-1, winID=-1;
+ CRClient *curClient;
+ CRMuralInfo *curMural = NULL;
+ CRContextInfo *curCtxInfo = NULL;
+#endif
+ CRVBOX_SAVE_STATE_GLOBAL Data;
+
+ crMemset(&Data, 0, sizeof (Data));
+
+#if 0
+ crVBoxServerCheckConsistency();
#endif
/* We shouldn't be called if there's no clients at all*/
@@ -811,6 +1643,14 @@ DECLEXPORT(int32_t) crVBoxServerSaveState(PSSMHANDLE pSSM)
return VINF_SUCCESS;
}
+#ifdef DEBUG_misha
+#define CR_DBG_STR_STATE_SAVE_START "VBox.Cr.StateSaveStart"
+#define CR_DBG_STR_STATE_SAVE_STOP "VBox.Cr.StateSaveStop"
+
+ if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY)
+ cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_SAVE_START), CR_DBG_STR_STATE_SAVE_START);
+#endif
+
/* Save rendering contexts creation info */
ui32 = crHashtableNumElements(cr_server.contextTable);
rc = SSMR3PutU32(pSSM, (uint32_t) ui32);
@@ -818,50 +1658,71 @@ DECLEXPORT(int32_t) crVBoxServerSaveState(PSSMHANDLE pSSM)
crHashtableWalk(cr_server.contextTable, crVBoxServerSaveCreateInfoFromCtxInfoCB, pSSM);
#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
+ curClient = cr_server.curClient;
/* Save current win and ctx IDs, as we'd rebind contexts when saving textures */
- if (cr_server.curClient)
+ if (curClient)
{
- ctxID = cr_server.curClient->currentContextNumber;
- winID = cr_server.curClient->currentWindow;
+ curCtxInfo = cr_server.curClient->currentCtxInfo;
+ curMural = cr_server.curClient->currentMural;
}
-#endif
-
- /* Save contexts state tracker data */
- /* @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.
- * Should be tested more with multiply guest opengl apps working when saving VM snapshot.
- */
- crHashtableWalk(cr_server.contextTable, crVBoxServerSaveContextStateCB, pSSM);
-
-#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
- /* Restore original win and ctx IDs*/
- if (cr_server.curClient)
+ else if (cr_server.numClients)
{
- crServerDispatchMakeCurrent(winID, 0, ctxID);
+ cr_server.curClient = cr_server.clients[0];
}
#endif
+ /* first save windows info */
/* Save windows creation info */
- ui32 = crHashtableNumElements(cr_server.pWindowCreateInfoTable);
- rc = SSMR3PutU32(pSSM, (uint32_t) ui32);
+ ui32 = crHashtableNumElements(cr_server.muralTable);
+ /* There should be default mural always */
+ CRASSERT(ui32>=1);
+ rc = SSMR3PutU32(pSSM, (uint32_t) ui32-1);
AssertRCReturn(rc, rc);
- crHashtableWalk(cr_server.pWindowCreateInfoTable, crVBoxServerSaveCreateInfoCB, pSSM);
+ crHashtableWalk(cr_server.muralTable, crVBoxServerSaveCreateInfoFromMuralInfoCB, pSSM);
/* Save cr_server.muralTable
* @todo we don't need it all, just geometry info actually
*/
- ui32 = crHashtableNumElements(cr_server.muralTable);
- /* There should be default mural always */
- CRASSERT(ui32>=1);
rc = SSMR3PutU32(pSSM, (uint32_t) ui32-1);
AssertRCReturn(rc, rc);
crHashtableWalk(cr_server.muralTable, crVBoxServerSaveMuralCB, pSSM);
- /* Save starting free context and window IDs */
- rc = SSMR3PutMem(pSSM, &cr_server.idsPool, sizeof(cr_server.idsPool));
+ /* we need to save front & backbuffer data for each mural first create a context -> mural association */
+ crVBoxServerBuildSaveStateGlobal(&Data);
+
+ rc = crStateSaveGlobals(pSSM);
AssertRCReturn(rc, rc);
+ Data.pSSM = pSSM;
+ /* Save contexts state tracker data */
+ /* @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.
+ * Should be tested more with multiply guest opengl apps working when saving VM snapshot.
+ */
+ crHashtableWalk(cr_server.contextTable, crVBoxServerSaveContextStateCB, &Data);
+ AssertRCReturn(Data.rc, Data.rc);
+
+ ui32 = crHashtableNumElements(Data.additionalMuralContextTable);
+ rc = SSMR3PutU32(pSSM, (uint32_t) ui32);
+ AssertRCReturn(rc, rc);
+
+ crHashtableWalk(Data.additionalMuralContextTable, crVBoxServerSaveAdditionalMuralsCB, &Data);
+ AssertRCReturn(Data.rc, Data.rc);
+
+#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
+ cr_server.curClient = curClient;
+ /* Restore original win and ctx IDs*/
+ if (curClient && curMural && curCtxInfo)
+ {
+ crServerPerformMakeCurrent(curMural, curCtxInfo);
+ }
+ else
+ {
+ cr_server.bForceMakeCurrentOnClientSwitch = GL_TRUE;
+ }
+#endif
+
/* Save clients info */
for (i = 0; i < cr_server.numClients; i++)
{
@@ -881,7 +1742,7 @@ DECLEXPORT(int32_t) crVBoxServerSaveState(PSSMHANDLE pSSM)
rc = SSMR3PutMem(pSSM, pClient, sizeof(*pClient));
AssertRCReturn(rc, rc);
- if (pClient->currentCtxInfo && pClient->currentCtxInfo->pContext && pClient->currentContextNumber>=0)
+ if (pClient->currentCtxInfo && pClient->currentCtxInfo->pContext && pClient->currentContextNumber > 0)
{
b = crHashtableGetDataKey(cr_server.contextTable, pClient->currentCtxInfo, &key);
CRASSERT(b);
@@ -889,7 +1750,7 @@ DECLEXPORT(int32_t) crVBoxServerSaveState(PSSMHANDLE pSSM)
AssertRCReturn(rc, rc);
}
- if (pClient->currentMural && pClient->currentWindow>=0)
+ if (pClient->currentMural && pClient->currentWindow > 0)
{
b = crHashtableGetDataKey(cr_server.muralTable, pClient->currentMural, &key);
CRASSERT(b);
@@ -899,8 +1760,21 @@ DECLEXPORT(int32_t) crVBoxServerSaveState(PSSMHANDLE pSSM)
}
}
+ rc = CrPMgrSaveState(pSSM);
+ AssertRCReturn(rc, rc);
+
+ /* all context gl error states should have now be synced with chromium erro states,
+ * reset the error if any */
+ while ((err = cr_server.head_spu->dispatch_table.GetError()) != GL_NO_ERROR)
+ crWarning("crServer: glGetError %d after saving snapshot", err);
+
cr_server.bIsInSavingState = GL_FALSE;
+#ifdef DEBUG_misha
+ if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY)
+ cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_SAVE_STOP), CR_DBG_STR_STATE_SAVE_STOP);
+#endif
+
return VINF_SUCCESS;
}
@@ -912,11 +1786,527 @@ static DECLCALLBACK(CRContext*) crVBoxServerGetContextCB(void* pvData)
return pContextInfo->pContext;
}
+typedef struct CR_SERVER_LOADSTATE_READER
+{
+ PSSMHANDLE pSSM;
+ uint32_t cbBuffer;
+ uint32_t cbData;
+ uint32_t offData;
+ uint8_t *pu8Buffer;
+} CR_SERVER_LOADSTATE_READER;
+
+static void crServerLsrInit(CR_SERVER_LOADSTATE_READER *pReader, PSSMHANDLE pSSM)
+{
+ memset(pReader, 0, sizeof (*pReader));
+ pReader->pSSM = pSSM;
+}
+
+static void crServerLsrTerm(CR_SERVER_LOADSTATE_READER *pReader)
+{
+ if (pReader->pu8Buffer)
+ RTMemFree(pReader->pu8Buffer);
+
+ /* sanity */
+ memset(pReader, 0, sizeof (*pReader));
+}
+
+static int crServerLsrDataGetMem(CR_SERVER_LOADSTATE_READER *pReader, void *pvBuffer, uint32_t cbBuffer)
+{
+ int rc = VINF_SUCCESS;
+ uint32_t cbRemaining = cbBuffer;
+ if (pReader->cbData)
+ {
+ uint8_t cbData = RT_MIN(pReader->cbData, cbBuffer);
+ memcpy(pvBuffer, pReader->pu8Buffer + pReader->offData, cbData);
+ pReader->cbData -= cbData;
+ pReader->offData += cbData;
+
+ cbRemaining -= cbData;
+ pvBuffer = ((uint8_t*)pvBuffer) + cbData;
+ }
+
+ if (cbRemaining)
+ {
+ rc = SSMR3GetMem(pReader->pSSM, pvBuffer, cbRemaining);
+ AssertRC(rc);
+ }
+
+ return rc;
+}
+
+static int crServerLsrDataGetU32(CR_SERVER_LOADSTATE_READER *pReader, uint32_t *pu32)
+{
+ return crServerLsrDataGetMem(pReader, pu32, sizeof (*pu32));
+}
+
+static int crServerLsrDataPutMem(CR_SERVER_LOADSTATE_READER *pReader, void *pvBuffer, uint32_t cbBuffer)
+{
+ if (!pReader->cbData && pReader->cbBuffer >= cbBuffer)
+ {
+ pReader->offData = 0;
+ pReader->cbData = cbBuffer;
+ memcpy(pReader->pu8Buffer, pvBuffer, cbBuffer);
+ }
+ else if (pReader->offData >= cbBuffer)
+ {
+ pReader->offData -= cbBuffer;
+ pReader->cbData += cbBuffer;
+ memcpy(pReader->pu8Buffer + pReader->offData, pvBuffer, cbBuffer);
+ }
+ else
+ {
+ uint8_t *pu8Buffer = pReader->pu8Buffer;
+
+ pReader->pu8Buffer = (uint8_t*)RTMemAlloc(cbBuffer + pReader->cbData);
+ if (!pReader->pu8Buffer)
+ {
+ crWarning("failed to allocate mem %d", cbBuffer + pReader->cbData);
+ return VERR_NO_MEMORY;
+ }
+
+ memcpy(pReader->pu8Buffer, pvBuffer, cbBuffer);
+ if (pu8Buffer)
+ {
+ memcpy(pReader->pu8Buffer + cbBuffer, pu8Buffer + pReader->offData, pReader->cbData);
+ RTMemFree(pu8Buffer);
+ }
+ else
+ {
+ Assert(!pReader->cbData);
+ }
+ pReader->offData = 0;
+ pReader->cbData += cbBuffer;
+ }
+
+ return VINF_SUCCESS;
+}
+
+/* data to be skipped */
+
+typedef struct CR_SERVER_BUGGY_MURAL_DATA_2
+{
+ void*ListHead_pNext;
+ void*ListHead_pPrev;
+ uint32_t cEntries;
+} CR_SERVER_BUGGY_MURAL_DATA_2;
+typedef struct CR_SERVER_BUGGY_MURAL_DATA_1
+{
+ /* VBOXVR_COMPOSITOR_ENTRY Ce; */
+ void*Ce_Node_pNext;
+ void*Ce_Node_pPrev;
+ CR_SERVER_BUGGY_MURAL_DATA_2 Vr;
+ /* VBOXVR_TEXTURE Tex; */
+ uint32_t Tex_width;
+ uint32_t Tex_height;
+ uint32_t Tex_target;
+ uint32_t Tex_hwid;
+ /* RTPOINT Pos; */
+ uint32_t Pos_x;
+ uint32_t Pos_y;
+ uint32_t fChanged;
+ uint32_t cRects;
+ void* paSrcRects;
+ void* paDstRects;
+} CR_SERVER_BUGGY_MURAL_DATA_1;
+
+typedef struct CR_SERVER_BUGGY_MURAL_DATA_4
+{
+ uint32_t u32Magic;
+ int32_t cLockers;
+ RTNATIVETHREAD NativeThreadOwner;
+ int32_t cNestings;
+ uint32_t fFlags;
+ void* EventSem;
+ R3R0PTRTYPE(PRTLOCKVALRECEXCL) pValidatorRec;
+ RTHCPTR Alignment;
+} CR_SERVER_BUGGY_MURAL_DATA_4;
+
+typedef struct CR_SERVER_BUGGY_MURAL_DATA_3
+{
+ void*Compositor_List_pNext;
+ void*Compositor_List_pPrev;
+ void*Compositor_pfnEntryRemoved;
+ float StretchX;
+ float StretchY;
+ uint32_t cRects;
+ uint32_t cRectsBuffer;
+ void*paSrcRects;
+ void*paDstRects;
+ CR_SERVER_BUGGY_MURAL_DATA_4 CritSect;
+} CR_SERVER_BUGGY_MURAL_DATA_3;
+
+typedef struct CR_SERVER_BUGGY_MURAL_DATA
+{
+ uint8_t fRootVrOn;
+ CR_SERVER_BUGGY_MURAL_DATA_1 RootVrCEntry;
+ CR_SERVER_BUGGY_MURAL_DATA_3 RootVrCompositor;
+} CR_SERVER_BUGGY_MURAL_DATA;
+
+AssertCompile(sizeof (CR_SERVER_BUGGY_MURAL_DATA) < sizeof (CRClient));
+
+static int32_t crVBoxServerLoadMurals(CR_SERVER_LOADSTATE_READER *pReader, uint32_t version)
+{
+ unsigned long key;
+ uint32_t ui, uiNumElems;
+ bool fBuggyMuralData = false;
+ /* Load windows */
+ int32_t rc = crServerLsrDataGetU32(pReader, &uiNumElems);
+ AssertRCReturn(rc, rc);
+ for (ui=0; ui<uiNumElems; ++ui)
+ {
+ CRCreateInfo_t createInfo;
+ char psz[200];
+ GLint winID;
+ unsigned long key;
+
+ rc = crServerLsrDataGetMem(pReader, &key, sizeof(key));
+ AssertRCReturn(rc, rc);
+ rc = crServerLsrDataGetMem(pReader, &createInfo, sizeof(createInfo));
+ AssertRCReturn(rc, rc);
+
+ CRASSERT(!pReader->cbData);
+
+ if (createInfo.pszDpyName)
+ {
+ rc = SSMR3GetStrZEx(pReader->pSSM, psz, 200, NULL);
+ AssertRCReturn(rc, rc);
+ createInfo.pszDpyName = psz;
+ }
+
+ winID = crServerDispatchWindowCreateEx(createInfo.pszDpyName, createInfo.visualBits, key);
+ CRASSERT((int64_t)winID == (int64_t)key);
+ }
+
+ /* Load cr_server.muralTable */
+ rc = SSMR3GetU32(pReader->pSSM, &uiNumElems);
+ AssertRCReturn(rc, rc);
+ for (ui=0; ui<uiNumElems; ++ui)
+ {
+ CRMuralInfo muralInfo;
+ CRMuralInfo *pActualMural = NULL;
+
+ rc = crServerLsrDataGetMem(pReader, &key, sizeof(key));
+ AssertRCReturn(rc, rc);
+ rc = crServerLsrDataGetMem(pReader, &muralInfo, RT_OFFSETOF(CRMuralInfo, CreateInfo));
+ AssertRCReturn(rc, rc);
+
+ if (version <= SHCROGL_SSM_VERSION_BEFORE_FRONT_DRAW_TRACKING)
+ muralInfo.bFbDraw = GL_TRUE;
+
+ if (!ui && version == SHCROGL_SSM_VERSION_WITH_BUGGY_MURAL_INFO)
+ {
+ /* Lookahead buffer used to determine whether the data erroneously stored root visible regions data */
+ union
+ {
+ void * apv[1];
+ CR_SERVER_BUGGY_MURAL_DATA Data;
+ /* need to chak spuWindow, so taking the offset of filed following it*/
+ uint8_t au8[RT_OFFSETOF(CRMuralInfo, screenId)];
+ RTRECT aVisRects[sizeof (CR_SERVER_BUGGY_MURAL_DATA) / sizeof (RTRECT)];
+ } LaBuf;
+
+ do {
+ /* first value is bool (uint8_t) value followed by pointer-size-based alignment.
+ * the mural memory is zero-initialized initially, so we can be sure the padding is zeroed */
+ rc = crServerLsrDataGetMem(pReader, &LaBuf, sizeof (LaBuf));
+ AssertRCReturn(rc, rc);
+ if (LaBuf.apv[0] != NULL && LaBuf.apv[0] != ((void*)1))
+ break;
+
+ /* check that the pointers are either valid or NULL */
+ if(LaBuf.Data.RootVrCEntry.Ce_Node_pNext && !RT_VALID_PTR(LaBuf.Data.RootVrCEntry.Ce_Node_pNext))
+ break;
+ if(LaBuf.Data.RootVrCEntry.Ce_Node_pPrev && !RT_VALID_PTR(LaBuf.Data.RootVrCEntry.Ce_Node_pPrev))
+ break;
+ if(LaBuf.Data.RootVrCEntry.Vr.ListHead_pNext && !RT_VALID_PTR(LaBuf.Data.RootVrCEntry.Vr.ListHead_pNext))
+ break;
+ if(LaBuf.Data.RootVrCEntry.Vr.ListHead_pPrev && !RT_VALID_PTR(LaBuf.Data.RootVrCEntry.Vr.ListHead_pPrev))
+ break;
+
+ /* the entry can can be the only one within the (mural) compositor,
+ * so its compositor entry node can either contain NULL pNext and pPrev,
+ * or both of them pointing to compositor's list head */
+ if (LaBuf.Data.RootVrCEntry.Ce_Node_pNext != LaBuf.Data.RootVrCEntry.Ce_Node_pPrev)
+ break;
+
+ /* can either both or none be NULL */
+ if (!LaBuf.Data.RootVrCEntry.Ce_Node_pNext != !LaBuf.Data.RootVrCEntry.Ce_Node_pPrev)
+ break;
+
+ if (!LaBuf.Data.fRootVrOn)
+ {
+ if (LaBuf.Data.RootVrCEntry.Ce_Node_pNext || LaBuf.Data.RootVrCEntry.Ce_Node_pPrev)
+ break;
+
+ /* either non-initialized (zeroed) or empty list */
+ if (LaBuf.Data.RootVrCEntry.Vr.ListHead_pNext != LaBuf.Data.RootVrCEntry.Vr.ListHead_pPrev)
+ break;
+
+ if (LaBuf.Data.RootVrCEntry.Vr.cEntries)
+ break;
+ }
+ else
+ {
+ /* the entry should be initialized */
+ if (!LaBuf.Data.RootVrCEntry.Vr.ListHead_pNext)
+ break;
+ if (!LaBuf.Data.RootVrCEntry.Vr.ListHead_pPrev)
+ break;
+
+ if (LaBuf.Data.RootVrCEntry.Vr.cEntries)
+ {
+ /* entry should be in compositor list*/
+ if (LaBuf.Data.RootVrCEntry.Ce_Node_pPrev == NULL)
+ break;
+ CRASSERT(LaBuf.Data.RootVrCEntry.Ce_Node_pNext);
+ }
+ else
+ {
+ /* entry should NOT be in compositor list*/
+ if (LaBuf.Data.RootVrCEntry.Ce_Node_pPrev != NULL)
+ break;
+ CRASSERT(!LaBuf.Data.RootVrCEntry.Ce_Node_pNext);
+ }
+ }
+
+#if 0
+ if (muralInfo.pVisibleRects)
+ {
+ int j;
+ int cRects = RT_MIN(muralInfo.cVisibleRects, RT_ELEMENTS(LaBuf.aVisRects));
+ CRASSERT(cRects);
+ for (j = 0; j < cRects; ++j)
+ {
+ PRTRECT pRect = &LaBuf.aVisRects[j];
+ if (pRect->xLeft >= pRect->xRight)
+ break;
+ if (pRect->yTop >= pRect->yBottom)
+ break;
+ if (pRect->xLeft < 0 || pRect->xRight < 0
+ || pRect->yTop < 0 || pRect->yBottom < 0)
+ break;
+ if (pRect->xLeft > (GLint)muralInfo.width
+ || pRect->xRight > (GLint)muralInfo.width)
+ break;
+ if (pRect->yTop > (GLint)muralInfo.height
+ || pRect->yBottom > (GLint)muralInfo.height)
+ break;
+ }
+
+ if (j < cRects)
+ {
+ fBuggyMuralData = true;
+ break;
+ }
+ }
+
+ if (muralInfo.pVisibleRects)
+ {
+ /* @todo: do we actually need any further checks here? */
+ fBuggyMuralData = true;
+ break;
+ }
+
+ /* no visible regions*/
+
+ if (ui == uiNumElems - 1)
+ {
+ /* this is the last mural, next it goes idsPool, whose content can not match the above template again */
+ fBuggyMuralData = true;
+ break;
+ }
+
+ /* next it goes a next mural info */
+// if (!fExpectPtr)
+// {
+// CRMuralInfo *pNextSpuWindowInfoMural = (CRMuralInfo*)((void*)&LaBuf);
+// if (!pNextSpuWindowInfoMural->spuWindow)
+// fBuggyMuralData = true;
+//
+// break;
+// }
+#endif
+ /* fExpectPtr == true, the valid pointer values should not match possible mural width/height/position */
+ fBuggyMuralData = true;
+ break;
+
+ } while (0);
+
+ rc = crServerLsrDataPutMem(pReader, &LaBuf, sizeof (LaBuf));
+ AssertRCReturn(rc, rc);
+ }
+
+ if (fBuggyMuralData)
+ {
+ CR_SERVER_BUGGY_MURAL_DATA Tmp;
+ rc = crServerLsrDataGetMem(pReader, &Tmp, sizeof (Tmp));
+ AssertRCReturn(rc, rc);
+ }
+
+ if (muralInfo.pVisibleRects)
+ {
+ muralInfo.pVisibleRects = crAlloc(4*sizeof(GLint)*muralInfo.cVisibleRects);
+ if (!muralInfo.pVisibleRects)
+ {
+ return VERR_NO_MEMORY;
+ }
+
+ rc = crServerLsrDataGetMem(pReader, muralInfo.pVisibleRects, 4*sizeof(GLint)*muralInfo.cVisibleRects);
+ AssertRCReturn(rc, rc);
+ }
+
+ pActualMural = (CRMuralInfo *)crHashtableSearch(cr_server.muralTable, key);
+ CRASSERT(pActualMural);
+
+ if (version >= SHCROGL_SSM_VERSION_WITH_WINDOW_CTX_USAGE)
+ {
+ rc = crServerLsrDataGetMem(pReader, pActualMural->ctxUsage, sizeof (pActualMural->ctxUsage));
+ CRASSERT(rc == VINF_SUCCESS);
+ }
+
+ /* Restore windows geometry info */
+ crServerDispatchWindowSize(key, muralInfo.width, muralInfo.height);
+ crServerDispatchWindowPosition(key, muralInfo.gX, muralInfo.gY);
+ /* Same workaround as described in stub.c:stubUpdateWindowVisibileRegions for compiz on a freshly booted VM*/
+ if (muralInfo.bReceivedRects)
+ {
+ crServerDispatchWindowVisibleRegion(key, muralInfo.cVisibleRects, muralInfo.pVisibleRects);
+ }
+ crServerDispatchWindowShow(key, muralInfo.bVisible);
+
+ if (muralInfo.pVisibleRects)
+ {
+ crFree(muralInfo.pVisibleRects);
+ }
+ }
+
+ CRASSERT(RT_SUCCESS(rc));
+ return VINF_SUCCESS;
+}
+
+static int crVBoxServerLoadFBImage(PSSMHANDLE pSSM, uint32_t version,
+ CRContextInfo* pContextInfo, CRMuralInfo *pMural)
+{
+ CRContext *pContext = pContextInfo->pContext;
+ int32_t rc = VINF_SUCCESS;
+ GLuint i;
+ /* can apply the data right away */
+ struct
+ {
+ CRFBData data;
+ CRFBDataElement buffer[3]; /* CRFBData::aElements[1] + buffer[3] gives 4: back, front, depth and stencil */
+ } Data;
+
+ Assert(sizeof (Data) >= RT_OFFSETOF(CRFBData, aElements[4]));
+
+ if (version >= SHCROGL_SSM_VERSION_WITH_SAVED_DEPTH_STENCIL_BUFFER)
+ {
+ if (!pMural->width || !pMural->height)
+ return VINF_SUCCESS;
+
+ rc = crVBoxServerFBImageDataInitEx(&Data.data, pContextInfo, pMural, GL_TRUE, version, 0, 0);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("crVBoxServerFBImageDataInit failed rc %d", rc);
+ return rc;
+ }
+ }
+ else
+ {
+ GLint storedWidth, storedHeight;
+
+ if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
+ {
+ CRASSERT(cr_server.currentCtxInfo == pContextInfo);
+ CRASSERT(cr_server.currentMural == pMural);
+ storedWidth = pMural->width;
+ storedHeight = pMural->height;
+ }
+ else
+ {
+ storedWidth = pContext->buffer.storedWidth;
+ storedHeight = pContext->buffer.storedHeight;
+ }
+
+ if (!storedWidth || !storedHeight)
+ return VINF_SUCCESS;
+
+ rc = crVBoxServerFBImageDataInitEx(&Data.data, pContextInfo, pMural, GL_TRUE, version, storedWidth, storedHeight);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("crVBoxServerFBImageDataInit failed rc %d", rc);
+ return rc;
+ }
+ }
+
+ CRASSERT(Data.data.cElements);
+
+ for (i = 0; i < Data.data.cElements; ++i)
+ {
+ CRFBDataElement * pEl = &Data.data.aElements[i];
+ rc = SSMR3GetMem(pSSM, pEl->pvData, pEl->cbData);
+ AssertRCReturn(rc, rc);
+ }
+
+ if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
+ {
+ CRBufferState *pBuf = &pContext->buffer;
+ /* can apply the data right away */
+ CRASSERT(cr_server.currentCtxInfo == &cr_server.MainContextInfo);
+ CRASSERT(cr_server.currentMural);
+
+ cr_server.head_spu->dispatch_table.MakeCurrent( pMural->spuWindow,
+ 0,
+ pContextInfo->SpuContext >= 0
+ ? pContextInfo->SpuContext
+ : cr_server.MainContextInfo.SpuContext);
+ crStateApplyFBImage(pContext, &Data.data);
+ CRASSERT(!pBuf->pFrontImg);
+ CRASSERT(!pBuf->pBackImg);
+ crVBoxServerFBImageDataTerm(&Data.data);
+
+ crServerPresentFBO(pMural);
+
+ CRASSERT(cr_server.currentMural);
+ cr_server.head_spu->dispatch_table.MakeCurrent( cr_server.currentMural->spuWindow,
+ 0,
+ cr_server.currentCtxInfo->SpuContext >= 0
+ ? cr_server.currentCtxInfo->SpuContext
+ : cr_server.MainContextInfo.SpuContext);
+ }
+ else
+ {
+ CRBufferState *pBuf = &pContext->buffer;
+ CRASSERT(!pBuf->pFrontImg);
+ CRASSERT(!pBuf->pBackImg);
+ CRASSERT(Data.data.cElements); /* <- older versions always saved front and back, and we filtered out the null-sized buffers above */
+
+ if (Data.data.cElements)
+ {
+ CRFBData *pLazyData = crAlloc(RT_OFFSETOF(CRFBData, aElements[Data.data.cElements]));
+ if (!RT_SUCCESS(rc))
+ {
+ crVBoxServerFBImageDataTerm(&Data.data);
+ crWarning("crAlloc failed");
+ return VERR_NO_MEMORY;
+ }
+
+ crMemcpy(pLazyData, &Data.data, RT_OFFSETOF(CRFBData, aElements[Data.data.cElements]));
+ pBuf->pFrontImg = pLazyData;
+ }
+ }
+
+ CRASSERT(RT_SUCCESS(rc));
+ return VINF_SUCCESS;
+}
+
DECLEXPORT(int32_t) crVBoxServerLoadState(PSSMHANDLE pSSM, uint32_t version)
{
int32_t rc, i;
uint32_t ui, uiNumElems;
unsigned long key;
+ GLenum err;
+ CR_SERVER_LOADSTATE_READER Reader;
if (!cr_server.bIsInLoadingState)
{
@@ -941,6 +2331,16 @@ DECLEXPORT(int32_t) crVBoxServerLoadState(PSSMHANDLE pSSM, uint32_t version)
return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
}
+ crServerLsrInit(&Reader, pSSM);
+
+#ifdef DEBUG_misha
+#define CR_DBG_STR_STATE_LOAD_START "VBox.Cr.StateLoadStart"
+#define CR_DBG_STR_STATE_LOAD_STOP "VBox.Cr.StateLoadStop"
+
+ if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY)
+ cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_LOAD_START), CR_DBG_STR_STATE_LOAD_START);
+#endif
+
/* Load and recreate rendering contexts */
rc = SSMR3GetU32(pSSM, &uiNumElems);
AssertRCReturn(rc, rc);
@@ -974,11 +2374,44 @@ DECLEXPORT(int32_t) crVBoxServerLoadState(PSSMHANDLE pSSM, uint32_t version)
pContext->shared->id=-1;
}
+ if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
+ {
+ CRASSERT(!Reader.pu8Buffer);
+ /* we have a mural data here */
+ rc = crVBoxServerLoadMurals(&Reader, version);
+ AssertRCReturn(rc, rc);
+ CRASSERT(!Reader.pu8Buffer);
+ }
+
+ if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA && uiNumElems)
+ {
+ /* set the current client to allow doing crServerPerformMakeCurrent later */
+ CRASSERT(cr_server.numClients);
+ cr_server.curClient = cr_server.clients[0];
+ }
+
+ rc = crStateLoadGlobals(pSSM, version);
+ AssertRCReturn(rc, rc);
+
+ if (uiNumElems)
+ {
+ /* ensure we have main context set up as current */
+ CRMuralInfo *pMural;
+ CRASSERT(cr_server.MainContextInfo.SpuContext > 0);
+ CRASSERT(!cr_server.currentCtxInfo);
+ CRASSERT(!cr_server.currentMural);
+ pMural = crServerGetDummyMural(cr_server.MainContextInfo.CreateInfo.realVisualBits);
+ CRASSERT(pMural);
+ crServerPerformMakeCurrent(pMural, &cr_server.MainContextInfo);
+ }
+
/* Restore context state data */
for (ui=0; ui<uiNumElems; ++ui)
{
CRContextInfo* pContextInfo;
CRContext *pContext;
+ CRMuralInfo *pMural = NULL;
+ int32_t winId = 0;
rc = SSMR3GetMem(pSSM, &key, sizeof(key));
AssertRCReturn(rc, rc);
@@ -988,82 +2421,91 @@ DECLEXPORT(int32_t) crVBoxServerLoadState(PSSMHANDLE pSSM, uint32_t version)
CRASSERT(pContextInfo->pContext);
pContext = pContextInfo->pContext;
- rc = crStateLoadContext(pContext, cr_server.contextTable, crVBoxServerGetContextCB, pSSM, version);
- AssertRCReturn(rc, rc);
- }
-
- /* Load windows */
- rc = SSMR3GetU32(pSSM, &uiNumElems);
- AssertRCReturn(rc, rc);
- for (ui=0; ui<uiNumElems; ++ui)
- {
- CRCreateInfo_t createInfo;
- char psz[200];
- GLint winID;
- unsigned long key;
-
- rc = SSMR3GetMem(pSSM, &key, sizeof(key));
- AssertRCReturn(rc, rc);
- rc = SSMR3GetMem(pSSM, &createInfo, sizeof(createInfo));
- AssertRCReturn(rc, rc);
-
- if (createInfo.pszDpyName)
+ if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
{
- rc = SSMR3GetStrZEx(pSSM, psz, 200, NULL);
+ rc = SSMR3GetMem(pSSM, &winId, sizeof(winId));
AssertRCReturn(rc, rc);
- createInfo.pszDpyName = psz;
+
+ if (winId)
+ {
+ pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, winId);
+ CRASSERT(pMural);
+ }
+ else
+ {
+ /* null winId means a dummy mural, get it */
+ pMural = crServerGetDummyMural(pContextInfo->CreateInfo.realVisualBits);
+ CRASSERT(pMural);
+ }
}
- winID = crServerDispatchWindowCreateEx(createInfo.pszDpyName, createInfo.visualBits, key);
- CRASSERT((int64_t)winID == (int64_t)key);
+ rc = crStateLoadContext(pContext, cr_server.contextTable, crVBoxServerGetContextCB, pSSM, version);
+ AssertRCReturn(rc, rc);
+
+ /*Restore front/back buffer images*/
+ rc = crVBoxServerLoadFBImage(pSSM, version, pContextInfo, pMural);
+ AssertRCReturn(rc, rc);
}
- /* Load cr_server.muralTable */
- rc = SSMR3GetU32(pSSM, &uiNumElems);
- AssertRCReturn(rc, rc);
- for (ui=0; ui<uiNumElems; ++ui)
+ if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
{
- CRMuralInfo muralInfo;
+ CRContextInfo *pContextInfo;
+ CRMuralInfo *pMural;
+ GLint ctxId;
- rc = SSMR3GetMem(pSSM, &key, sizeof(key));
- AssertRCReturn(rc, rc);
- rc = SSMR3GetMem(pSSM, &muralInfo, sizeof(muralInfo));
+ rc = SSMR3GetU32(pSSM, &uiNumElems);
AssertRCReturn(rc, rc);
+ for (ui=0; ui<uiNumElems; ++ui)
+ {
+ CRbitvalue initialCtxUsage[CR_MAX_BITARRAY];
+ CRMuralInfo *pInitialCurMural;
- if (version <= SHCROGL_SSM_VERSION_BEFORE_FRONT_DRAW_TRACKING)
- muralInfo.bFbDraw = GL_TRUE;
+ rc = SSMR3GetMem(pSSM, &key, sizeof(key));
+ AssertRCReturn(rc, rc);
- if (muralInfo.pVisibleRects)
- {
- muralInfo.pVisibleRects = crAlloc(4*sizeof(GLint)*muralInfo.cVisibleRects);
- if (!muralInfo.pVisibleRects)
+ rc = SSMR3GetMem(pSSM, &ctxId, sizeof(ctxId));
+ AssertRCReturn(rc, rc);
+
+ pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, key);
+ CRASSERT(pMural);
+ if (ctxId)
{
- return VERR_NO_MEMORY;
+ pContextInfo = (CRContextInfo *)crHashtableSearch(cr_server.contextTable, ctxId);
+ CRASSERT(pContextInfo);
}
+ else
+ pContextInfo = &cr_server.MainContextInfo;
- rc = SSMR3GetMem(pSSM, muralInfo.pVisibleRects, 4*sizeof(GLint)*muralInfo.cVisibleRects);
+ crMemcpy(initialCtxUsage, pMural->ctxUsage, sizeof (initialCtxUsage));
+ pInitialCurMural = pContextInfo->currentMural;
+
+ rc = crVBoxServerLoadFBImage(pSSM, version, pContextInfo, pMural);
AssertRCReturn(rc, rc);
- }
- /* Restore windows geometry info */
- crServerDispatchWindowSize(key, muralInfo.width, muralInfo.height);
- crServerDispatchWindowPosition(key, muralInfo.gX, muralInfo.gY);
- /* Same workaround as described in stub.c:stubUpdateWindowVisibileRegions for compiz on a freshly booted VM*/
- if (muralInfo.bReceivedRects)
- {
- crServerDispatchWindowVisibleRegion(key, muralInfo.cVisibleRects, muralInfo.pVisibleRects);
+ /* restore the reference data, we synchronize it with the HW state in a later crServerPerformMakeCurrent call */
+ crMemcpy(pMural->ctxUsage, initialCtxUsage, sizeof (initialCtxUsage));
+ pContextInfo->currentMural = pInitialCurMural;
}
- crServerDispatchWindowShow(key, muralInfo.bVisible);
- if (muralInfo.pVisibleRects)
- {
- crFree(muralInfo.pVisibleRects);
- }
+ CRASSERT(!uiNumElems || cr_server.currentCtxInfo == &cr_server.MainContextInfo);
+
+ cr_server.curClient = NULL;
+ cr_server.bForceMakeCurrentOnClientSwitch = GL_TRUE;
}
+ else
+ {
+ CRServerFreeIDsPool_t dummyIdsPool;
- /* Load starting free context and window IDs */
- rc = SSMR3GetMem(pSSM, &cr_server.idsPool, sizeof(cr_server.idsPool));
- CRASSERT(rc == VINF_SUCCESS);
+ CRASSERT(!Reader.pu8Buffer);
+
+ /* we have a mural data here */
+ rc = crVBoxServerLoadMurals(&Reader, version);
+ AssertRCReturn(rc, rc);
+
+ /* not used any more, just read it out and ignore */
+ rc = crServerLsrDataGetMem(&Reader, &dummyIdsPool, sizeof(dummyIdsPool));
+ CRASSERT(rc == VINF_SUCCESS);
+ }
/* Load clients info */
for (i = 0; i < cr_server.numClients; i++)
@@ -1074,21 +2516,21 @@ DECLEXPORT(int32_t) crVBoxServerLoadState(PSSMHANDLE pSSM, uint32_t version)
CRClient client;
unsigned long ctxID=-1, winID=-1;
- rc = SSMR3GetU32(pSSM, &ui);
+ rc = crServerLsrDataGetU32(&Reader, &ui);
AssertRCReturn(rc, rc);
/* If this assert fires, then we should search correct client in the list first*/
CRASSERT(ui == pClient->conn->u32ClientID);
if (version>=4)
{
- rc = SSMR3GetU32(pSSM, &pClient->conn->vMajor);
+ rc = crServerLsrDataGetU32(&Reader, &pClient->conn->vMajor);
AssertRCReturn(rc, rc);
- rc = SSMR3GetU32(pSSM, &pClient->conn->vMinor);
+ rc = crServerLsrDataGetU32(&Reader, &pClient->conn->vMinor);
AssertRCReturn(rc, rc);
}
- rc = SSMR3GetMem(pSSM, &client, sizeof(client));
+ rc = crServerLsrDataGetMem(&Reader, &client, sizeof(client));
CRASSERT(rc == VINF_SUCCESS);
client.conn = pClient->conn;
@@ -1105,9 +2547,9 @@ DECLEXPORT(int32_t) crVBoxServerLoadState(PSSMHANDLE pSSM, uint32_t version)
cr_server.curClient = pClient;
- if (client.currentCtxInfo && client.currentContextNumber>=0)
+ if (client.currentCtxInfo && client.currentContextNumber > 0)
{
- rc = SSMR3GetMem(pSSM, &ctxID, sizeof(ctxID));
+ rc = crServerLsrDataGetMem(&Reader, &ctxID, sizeof(ctxID));
AssertRCReturn(rc, rc);
client.currentCtxInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, ctxID);
CRASSERT(client.currentCtxInfo);
@@ -1116,9 +2558,9 @@ DECLEXPORT(int32_t) crVBoxServerLoadState(PSSMHANDLE pSSM, uint32_t version)
//pClient->currentContextNumber = ctxID;
}
- if (client.currentMural && client.currentWindow>=0)
+ if (client.currentMural && client.currentWindow > 0)
{
- rc = SSMR3GetMem(pSSM, &winID, sizeof(winID));
+ rc = crServerLsrDataGetMem(&Reader, &winID, sizeof(winID));
AssertRCReturn(rc, rc);
client.currentMural = (CRMuralInfo*) crHashtableSearch(cr_server.muralTable, winID);
CRASSERT(client.currentMural);
@@ -1126,6 +2568,8 @@ DECLEXPORT(int32_t) crVBoxServerLoadState(PSSMHANDLE pSSM, uint32_t version)
//pClient->currentWindow = winID;
}
+ CRASSERT(!Reader.cbData);
+
/* Restore client active context and window */
crServerDispatchMakeCurrent(winID, 0, ctxID);
@@ -1195,40 +2639,68 @@ DECLEXPORT(int32_t) crVBoxServerLoadState(PSSMHANDLE pSSM, uint32_t version)
cr_server.curClient = NULL;
+ if (version >= SHCROGL_SSM_VERSION_WITH_SCREEN_INFO)
{
- GLenum err = crServerDispatchGetError();
-
- if (err != GL_NO_ERROR)
- {
- crWarning("crServer: glGetError %d after loading snapshot", err);
- }
+ rc = CrPMgrLoadState(pSSM, version);
+ AssertRCReturn(rc, rc);
}
+ while ((err = cr_server.head_spu->dispatch_table.GetError()) != GL_NO_ERROR)
+ crWarning("crServer: glGetError %d after loading snapshot", err);
+
cr_server.bIsInLoadingState = GL_FALSE;
+#if 0
+ crVBoxServerCheckConsistency();
+#endif
+
+#ifdef DEBUG_misha
+ if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY)
+ cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_LOAD_STOP), CR_DBG_STR_STATE_LOAD_STOP);
+#endif
+
+ CRASSERT(!Reader.cbData);
+ crServerLsrTerm(&Reader);
+
return VINF_SUCCESS;
}
#define SCREEN(i) (cr_server.screen[i])
#define MAPPED(screen) ((screen).winID != 0)
-static void crVBoxServerReparentMuralCB(unsigned long key, void *data1, void *data2)
+extern DECLEXPORT(void) crServerVBoxSetNotifyEventCB(PFNCRSERVERNOTIFYEVENT pfnCb)
{
- CRMuralInfo *pMI = (CRMuralInfo*) data1;
- int *sIndex = (int*) data2;
+ cr_server.pfnNotifyEventCB = pfnCb;
+}
- if (pMI->screenId == *sIndex)
+void crVBoxServerNotifyEvent(int32_t idScreen, uint32_t uEvent, void*pvData)
+{
+ /* this is something unexpected, but just in case */
+ if (idScreen >= cr_server.screenCount)
{
- renderspuReparentWindow(pMI->spuWindow);
+ crWarning("invalid screen id %d", idScreen);
+ return;
}
+
+ cr_server.pfnNotifyEventCB(idScreen, uEvent, pvData);
}
-static void crVBoxServerCheckMuralCB(unsigned long key, void *data1, void *data2)
+void crServerWindowReparent(CRMuralInfo *pMural)
+{
+ pMural->fHasParentWindow = !!cr_server.screen[pMural->screenId].winID;
+
+ renderspuReparentWindow(pMural->spuWindow);
+}
+
+static void crVBoxServerReparentMuralCB(unsigned long key, void *data1, void *data2)
{
CRMuralInfo *pMI = (CRMuralInfo*) data1;
- (void) data2;
+ int *sIndex = (int*) data2;
- crServerCheckMuralGeometry(pMI);
+ if (pMI->screenId == *sIndex)
+ {
+ crServerWindowReparent(pMI);
+ }
}
DECLEXPORT(int32_t) crVBoxServerSetScreenCount(int sCount)
@@ -1269,9 +2741,14 @@ DECLEXPORT(int32_t) crVBoxServerUnmapScreen(int sIndex)
renderspuSetWindowId(0);
crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex);
+
+ crHashtableWalk(cr_server.dummyMuralTable, crVBoxServerReparentMuralCB, &sIndex);
+
+ CrPMgrScreenChanged((uint32_t)sIndex);
}
renderspuSetWindowId(SCREEN(0).winID);
+
return VINF_SUCCESS;
}
@@ -1296,9 +2773,9 @@ DECLEXPORT(int32_t) crVBoxServerMapScreen(int sIndex, int32_t x, int32_t y, uint
renderspuSetWindowId(SCREEN(sIndex).winID);
crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex);
- renderspuSetWindowId(SCREEN(0).winID);
- crHashtableWalk(cr_server.muralTable, crVBoxServerCheckMuralCB, NULL);
+ crHashtableWalk(cr_server.dummyMuralTable, crVBoxServerReparentMuralCB, &sIndex);
+ renderspuSetWindowId(SCREEN(0).winID);
#ifndef WINDOWS
/*Restore FB content for clients, which have current window on a screen being remapped*/
@@ -1310,7 +2787,7 @@ DECLEXPORT(int32_t) crVBoxServerMapScreen(int sIndex, int32_t x, int32_t y, uint
cr_server.curClient = cr_server.clients[i];
if (cr_server.curClient->currentCtxInfo
&& cr_server.curClient->currentCtxInfo->pContext
- && (cr_server.curClient->currentCtxInfo->pContext->buffer.pFrontImg || cr_server.curClient->currentCtxInfo->pContext->buffer.pBackImg)
+ && (cr_server.curClient->currentCtxInfo->pContext->buffer.pFrontImg)
&& cr_server.curClient->currentMural
&& cr_server.curClient->currentMural->screenId == sIndex
&& cr_server.curClient->currentCtxInfo->pContext->buffer.storedHeight == h
@@ -1318,25 +2795,74 @@ DECLEXPORT(int32_t) crVBoxServerMapScreen(int sIndex, int32_t x, int32_t y, uint
{
int clientWindow = cr_server.curClient->currentWindow;
int clientContext = cr_server.curClient->currentContextNumber;
+ CRFBData *pLazyData = (CRFBData *)cr_server.curClient->currentCtxInfo->pContext->buffer.pFrontImg;
if (clientWindow && clientWindow != cr_server.currentWindow)
{
crServerDispatchMakeCurrent(clientWindow, 0, clientContext);
}
- crStateApplyFBImage(cr_server.curClient->currentCtxInfo->pContext);
+ crStateApplyFBImage(cr_server.curClient->currentCtxInfo->pContext, pLazyData);
+ crStateFreeFBImageLegacy(cr_server.curClient->currentCtxInfo->pContext);
}
}
cr_server.curClient = NULL;
}
#endif
+ CrPMgrScreenChanged((uint32_t)sIndex);
+
return VINF_SUCCESS;
}
-DECLEXPORT(int32_t) crVBoxServerSetRootVisibleRegion(GLint cRects, GLint *pRects)
+DECLEXPORT(int32_t) crVBoxServerSetRootVisibleRegion(GLint cRects, const RTRECT *pRects)
{
- renderspuSetRootVisibleRegion(cRects, pRects);
+ int32_t rc = VINF_SUCCESS;
+ GLboolean fOldRootVrOn = cr_server.fRootVrOn;
+
+ /* non-zero rects pointer indicate rects are present and switched on
+ * i.e. cRects==0 and pRects!=NULL means root visible regioning is ON and there are no visible regions,
+ * while pRects==NULL means root visible regioning is OFF, i.e. everything is visible */
+ if (pRects)
+ {
+ crMemset(&cr_server.RootVrCurPoint, 0, sizeof (cr_server.RootVrCurPoint));
+ rc = VBoxVrListRectsSet(&cr_server.RootVr, cRects, pRects, NULL);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("VBoxVrListRectsSet failed! rc %d", rc);
+ return rc;
+ }
+
+ cr_server.fRootVrOn = GL_TRUE;
+ }
+ else
+ {
+ if (!cr_server.fRootVrOn)
+ return VINF_SUCCESS;
+
+ VBoxVrListClear(&cr_server.RootVr);
+
+ cr_server.fRootVrOn = GL_FALSE;
+ }
+
+ if (!fOldRootVrOn != !cr_server.fRootVrOn)
+ {
+ rc = CrPMgrModeRootVr(cr_server.fRootVrOn);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("CrPMgrModeRootVr failed rc %d", rc);
+ return rc;
+ }
+ }
+ else if (cr_server.fRootVrOn)
+ {
+ rc = CrPMgrRootVrUpdate();
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("CrPMgrRootVrUpdate failed rc %d", rc);
+ return rc;
+ }
+ }
return VINF_SUCCESS;
}
@@ -1348,21 +2874,7 @@ DECLEXPORT(void) crVBoxServerSetPresentFBOCB(PFNCRSERVERPRESENTFBO pfnPresentFBO
DECLEXPORT(int32_t) crVBoxServerSetOffscreenRendering(GLboolean value)
{
- if (cr_server.bForceOffscreenRendering==value)
- {
- return VINF_SUCCESS;
- }
-
- if (value && !crServerSupportRedirMuralFBO())
- {
- return VERR_NOT_SUPPORTED;
- }
-
- cr_server.bForceOffscreenRendering=value;
-
- crHashtableWalk(cr_server.muralTable, crVBoxServerCheckMuralCB, NULL);
-
- return VINF_SUCCESS;
+ return CrPMgrModeVrdp(value);
}
DECLEXPORT(int32_t) crVBoxServerOutputRedirectSet(const CROutputRedirect *pCallbacks)
@@ -1371,74 +2883,502 @@ DECLEXPORT(int32_t) crVBoxServerOutputRedirectSet(const CROutputRedirect *pCallb
if (pCallbacks)
{
cr_server.outputRedirect = *pCallbacks;
- cr_server.bUseOutputRedirect = true;
}
else
{
- cr_server.bUseOutputRedirect = false;
+ memset (&cr_server.outputRedirect, 0, sizeof (cr_server.outputRedirect));
}
- // @todo dynamically intercept already existing output:
- // crHashtableWalk(cr_server.muralTable, crVBoxServerOutputRedirectCB, NULL);
+ return VINF_SUCCESS;
+}
+
+DECLEXPORT(int32_t) crVBoxServerSetScreenViewport(int sIndex, int32_t x, int32_t y, uint32_t w, uint32_t h)
+{
+ CRScreenViewportInfo *pViewport;
+ RTRECT NewRect;
+ int rc;
+
+ crDebug("crVBoxServerSetScreenViewport(%i)", sIndex);
+
+ if (sIndex<0 || sIndex>=cr_server.screenCount)
+ {
+ crWarning("crVBoxServerSetScreenViewport: invalid screen id %d", sIndex);
+ return VERR_INVALID_PARAMETER;
+ }
+
+ NewRect.xLeft = x;
+ NewRect.yTop = y;
+ NewRect.xRight = x + w;
+ NewRect.yBottom = y + h;
+
+ pViewport = &cr_server.screenVieport[sIndex];
+ /*always do viewport updates no matter whether the rectangle actually changes,
+ * this is needed to ensure window is adjusted properly on OSX */
+ pViewport->Rect = NewRect;
+ rc = CrPMgrViewportUpdate((uint32_t)sIndex);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("CrPMgrViewportUpdate failed %d", rc);
+ return rc;
+ }
return VINF_SUCCESS;
}
-static void crVBoxServerUpdateScreenViewportCB(unsigned long key, void *data1, void *data2)
+static void crVBoxServerDefaultContextSet()
{
- CRMuralInfo *mural = (CRMuralInfo*) data1;
- int *sIndex = (int*) data2;
+ GLint spuWindow, spuCtx;
- if (mural->screenId != *sIndex)
- return;
+ if (cr_server.MainContextInfo.SpuContext)
+ {
+ CRMuralInfo *pMural = crServerGetDummyMural(cr_server.MainContextInfo.CreateInfo.realVisualBits);
+ if (!pMural)
+ {
+ WARN(("dummy mural is NULL"));
+ spuCtx = CR_RENDER_DEFAULT_CONTEXT_ID;
+ spuWindow = CR_RENDER_DEFAULT_WINDOW_ID;
+ }
+ else
+ {
+ spuCtx = cr_server.MainContextInfo.SpuContext;
+ spuWindow = pMural->CreateInfo.realVisualBits;
+ }
+ }
+ else
+ {
+ spuCtx = CR_RENDER_DEFAULT_CONTEXT_ID;
+ spuWindow = CR_RENDER_DEFAULT_WINDOW_ID;
+ }
- crServerCheckMuralGeometry(mural);
+ cr_server.head_spu->dispatch_table.MakeCurrent(spuWindow, 0, spuCtx);
}
+#ifdef VBOX_WITH_CRHGSMI
-DECLEXPORT(int32_t) crVBoxServerSetScreenViewport(int sIndex, int32_t x, int32_t y, uint32_t w, uint32_t h)
+static int32_t crVBoxServerCmdVbvaCrCmdProcess(struct VBOXCMDVBVA_CRCMD_CMD *pCmd, uint32_t cbCmd)
{
- CRScreenViewportInfo *pVieport;
- GLboolean fPosChanged, fSizeChanged;
+ int32_t rc;
+ uint32_t cBuffers = pCmd->cBuffers;
+ uint32_t cParams;
+ uint32_t cbHdr;
+ CRVBOXHGSMIHDR *pHdr;
+ uint32_t u32Function;
+ uint32_t u32ClientID;
+ CRClient *pClient;
- crDebug("crVBoxServerSetScreenViewport(%i)", sIndex);
+ if (!g_pvVRamBase)
+ {
+ WARN(("g_pvVRamBase is not initialized"));
+ return VERR_INVALID_STATE;
+ }
- if (sIndex<0 || sIndex>=cr_server.screenCount)
+ if (!cBuffers)
{
- crWarning("crVBoxServerSetScreenViewport: invalid screen id %d", sIndex);
+ WARN(("zero buffers passed in!"));
return VERR_INVALID_PARAMETER;
}
- pVieport = &cr_server.screenVieport[sIndex];
- fPosChanged = (pVieport->x != x || pVieport->y != y);
- fSizeChanged = (pVieport->w != w || pVieport->h != h);
+ cParams = cBuffers-1;
- if (!fPosChanged && !fSizeChanged)
+ if (cbCmd != RT_OFFSETOF(VBOXCMDVBVA_CRCMD_CMD, aBuffers[cBuffers]))
{
- crDebug("crVBoxServerSetScreenViewport: no changes");
- return VINF_SUCCESS;
+ WARN(("invalid buffer size"));
+ return VERR_INVALID_PARAMETER;
}
- if (fPosChanged)
+ cbHdr = pCmd->aBuffers[0].cbBuffer;
+ pHdr = VBOXCRHGSMI_PTR_SAFE(pCmd->aBuffers[0].offBuffer, cbHdr, CRVBOXHGSMIHDR);
+ if (!pHdr)
{
- pVieport->x = x;
- pVieport->y = y;
+ WARN(("invalid header buffer!"));
+ return VERR_INVALID_PARAMETER;
+ }
- crHashtableWalk(cr_server.muralTable, crVBoxServerUpdateScreenViewportCB, &sIndex);
+ if (cbHdr < sizeof (*pHdr))
+ {
+ WARN(("invalid header buffer size!"));
+ return VERR_INVALID_PARAMETER;
}
- if (fSizeChanged)
+ u32Function = pHdr->u32Function;
+ u32ClientID = pHdr->u32ClientID;
+
+ switch (u32Function)
{
- pVieport->w = w;
- pVieport->h = h;
+ case SHCRGL_GUEST_FN_WRITE:
+ {
+ Log(("svcCall: SHCRGL_GUEST_FN_WRITE\n"));
+
+ /* @todo: Verify */
+ if (cParams == 1)
+ {
+ CRVBOXHGSMIWRITE* pFnCmd = (CRVBOXHGSMIWRITE*)pHdr;
+ VBOXCMDVBVA_CRCMD_BUFFER *pBuf = &pCmd->aBuffers[1];
+ /* Fetch parameters. */
+ uint32_t cbBuffer = pBuf->cbBuffer;
+ uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
+
+ if (cbHdr < sizeof (*pFnCmd))
+ {
+ crWarning("invalid write cmd buffer size!");
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ CRASSERT(cbBuffer);
+ if (!pBuffer)
+ {
+ crWarning("invalid buffer data received from guest!");
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ rc = crVBoxServerClientGet(u32ClientID, &pClient);
+ if (RT_FAILURE(rc))
+ {
+ break;
+ }
+
+ /* This should never fire unless we start to multithread */
+ CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
+ CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
+
+ pClient->conn->pBuffer = pBuffer;
+ pClient->conn->cbBuffer = cbBuffer;
+ CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr, false);
+ rc = crVBoxServerInternalClientWriteRead(pClient);
+ CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
+ return rc;
+ }
+ else
+ {
+ crWarning("invalid number of args");
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+ break;
+ }
+
+ case SHCRGL_GUEST_FN_INJECT:
+ {
+ Log(("svcCall: SHCRGL_GUEST_FN_INJECT\n"));
+
+ /* @todo: Verify */
+ if (cParams == 1)
+ {
+ CRVBOXHGSMIINJECT *pFnCmd = (CRVBOXHGSMIINJECT*)pHdr;
+ /* Fetch parameters. */
+ uint32_t u32InjectClientID = pFnCmd->u32ClientID;
+ VBOXCMDVBVA_CRCMD_BUFFER *pBuf = &pCmd->aBuffers[1];
+ uint32_t cbBuffer = pBuf->cbBuffer;
+ uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
+
+ if (cbHdr < sizeof (*pFnCmd))
+ {
+ crWarning("invalid inject cmd buffer size!");
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ CRASSERT(cbBuffer);
+ if (!pBuffer)
+ {
+ crWarning("invalid buffer data received from guest!");
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ rc = crVBoxServerClientGet(u32InjectClientID, &pClient);
+ if (RT_FAILURE(rc))
+ {
+ break;
+ }
+
+ /* This should never fire unless we start to multithread */
+ CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
+ CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
+
+ pClient->conn->pBuffer = pBuffer;
+ pClient->conn->cbBuffer = cbBuffer;
+ CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr, false);
+ rc = crVBoxServerInternalClientWriteRead(pClient);
+ CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
+ return rc;
+ }
+
+ crWarning("invalid number of args");
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ case SHCRGL_GUEST_FN_READ:
+ {
+ Log(("svcCall: SHCRGL_GUEST_FN_READ\n"));
+
+ /* @todo: Verify */
+ if (cParams == 1)
+ {
+ CRVBOXHGSMIREAD *pFnCmd = (CRVBOXHGSMIREAD*)pHdr;
+ VBOXCMDVBVA_CRCMD_BUFFER *pBuf = &pCmd->aBuffers[1];
+ /* Fetch parameters. */
+ uint32_t cbBuffer = pBuf->cbBuffer;
+ uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
+
+ if (cbHdr < sizeof (*pFnCmd))
+ {
+ crWarning("invalid read cmd buffer size!");
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+
+ if (!pBuffer)
+ {
+ crWarning("invalid buffer data received from guest!");
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ rc = crVBoxServerClientGet(u32ClientID, &pClient);
+ if (RT_FAILURE(rc))
+ {
+ break;
+ }
+
+ CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
+
+ rc = crVBoxServerInternalClientRead(pClient, pBuffer, &cbBuffer);
+
+ /* Return the required buffer size always */
+ pFnCmd->cbBuffer = cbBuffer;
+
+ CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
+
+ /* the read command is never pended, complete it right away */
+ pHdr->result = rc;
+
+ return VINF_SUCCESS;
+ }
+
+ crWarning("invalid number of args");
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ case SHCRGL_GUEST_FN_WRITE_READ:
+ {
+ Log(("svcCall: SHCRGL_GUEST_FN_WRITE_READ\n"));
+
+ /* @todo: Verify */
+ if (cParams == 2)
+ {
+ CRVBOXHGSMIWRITEREAD *pFnCmd = (CRVBOXHGSMIWRITEREAD*)pHdr;
+ VBOXCMDVBVA_CRCMD_BUFFER *pBuf = &pCmd->aBuffers[1];
+ VBOXCMDVBVA_CRCMD_BUFFER *pWbBuf = &pCmd->aBuffers[2];
+
+ /* Fetch parameters. */
+ uint32_t cbBuffer = pBuf->cbBuffer;
+ uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
+
+ uint32_t cbWriteback = pWbBuf->cbBuffer;
+ char *pWriteback = VBOXCRHGSMI_PTR_SAFE(pWbBuf->offBuffer, cbWriteback, char);
+
+ if (cbHdr < sizeof (*pFnCmd))
+ {
+ crWarning("invalid write_read cmd buffer size!");
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+
+ CRASSERT(cbBuffer);
+ if (!pBuffer)
+ {
+ crWarning("invalid write buffer data received from guest!");
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ CRASSERT(cbWriteback);
+ if (!pWriteback)
+ {
+ crWarning("invalid writeback buffer data received from guest!");
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+ rc = crVBoxServerClientGet(u32ClientID, &pClient);
+ if (RT_FAILURE(rc))
+ {
+ pHdr->result = rc;
+ return VINF_SUCCESS;
+ }
+
+ /* This should never fire unless we start to multithread */
+ CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
+ CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
+
+ pClient->conn->pBuffer = pBuffer;
+ pClient->conn->cbBuffer = cbBuffer;
+ CRVBOXHGSMI_CMDDATA_SETWB(&pClient->conn->CmdData, pCmd, pHdr, pWriteback, cbWriteback, &pFnCmd->cbWriteback, false);
+ rc = crVBoxServerInternalClientWriteRead(pClient);
+ CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
+ return rc;
+ }
+
+ crWarning("invalid number of args");
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ case SHCRGL_GUEST_FN_SET_VERSION:
+ {
+ crWarning("invalid function");
+ rc = VERR_NOT_IMPLEMENTED;
+ break;
+ }
+
+ case SHCRGL_GUEST_FN_SET_PID:
+ {
+ crWarning("invalid function");
+ rc = VERR_NOT_IMPLEMENTED;
+ break;
+ }
+
+ default:
+ {
+ crWarning("invalid function");
+ rc = VERR_NOT_IMPLEMENTED;
+ break;
+ }
- /* no need to do anything here actually */
}
+
+ /* we can be on fail only here */
+ CRASSERT(RT_FAILURE(rc));
+ pHdr->result = rc;
+
+ return rc;
+}
+
+static DECLCALLBACK(int) crVBoxCrCmdEnable(HVBOXCRCMDSVR hSvr, VBOXCRCMD_SVRENABLE_INFO *pInfo)
+{
+ cr_server.CrCmdClientInfo = *pInfo;
+
+ crVBoxServerDefaultContextSet();
+
return VINF_SUCCESS;
}
+static DECLCALLBACK(int) crVBoxCrCmdDisable(HVBOXCRCMDSVR hSvr)
+{
+ cr_server.head_spu->dispatch_table.MakeCurrent(0, 0, 0);
+
+ memset(&cr_server.CrCmdClientInfo, 0, sizeof (cr_server.CrCmdClientInfo));
+
+ return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) crVBoxCrCmdHostCtl(HVBOXCRCMDSVR hSvr, uint8_t* pCmd, uint32_t cbCmd)
+{
+ return crVBoxServerHostCtl((VBOXCRCMDCTL*)pCmd, cbCmd);
+}
+
+static DECLCALLBACK(int) crVBoxCrCmdGuestCtl(HVBOXCRCMDSVR hSvr, uint8_t* pCmd, uint32_t cbCmd)
+{
+ VBOXCMDVBVA_3DCTL *pCtl = (VBOXCMDVBVA_3DCTL*)pCmd;
+ if (cbCmd < sizeof (VBOXCMDVBVA_3DCTL))
+ {
+ WARN(("invalid buffer size"));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ switch (pCtl->u32Type)
+ {
+ case VBOXCMDVBVA3DCTL_TYPE_CONNECT:
+ {
+ VBOXCMDVBVA_3DCTL_CONNECT *pConnect = (VBOXCMDVBVA_3DCTL_CONNECT*)pCtl;
+
+ return VERR_NOT_SUPPORTED;
+ }
+ case VBOXCMDVBVA3DCTL_TYPE_DISCONNECT:
+ {
+ return VERR_NOT_SUPPORTED;
+ }
+ case VBOXCMDVBVA3DCTL_TYPE_CMD:
+ {
+ VBOXCMDVBVA_3DCTL_CMD *p3DCmd;
+ if (cbCmd < sizeof (VBOXCMDVBVA_3DCTL_CMD))
+ {
+ WARN(("invalid size"));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ p3DCmd = (VBOXCMDVBVA_3DCTL_CMD*)pCmd;
+
+ return crVBoxCrCmdCmd(NULL, &p3DCmd->Cmd, cbCmd - RT_OFFSETOF(VBOXCMDVBVA_3DCTL_CMD, Cmd));
+ }
+ default:
+ WARN(("invalid function"));
+ return VERR_INVALID_PARAMETER;
+ }
+}
+
+static DECLCALLBACK(int) crVBoxCrCmdSaveState(HVBOXCRCMDSVR hSvr, PSSMHANDLE pSSM)
+{
+ AssertFailed();
+ return VERR_NOT_IMPLEMENTED;
+}
+
+static DECLCALLBACK(int) crVBoxCrCmdLoadState(HVBOXCRCMDSVR hSvr, PSSMHANDLE pSSM, uint32_t u32Version)
+{
+ AssertFailed();
+ return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) crVBoxCrCmdCmd(HVBOXCRCMDSVR hSvr, PVBOXCMDVBVA_HDR pCmd, uint32_t cbCmd)
+{
+ AssertFailed();
+ switch (pCmd->u8OpCode)
+ {
+ case VBOXCMDVBVA_OPTYPE_CRCMD:
+ {
+ VBOXCMDVBVA_CRCMD *pCrCmdDr;
+ VBOXCMDVBVA_CRCMD_CMD *pCrCmd;
+ int rc;
+ pCrCmdDr = (VBOXCMDVBVA_CRCMD*)pCmd;
+ pCrCmd = &pCrCmdDr->Cmd;
+ if (cbCmd < sizeof (VBOXCMDVBVA_CRCMD))
+ {
+ WARN(("invalid buffer size"));
+ pCmd->u.i8Result = -1;
+ break;
+ }
+ rc = crVBoxServerCmdVbvaCrCmdProcess(pCrCmd, cbCmd - RT_OFFSETOF(VBOXCMDVBVA_CRCMD, Cmd));
+ if (RT_SUCCESS(rc))
+ {
+ /* success */
+ pCmd->u.i8Result = 0;
+ }
+ else
+ {
+ WARN(("crVBoxServerCmdVbvaCrCmdProcess failed, rc %d", rc));
+ pCmd->u.i8Result = -1;
+ }
+ break;
+ }
+ case VBOXCMDVBVA_OPTYPE_BLT_OFFPRIMSZFMT_OR_ID:
+ {
+ crVBoxServerCrCmdBltProcess(pCmd, cbCmd);
+ break;
+ }
+ default:
+ WARN(("unsupported command"));
+ pCmd->u.i8Result = -1;
+ }
+ return VINF_SUCCESS;
+}
-#ifdef VBOX_WITH_CRHGSMI
/* We moved all CrHgsmi command processing to crserverlib to keep the logic of dealing with CrHgsmi commands in one place.
*
* For now we need the notion of CrHgdmi commands in the crserver_lib to be able to complete it asynchronously once it is really processed.
@@ -1452,8 +3392,11 @@ DECLEXPORT(int32_t) crVBoxServerSetScreenViewport(int sIndex, int32_t x, int32_t
*
* NOTE: it is ALWAYS responsibility of the crVBoxServerCrHgsmiCmd to complete the command!
* */
+
+
int32_t crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t cbCmd)
{
+
int32_t rc;
uint32_t cBuffers = pCmd->cBuffers;
uint32_t cParams;
@@ -1465,14 +3408,16 @@ int32_t crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t c
if (!g_pvVRamBase)
{
- crWarning("g_pvVRamBase is not initialized");
+ WARN(("g_pvVRamBase is not initialized"));
+
crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_STATE);
return VINF_SUCCESS;
}
if (!cBuffers)
{
- crWarning("zero buffers passed in!");
+ WARN(("zero buffers passed in!"));
+
crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
return VINF_SUCCESS;
}
@@ -1483,14 +3428,16 @@ int32_t crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t c
pHdr = VBOXCRHGSMI_PTR_SAFE(pCmd->aBuffers[0].offBuffer, cbHdr, CRVBOXHGSMIHDR);
if (!pHdr)
{
- crWarning("invalid header buffer!");
+ WARN(("invalid header buffer!"));
+
crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
return VINF_SUCCESS;
}
if (cbHdr < sizeof (*pHdr))
{
- crWarning("invalid header buffer size!");
+ WARN(("invalid header buffer size!"));
+
crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
return VINF_SUCCESS;
}
@@ -1502,7 +3449,7 @@ int32_t crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t c
{
case SHCRGL_GUEST_FN_WRITE:
{
- crDebug(("svcCall: SHCRGL_GUEST_FN_WRITE\n"));
+ Log(("svcCall: SHCRGL_GUEST_FN_WRITE\n"));
/* @todo: Verify */
if (cParams == 1)
@@ -1540,7 +3487,7 @@ int32_t crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t c
pClient->conn->pBuffer = pBuffer;
pClient->conn->cbBuffer = cbBuffer;
- CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr);
+ CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr, true);
rc = crVBoxServerInternalClientWriteRead(pClient);
CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
return rc;
@@ -1556,7 +3503,7 @@ int32_t crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t c
case SHCRGL_GUEST_FN_INJECT:
{
- crDebug(("svcCall: SHCRGL_GUEST_FN_INJECT\n"));
+ Log(("svcCall: SHCRGL_GUEST_FN_INJECT\n"));
/* @todo: Verify */
if (cParams == 1)
@@ -1595,7 +3542,7 @@ int32_t crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t c
pClient->conn->pBuffer = pBuffer;
pClient->conn->cbBuffer = cbBuffer;
- CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr);
+ CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr, true);
rc = crVBoxServerInternalClientWriteRead(pClient);
CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
return rc;
@@ -1608,7 +3555,7 @@ int32_t crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t c
case SHCRGL_GUEST_FN_READ:
{
- crDebug(("svcCall: SHCRGL_GUEST_FN_READ\n"));
+ Log(("svcCall: SHCRGL_GUEST_FN_READ\n"));
/* @todo: Verify */
if (cParams == 1)
@@ -1651,6 +3598,7 @@ int32_t crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t c
/* the read command is never pended, complete it right away */
pHdr->result = rc;
+
crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
return VINF_SUCCESS;
}
@@ -1662,7 +3610,7 @@ int32_t crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t c
case SHCRGL_GUEST_FN_WRITE_READ:
{
- crDebug(("svcCall: SHCRGL_GUEST_FN_WRITE_READ\n"));
+ Log(("svcCall: SHCRGL_GUEST_FN_WRITE_READ\n"));
/* @todo: Verify */
if (cParams == 2)
@@ -1715,7 +3663,7 @@ int32_t crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t c
pClient->conn->pBuffer = pBuffer;
pClient->conn->cbBuffer = cbBuffer;
- CRVBOXHGSMI_CMDDATA_SETWB(&pClient->conn->CmdData, pCmd, pHdr, pWriteback, cbWriteback, &pFnCmd->cbWriteback);
+ CRVBOXHGSMI_CMDDATA_SETWB(&pClient->conn->CmdData, pCmd, pHdr, pWriteback, cbWriteback, &pFnCmd->cbWriteback, true);
rc = crVBoxServerInternalClientWriteRead(pClient);
CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
return rc;
@@ -1752,8 +3700,24 @@ int32_t crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t c
/* we can be on fail only here */
CRASSERT(RT_FAILURE(rc));
pHdr->result = rc;
+
crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
return rc;
+
+}
+
+static DECLCALLBACK(bool) crVBoxServerHasData()
+{
+ HCR_FRAMEBUFFER hFb = CrPMgrFbGetFirstEnabled();
+ for (;
+ hFb;
+ hFb = CrPMgrFbGetNextEnabled(hFb))
+ {
+ if (CrFbHas3DData(hFb))
+ return true;
+ }
+
+ return false;
}
int32_t crVBoxServerCrHgsmiCtl(struct VBOXVDMACMD_CHROMIUM_CTL *pCtl, uint32_t cbCtl)
@@ -1767,6 +3731,14 @@ int32_t crVBoxServerCrHgsmiCtl(struct VBOXVDMACMD_CHROMIUM_CTL *pCtl, uint32_t c
PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP pSetup = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP)pCtl;
g_pvVRamBase = (uint8_t*)pSetup->pvVRamBase;
g_cbVRam = pSetup->cbVRam;
+ pSetup->CrCmdServerInfo.hSvr = NULL;
+ pSetup->CrCmdServerInfo.pfnEnable = crVBoxCrCmdEnable;
+ pSetup->CrCmdServerInfo.pfnDisable = crVBoxCrCmdDisable;
+ pSetup->CrCmdServerInfo.pfnCmd = crVBoxCrCmdCmd;
+ pSetup->CrCmdServerInfo.pfnHostCtl = crVBoxCrCmdHostCtl;
+ pSetup->CrCmdServerInfo.pfnGuestCtl = crVBoxCrCmdGuestCtl;
+ pSetup->CrCmdServerInfo.pfnSaveState = crVBoxCrCmdSaveState;
+ pSetup->CrCmdServerInfo.pfnLoadState = crVBoxCrCmdLoadState;
rc = VINF_SUCCESS;
break;
}
@@ -1774,11 +3746,14 @@ int32_t crVBoxServerCrHgsmiCtl(struct VBOXVDMACMD_CHROMIUM_CTL *pCtl, uint32_t c
case VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_END:
rc = VINF_SUCCESS;
break;
- case VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_COMPLETION:
+ case VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_MAINCB:
{
- PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_COMPLETION pSetup = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_COMPLETION)pCtl;
+ PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_MAINCB pSetup = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_MAINCB)pCtl;
g_hCrHgsmiCompletion = pSetup->hCompletion;
g_pfnCrHgsmiCompletion = pSetup->pfnCompletion;
+
+ pSetup->MainInterface.pfnHasData = crVBoxServerHasData;
+
rc = VINF_SUCCESS;
break;
}
@@ -1795,4 +3770,40 @@ int32_t crVBoxServerCrHgsmiCtl(struct VBOXVDMACMD_CHROMIUM_CTL *pCtl, uint32_t c
* or Hgcm Host Fast Call commands that do require completion. All this details are hidden here */
return rc;
}
+
+int32_t crVBoxServerHgcmEnable(HVBOXCRCMDCTL_REMAINING_HOST_COMMAND hRHCmd, PFNVBOXCRCMDCTL_REMAINING_HOST_COMMAND pfnRHCmd)
+{
+ int rc = VINF_SUCCESS;
+ uint8_t* pCtl;
+ uint32_t cbCtl;
+
+ if (cr_server.numClients)
+ {
+ WARN(("cr_server.numClients(%d) is not NULL", cr_server.numClients));
+ return VERR_INVALID_STATE;
+ }
+
+ for (pCtl = pfnRHCmd(hRHCmd, &cbCtl, rc); pCtl; pCtl = pfnRHCmd(hRHCmd, &cbCtl, rc))
+ {
+ rc = crVBoxCrCmdHostCtl(NULL, pCtl, cbCtl);
+ }
+
+ crVBoxServerDefaultContextSet();
+
+ return VINF_SUCCESS;
+}
+
+int32_t crVBoxServerHgcmDisable()
+{
+ if (cr_server.numClients)
+ {
+ WARN(("cr_server.numClients(%d) is not NULL", cr_server.numClients));
+ return VERR_INVALID_STATE;
+ }
+
+ cr_server.head_spu->dispatch_table.MakeCurrent(0, 0, 0);
+
+ return VINF_SUCCESS;
+}
+
#endif