VirtualBox

source: vbox/trunk/src/VBox/Devices/Graphics/DevVGA_VDMA.cpp@ 33000

Last change on this file since 33000 was 32904, checked in by vboxsync, 14 years ago

wddm/3d: better shgsmi channel perf test

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 26.9 KB
Line 
1/** @file
2 * Video DMA (VDMA) support.
3 */
4
5/*
6 * Copyright (C) 2006-2009 Oracle Corporation
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 */
16//#include <VBox/VMMDev.h>
17#include <VBox/pdmdev.h>
18#include <VBox/VBoxVideo.h>
19#include <iprt/semaphore.h>
20#include <iprt/thread.h>
21#include <iprt/mem.h>
22
23#include "DevVGA.h"
24#include "HGSMI/SHGSMIHost.h"
25#include "HGSMI/HGSMIHostHlp.h"
26
27typedef enum
28{
29 VBOXVDMAPIPE_STATE_CLOSED = 0,
30 VBOXVDMAPIPE_STATE_CREATED = 1,
31 VBOXVDMAPIPE_STATE_OPENNED = 2,
32 VBOXVDMAPIPE_STATE_CLOSING = 3
33} VBOXVDMAPIPE_STATE;
34
35typedef struct VBOXVDMAPIPE
36{
37 RTSEMEVENT hEvent;
38 /* critical section for accessing pipe properties */
39 RTCRITSECT hCritSect;
40 VBOXVDMAPIPE_STATE enmState;
41 /* true iff the other end needs Event notification */
42 bool bNeedNotify;
43} VBOXVDMAPIPE, *PVBOXVDMAPIPE;
44
45typedef enum
46{
47 VBOXVDMAPIPE_CMD_TYPE_UNDEFINED = 0,
48 VBOXVDMAPIPE_CMD_TYPE_DMACMD = 1,
49 VBOXVDMAPIPE_CMD_TYPE_DMACTL = 2
50} VBOXVDMAPIPE_CMD_TYPE;
51
52typedef struct VBOXVDMAPIPE_CMD_BODY
53{
54 VBOXVDMAPIPE_CMD_TYPE enmType;
55 union
56 {
57 PVBOXVDMACBUF_DR pDr;
58 PVBOXVDMA_CTL pCtl;
59 void *pvCmd;
60 } u;
61}VBOXVDMAPIPE_CMD_BODY, *PVBOXVDMAPIPE_CMD_BODY;
62
63typedef struct VBOXVDMAPIPE_CMD
64{
65 HGSMILISTENTRY Entry;
66 VBOXVDMAPIPE_CMD_BODY Cmd;
67} VBOXVDMAPIPE_CMD, *PVBOXVDMAPIPE_CMD;
68
69#define VBOXVDMAPIPE_CMD_FROM_ENTRY(_pE) ( (PVBOXVDMAPIPE_CMD)((uint8_t *)(_pE) - RT_OFFSETOF(VBOXVDMAPIPE_CMD, Entry)) )
70
71typedef struct VBOXVDMAPIPE_CMD_POOL
72{
73 HGSMILIST List;
74 uint32_t cCmds;
75 VBOXVDMAPIPE_CMD aCmds[1];
76} VBOXVDMAPIPE_CMD_POOL, *PVBOXVDMAPIPE_CMD_POOL;
77
78typedef struct VBOXVDMAHOST
79{
80 VBOXVDMAPIPE Pipe;
81 HGSMILIST PendingList;
82 RTTHREAD hWorkerThread;
83 PHGSMIINSTANCE pHgsmi;
84 PVGASTATE pVGAState;
85 bool bEnabled;
86 VBOXVDMAPIPE_CMD_POOL CmdPool;
87} VBOXVDMAHOST, *PVBOXVDMAHOST;
88
89/* to simplify things and to avoid extra backend if modifications we assume the VBOXVDMA_RECTL is the same as VBVACMDHDR */
90AssertCompile(sizeof(VBOXVDMA_RECTL) == sizeof(VBVACMDHDR));
91AssertCompile(RT_SIZEOFMEMB(VBOXVDMA_RECTL, left) == RT_SIZEOFMEMB(VBVACMDHDR, x));
92AssertCompile(RT_SIZEOFMEMB(VBOXVDMA_RECTL, top) == RT_SIZEOFMEMB(VBVACMDHDR, y));
93AssertCompile(RT_SIZEOFMEMB(VBOXVDMA_RECTL, width) == RT_SIZEOFMEMB(VBVACMDHDR, w));
94AssertCompile(RT_SIZEOFMEMB(VBOXVDMA_RECTL, height) == RT_SIZEOFMEMB(VBVACMDHDR, h));
95AssertCompile(RT_OFFSETOF(VBOXVDMA_RECTL, left) == RT_OFFSETOF(VBVACMDHDR, x));
96AssertCompile(RT_OFFSETOF(VBOXVDMA_RECTL, top) == RT_OFFSETOF(VBVACMDHDR, y));
97AssertCompile(RT_OFFSETOF(VBOXVDMA_RECTL, width) == RT_OFFSETOF(VBVACMDHDR, w));
98AssertCompile(RT_OFFSETOF(VBOXVDMA_RECTL, height) == RT_OFFSETOF(VBVACMDHDR, h));
99
100static int vboxVDMANotifyPrimaryUpdate (PVGASTATE pVGAState, unsigned uScreenId, const VBOXVDMA_RECTL * pRectl)
101{
102 pVGAState->pDrv->pfnVBVAUpdateBegin (pVGAState->pDrv, uScreenId);
103
104 /* Updates the rectangle and sends the command to the VRDP server. */
105 pVGAState->pDrv->pfnVBVAUpdateProcess (pVGAState->pDrv, uScreenId,
106 (const PVBVACMDHDR)pRectl /* <- see above AssertCompile's and comments */,
107 sizeof (VBOXVDMA_RECTL));
108
109 pVGAState->pDrv->pfnVBVAUpdateEnd (pVGAState->pDrv, uScreenId, pRectl->left, pRectl->top,
110 pRectl->width, pRectl->height);
111
112 return VINF_SUCCESS;
113}
114
115static int vboxVDMACmdExecBltPerform(PVBOXVDMAHOST pVdma,
116 uint8_t *pvDstSurf, const uint8_t *pvSrcSurf,
117 const PVBOXVDMA_SURF_DESC pDstDesc, const PVBOXVDMA_SURF_DESC pSrcDesc,
118 const VBOXVDMA_RECTL * pDstRectl, const VBOXVDMA_RECTL * pSrcRectl)
119{
120 /* we do not support color conversion */
121 Assert(pDstDesc->format == pSrcDesc->format);
122 /* we do not support stretching */
123 Assert(pDstRectl->height == pSrcRectl->height);
124 Assert(pDstRectl->width == pSrcRectl->width);
125 if (pDstDesc->format != pSrcDesc->format)
126 return VERR_INVALID_FUNCTION;
127 if (pDstDesc->width == pDstRectl->width
128 && pSrcDesc->width == pSrcRectl->width
129 && pSrcDesc->width == pDstDesc->width)
130 {
131 Assert(!pDstRectl->left);
132 Assert(!pSrcRectl->left);
133 uint32_t cbOff = pDstDesc->pitch * pDstRectl->top;
134 uint32_t cbSize = pDstDesc->pitch * pDstRectl->height;
135 memcpy(pvDstSurf + cbOff, pvSrcSurf + cbOff, cbSize);
136 }
137 else
138 {
139 uint32_t offDstLineStart = pDstRectl->left * pDstDesc->bpp >> 3;
140 uint32_t offDstLineEnd = ((pDstRectl->left * pDstDesc->bpp + 7) >> 3) + ((pDstDesc->bpp * pDstRectl->width + 7) >> 3);
141 uint32_t cbDstLine = offDstLineEnd - offDstLineStart;
142 uint32_t offDstStart = pDstDesc->pitch * pDstRectl->top + offDstLineStart;
143 Assert(cbDstLine <= pDstDesc->pitch);
144 uint32_t cbDstSkip = pDstDesc->pitch;
145 uint8_t * pvDstStart = pvDstSurf + offDstStart;
146
147 uint32_t offSrcLineStart = pSrcRectl->left * pSrcDesc->bpp >> 3;
148 uint32_t offSrcLineEnd = ((pSrcRectl->left * pSrcDesc->bpp + 7) >> 3) + ((pSrcDesc->bpp * pSrcRectl->width + 7) >> 3);
149 uint32_t cbSrcLine = offSrcLineEnd - offSrcLineStart;
150 uint32_t offSrcStart = pSrcDesc->pitch * pSrcRectl->top + offSrcLineStart;
151 Assert(cbSrcLine <= pSrcDesc->pitch);
152 uint32_t cbSrcSkip = pSrcDesc->pitch;
153 const uint8_t * pvSrcStart = pvSrcSurf + offSrcStart;
154
155 Assert(cbDstLine == cbSrcLine);
156
157 for (uint32_t i = 0; ; ++i)
158 {
159 memcpy (pvDstStart, pvSrcStart, cbDstLine);
160 if (i == pDstRectl->height)
161 break;
162 pvDstStart += cbDstSkip;
163 pvSrcStart += cbSrcSkip;
164 }
165 }
166 return VINF_SUCCESS;
167}
168
169static void vboxVDMARectlUnite(VBOXVDMA_RECTL * pRectl1, const VBOXVDMA_RECTL * pRectl2)
170{
171 if (!pRectl1->width)
172 *pRectl1 = *pRectl2;
173 else
174 {
175 int16_t x21 = pRectl1->left + pRectl1->width;
176 int16_t x22 = pRectl2->left + pRectl2->width;
177 if (pRectl1->left > pRectl2->left)
178 {
179 pRectl1->left = pRectl2->left;
180 pRectl1->width = x21 < x22 ? x22 - pRectl1->left : x21 - pRectl1->left;
181 }
182 else if (x21 < x22)
183 pRectl1->width = x22 - pRectl1->left;
184
185 x21 = pRectl1->top + pRectl1->height;
186 x22 = pRectl2->top + pRectl2->height;
187 if (pRectl1->top > pRectl2->top)
188 {
189 pRectl1->top = pRectl2->top;
190 pRectl1->height = x21 < x22 ? x22 - pRectl1->top : x21 - pRectl1->top;
191 }
192 else if (x21 < x22)
193 pRectl1->height = x22 - pRectl1->top;
194 }
195}
196
197/*
198 * @return on success the number of bytes the command contained, otherwise - VERR_xxx error code
199 */
200static int vboxVDMACmdExecBlt(PVBOXVDMAHOST pVdma, const PVBOXVDMACMD_DMA_PRESENT_BLT pBlt, uint32_t cbBuffer)
201{
202 const uint32_t cbBlt = VBOXVDMACMD_BODY_FIELD_OFFSET(uint32_t, VBOXVDMACMD_DMA_PRESENT_BLT, aDstSubRects[pBlt->cDstSubRects]);
203 Assert(cbBlt <= cbBuffer);
204 if (cbBuffer < cbBlt)
205 return VERR_INVALID_FUNCTION;
206
207 /* we do not support stretching for now */
208 Assert(pBlt->srcRectl.width == pBlt->dstRectl.width);
209 Assert(pBlt->srcRectl.height == pBlt->dstRectl.height);
210 if (pBlt->srcRectl.width != pBlt->dstRectl.width)
211 return VERR_INVALID_FUNCTION;
212 if (pBlt->srcRectl.height != pBlt->dstRectl.height)
213 return VERR_INVALID_FUNCTION;
214 Assert(pBlt->cDstSubRects);
215
216 uint8_t * pvRam = pVdma->pVGAState->vram_ptrR3;
217 VBOXVDMA_RECTL updateRectl = {0};
218
219 if (pBlt->cDstSubRects)
220 {
221 VBOXVDMA_RECTL dstRectl, srcRectl;
222 const VBOXVDMA_RECTL *pDstRectl, *pSrcRectl;
223 for (uint32_t i = 0; i < pBlt->cDstSubRects; ++i)
224 {
225 pDstRectl = &pBlt->aDstSubRects[i];
226 if (pBlt->dstRectl.left || pBlt->dstRectl.top)
227 {
228 dstRectl.left = pDstRectl->left + pBlt->dstRectl.left;
229 dstRectl.top = pDstRectl->top + pBlt->dstRectl.top;
230 dstRectl.width = pDstRectl->width;
231 dstRectl.height = pDstRectl->height;
232 pDstRectl = &dstRectl;
233 }
234
235 pSrcRectl = &pBlt->aDstSubRects[i];
236 if (pBlt->srcRectl.left || pBlt->srcRectl.top)
237 {
238 srcRectl.left = pSrcRectl->left + pBlt->srcRectl.left;
239 srcRectl.top = pSrcRectl->top + pBlt->srcRectl.top;
240 srcRectl.width = pSrcRectl->width;
241 srcRectl.height = pSrcRectl->height;
242 pSrcRectl = &srcRectl;
243 }
244
245 int rc = vboxVDMACmdExecBltPerform(pVdma, pvRam + pBlt->offDst, pvRam + pBlt->offSrc,
246 &pBlt->dstDesc, &pBlt->srcDesc,
247 pDstRectl,
248 pSrcRectl);
249 AssertRC(rc);
250 if (!RT_SUCCESS(rc))
251 return rc;
252
253 vboxVDMARectlUnite(&updateRectl, pDstRectl);
254 }
255 }
256 else
257 {
258 int rc = vboxVDMACmdExecBltPerform(pVdma, pvRam + pBlt->offDst, pvRam + pBlt->offSrc,
259 &pBlt->dstDesc, &pBlt->srcDesc,
260 &pBlt->dstRectl,
261 &pBlt->srcRectl);
262 AssertRC(rc);
263 if (!RT_SUCCESS(rc))
264 return rc;
265
266 vboxVDMARectlUnite(&updateRectl, &pBlt->dstRectl);
267 }
268
269 int iView = 0;
270 /* @todo: fixme: check if update is needed and get iView */
271 vboxVDMANotifyPrimaryUpdate (pVdma->pVGAState, iView, &updateRectl);
272
273 return cbBlt;
274}
275
276static int vboxVDMACmdExec(PVBOXVDMAHOST pVdma, const uint8_t *pvBuffer, uint32_t cbBuffer)
277{
278 do
279 {
280 Assert(pvBuffer);
281 Assert(cbBuffer >= VBOXVDMACMD_HEADER_SIZE());
282
283 if (!pvBuffer)
284 return VERR_INVALID_PARAMETER;
285 if (cbBuffer < VBOXVDMACMD_HEADER_SIZE())
286 return VERR_INVALID_PARAMETER;
287
288 PVBOXVDMACMD pCmd = (PVBOXVDMACMD)pvBuffer;
289 uint32_t cbCmd = 0;
290 switch (pCmd->enmType)
291 {
292 case VBOXVDMACMD_TYPE_CHROMIUM_CMD:
293 {
294#ifdef VBOXWDDM_TEST_UHGSMI
295 static int count = 0;
296 static uint64_t start, end;
297 if (count==0)
298 {
299 start = RTTimeNanoTS();
300 }
301 ++count;
302 if (count==100000)
303 {
304 end = RTTimeNanoTS();
305 float ems = (end-start)/1000000.f;
306 LogRel(("100000 calls took %i ms, %i cps\n", (int)ems, (int)(100000.f*1000.f/ems) ));
307 }
308#endif
309 /* todo: post the buffer to chromium */
310 return VINF_SUCCESS;
311 }
312 case VBOXVDMACMD_TYPE_DMA_PRESENT_BLT:
313 {
314 const PVBOXVDMACMD_DMA_PRESENT_BLT pBlt = VBOXVDMACMD_BODY(pCmd, VBOXVDMACMD_DMA_PRESENT_BLT);
315 int cbBlt = vboxVDMACmdExecBlt(pVdma, pBlt, cbBuffer);
316 Assert(cbBlt >= 0);
317 Assert((uint32_t)cbBlt <= cbBuffer);
318 if (cbBlt >= 0)
319 {
320 if (cbBlt == cbBuffer)
321 return VINF_SUCCESS;
322 else
323 {
324 cbBuffer -= (uint32_t)cbBlt;
325 pvBuffer -= cbBlt;
326 }
327 }
328 else
329 return cbBlt; /* error */
330 break;
331 }
332 default:
333 AssertBreakpoint();
334 return VERR_INVALID_FUNCTION;
335 }
336 } while (1);
337
338 /* we should not be here */
339 AssertBreakpoint();
340 return VERR_INVALID_STATE;
341}
342
343int vboxVDMAPipeConstruct(PVBOXVDMAPIPE pPipe)
344{
345 int rc = RTSemEventCreate(&pPipe->hEvent);
346 AssertRC(rc);
347 if (RT_SUCCESS(rc))
348 {
349 rc = RTCritSectInit(&pPipe->hCritSect);
350 AssertRC(rc);
351 if (RT_SUCCESS(rc))
352 {
353 pPipe->enmState = VBOXVDMAPIPE_STATE_CREATED;
354 pPipe->bNeedNotify = true;
355 return VINF_SUCCESS;
356// RTCritSectDelete(pPipe->hCritSect);
357 }
358 RTSemEventDestroy(pPipe->hEvent);
359 }
360 return rc;
361}
362
363int vboxVDMAPipeOpenServer(PVBOXVDMAPIPE pPipe)
364{
365 int rc = RTCritSectEnter(&pPipe->hCritSect);
366 AssertRC(rc);
367 if (RT_SUCCESS(rc))
368 {
369 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CREATED);
370 switch (pPipe->enmState)
371 {
372 case VBOXVDMAPIPE_STATE_CREATED:
373 pPipe->enmState = VBOXVDMAPIPE_STATE_OPENNED;
374 pPipe->bNeedNotify = false;
375 rc = VINF_SUCCESS;
376 break;
377 case VBOXVDMAPIPE_STATE_OPENNED:
378 pPipe->bNeedNotify = false;
379 rc = VINF_ALREADY_INITIALIZED;
380 break;
381 default:
382 AssertBreakpoint();
383 rc = VERR_INVALID_STATE;
384 break;
385 }
386
387 RTCritSectLeave(&pPipe->hCritSect);
388 }
389 return rc;
390}
391
392int vboxVDMAPipeCloseServer(PVBOXVDMAPIPE pPipe)
393{
394 int rc = RTCritSectEnter(&pPipe->hCritSect);
395 AssertRC(rc);
396 if (RT_SUCCESS(rc))
397 {
398 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED
399 || pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSING);
400 switch (pPipe->enmState)
401 {
402 case VBOXVDMAPIPE_STATE_CLOSING:
403 pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSED;
404 rc = VINF_SUCCESS;
405 break;
406 case VBOXVDMAPIPE_STATE_CLOSED:
407 rc = VINF_ALREADY_INITIALIZED;
408 break;
409 default:
410 AssertBreakpoint();
411 rc = VERR_INVALID_STATE;
412 break;
413 }
414
415 RTCritSectLeave(&pPipe->hCritSect);
416 }
417 return rc;
418}
419
420int vboxVDMAPipeCloseClient(PVBOXVDMAPIPE pPipe)
421{
422 int rc = RTCritSectEnter(&pPipe->hCritSect);
423 AssertRC(rc);
424 if (RT_SUCCESS(rc))
425 {
426 bool bNeedNotify = false;
427 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED
428 || pPipe->enmState == VBOXVDMAPIPE_STATE_CREATED
429 || pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED);
430 switch (pPipe->enmState)
431 {
432 case VBOXVDMAPIPE_STATE_OPENNED:
433 pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSING;
434 bNeedNotify = pPipe->bNeedNotify;
435 pPipe->bNeedNotify = false;
436 break;
437 case VBOXVDMAPIPE_STATE_CREATED:
438 pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSED;
439 pPipe->bNeedNotify = false;
440 break;
441 case VBOXVDMAPIPE_STATE_CLOSED:
442 rc = VINF_ALREADY_INITIALIZED;
443 break;
444 default:
445 AssertBreakpoint();
446 rc = VERR_INVALID_STATE;
447 break;
448 }
449
450 RTCritSectLeave(&pPipe->hCritSect);
451
452 if (bNeedNotify)
453 {
454 rc = RTSemEventSignal(pPipe->hEvent);
455 AssertRC(rc);
456 }
457 }
458 return rc;
459}
460
461
462typedef DECLCALLBACK(bool) FNHVBOXVDMARWCB(PVBOXVDMAPIPE pPipe, void *pvCallback);
463typedef FNHVBOXVDMARWCB *PFNHVBOXVDMARWCB;
464
465int vboxVDMAPipeModifyServer(PVBOXVDMAPIPE pPipe, PFNHVBOXVDMARWCB pfnCallback, void * pvCallback)
466{
467 int rc = RTCritSectEnter(&pPipe->hCritSect);
468 AssertRC(rc);
469 if (RT_SUCCESS(rc))
470 {
471 do
472 {
473 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED
474 || pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSING);
475
476 if (pPipe->enmState >= VBOXVDMAPIPE_STATE_OPENNED)
477 {
478 bool bProcessing = pfnCallback(pPipe, pvCallback);
479 pPipe->bNeedNotify = !bProcessing;
480 if (bProcessing)
481 {
482 RTCritSectLeave(&pPipe->hCritSect);
483 rc = VINF_SUCCESS;
484 break;
485 }
486 else if (pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSING)
487 {
488 pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSED;
489 RTCritSectLeave(&pPipe->hCritSect);
490 rc = VINF_EOF;
491 break;
492 }
493 }
494 else
495 {
496 AssertBreakpoint();
497 rc = VERR_INVALID_STATE;
498 RTCritSectLeave(&pPipe->hCritSect);
499 break;
500 }
501
502 RTCritSectLeave(&pPipe->hCritSect);
503
504 rc = RTSemEventWait(pPipe->hEvent, RT_INDEFINITE_WAIT);
505 AssertRC(rc);
506 if (!RT_SUCCESS(rc))
507 break;
508
509 rc = RTCritSectEnter(&pPipe->hCritSect);
510 AssertRC(rc);
511 if (!RT_SUCCESS(rc))
512 break;
513 } while (1);
514 }
515
516 return rc;
517}
518
519int vboxVDMAPipeModifyClient(PVBOXVDMAPIPE pPipe, PFNHVBOXVDMARWCB pfnCallback, void * pvCallback)
520{
521 int rc = RTCritSectEnter(&pPipe->hCritSect);
522 AssertRC(rc);
523 if (RT_SUCCESS(rc))
524 {
525 bool bNeedNotify = false;
526 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED);
527 if (pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED)
528 {
529 bool bModified = pfnCallback(pPipe, pvCallback);
530 if (bModified)
531 {
532 bNeedNotify = pPipe->bNeedNotify;
533 pPipe->bNeedNotify = false;
534 }
535 }
536 else
537 rc = VERR_INVALID_STATE;
538
539 RTCritSectLeave(&pPipe->hCritSect);
540
541 if (bNeedNotify)
542 {
543 rc = RTSemEventSignal(pPipe->hEvent);
544 AssertRC(rc);
545 }
546 }
547 return rc;
548}
549
550int vboxVDMAPipeDestruct(PVBOXVDMAPIPE pPipe)
551{
552 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED
553 || pPipe->enmState == VBOXVDMAPIPE_STATE_CREATED);
554 /* ensure the pipe is closed */
555 vboxVDMAPipeCloseClient(pPipe);
556
557 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED);
558
559 if (pPipe->enmState != VBOXVDMAPIPE_STATE_CLOSED)
560 return VERR_INVALID_STATE;
561
562 int rc = RTCritSectDelete(&pPipe->hCritSect);
563 AssertRC(rc);
564
565 rc = RTSemEventDestroy(pPipe->hEvent);
566 AssertRC(rc);
567
568 return VINF_SUCCESS;
569}
570
571static void vboxVDMACommandProcess(PVBOXVDMAHOST pVdma, PVBOXVDMACBUF_DR pCmd)
572{
573 PHGSMIINSTANCE pHgsmi = pVdma->pHgsmi;
574 const uint8_t * pvBuf;
575 PGMPAGEMAPLOCK Lock;
576 int rc;
577 bool bReleaseLocked = false;
578
579 do
580 {
581 PPDMDEVINS pDevIns = pVdma->pVGAState->pDevInsR3;
582
583 if (pCmd->fFlags & VBOXVDMACBUF_FLAG_BUF_FOLLOWS_DR)
584 pvBuf = VBOXVDMACBUF_DR_TAIL(pCmd, const uint8_t);
585 else if (pCmd->fFlags & VBOXVDMACBUF_FLAG_BUF_VRAM_OFFSET)
586 {
587 uint8_t * pvRam = pVdma->pVGAState->vram_ptrR3;
588 pvBuf = pvRam + pCmd->Location.offVramBuf;
589 }
590 else
591 {
592 RTGCPHYS phPage = pCmd->Location.phBuf & ~0xfffULL;
593 uint32_t offset = pCmd->Location.phBuf & 0xfff;
594 Assert(offset + pCmd->cbBuf <= 0x1000);
595 if (offset + pCmd->cbBuf > 0x1000)
596 {
597 /* @todo: more advanced mechanism of command buffer proc is actually needed */
598 rc = VERR_INVALID_PARAMETER;
599 break;
600 }
601
602 const void * pvPageBuf;
603 rc = PDMDevHlpPhysGCPhys2CCPtrReadOnly(pDevIns, phPage, 0, &pvPageBuf, &Lock);
604 AssertRC(rc);
605 if (!RT_SUCCESS(rc))
606 {
607 /* @todo: if (rc == VERR_PGM_PHYS_PAGE_RESERVED) -> fall back on using PGMPhysRead ?? */
608 break;
609 }
610
611 pvBuf = (const uint8_t *)pvPageBuf;
612 pvBuf += offset;
613
614 bReleaseLocked = true;
615 }
616
617 rc = vboxVDMACmdExec(pVdma, pvBuf, pCmd->cbBuf);
618 AssertRC(rc);
619
620 if (bReleaseLocked)
621 PDMDevHlpPhysReleasePageMappingLock(pDevIns, &Lock);
622 } while (0);
623
624 pCmd->rc = rc;
625
626 rc = VBoxSHGSMICommandComplete (pHgsmi, pCmd);
627 AssertRC(rc);
628}
629
630static void vboxVDMAControlProcess(PVBOXVDMAHOST pVdma, PVBOXVDMA_CTL pCmd)
631{
632 PHGSMIINSTANCE pHgsmi = pVdma->pHgsmi;
633 pCmd->i32Result = VINF_SUCCESS;
634 int rc = VBoxSHGSMICommandComplete (pHgsmi, pCmd);
635 AssertRC(rc);
636}
637
638typedef struct
639{
640 struct VBOXVDMAHOST *pVdma;
641 VBOXVDMAPIPE_CMD_BODY Cmd;
642 bool bHasCmd;
643} VBOXVDMACMD_PROCESS_CONTEXT, *PVBOXVDMACMD_PROCESS_CONTEXT;
644
645static DECLCALLBACK(bool) vboxVDMACommandProcessCb(PVBOXVDMAPIPE pPipe, void *pvCallback)
646{
647 PVBOXVDMACMD_PROCESS_CONTEXT pContext = (PVBOXVDMACMD_PROCESS_CONTEXT)pvCallback;
648 struct VBOXVDMAHOST *pVdma = pContext->pVdma;
649 HGSMILISTENTRY *pEntry = hgsmiListRemoveHead(&pVdma->PendingList);
650 if (pEntry)
651 {
652 PVBOXVDMAPIPE_CMD pPipeCmd = VBOXVDMAPIPE_CMD_FROM_ENTRY(pEntry);
653 Assert(pPipeCmd);
654 pContext->Cmd = pPipeCmd->Cmd;
655 hgsmiListPrepend(&pVdma->CmdPool.List, pEntry);
656 pContext->bHasCmd = true;
657 return true;
658 }
659
660 pContext->bHasCmd = false;
661 return false;
662}
663
664static DECLCALLBACK(int) vboxVDMAWorkerThread(RTTHREAD ThreadSelf, void *pvUser)
665{
666 PVBOXVDMAHOST pVdma = (PVBOXVDMAHOST)pvUser;
667 PHGSMIINSTANCE pHgsmi = pVdma->pHgsmi;
668 VBOXVDMACMD_PROCESS_CONTEXT Context;
669 Context.pVdma = pVdma;
670
671 int rc = vboxVDMAPipeOpenServer(&pVdma->Pipe);
672 AssertRC(rc);
673 if (RT_SUCCESS(rc))
674 {
675 do
676 {
677 rc = vboxVDMAPipeModifyServer(&pVdma->Pipe, vboxVDMACommandProcessCb, &Context);
678 AssertRC(rc);
679 if (RT_SUCCESS(rc))
680 {
681 switch (Context.Cmd.enmType)
682 {
683 case VBOXVDMAPIPE_CMD_TYPE_DMACMD:
684 {
685 PVBOXVDMACBUF_DR pDr = Context.Cmd.u.pDr;
686 vboxVDMACommandProcess(pVdma, pDr);
687 break;
688 }
689 case VBOXVDMAPIPE_CMD_TYPE_DMACTL:
690 {
691 PVBOXVDMA_CTL pCtl = Context.Cmd.u.pCtl;
692 vboxVDMAControlProcess(pVdma, pCtl);
693 break;
694 }
695 default:
696 AssertBreakpoint();
697 break;
698 }
699
700 if (rc == VINF_EOF)
701 {
702 rc = VINF_SUCCESS;
703 break;
704 }
705 }
706 else
707 break;
708 } while (1);
709 }
710
711 /* always try to close the pipe to make sure the client side is notified */
712 int tmpRc = vboxVDMAPipeCloseServer(&pVdma->Pipe);
713 AssertRC(tmpRc);
714 return rc;
715}
716
717int vboxVDMAConstruct(PVGASTATE pVGAState, struct VBOXVDMAHOST **ppVdma, uint32_t cPipeElements)
718{
719 int rc;
720 PVBOXVDMAHOST pVdma = (PVBOXVDMAHOST)RTMemAllocZ (RT_OFFSETOF(VBOXVDMAHOST, CmdPool.aCmds[cPipeElements]));
721 Assert(pVdma);
722 if (pVdma)
723 {
724 hgsmiListInit(&pVdma->PendingList);
725 pVdma->pHgsmi = pVGAState->pHGSMI;
726 pVdma->pVGAState = pVGAState;
727 rc = vboxVDMAPipeConstruct(&pVdma->Pipe);
728 AssertRC(rc);
729 if (RT_SUCCESS(rc))
730 {
731 rc = RTThreadCreate(&pVdma->hWorkerThread, vboxVDMAWorkerThread, pVdma, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "VDMA");
732 AssertRC(rc);
733 if (RT_SUCCESS(rc))
734 {
735 hgsmiListInit(&pVdma->CmdPool.List);
736 pVdma->CmdPool.cCmds = cPipeElements;
737 for (uint32_t i = 0; i < cPipeElements; ++i)
738 {
739 hgsmiListAppend(&pVdma->CmdPool.List, &pVdma->CmdPool.aCmds[i].Entry);
740 }
741 *ppVdma = pVdma;
742 return VINF_SUCCESS;
743 }
744
745 int tmpRc = vboxVDMAPipeDestruct(&pVdma->Pipe);
746 AssertRC(tmpRc);
747 }
748
749 RTMemFree(pVdma);
750 }
751 else
752 rc = VERR_OUT_OF_RESOURCES;
753
754 return rc;
755}
756
757int vboxVDMADestruct(struct VBOXVDMAHOST **pVdma)
758{
759 AssertBreakpoint();
760 return VINF_SUCCESS;
761}
762
763typedef struct
764{
765 struct VBOXVDMAHOST *pVdma;
766 VBOXVDMAPIPE_CMD_BODY Cmd;
767 bool bQueued;
768} VBOXVDMACMD_SUBMIT_CONTEXT, *PVBOXVDMACMD_SUBMIT_CONTEXT;
769
770DECLCALLBACK(bool) vboxVDMACommandSubmitCb(PVBOXVDMAPIPE pPipe, void *pvCallback)
771{
772 PVBOXVDMACMD_SUBMIT_CONTEXT pContext = (PVBOXVDMACMD_SUBMIT_CONTEXT)pvCallback;
773 struct VBOXVDMAHOST *pVdma = pContext->pVdma;
774 HGSMILISTENTRY *pEntry = hgsmiListRemoveHead(&pVdma->CmdPool.List);
775 Assert(pEntry);
776 if (pEntry)
777 {
778 PVBOXVDMAPIPE_CMD pPipeCmd = VBOXVDMAPIPE_CMD_FROM_ENTRY(pEntry);
779 pPipeCmd->Cmd = pContext->Cmd;
780 VBoxSHGSMICommandMarkAsynchCompletion(pContext->Cmd.u.pvCmd);
781 pContext->bQueued = true;
782 hgsmiListAppend(&pVdma->PendingList, pEntry);
783 return true;
784 }
785
786 /* @todo: should we try to flush some commands here? */
787 pContext->bQueued = false;
788 return false;
789}
790
791void vboxVDMAControl(struct VBOXVDMAHOST *pVdma, PVBOXVDMA_CTL pCmd)
792{
793#if 1
794 PHGSMIINSTANCE pIns = pVdma->pHgsmi;
795
796 switch (pCmd->enmCtl)
797 {
798 case VBOXVDMA_CTL_TYPE_ENABLE:
799 pVdma->bEnabled = true;
800 pCmd->i32Result = VINF_SUCCESS;
801 break;
802 case VBOXVDMA_CTL_TYPE_DISABLE:
803 pVdma->bEnabled = false;
804 pCmd->i32Result = VINF_SUCCESS;
805 break;
806 case VBOXVDMA_CTL_TYPE_FLUSH:
807 pCmd->i32Result = VINF_SUCCESS;
808 break;
809 default:
810 AssertBreakpoint();
811 pCmd->i32Result = VERR_NOT_SUPPORTED;
812 }
813
814 int rc = VBoxSHGSMICommandComplete (pIns, pCmd);
815 AssertRC(rc);
816#else
817 /* test asinch completion */
818 VBOXVDMACMD_SUBMIT_CONTEXT Context;
819 Context.pVdma = pVdma;
820 Context.Cmd.enmType = VBOXVDMAPIPE_CMD_TYPE_DMACTL;
821 Context.Cmd.u.pCtl = pCmd;
822
823 int rc = vboxVDMAPipeModifyClient(&pVdma->Pipe, vboxVDMACommandSubmitCb, &Context);
824 AssertRC(rc);
825 if (RT_SUCCESS(rc))
826 {
827 Assert(Context.bQueued);
828 if (Context.bQueued)
829 {
830 /* success */
831 return;
832 }
833 rc = VERR_OUT_OF_RESOURCES;
834 }
835
836 /* failure */
837 Assert(RT_FAILURE(rc));
838 PHGSMIINSTANCE pIns = pVdma->pHgsmi;
839 pCmd->i32Result = rc;
840 int tmpRc = VBoxSHGSMICommandComplete (pIns, pCmd);
841 AssertRC(tmpRc);
842
843#endif
844}
845
846void vboxVDMACommand(struct VBOXVDMAHOST *pVdma, PVBOXVDMACBUF_DR pCmd)
847{
848 VBOXVDMACMD_SUBMIT_CONTEXT Context;
849 Context.pVdma = pVdma;
850 Context.Cmd.enmType = VBOXVDMAPIPE_CMD_TYPE_DMACMD;
851 Context.Cmd.u.pDr = pCmd;
852
853 int rc = vboxVDMAPipeModifyClient(&pVdma->Pipe, vboxVDMACommandSubmitCb, &Context);
854 AssertRC(rc);
855 if (RT_SUCCESS(rc))
856 {
857 Assert(Context.bQueued);
858 if (Context.bQueued)
859 {
860 /* success */
861 return;
862 }
863 rc = VERR_OUT_OF_RESOURCES;
864 }
865
866 /* failure */
867 Assert(RT_FAILURE(rc));
868 PHGSMIINSTANCE pIns = pVdma->pHgsmi;
869 pCmd->rc = rc;
870 int tmpRc = VBoxSHGSMICommandComplete (pIns, pCmd);
871 AssertRC(tmpRc);
872}
873
874bool vboxVDMAIsEnabled(PVBOXVDMAHOST pVdma)
875{
876 return pVdma->bEnabled;
877}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use