VirtualBox

source: vbox/trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/server_stream.cpp@ 79257

Last change on this file since 79257 was 78793, checked in by vboxsync, 6 years ago

HostServices/SharedOpenGL/crserverlib/server_stream.cpp: Fix buffer size calculation

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 27.7 KB
Line 
1/* Copyright (c) 2001, Stanford University
2 * All rights reserved
3 *
4 * See the file LICENSE.txt for information on redistributing this software.
5 */
6
7#include "server.h"
8#include "cr_unpack.h"
9#include "cr_error.h"
10#include "cr_mem.h"
11#include "server_dispatch.h"
12
13
14/**
15 * Accept a new client connection, create a new CRClient and add to run queue.
16 */
17void
18crServerAddNewClient(void)
19{
20 CRClient *newClient = (CRClient *) crCalloc(sizeof(CRClient));
21
22 if (newClient) {
23 newClient->spu_id = cr_server.client_spu_id;
24 newClient->conn = crNetAcceptClient( cr_server.protocol, NULL,
25 cr_server.tcpip_port,
26 cr_server.mtu, 1 );
27
28 newClient->currentCtxInfo = &cr_server.MainContextInfo;
29
30 /* add to array */
31 cr_server.clients[cr_server.numClients++] = newClient;
32
33 crServerAddToRunQueue( newClient );
34 }
35}
36
37
38/**
39 * Check if client is in the run queue.
40 */
41static GLboolean
42FindClientInQueue(CRClient *client)
43{
44 RunQueue *q = cr_server.run_queue;
45 while (q) {
46 if (q->client == client) {
47 return 1;
48 }
49 q = q->next;
50 if (q == cr_server.run_queue)
51 return 0; /* back head */
52 }
53 return 0;
54}
55
56
57#if 0
58static int
59PrintQueue(void)
60{
61 RunQueue *q = cr_server.run_queue;
62 int count = 0;
63 crDebug("Queue entries:");
64 while (q) {
65 count++;
66 crDebug("Entry: %p client: %p", q, q->client);
67 q = q->next;
68 if (q == cr_server.run_queue)
69 return count;
70 }
71 return count;
72}
73#endif
74
75
76void crServerAddToRunQueue( CRClient *client )
77{
78 RunQueue *q = (RunQueue *) crAlloc( sizeof( *q ) );
79
80#ifdef VBOX_WITH_CRHGSMI
81 client->conn->pClient = client;
82 CRVBOXHGSMI_CMDDATA_CLEANUP(&client->conn->CmdData);
83#endif
84
85 /* give this client a unique number if needed */
86 if (!client->number) {
87 client->number = client->conn->u32ClientID;
88 }
89
90 crDebug("Adding client %p to the run queue", client);
91
92 if (FindClientInQueue(client)) {
93 crError("CRServer: client %p already in the queue!", client);
94 }
95
96 q->client = client;
97 q->blocked = 0;
98
99 if (!cr_server.run_queue)
100 {
101 /* adding to empty queue */
102 cr_server.run_queue = q;
103 q->next = q;
104 q->prev = q;
105 }
106 else
107 {
108 /* insert in doubly-linked list */
109 q->next = cr_server.run_queue->next;
110 cr_server.run_queue->next->prev = q;
111
112 q->prev = cr_server.run_queue;
113 cr_server.run_queue->next = q;
114 }
115}
116
117static void crServerCleanupClient(CRClient *client)
118{
119 int32_t pos;
120 CRClient *oldclient = cr_server.curClient;
121
122 cr_server.curClient = client;
123
124 /* Destroy any windows created by the client */
125 for (pos = 0; pos<CR_MAX_WINDOWS; pos++)
126 {
127 if (client->windowList[pos])
128 {
129 cr_server.dispatch.WindowDestroy(client->windowList[pos]);
130 }
131 }
132
133 /* Check if we have context(s) made by this client left, could happen if client side code is lazy */
134 for (pos = 0; pos<CR_MAX_CONTEXTS; pos++)
135 {
136 if (client->contextList[pos])
137 {
138 cr_server.dispatch.DestroyContext(client->contextList[pos]);
139 }
140 }
141
142 cr_server.curClient = oldclient;
143}
144
145static void crServerCleanupByPID(uint64_t pid)
146{
147 CRClientNode *pNode=cr_server.pCleanupClient, *pNext;
148
149 while (pNode)
150 {
151 if (pNode->pClient->pid==pid)
152 {
153 crServerCleanupClient(pNode->pClient);
154 crFree(pNode->pClient);
155 if (pNode->prev)
156 {
157 pNode->prev->next=pNode->next;
158 }
159 else
160 {
161 cr_server.pCleanupClient=pNode->next;
162 }
163 if (pNode->next)
164 {
165 pNode->next->prev = pNode->prev;
166 }
167
168 pNext=pNode->next;
169 crFree(pNode);
170 pNode=pNext;
171 }
172 else
173 {
174 pNode=pNode->next;
175 }
176 }
177}
178
179void
180crServerDeleteClient( CRClient *client )
181{
182 int i, j;
183 int cleanup=1;
184
185 crDebug("Deleting client %p (%d msgs left)", client, crNetNumMessages(client->conn));
186
187#if 0
188 if (crNetNumMessages(client->conn) > 0) {
189 crDebug("Delay destroying client: message still pending");
190 return;
191 }
192#endif
193
194 if (!FindClientInQueue(client)) {
195 /* this should never happen */
196 crError("CRServer: client %p not found in the queue!", client);
197 }
198
199 /* remove from clients[] array */
200 for (i = 0; i < cr_server.numClients; i++) {
201 if (cr_server.clients[i] == client) {
202 /* found it */
203 for (j = i; j < cr_server.numClients - 1; j++)
204 cr_server.clients[j] = cr_server.clients[j + 1];
205 cr_server.numClients--;
206 break;
207 }
208 }
209
210 /* check if there're any other guest threads in same process */
211 for (i=0; i < cr_server.numClients; i++)
212 {
213 if (cr_server.clients[i]->pid==client->pid)
214 {
215 cleanup=0;
216 break;
217 }
218 }
219
220 if (cleanup)
221 {
222 crServerCleanupClient(client);
223 }
224
225 /* remove from the run queue */
226 if (cr_server.run_queue)
227 {
228 RunQueue *q = cr_server.run_queue;
229 RunQueue *qStart = cr_server.run_queue;
230 do {
231 if (q->client == client)
232 {
233 /* this test seems a bit excessive */
234 if ((q->next == q->prev) && (q->next == q) && (cr_server.run_queue == q))
235 {
236 /* We're removing/deleting the only client */
237 CRASSERT(cr_server.numClients == 0);
238 crFree(q);
239 cr_server.run_queue = NULL;
240 cr_server.curClient = NULL;
241 crDebug("Last client deleted - empty run queue.");
242 }
243 else
244 {
245 /* remove from doubly linked list and free the node */
246 if (cr_server.curClient == q->client)
247 cr_server.curClient = NULL;
248 if (cr_server.run_queue == q)
249 cr_server.run_queue = q->next;
250 q->prev->next = q->next;
251 q->next->prev = q->prev;
252 crFree(q);
253 }
254 break;
255 }
256 q = q->next;
257 } while (q != qStart);
258 }
259
260 crNetFreeConnection(client->conn);
261 client->conn = NULL;
262
263 if (cleanup)
264 {
265 crServerCleanupByPID(client->pid);
266 crFree(client);
267 }
268 else
269 {
270 CRClientNode *pNode = (CRClientNode *)crAlloc(sizeof(CRClientNode));
271 if (!pNode)
272 {
273 crWarning("Not enough memory, forcing client cleanup");
274 crServerCleanupClient(client);
275 crServerCleanupByPID(client->pid);
276 crFree(client);
277 return;
278 }
279 pNode->pClient = client;
280 pNode->prev = NULL;
281 pNode->next = cr_server.pCleanupClient;
282 cr_server.pCleanupClient = pNode;
283 }
284
285 if (!cr_server.numClients)
286 {
287 /* if no clients, the guest driver may be unloaded,
288 * and thus the visible regions situation might not be under control anymore,
289 * so cleanup the 3D framebuffer data here
290 * @todo: what really should happen is that guest driver on unload
291 * posts some request to host that would copy the current framebuffer 3D data to the 2D buffer
292 * (i.e. to the memory used by the standard IFramebuffer API) */
293 HCR_FRAMEBUFFER hFb;
294 for (hFb = CrPMgrFbGetFirstEnabled(); hFb; hFb = CrPMgrFbGetNextEnabled(hFb))
295 {
296 int rc = CrFbUpdateBegin(hFb);
297 if (RT_SUCCESS(rc))
298 {
299 CrFbRegionsClear(hFb);
300 CrFbUpdateEnd(hFb);
301 }
302 else
303 WARN(("CrFbUpdateBegin failed %d", rc));
304 }
305 }
306}
307
308/**
309 * Test if the given client is in the middle of a glBegin/End or
310 * glNewList/EndList pair.
311 * This is used to test if we can advance to the next client.
312 * \return GL_TRUE if so, GL_FALSE otherwise.
313 */
314GLboolean
315crServerClientInBeginEnd(const CRClient *client)
316{
317 if (client->currentCtxInfo
318 && client->currentCtxInfo->pContext
319 && (client->currentCtxInfo->pContext->lists.currentIndex != 0 ||
320 client->currentCtxInfo->pContext->current.inBeginEnd ||
321 client->currentCtxInfo->pContext->occlusion.currentQueryObject)) {
322 return GL_TRUE;
323 }
324 else {
325 return GL_FALSE;
326 }
327}
328
329
330/**
331 * Find the next client in the run queue that's not blocked and has a
332 * waiting message.
333 * Check if all clients are blocked (on barriers, semaphores), if so we've
334 * deadlocked!
335 * If no clients have a waiting message, call crNetRecv to get something
336 * if 'block' is true, else return NULL if 'block' if false.
337 */
338static RunQueue *
339getNextClient(GLboolean block)
340{
341 while (1)
342 {
343 if (cr_server.run_queue)
344 {
345 GLboolean all_blocked = GL_TRUE;
346 GLboolean done_something = GL_FALSE;
347 RunQueue *start = cr_server.run_queue;
348
349 /* check if this client's connection has gone away */
350 if (!cr_server.run_queue->client->conn
351 || (cr_server.run_queue->client->conn->type == CR_NO_CONNECTION
352 && crNetNumMessages(cr_server.run_queue->client->conn) == 0))
353 {
354 crServerDeleteClient( cr_server.run_queue->client );
355 start = cr_server.run_queue;
356 }
357
358 if (cr_server.run_queue == NULL) {
359 /* empty queue */
360 return NULL;
361 }
362
363 if (crServerClientInBeginEnd(cr_server.run_queue->client)) {
364 /* We _must_ service this client and no other.
365 * If we've got a message waiting on this client's connection we'll
366 * service it. Else, return NULL.
367 */
368 if (crNetNumMessages(cr_server.run_queue->client->conn) > 0)
369 return cr_server.run_queue;
370 else
371 return NULL;
372 }
373
374 /* loop over entries in run queue, looking for next one that's ready */
375 while (!done_something || cr_server.run_queue != start)
376 {
377 done_something = GL_TRUE;
378 if (!cr_server.run_queue->blocked)
379 {
380 all_blocked = GL_FALSE;
381 }
382 if (!cr_server.run_queue->blocked
383 && cr_server.run_queue->client->conn
384 && crNetNumMessages(cr_server.run_queue->client->conn) > 0)
385 {
386 /* OK, this client isn't blocked and has a queued message */
387 return cr_server.run_queue;
388 }
389 cr_server.run_queue = cr_server.run_queue->next;
390 }
391
392 if (all_blocked)
393 {
394 /* XXX crError is fatal? Should this be an info/warning msg? */
395 crError( "crserver: DEADLOCK! (numClients=%d, all blocked)",
396 cr_server.numClients );
397 if (cr_server.numClients < (int) cr_server.maxBarrierCount) {
398 crError("Waiting for more clients!!!");
399 while (cr_server.numClients < (int) cr_server.maxBarrierCount) {
400 crNetRecv();
401 }
402 }
403 }
404 }
405
406 if (!block)
407 return NULL;
408
409 /* no one had any work, get some! */
410 crNetRecv();
411
412 } /* while */
413
414 /* UNREACHED */
415 /* return NULL; */
416}
417
418typedef struct CR_SERVER_PENDING_MSG
419{
420 RTLISTNODE Node;
421 uint32_t cbMsg;
422 CRMessage Msg;
423} CR_SERVER_PENDING_MSG;
424
425static int crServerPendMsg(CRConnection *conn, const CRMessage *msg, int cbMsg)
426{
427 CR_SERVER_PENDING_MSG *pMsg;
428
429 if (!cbMsg)
430 {
431 WARN(("cbMsg is null!"));
432 return VERR_INVALID_PARAMETER;
433 }
434
435 pMsg = (CR_SERVER_PENDING_MSG*)RTMemAlloc(cbMsg + RT_UOFFSETOF(CR_SERVER_PENDING_MSG, Msg));
436 if (!pMsg)
437 {
438 WARN(("RTMemAlloc failed"));
439 return VERR_NO_MEMORY;
440 }
441
442 pMsg->cbMsg = cbMsg;
443
444 memcpy(&pMsg->Msg, msg, cbMsg);
445
446 RTListAppend(&conn->PendingMsgList, &pMsg->Node);
447
448 return VINF_SUCCESS;
449}
450
451int crServerPendSaveState(PSSMHANDLE pSSM)
452{
453 int i, rc;
454
455 for (i = 0; i < cr_server.numClients; i++)
456 {
457 CR_SERVER_PENDING_MSG *pIter;
458 CRClient *pClient = cr_server.clients[i];
459 CRConnection *pConn;
460 if (!pClient || !pClient->conn)
461 {
462 WARN(("invalid client state"));
463 continue;
464 }
465
466 pConn = pClient->conn;
467
468 if (RTListIsEmpty(&pConn->PendingMsgList))
469 continue;
470
471 CRASSERT(pConn->u32ClientID);
472
473 rc = SSMR3PutU32(pSSM, pConn->u32ClientID);
474 AssertRCReturn(rc, rc);
475
476 RTListForEach(&pConn->PendingMsgList, pIter, CR_SERVER_PENDING_MSG, Node)
477 {
478 CRASSERT(pIter->cbMsg);
479
480 rc = SSMR3PutU32(pSSM, pIter->cbMsg);
481 AssertRCReturn(rc, rc);
482
483 rc = SSMR3PutMem(pSSM, &pIter->Msg, pIter->cbMsg);
484 AssertRCReturn(rc, rc);
485 }
486
487 rc = SSMR3PutU32(pSSM, 0);
488 AssertRCReturn(rc, rc);
489 }
490
491 rc = SSMR3PutU32(pSSM, 0);
492 AssertRCReturn(rc, rc);
493
494 return VINF_SUCCESS;
495}
496
497int crServerPendLoadState(PSSMHANDLE pSSM, uint32_t u32Version)
498{
499 int rc;
500 uint32_t u32;
501 CRClient *pClient;
502
503 if (u32Version < SHCROGL_SSM_VERSION_WITH_PEND_CMD_INFO)
504 return VINF_SUCCESS;
505
506 rc = SSMR3GetU32(pSSM, &u32);
507 AssertRCReturn(rc, rc);
508
509 if (!u32)
510 return VINF_SUCCESS;
511
512 do {
513 rc = crVBoxServerClientGet(u32, &pClient);
514 AssertRCReturn(rc, rc);
515
516 for(;;)
517 {
518 CR_SERVER_PENDING_MSG *pMsg;
519
520 rc = SSMR3GetU32(pSSM, &u32);
521 AssertRCReturn(rc, rc);
522
523 if (!u32)
524 break;
525
526 pMsg = (CR_SERVER_PENDING_MSG*)RTMemAlloc(u32 + RT_UOFFSETOF(CR_SERVER_PENDING_MSG, Msg));
527 if (!pMsg)
528 {
529 WARN(("RTMemAlloc failed"));
530 return VERR_NO_MEMORY;
531 }
532
533 pMsg->cbMsg = u32;
534 rc = SSMR3GetMem(pSSM, &pMsg->Msg, u32);
535 AssertRCReturn(rc, rc);
536
537 RTListAppend(&pClient->conn->PendingMsgList, &pMsg->Node);
538 }
539
540 rc = SSMR3GetU32(pSSM, &u32);
541 AssertRCReturn(rc, rc);
542 } while (u32);
543
544 rc = SSMR3GetU32(pSSM, &u32);
545 AssertRCReturn(rc, rc);
546
547 return VINF_SUCCESS;
548}
549
550static void crServerPendProcess(CRConnection *conn)
551{
552 CR_SERVER_PENDING_MSG *pIter, *pNext;
553
554 cr_server.fProcessingPendedCommands = GL_TRUE;
555
556 RTListForEachSafe(&conn->PendingMsgList, pIter, pNext, CR_SERVER_PENDING_MSG, Node)
557 {
558 CRMessage *msg = &pIter->Msg;
559 const CRMessageOpcodes *msg_opcodes;
560 int opcodeBytes;
561 const uint8_t *data_ptr, *data_ptr_end;
562
563 RTListNodeRemove(&pIter->Node);
564
565 CRASSERT(msg->header.type == CR_MESSAGE_OPCODES);
566
567 msg_opcodes = (const CRMessageOpcodes *) msg;
568 opcodeBytes = (msg_opcodes->numOpcodes + 3) & ~0x03;
569
570 data_ptr = (const uint8_t *) msg_opcodes + sizeof (CRMessageOpcodes) + opcodeBytes;
571 data_ptr_end = (const uint8_t *)msg_opcodes + pIter->cbMsg;
572
573 CrUnpackerState UnpackerState;
574 UnpackerState.pbOpcodes = data_ptr - 1;
575 UnpackerState.cOpcodes = msg_opcodes->numOpcodes;
576 UnpackerState.pbUnpackData = data_ptr;
577 UnpackerState.cbUnpackDataLeft = data_ptr - data_ptr_end;
578 UnpackerState.pReturnPtr = &cr_server.return_ptr;
579 UnpackerState.pWritebackPtr = &cr_server.writeback_ptr;
580 UnpackerState.pDispatchTbl = &(cr_server.dispatch);
581 UnpackerState.rcUnpack = VINF_SUCCESS;
582 UnpackerState.pStateTracker = &cr_server.StateTracker;
583
584 cr_server.pUnpackerState = &UnpackerState;
585 crUnpack(&UnpackerState);
586 cr_server.pUnpackerState = NULL;
587 RTMemFree(pIter);
588 }
589
590 cr_server.fProcessingPendedCommands = GL_FALSE;
591}
592
593/**
594 * This function takes the given message (which should be a buffer of
595 * rendering commands) and executes it.
596 */
597static void
598crServerDispatchMessage(CRConnection *conn, CRMessage *msg, int cbMsg)
599{
600 const CRMessageOpcodes *msg_opcodes;
601 int opcodeBytes;
602 const uint8_t *data_ptr, *data_ptr_end;
603#ifdef VBOX_WITH_CRHGSMI
604 PCRVBOXHGSMI_CMDDATA pCmdData = NULL;
605#endif
606 CR_UNPACK_BUFFER_TYPE enmType;
607 bool fUnpack = true;
608
609 if (msg->header.type == CR_MESSAGE_REDIR_PTR)
610 {
611#ifdef VBOX_WITH_CRHGSMI
612 pCmdData = &msg->redirptr.CmdData;
613#endif
614 msg = (CRMessage *) msg->redirptr.pMessage;
615 }
616
617 CRASSERT(msg->header.type == CR_MESSAGE_OPCODES);
618
619 msg_opcodes = (const CRMessageOpcodes *) msg;
620 opcodeBytes = (msg_opcodes->numOpcodes + 3) & ~0x03;
621
622#ifdef VBOXCR_LOGFPS
623 CRASSERT(cr_server.curClient && cr_server.curClient->conn && cr_server.curClient->conn->id == msg->header.conn_id);
624 cr_server.curClient->conn->opcodes_count += msg_opcodes->numOpcodes;
625#endif
626
627 data_ptr = (const uint8_t *) msg_opcodes + sizeof(CRMessageOpcodes) + opcodeBytes;
628 data_ptr_end = (const uint8_t *)msg_opcodes + cbMsg; // Pointer to the first byte after message data
629
630 enmType = crUnpackGetBufferType(data_ptr - 1, /* first command's opcode */
631 msg_opcodes->numOpcodes /* how many opcodes */);
632 switch (enmType)
633 {
634 case CR_UNPACK_BUFFER_TYPE_GENERIC:
635 {
636 if (RTListIsEmpty(&conn->PendingMsgList))
637 break;
638
639 if (RT_SUCCESS(crServerPendMsg(conn, msg, cbMsg)))
640 {
641 fUnpack = false;
642 break;
643 }
644
645 WARN(("crServerPendMsg failed"));
646 crServerPendProcess(conn);
647 break;
648 }
649 case CR_UNPACK_BUFFER_TYPE_CMDBLOCK_BEGIN:
650 {
651 if (RTListIsEmpty(&conn->PendingMsgList))
652 {
653 if (RT_SUCCESS(crServerPendMsg(conn, msg, cbMsg)))
654 {
655 Assert(!RTListIsEmpty(&conn->PendingMsgList));
656 fUnpack = false;
657 break;
658 }
659 else
660 WARN(("crServerPendMsg failed"));
661 }
662 else
663 WARN(("Pend List is NOT empty, drain the current list, and ignore this command"));
664
665 crServerPendProcess(conn);
666 break;
667 }
668 case CR_UNPACK_BUFFER_TYPE_CMDBLOCK_FLUSH: /* just flush for now */
669 {
670 CrPMgrClearRegionsGlobal(); /* clear regions to ensure we don't do MakeCurrent and friends */
671 crServerPendProcess(conn);
672 Assert(RTListIsEmpty(&conn->PendingMsgList));
673 break;
674 }
675 case CR_UNPACK_BUFFER_TYPE_CMDBLOCK_END:
676 {
677// CRASSERT(!RTListIsEmpty(&conn->PendingMsgList));
678 crServerPendProcess(conn);
679 Assert(RTListIsEmpty(&conn->PendingMsgList));
680 break;
681 }
682 default:
683 WARN(("unsupported buffer type"));
684 break;
685 }
686
687 if (fUnpack)
688 {
689 CrUnpackerState UnpackerState;
690 UnpackerState.pbOpcodes = data_ptr - 1;
691 UnpackerState.cOpcodes = msg_opcodes->numOpcodes;
692 UnpackerState.pbUnpackData = data_ptr;
693 UnpackerState.cbUnpackDataLeft = data_ptr_end - data_ptr;
694 UnpackerState.pReturnPtr = &cr_server.return_ptr;
695 UnpackerState.pWritebackPtr = &cr_server.writeback_ptr;
696 UnpackerState.pDispatchTbl = &(cr_server.dispatch);
697 UnpackerState.rcUnpack = VINF_SUCCESS;
698 UnpackerState.pStateTracker = &cr_server.StateTracker;
699
700 cr_server.pUnpackerState = &UnpackerState;
701 crUnpack(&UnpackerState);
702 cr_server.pUnpackerState = NULL;
703 }
704
705#ifdef VBOX_WITH_CRHGSMI
706 if (pCmdData)
707 {
708 int rc = VINF_SUCCESS;
709 CRVBOXHGSMI_CMDDATA_ASSERT_CONSISTENT(pCmdData);
710 if (CRVBOXHGSMI_CMDDATA_IS_SETWB(pCmdData))
711 {
712 uint32_t cbWriteback = pCmdData->cbWriteback;
713 rc = crVBoxServerInternalClientRead(conn->pClient, (uint8_t*)pCmdData->pWriteback, &cbWriteback);
714 Assert(rc == VINF_SUCCESS || rc == VERR_BUFFER_OVERFLOW);
715 *pCmdData->pcbWriteback = cbWriteback;
716 }
717 VBOXCRHGSMI_CMD_CHECK_COMPLETE(pCmdData, rc);
718 }
719#endif
720}
721
722
723typedef enum
724{
725 CLIENT_GONE = 1, /* the client has disconnected */
726 CLIENT_NEXT = 2, /* we can advance to next client */
727 CLIENT_MORE = 3 /* we need to keep servicing current client */
728} ClientStatus;
729
730
731/**
732 * Process incoming/pending message for the given client (queue entry).
733 * \return CLIENT_GONE if this client has gone away/exited,
734 * CLIENT_NEXT if we can advance to the next client
735 * CLIENT_MORE if we have to process more messages for this client.
736 */
737static ClientStatus
738crServerServiceClient(const RunQueue *qEntry)
739{
740 CRMessage *msg;
741 CRConnection *conn;
742
743 /* set current client pointer */
744 cr_server.curClient = qEntry->client;
745
746 conn = cr_server.run_queue->client->conn;
747
748 /* service current client as long as we can */
749 while (conn && conn->type != CR_NO_CONNECTION &&
750 crNetNumMessages(conn) > 0) {
751 unsigned int len;
752
753 /*
754 crDebug("%d messages on %p",
755 crNetNumMessages(conn), (void *) conn);
756 */
757
758 /* Don't use GetMessage, because we want to do our own crNetRecv() calls
759 * here ourself.
760 * Note that crNetPeekMessage() DOES remove the message from the queue
761 * if there is one.
762 */
763 len = crNetPeekMessage( conn, &msg );
764 CRASSERT(len > 0);
765 if (msg->header.type != CR_MESSAGE_OPCODES
766 && msg->header.type != CR_MESSAGE_REDIR_PTR) {
767 crError( "SPU %d sent me CRAP (type=0x%x)",
768 cr_server.curClient->spu_id, msg->header.type );
769 }
770
771 /* Do the context switch here. No sense in switching before we
772 * really have any work to process. This is a no-op if we're
773 * not really switching contexts.
774 *
775 * XXX This isn't entirely sound. The crStateMakeCurrent() call
776 * will compute the state difference and dispatch it using
777 * the head SPU's dispatch table.
778 *
779 * This is a problem if this is the first buffer coming in,
780 * and the head SPU hasn't had a chance to do a MakeCurrent()
781 * yet (likely because the MakeCurrent() command is in the
782 * buffer itself).
783 *
784 * At best, in this case, the functions are no-ops, and
785 * are essentially ignored by the SPU. In the typical
786 * case, things aren't too bad; if the SPU just calls
787 * crState*() functions to update local state, everything
788 * will work just fine.
789 *
790 * In the worst (but unusual) case where a nontrivial
791 * SPU is at the head of a crserver's SPU chain (say,
792 * in a multiple-tiered "tilesort" arrangement, as
793 * seen in the "multitilesort.conf" configuration), the
794 * SPU may rely on state set during the MakeCurrent() that
795 * may not be present yet, because no MakeCurrent() has
796 * yet been dispatched.
797 *
798 * This headache will have to be revisited in the future;
799 * for now, SPUs that could head a crserver's SPU chain
800 * will have to detect the case that their functions are
801 * being called outside of a MakeCurrent(), and will have
802 * to handle the situation gracefully. (This is currently
803 * the case with the "tilesort" SPU.)
804 */
805
806#if 0
807 crStateMakeCurrent( cr_server.curClient->currentCtx );
808#else
809 /* Check if the current window is the one that the client wants to
810 * draw into. If not, dispatch a MakeCurrent to activate the proper
811 * window.
812 */
813 if (cr_server.curClient) {
814 int clientWindow = cr_server.curClient->currentWindow;
815 int clientContext = cr_server.curClient->currentContextNumber;
816 CRContextInfo *clientCtxInfo = cr_server.curClient->currentCtxInfo;
817 if (clientCtxInfo != cr_server.currentCtxInfo
818 || clientWindow != cr_server.currentWindow
819 || cr_server.bForceMakeCurrentOnClientSwitch) {
820 crServerDispatchMakeCurrent(clientWindow, 0, clientContext);
821 /*
822 CRASSERT(cr_server.currentWindow == clientWindow);
823 */
824 }
825 }
826#endif
827
828 /* Force scissor, viewport and projection matrix update in
829 * crServerSetOutputBounds().
830 */
831 cr_server.currentSerialNo = 0;
832
833 /* Commands get dispatched here */
834 crServerDispatchMessage( conn, msg, len );
835
836 crNetFree( conn, msg );
837
838 if (qEntry->blocked) {
839 /* Note/assert: we should not be inside a glBegin/End or glNewList/
840 * glEndList pair at this time!
841 */
842 CRASSERT(0);
843 return CLIENT_NEXT;
844 }
845
846 } /* while */
847
848 /*
849 * Check if client/connection is gone
850 */
851 if (!conn || conn->type == CR_NO_CONNECTION) {
852 crDebug("Delete client %p at %d", cr_server.run_queue->client, __LINE__);
853 crServerDeleteClient( cr_server.run_queue->client );
854 return CLIENT_GONE;
855 }
856
857 /*
858 * Determine if we can advance to next client.
859 * If we're currently inside a glBegin/End primitive or building a display
860 * list we can't service another client until we're done with the
861 * primitive/list.
862 */
863 if (crServerClientInBeginEnd(cr_server.curClient)) {
864 /* The next message has to come from the current client's connection. */
865 CRASSERT(!qEntry->blocked);
866 return CLIENT_MORE;
867 }
868 else {
869 /* get next client */
870 return CLIENT_NEXT;
871 }
872}
873
874
875
876/**
877 * Check if any of the clients need servicing.
878 * If so, service one client and return.
879 * Else, just return.
880 */
881void
882crServerServiceClients(void)
883{
884 RunQueue *q;
885
886 q = getNextClient(GL_FALSE); /* don't block */
887 while (q)
888 {
889 ClientStatus stat = crServerServiceClient(q);
890 if (stat == CLIENT_NEXT && cr_server.run_queue->next) {
891 /* advance to next client */
892 cr_server.run_queue = cr_server.run_queue->next;
893 }
894 q = getNextClient(GL_FALSE);
895 }
896}
897
898
899
900
901/**
902 * Main crserver loop. Service connections from all connected clients.
903 * XXX add a config option to specify whether the crserver
904 * should exit when there's no more clients.
905 */
906void
907crServerSerializeRemoteStreams(void)
908{
909 /*MSG msg;*/
910
911 while (cr_server.run_queue)
912 {
913 crServerServiceClients();
914 /*if (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
915 {
916 if (msg.message == WM_QUIT)
917 {
918 PostQuitMessage((int)msg.wParam);
919 break;
920 }
921 TranslateMessage( &msg );
922 DispatchMessage( &msg );
923 }*/
924 }
925}
926
927
928/**
929 * This will be called by the network layer when it's received a new message.
930 */
931int
932crServerRecv( CRConnection *conn, CRMessage *msg, unsigned int len )
933{
934 RT_NOREF(conn);
935
936 CRMessage *pRealMsg;
937 (void) len;
938
939 pRealMsg = (msg->header.type!=CR_MESSAGE_REDIR_PTR) ? msg : (CRMessage*) msg->redirptr.pMessage;
940
941 switch( pRealMsg->header.type )
942 {
943 /* Called when using multiple threads */
944 case CR_MESSAGE_NEWCLIENT:
945 crServerAddNewClient();
946 return 1; /* msg handled */
947 default:
948 /*crWarning( "Why is the crserver getting a message of type 0x%x?",
949 msg->header.type ); */
950 ;
951 }
952 return 0; /* not handled */
953}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette