VirtualBox

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

Last change on this file since 37808 was 37490, checked in by vboxsync, 14 years ago

wddm: autoresize fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 40.3 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/vmm/pdmdev.h>
18#include <VBox/VBoxVideo.h>
19#include <iprt/semaphore.h>
20#include <iprt/thread.h>
21#include <iprt/mem.h>
22#include <iprt/asm.h>
23
24#include "DevVGA.h"
25#include "HGSMI/SHGSMIHost.h"
26#include "HGSMI/HGSMIHostHlp.h"
27
28#ifdef VBOX_VDMA_WITH_WORKERTHREAD
29typedef enum
30{
31 VBOXVDMAPIPE_STATE_CLOSED = 0,
32 VBOXVDMAPIPE_STATE_CREATED = 1,
33 VBOXVDMAPIPE_STATE_OPENNED = 2,
34 VBOXVDMAPIPE_STATE_CLOSING = 3
35} VBOXVDMAPIPE_STATE;
36
37typedef struct VBOXVDMAPIPE
38{
39 RTSEMEVENT hEvent;
40 /* critical section for accessing pipe properties */
41 RTCRITSECT hCritSect;
42 VBOXVDMAPIPE_STATE enmState;
43 /* true iff the other end needs Event notification */
44 bool bNeedNotify;
45} VBOXVDMAPIPE, *PVBOXVDMAPIPE;
46
47typedef enum
48{
49 VBOXVDMAPIPE_CMD_TYPE_UNDEFINED = 0,
50 VBOXVDMAPIPE_CMD_TYPE_DMACMD = 1,
51 VBOXVDMAPIPE_CMD_TYPE_DMACTL = 2
52} VBOXVDMAPIPE_CMD_TYPE;
53
54typedef struct VBOXVDMAPIPE_CMD_BODY
55{
56 VBOXVDMAPIPE_CMD_TYPE enmType;
57 union
58 {
59 PVBOXVDMACBUF_DR pDr;
60 PVBOXVDMA_CTL pCtl;
61 void *pvCmd;
62 } u;
63}VBOXVDMAPIPE_CMD_BODY, *PVBOXVDMAPIPE_CMD_BODY;
64
65typedef struct VBOXVDMAPIPE_CMD
66{
67 HGSMILISTENTRY Entry;
68 VBOXVDMAPIPE_CMD_BODY Cmd;
69} VBOXVDMAPIPE_CMD, *PVBOXVDMAPIPE_CMD;
70
71#define VBOXVDMAPIPE_CMD_FROM_ENTRY(_pE) ( (PVBOXVDMAPIPE_CMD)((uint8_t *)(_pE) - RT_OFFSETOF(VBOXVDMAPIPE_CMD, Entry)) )
72
73typedef struct VBOXVDMAPIPE_CMD_POOL
74{
75 HGSMILIST List;
76 uint32_t cCmds;
77 VBOXVDMAPIPE_CMD aCmds[1];
78} VBOXVDMAPIPE_CMD_POOL, *PVBOXVDMAPIPE_CMD_POOL;
79#endif
80
81typedef struct VBOXVDMAHOST
82{
83 PHGSMIINSTANCE pHgsmi;
84 PVGASTATE pVGAState;
85#ifdef VBOX_VDMA_WITH_WORKERTHREAD
86 VBOXVDMAPIPE Pipe;
87 HGSMILIST PendingList;
88 RTTHREAD hWorkerThread;
89 VBOXVDMAPIPE_CMD_POOL CmdPool;
90#endif
91} VBOXVDMAHOST, *PVBOXVDMAHOST;
92
93
94#ifdef VBOX_WITH_CRHGSMI
95
96typedef DECLCALLBACK(void) FNVBOXVDMACRCTL_CALLBACK(PVGASTATE pVGAState, PVBOXVDMACMD_CHROMIUM_CTL pCmd, void* pvContext);
97typedef FNVBOXVDMACRCTL_CALLBACK *PFNVBOXVDMACRCTL_CALLBACK;
98
99typedef struct VBOXVDMACMD_CHROMIUM_CTL_PRIVATE
100{
101 uint32_t cRefs;
102 int32_t rc;
103 PFNVBOXVDMACRCTL_CALLBACK pfnCompletion;
104 void *pvCompletion;
105 VBOXVDMACMD_CHROMIUM_CTL Cmd;
106} VBOXVDMACMD_CHROMIUM_CTL_PRIVATE, *PVBOXVDMACMD_CHROMIUM_CTL_PRIVATE;
107
108#define VBOXVDMACMD_CHROMIUM_CTL_PRIVATE_FROM_CTL(_p) ((PVBOXVDMACMD_CHROMIUM_CTL_PRIVATE)(((uint8_t*)(_p)) - RT_OFFSETOF(VBOXVDMACMD_CHROMIUM_CTL_PRIVATE, Cmd)))
109
110static PVBOXVDMACMD_CHROMIUM_CTL vboxVDMACrCtlCreate(VBOXVDMACMD_CHROMIUM_CTL_TYPE enmCmd, uint32_t cbCmd)
111{
112 PVBOXVDMACMD_CHROMIUM_CTL_PRIVATE pHdr = (PVBOXVDMACMD_CHROMIUM_CTL_PRIVATE)RTMemAllocZ(cbCmd + RT_OFFSETOF(VBOXVDMACMD_CHROMIUM_CTL_PRIVATE, Cmd));
113 Assert(pHdr);
114 if (pHdr)
115 {
116 pHdr->cRefs = 1;
117 pHdr->rc = VERR_NOT_IMPLEMENTED;
118 pHdr->Cmd.enmType = enmCmd;
119 pHdr->Cmd.cbCmd = cbCmd;
120 return &pHdr->Cmd;
121 }
122
123 return NULL;
124}
125
126DECLINLINE(void) vboxVDMACrCtlRelease (PVBOXVDMACMD_CHROMIUM_CTL pCmd)
127{
128 PVBOXVDMACMD_CHROMIUM_CTL_PRIVATE pHdr = VBOXVDMACMD_CHROMIUM_CTL_PRIVATE_FROM_CTL(pCmd);
129 uint32_t cRefs = ASMAtomicDecU32(&pHdr->cRefs);
130 if(!cRefs)
131 {
132 RTMemFree(pHdr);
133 }
134}
135
136DECLINLINE(void) vboxVDMACrCtlRetain (PVBOXVDMACMD_CHROMIUM_CTL pCmd)
137{
138 PVBOXVDMACMD_CHROMIUM_CTL_PRIVATE pHdr = VBOXVDMACMD_CHROMIUM_CTL_PRIVATE_FROM_CTL(pCmd);
139 ASMAtomicIncU32(&pHdr->cRefs);
140}
141
142DECLINLINE(int) vboxVDMACrCtlGetRc (PVBOXVDMACMD_CHROMIUM_CTL pCmd)
143{
144 PVBOXVDMACMD_CHROMIUM_CTL_PRIVATE pHdr = VBOXVDMACMD_CHROMIUM_CTL_PRIVATE_FROM_CTL(pCmd);
145 return pHdr->rc;
146}
147
148static DECLCALLBACK(void) vboxVDMACrCtlCbSetEvent(PVGASTATE pVGAState, PVBOXVDMACMD_CHROMIUM_CTL pCmd, void* pvContext)
149{
150 RTSemEventSignal((RTSEMEVENT)pvContext);
151}
152
153static DECLCALLBACK(void) vboxVDMACrCtlCbReleaseCmd(PVGASTATE pVGAState, PVBOXVDMACMD_CHROMIUM_CTL pCmd, void* pvContext)
154{
155 vboxVDMACrCtlRelease(pCmd);
156}
157
158
159static int vboxVDMACrCtlPostAsync (PVGASTATE pVGAState, PVBOXVDMACMD_CHROMIUM_CTL pCmd, PFNVBOXVDMACRCTL_CALLBACK pfnCompletion, void *pvCompletion)
160{
161 if (pVGAState->pDrv->pfnCrHgsmiControlProcess)
162 {
163 PVBOXVDMACMD_CHROMIUM_CTL_PRIVATE pHdr = VBOXVDMACMD_CHROMIUM_CTL_PRIVATE_FROM_CTL(pCmd);
164 pHdr->pfnCompletion = pfnCompletion;
165 pHdr->pvCompletion = pvCompletion;
166 pVGAState->pDrv->pfnCrHgsmiControlProcess(pVGAState->pDrv, pCmd);
167 return VINF_SUCCESS;
168 }
169#ifdef DEBUG_misha
170 Assert(0);
171#endif
172 return VERR_NOT_SUPPORTED;
173}
174
175static int vboxVDMACrCtlPost(PVGASTATE pVGAState, PVBOXVDMACMD_CHROMIUM_CTL pCmd)
176{
177 RTSEMEVENT hComplEvent;
178 int rc = RTSemEventCreate(&hComplEvent);
179 AssertRC(rc);
180 if(RT_SUCCESS(rc))
181 {
182 rc = vboxVDMACrCtlPostAsync (pVGAState, pCmd, vboxVDMACrCtlCbSetEvent, (void*)hComplEvent);
183#ifdef DEBUG_misha
184 AssertRC(rc);
185#endif
186 if (RT_SUCCESS(rc))
187 {
188 rc = RTSemEventWaitNoResume(hComplEvent, RT_INDEFINITE_WAIT);
189 AssertRC(rc);
190 if(RT_SUCCESS(rc))
191 {
192 RTSemEventDestroy(hComplEvent);
193 }
194 }
195 else
196 {
197 /* the command is completed */
198 RTSemEventDestroy(hComplEvent);
199 }
200 }
201 return rc;
202}
203
204static int vboxVDMACrCtlHgsmiSetup(struct VBOXVDMAHOST *pVdma)
205{
206 PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP pCmd = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP)vboxVDMACrCtlCreate(
207 VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP, sizeof (*pCmd));
208 if (pCmd)
209 {
210 PVGASTATE pVGAState = pVdma->pVGAState;
211 pCmd->pvRamBase = pVGAState->vram_ptrR3;
212 int rc = vboxVDMACrCtlPost(pVGAState, &pCmd->Hdr);
213 AssertRC(rc);
214 if (RT_SUCCESS(rc))
215 {
216 rc = vboxVDMACrCtlGetRc(&pCmd->Hdr);
217 }
218 vboxVDMACrCtlRelease(&pCmd->Hdr);
219 return rc;
220 }
221 return VERR_NO_MEMORY;
222}
223
224static int vboxVDMACmdExecBpbTransfer(PVBOXVDMAHOST pVdma, const PVBOXVDMACMD_DMA_BPB_TRANSFER pTransfer, uint32_t cbBuffer);
225
226/* check if this is external cmd to be passed to chromium backend */
227static bool vboxVDMACmdCheckCrCmd(struct VBOXVDMAHOST *pVdma, PVBOXVDMACBUF_DR pCmd)
228{
229 PVBOXVDMACMD pDmaCmd;
230 uint8_t * pvRam = pVdma->pVGAState->vram_ptrR3;
231 bool bCompleted = false;
232
233 if (pCmd->fFlags & VBOXVDMACBUF_FLAG_BUF_FOLLOWS_DR)
234 pDmaCmd = VBOXVDMACBUF_DR_TAIL(pCmd, VBOXVDMACMD);
235 else
236 pDmaCmd = NULL;
237
238 if (pDmaCmd)
239 {
240 uint32_t cbCmd = pCmd->cbBuf;
241 Assert(cbCmd >= VBOXVDMACMD_HEADER_SIZE());
242
243 if (cbCmd >= VBOXVDMACMD_HEADER_SIZE())
244 {
245 switch (pDmaCmd->enmType)
246 {
247 case VBOXVDMACMD_TYPE_CHROMIUM_CMD:
248 {
249 PVBOXVDMACMD_CHROMIUM_CMD pCrCmd = VBOXVDMACMD_BODY(pDmaCmd, VBOXVDMACMD_CHROMIUM_CMD);
250 PVGASTATE pVGAState = pVdma->pVGAState;
251 bCompleted = true;
252 if (pVGAState->pDrv->pfnCrHgsmiCommandProcess)
253 {
254 VBoxSHGSMICommandMarkAsynchCompletion(pCmd);
255 pVGAState->pDrv->pfnCrHgsmiCommandProcess(pVGAState->pDrv, pCrCmd);
256 break;
257 }
258 else
259 {
260 Assert(0);
261 }
262
263 int tmpRc = VBoxSHGSMICommandComplete (pVdma->pHgsmi, pCmd);
264 AssertRC(tmpRc);
265// uint32_t cBufs = pCrCmd->cBuffers;
266// for (uint32_t i = 0; i < cBufs; ++i)
267// {
268// PVBOXVDMACMD_CHROMIUM_BUFFER pBuf = &pCrCmd->aBuffers[i];
269// void *pvBuffer = pvRam + pBuf->offBuffer;
270// uint32_t cbBuffer = pBuf->cbBuffer;
271// }
272 break;
273 }
274 case VBOXVDMACMD_TYPE_DMA_BPB_TRANSFER:
275 {
276 PVBOXVDMACMD_DMA_BPB_TRANSFER pTransfer = VBOXVDMACMD_BODY(pDmaCmd, VBOXVDMACMD_DMA_BPB_TRANSFER);
277 int rc = vboxVDMACmdExecBpbTransfer(pVdma, pTransfer, sizeof (*pTransfer));
278 AssertRC(rc);
279 if (RT_SUCCESS(rc))
280 {
281 pCmd->rc = VINF_SUCCESS;
282 rc = VBoxSHGSMICommandComplete (pVdma->pHgsmi, pCmd);
283 AssertRC(rc);
284 bCompleted = true;
285 }
286 break;
287 }
288 default:
289 break;
290 }
291 }
292 }
293 return bCompleted;
294}
295
296int vboxVDMACrHgsmiCommandCompleteAsync(PPDMIDISPLAYVBVACALLBACKS pInterface, PVBOXVDMACMD_CHROMIUM_CMD pCmd, int rc)
297{
298 PVGASTATE pVGAState = PPDMIDISPLAYVBVACALLBACKS_2_PVGASTATE(pInterface);
299 PHGSMIINSTANCE pIns = pVGAState->pHGSMI;
300 VBOXVDMACMD *pDmaHdr = VBOXVDMACMD_FROM_BODY(pCmd);
301 VBOXVDMACBUF_DR *pDr = VBOXVDMACBUF_DR_FROM_TAIL(pDmaHdr);
302 AssertRC(rc);
303 pDr->rc = rc;
304
305 Assert(pVGAState->fGuestCaps & VBVACAPS_COMPLETEGCMD_BY_IOREAD);
306 rc = VBoxSHGSMICommandComplete(pIns, pDr);
307 AssertRC(rc);
308 return rc;
309}
310
311int vboxVDMACrHgsmiControlCompleteAsync(PPDMIDISPLAYVBVACALLBACKS pInterface, PVBOXVDMACMD_CHROMIUM_CTL pCmd, int rc)
312{
313 PVGASTATE pVGAState = PPDMIDISPLAYVBVACALLBACKS_2_PVGASTATE(pInterface);
314 PVBOXVDMACMD_CHROMIUM_CTL_PRIVATE pCmdPrivate = VBOXVDMACMD_CHROMIUM_CTL_PRIVATE_FROM_CTL(pCmd);
315 pCmdPrivate->rc = rc;
316 if (pCmdPrivate->pfnCompletion)
317 {
318 pCmdPrivate->pfnCompletion(pVGAState, pCmd, pCmdPrivate->pvCompletion);
319 }
320 return VINF_SUCCESS;
321}
322
323#endif
324
325#ifdef VBOX_VDMA_WITH_WORKERTHREAD
326/* to simplify things and to avoid extra backend if modifications we assume the VBOXVDMA_RECTL is the same as VBVACMDHDR */
327AssertCompile(sizeof(VBOXVDMA_RECTL) == sizeof(VBVACMDHDR));
328AssertCompile(RT_SIZEOFMEMB(VBOXVDMA_RECTL, left) == RT_SIZEOFMEMB(VBVACMDHDR, x));
329AssertCompile(RT_SIZEOFMEMB(VBOXVDMA_RECTL, top) == RT_SIZEOFMEMB(VBVACMDHDR, y));
330AssertCompile(RT_SIZEOFMEMB(VBOXVDMA_RECTL, width) == RT_SIZEOFMEMB(VBVACMDHDR, w));
331AssertCompile(RT_SIZEOFMEMB(VBOXVDMA_RECTL, height) == RT_SIZEOFMEMB(VBVACMDHDR, h));
332AssertCompile(RT_OFFSETOF(VBOXVDMA_RECTL, left) == RT_OFFSETOF(VBVACMDHDR, x));
333AssertCompile(RT_OFFSETOF(VBOXVDMA_RECTL, top) == RT_OFFSETOF(VBVACMDHDR, y));
334AssertCompile(RT_OFFSETOF(VBOXVDMA_RECTL, width) == RT_OFFSETOF(VBVACMDHDR, w));
335AssertCompile(RT_OFFSETOF(VBOXVDMA_RECTL, height) == RT_OFFSETOF(VBVACMDHDR, h));
336
337static int vboxVDMANotifyPrimaryUpdate (PVGASTATE pVGAState, unsigned uScreenId, const VBOXVDMA_RECTL * pRectl)
338{
339 pVGAState->pDrv->pfnVBVAUpdateBegin (pVGAState->pDrv, uScreenId);
340
341 /* Updates the rectangle and sends the command to the VRDP server. */
342 pVGAState->pDrv->pfnVBVAUpdateProcess (pVGAState->pDrv, uScreenId,
343 (const PVBVACMDHDR)pRectl /* <- see above AssertCompile's and comments */,
344 sizeof (VBOXVDMA_RECTL));
345
346 pVGAState->pDrv->pfnVBVAUpdateEnd (pVGAState->pDrv, uScreenId, pRectl->left, pRectl->top,
347 pRectl->width, pRectl->height);
348
349 return VINF_SUCCESS;
350}
351#endif
352
353static int vboxVDMACmdExecBltPerform(PVBOXVDMAHOST pVdma,
354 uint8_t *pvDstSurf, const uint8_t *pvSrcSurf,
355 const PVBOXVDMA_SURF_DESC pDstDesc, const PVBOXVDMA_SURF_DESC pSrcDesc,
356 const VBOXVDMA_RECTL * pDstRectl, const VBOXVDMA_RECTL * pSrcRectl)
357{
358 /* we do not support color conversion */
359 Assert(pDstDesc->format == pSrcDesc->format);
360 /* we do not support stretching */
361 Assert(pDstRectl->height == pSrcRectl->height);
362 Assert(pDstRectl->width == pSrcRectl->width);
363 if (pDstDesc->format != pSrcDesc->format)
364 return VERR_INVALID_FUNCTION;
365 if (pDstDesc->width == pDstRectl->width
366 && pSrcDesc->width == pSrcRectl->width
367 && pSrcDesc->width == pDstDesc->width)
368 {
369 Assert(!pDstRectl->left);
370 Assert(!pSrcRectl->left);
371 uint32_t cbOff = pDstDesc->pitch * pDstRectl->top;
372 uint32_t cbSize = pDstDesc->pitch * pDstRectl->height;
373 memcpy(pvDstSurf + cbOff, pvSrcSurf + cbOff, cbSize);
374 }
375 else
376 {
377 uint32_t offDstLineStart = pDstRectl->left * pDstDesc->bpp >> 3;
378 uint32_t offDstLineEnd = ((pDstRectl->left * pDstDesc->bpp + 7) >> 3) + ((pDstDesc->bpp * pDstRectl->width + 7) >> 3);
379 uint32_t cbDstLine = offDstLineEnd - offDstLineStart;
380 uint32_t offDstStart = pDstDesc->pitch * pDstRectl->top + offDstLineStart;
381 Assert(cbDstLine <= pDstDesc->pitch);
382 uint32_t cbDstSkip = pDstDesc->pitch;
383 uint8_t * pvDstStart = pvDstSurf + offDstStart;
384
385 uint32_t offSrcLineStart = pSrcRectl->left * pSrcDesc->bpp >> 3;
386 uint32_t offSrcLineEnd = ((pSrcRectl->left * pSrcDesc->bpp + 7) >> 3) + ((pSrcDesc->bpp * pSrcRectl->width + 7) >> 3);
387 uint32_t cbSrcLine = offSrcLineEnd - offSrcLineStart;
388 uint32_t offSrcStart = pSrcDesc->pitch * pSrcRectl->top + offSrcLineStart;
389 Assert(cbSrcLine <= pSrcDesc->pitch);
390 uint32_t cbSrcSkip = pSrcDesc->pitch;
391 const uint8_t * pvSrcStart = pvSrcSurf + offSrcStart;
392
393 Assert(cbDstLine == cbSrcLine);
394
395 for (uint32_t i = 0; ; ++i)
396 {
397 memcpy (pvDstStart, pvSrcStart, cbDstLine);
398 if (i == pDstRectl->height)
399 break;
400 pvDstStart += cbDstSkip;
401 pvSrcStart += cbSrcSkip;
402 }
403 }
404 return VINF_SUCCESS;
405}
406
407static void vboxVDMARectlUnite(VBOXVDMA_RECTL * pRectl1, const VBOXVDMA_RECTL * pRectl2)
408{
409 if (!pRectl1->width)
410 *pRectl1 = *pRectl2;
411 else
412 {
413 int16_t x21 = pRectl1->left + pRectl1->width;
414 int16_t x22 = pRectl2->left + pRectl2->width;
415 if (pRectl1->left > pRectl2->left)
416 {
417 pRectl1->left = pRectl2->left;
418 pRectl1->width = x21 < x22 ? x22 - pRectl1->left : x21 - pRectl1->left;
419 }
420 else if (x21 < x22)
421 pRectl1->width = x22 - pRectl1->left;
422
423 x21 = pRectl1->top + pRectl1->height;
424 x22 = pRectl2->top + pRectl2->height;
425 if (pRectl1->top > pRectl2->top)
426 {
427 pRectl1->top = pRectl2->top;
428 pRectl1->height = x21 < x22 ? x22 - pRectl1->top : x21 - pRectl1->top;
429 }
430 else if (x21 < x22)
431 pRectl1->height = x22 - pRectl1->top;
432 }
433}
434
435/*
436 * @return on success the number of bytes the command contained, otherwise - VERR_xxx error code
437 */
438static int vboxVDMACmdExecBlt(PVBOXVDMAHOST pVdma, const PVBOXVDMACMD_DMA_PRESENT_BLT pBlt, uint32_t cbBuffer)
439{
440 const uint32_t cbBlt = VBOXVDMACMD_BODY_FIELD_OFFSET(uint32_t, VBOXVDMACMD_DMA_PRESENT_BLT, aDstSubRects[pBlt->cDstSubRects]);
441 Assert(cbBlt <= cbBuffer);
442 if (cbBuffer < cbBlt)
443 return VERR_INVALID_FUNCTION;
444
445 /* we do not support stretching for now */
446 Assert(pBlt->srcRectl.width == pBlt->dstRectl.width);
447 Assert(pBlt->srcRectl.height == pBlt->dstRectl.height);
448 if (pBlt->srcRectl.width != pBlt->dstRectl.width)
449 return VERR_INVALID_FUNCTION;
450 if (pBlt->srcRectl.height != pBlt->dstRectl.height)
451 return VERR_INVALID_FUNCTION;
452 Assert(pBlt->cDstSubRects);
453
454 uint8_t * pvRam = pVdma->pVGAState->vram_ptrR3;
455 VBOXVDMA_RECTL updateRectl = {0, 0, 0, 0};
456
457 if (pBlt->cDstSubRects)
458 {
459 VBOXVDMA_RECTL dstRectl, srcRectl;
460 const VBOXVDMA_RECTL *pDstRectl, *pSrcRectl;
461 for (uint32_t i = 0; i < pBlt->cDstSubRects; ++i)
462 {
463 pDstRectl = &pBlt->aDstSubRects[i];
464 if (pBlt->dstRectl.left || pBlt->dstRectl.top)
465 {
466 dstRectl.left = pDstRectl->left + pBlt->dstRectl.left;
467 dstRectl.top = pDstRectl->top + pBlt->dstRectl.top;
468 dstRectl.width = pDstRectl->width;
469 dstRectl.height = pDstRectl->height;
470 pDstRectl = &dstRectl;
471 }
472
473 pSrcRectl = &pBlt->aDstSubRects[i];
474 if (pBlt->srcRectl.left || pBlt->srcRectl.top)
475 {
476 srcRectl.left = pSrcRectl->left + pBlt->srcRectl.left;
477 srcRectl.top = pSrcRectl->top + pBlt->srcRectl.top;
478 srcRectl.width = pSrcRectl->width;
479 srcRectl.height = pSrcRectl->height;
480 pSrcRectl = &srcRectl;
481 }
482
483 int rc = vboxVDMACmdExecBltPerform(pVdma, pvRam + pBlt->offDst, pvRam + pBlt->offSrc,
484 &pBlt->dstDesc, &pBlt->srcDesc,
485 pDstRectl,
486 pSrcRectl);
487 AssertRC(rc);
488 if (!RT_SUCCESS(rc))
489 return rc;
490
491 vboxVDMARectlUnite(&updateRectl, pDstRectl);
492 }
493 }
494 else
495 {
496 int rc = vboxVDMACmdExecBltPerform(pVdma, pvRam + pBlt->offDst, pvRam + pBlt->offSrc,
497 &pBlt->dstDesc, &pBlt->srcDesc,
498 &pBlt->dstRectl,
499 &pBlt->srcRectl);
500 AssertRC(rc);
501 if (!RT_SUCCESS(rc))
502 return rc;
503
504 vboxVDMARectlUnite(&updateRectl, &pBlt->dstRectl);
505 }
506
507#ifdef VBOX_VDMA_WITH_WORKERTHREAD
508 int iView = 0;
509 /* @todo: fixme: check if update is needed and get iView */
510 vboxVDMANotifyPrimaryUpdate (pVdma->pVGAState, iView, &updateRectl);
511#endif
512
513 return cbBlt;
514}
515
516static int vboxVDMACmdExecBpbTransfer(PVBOXVDMAHOST pVdma, const PVBOXVDMACMD_DMA_BPB_TRANSFER pTransfer, uint32_t cbBuffer)
517{
518 if (cbBuffer < sizeof (*pTransfer))
519 return VERR_INVALID_PARAMETER;
520
521 PVGASTATE pVGAState = pVdma->pVGAState;
522 uint8_t * pvRam = pVGAState->vram_ptrR3;
523 PGMPAGEMAPLOCK SrcLock;
524 PGMPAGEMAPLOCK DstLock;
525 PPDMDEVINS pDevIns = pVdma->pVGAState->pDevInsR3;
526 const void * pvSrc;
527 void * pvDst;
528 int rc = VINF_SUCCESS;
529 uint32_t cbTransfer = pTransfer->cbTransferSize;
530 uint32_t cbTransfered = 0;
531 bool bSrcLocked = false;
532 bool bDstLocked = false;
533 do
534 {
535 uint32_t cbSubTransfer = cbTransfer;
536 if (pTransfer->fFlags & VBOXVDMACMD_DMA_BPB_TRANSFER_F_SRC_VRAMOFFSET)
537 {
538 pvSrc = pvRam + pTransfer->Src.offVramBuf + cbTransfered;
539 }
540 else
541 {
542 RTGCPHYS phPage = pTransfer->Src.phBuf;
543 phPage += cbTransfered;
544 rc = PDMDevHlpPhysGCPhys2CCPtrReadOnly(pDevIns, phPage, 0, &pvSrc, &SrcLock);
545 AssertRC(rc);
546 if (RT_SUCCESS(rc))
547 {
548 bSrcLocked = true;
549 cbSubTransfer = RT_MIN(cbSubTransfer, 0x1000);
550 }
551 else
552 {
553 break;
554 }
555 }
556
557 if (pTransfer->fFlags & VBOXVDMACMD_DMA_BPB_TRANSFER_F_DST_VRAMOFFSET)
558 {
559 pvDst = pvRam + pTransfer->Dst.offVramBuf + cbTransfered;
560 }
561 else
562 {
563 RTGCPHYS phPage = pTransfer->Dst.phBuf;
564 phPage += cbTransfered;
565 rc = PDMDevHlpPhysGCPhys2CCPtr(pDevIns, phPage, 0, &pvDst, &DstLock);
566 AssertRC(rc);
567 if (RT_SUCCESS(rc))
568 {
569 bDstLocked = true;
570 cbSubTransfer = RT_MIN(cbSubTransfer, 0x1000);
571 }
572 else
573 {
574 break;
575 }
576 }
577
578 if (RT_SUCCESS(rc))
579 {
580 memcpy(pvDst, pvSrc, cbSubTransfer);
581 cbTransfer -= cbSubTransfer;
582 cbTransfered += cbSubTransfer;
583 }
584 else
585 {
586 cbTransfer = 0; /* to break */
587 }
588
589 if (bSrcLocked)
590 PDMDevHlpPhysReleasePageMappingLock(pDevIns, &SrcLock);
591 if (bDstLocked)
592 PDMDevHlpPhysReleasePageMappingLock(pDevIns, &DstLock);
593 } while (cbTransfer);
594
595 if (RT_SUCCESS(rc))
596 return sizeof (*pTransfer);
597 return rc;
598}
599
600static int vboxVDMACmdExec(PVBOXVDMAHOST pVdma, const uint8_t *pvBuffer, uint32_t cbBuffer)
601{
602 do
603 {
604 Assert(pvBuffer);
605 Assert(cbBuffer >= VBOXVDMACMD_HEADER_SIZE());
606
607 if (!pvBuffer)
608 return VERR_INVALID_PARAMETER;
609 if (cbBuffer < VBOXVDMACMD_HEADER_SIZE())
610 return VERR_INVALID_PARAMETER;
611
612 PVBOXVDMACMD pCmd = (PVBOXVDMACMD)pvBuffer;
613 uint32_t cbCmd = 0;
614 switch (pCmd->enmType)
615 {
616 case VBOXVDMACMD_TYPE_CHROMIUM_CMD:
617 {
618#ifdef VBOXWDDM_TEST_UHGSMI
619 static int count = 0;
620 static uint64_t start, end;
621 if (count==0)
622 {
623 start = RTTimeNanoTS();
624 }
625 ++count;
626 if (count==100000)
627 {
628 end = RTTimeNanoTS();
629 float ems = (end-start)/1000000.f;
630 LogRel(("100000 calls took %i ms, %i cps\n", (int)ems, (int)(100000.f*1000.f/ems) ));
631 }
632#endif
633 /* todo: post the buffer to chromium */
634 return VINF_SUCCESS;
635 }
636 case VBOXVDMACMD_TYPE_DMA_PRESENT_BLT:
637 {
638 const PVBOXVDMACMD_DMA_PRESENT_BLT pBlt = VBOXVDMACMD_BODY(pCmd, VBOXVDMACMD_DMA_PRESENT_BLT);
639 int cbBlt = vboxVDMACmdExecBlt(pVdma, pBlt, cbBuffer);
640 Assert(cbBlt >= 0);
641 Assert((uint32_t)cbBlt <= cbBuffer);
642 if (cbBlt >= 0)
643 {
644 if ((uint32_t)cbBlt == cbBuffer)
645 return VINF_SUCCESS;
646 else
647 {
648 cbBuffer -= (uint32_t)cbBlt;
649 pvBuffer -= cbBlt;
650 }
651 }
652 else
653 return cbBlt; /* error */
654 break;
655 }
656 case VBOXVDMACMD_TYPE_DMA_BPB_TRANSFER:
657 {
658 const PVBOXVDMACMD_DMA_BPB_TRANSFER pTransfer = VBOXVDMACMD_BODY(pCmd, VBOXVDMACMD_DMA_BPB_TRANSFER);
659 int cbTransfer = vboxVDMACmdExecBpbTransfer(pVdma, pTransfer, cbBuffer);
660 Assert(cbTransfer >= 0);
661 Assert((uint32_t)cbTransfer <= cbBuffer);
662 if (cbTransfer >= 0)
663 {
664 if ((uint32_t)cbTransfer == cbBuffer)
665 return VINF_SUCCESS;
666 else
667 {
668 cbBuffer -= (uint32_t)cbTransfer;
669 pvBuffer -= cbTransfer;
670 }
671 }
672 else
673 return cbTransfer; /* error */
674 break;
675 }
676 case VBOXVDMACMD_TYPE_DMA_NOP:
677 return VINF_SUCCESS;
678 case VBOXVDMACMD_TYPE_CHILD_STATUS_IRQ:
679 return VINF_SUCCESS;
680 default:
681 AssertBreakpoint();
682 return VERR_INVALID_FUNCTION;
683 }
684 } while (1);
685
686 /* we should not be here */
687 AssertBreakpoint();
688 return VERR_INVALID_STATE;
689}
690
691#ifdef VBOX_VDMA_WITH_WORKERTHREAD
692
693int vboxVDMAPipeConstruct(PVBOXVDMAPIPE pPipe)
694{
695 int rc = RTSemEventCreate(&pPipe->hEvent);
696 AssertRC(rc);
697 if (RT_SUCCESS(rc))
698 {
699 rc = RTCritSectInit(&pPipe->hCritSect);
700 AssertRC(rc);
701 if (RT_SUCCESS(rc))
702 {
703 pPipe->enmState = VBOXVDMAPIPE_STATE_CREATED;
704 pPipe->bNeedNotify = true;
705 return VINF_SUCCESS;
706// RTCritSectDelete(pPipe->hCritSect);
707 }
708 RTSemEventDestroy(pPipe->hEvent);
709 }
710 return rc;
711}
712
713int vboxVDMAPipeOpenServer(PVBOXVDMAPIPE pPipe)
714{
715 int rc = RTCritSectEnter(&pPipe->hCritSect);
716 AssertRC(rc);
717 if (RT_SUCCESS(rc))
718 {
719 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CREATED);
720 switch (pPipe->enmState)
721 {
722 case VBOXVDMAPIPE_STATE_CREATED:
723 pPipe->enmState = VBOXVDMAPIPE_STATE_OPENNED;
724 pPipe->bNeedNotify = false;
725 rc = VINF_SUCCESS;
726 break;
727 case VBOXVDMAPIPE_STATE_OPENNED:
728 pPipe->bNeedNotify = false;
729 rc = VINF_ALREADY_INITIALIZED;
730 break;
731 default:
732 AssertBreakpoint();
733 rc = VERR_INVALID_STATE;
734 break;
735 }
736
737 RTCritSectLeave(&pPipe->hCritSect);
738 }
739 return rc;
740}
741
742int vboxVDMAPipeCloseServer(PVBOXVDMAPIPE pPipe)
743{
744 int rc = RTCritSectEnter(&pPipe->hCritSect);
745 AssertRC(rc);
746 if (RT_SUCCESS(rc))
747 {
748 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED
749 || pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSING);
750 switch (pPipe->enmState)
751 {
752 case VBOXVDMAPIPE_STATE_CLOSING:
753 pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSED;
754 rc = VINF_SUCCESS;
755 break;
756 case VBOXVDMAPIPE_STATE_CLOSED:
757 rc = VINF_ALREADY_INITIALIZED;
758 break;
759 default:
760 AssertBreakpoint();
761 rc = VERR_INVALID_STATE;
762 break;
763 }
764
765 RTCritSectLeave(&pPipe->hCritSect);
766 }
767 return rc;
768}
769
770int vboxVDMAPipeCloseClient(PVBOXVDMAPIPE pPipe)
771{
772 int rc = RTCritSectEnter(&pPipe->hCritSect);
773 AssertRC(rc);
774 if (RT_SUCCESS(rc))
775 {
776 bool bNeedNotify = false;
777 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED
778 || pPipe->enmState == VBOXVDMAPIPE_STATE_CREATED
779 || pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED);
780 switch (pPipe->enmState)
781 {
782 case VBOXVDMAPIPE_STATE_OPENNED:
783 pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSING;
784 bNeedNotify = pPipe->bNeedNotify;
785 pPipe->bNeedNotify = false;
786 break;
787 case VBOXVDMAPIPE_STATE_CREATED:
788 pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSED;
789 pPipe->bNeedNotify = false;
790 break;
791 case VBOXVDMAPIPE_STATE_CLOSED:
792 rc = VINF_ALREADY_INITIALIZED;
793 break;
794 default:
795 AssertBreakpoint();
796 rc = VERR_INVALID_STATE;
797 break;
798 }
799
800 RTCritSectLeave(&pPipe->hCritSect);
801
802 if (bNeedNotify)
803 {
804 rc = RTSemEventSignal(pPipe->hEvent);
805 AssertRC(rc);
806 }
807 }
808 return rc;
809}
810
811
812typedef DECLCALLBACK(bool) FNHVBOXVDMARWCB(PVBOXVDMAPIPE pPipe, void *pvCallback);
813typedef FNHVBOXVDMARWCB *PFNHVBOXVDMARWCB;
814
815int vboxVDMAPipeModifyServer(PVBOXVDMAPIPE pPipe, PFNHVBOXVDMARWCB pfnCallback, void * pvCallback)
816{
817 int rc = RTCritSectEnter(&pPipe->hCritSect);
818 AssertRC(rc);
819 if (RT_SUCCESS(rc))
820 {
821 do
822 {
823 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED
824 || pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSING);
825
826 if (pPipe->enmState >= VBOXVDMAPIPE_STATE_OPENNED)
827 {
828 bool bProcessing = pfnCallback(pPipe, pvCallback);
829 pPipe->bNeedNotify = !bProcessing;
830 if (bProcessing)
831 {
832 RTCritSectLeave(&pPipe->hCritSect);
833 rc = VINF_SUCCESS;
834 break;
835 }
836 else if (pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSING)
837 {
838 pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSED;
839 RTCritSectLeave(&pPipe->hCritSect);
840 rc = VINF_EOF;
841 break;
842 }
843 }
844 else
845 {
846 AssertBreakpoint();
847 rc = VERR_INVALID_STATE;
848 RTCritSectLeave(&pPipe->hCritSect);
849 break;
850 }
851
852 RTCritSectLeave(&pPipe->hCritSect);
853
854 rc = RTSemEventWait(pPipe->hEvent, RT_INDEFINITE_WAIT);
855 AssertRC(rc);
856 if (!RT_SUCCESS(rc))
857 break;
858
859 rc = RTCritSectEnter(&pPipe->hCritSect);
860 AssertRC(rc);
861 if (!RT_SUCCESS(rc))
862 break;
863 } while (1);
864 }
865
866 return rc;
867}
868
869int vboxVDMAPipeModifyClient(PVBOXVDMAPIPE pPipe, PFNHVBOXVDMARWCB pfnCallback, void * pvCallback)
870{
871 int rc = RTCritSectEnter(&pPipe->hCritSect);
872 AssertRC(rc);
873 if (RT_SUCCESS(rc))
874 {
875 bool bNeedNotify = false;
876 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED);
877 if (pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED)
878 {
879 bool bModified = pfnCallback(pPipe, pvCallback);
880 if (bModified)
881 {
882 bNeedNotify = pPipe->bNeedNotify;
883 pPipe->bNeedNotify = false;
884 }
885 }
886 else
887 rc = VERR_INVALID_STATE;
888
889 RTCritSectLeave(&pPipe->hCritSect);
890
891 if (bNeedNotify)
892 {
893 rc = RTSemEventSignal(pPipe->hEvent);
894 AssertRC(rc);
895 }
896 }
897 return rc;
898}
899
900int vboxVDMAPipeDestruct(PVBOXVDMAPIPE pPipe)
901{
902 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED
903 || pPipe->enmState == VBOXVDMAPIPE_STATE_CREATED);
904 /* ensure the pipe is closed */
905 vboxVDMAPipeCloseClient(pPipe);
906
907 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED);
908
909 if (pPipe->enmState != VBOXVDMAPIPE_STATE_CLOSED)
910 return VERR_INVALID_STATE;
911
912 int rc = RTCritSectDelete(&pPipe->hCritSect);
913 AssertRC(rc);
914
915 rc = RTSemEventDestroy(pPipe->hEvent);
916 AssertRC(rc);
917
918 return VINF_SUCCESS;
919}
920#endif
921
922static void vboxVDMACommandProcess(PVBOXVDMAHOST pVdma, PVBOXVDMACBUF_DR pCmd)
923{
924 PHGSMIINSTANCE pHgsmi = pVdma->pHgsmi;
925 const uint8_t * pvBuf;
926 PGMPAGEMAPLOCK Lock;
927 int rc;
928 bool bReleaseLocked = false;
929
930 do
931 {
932 PPDMDEVINS pDevIns = pVdma->pVGAState->pDevInsR3;
933
934 if (pCmd->fFlags & VBOXVDMACBUF_FLAG_BUF_FOLLOWS_DR)
935 pvBuf = VBOXVDMACBUF_DR_TAIL(pCmd, const uint8_t);
936 else if (pCmd->fFlags & VBOXVDMACBUF_FLAG_BUF_VRAM_OFFSET)
937 {
938 uint8_t * pvRam = pVdma->pVGAState->vram_ptrR3;
939 pvBuf = pvRam + pCmd->Location.offVramBuf;
940 }
941 else
942 {
943 RTGCPHYS phPage = pCmd->Location.phBuf & ~0xfffULL;
944 uint32_t offset = pCmd->Location.phBuf & 0xfff;
945 Assert(offset + pCmd->cbBuf <= 0x1000);
946 if (offset + pCmd->cbBuf > 0x1000)
947 {
948 /* @todo: more advanced mechanism of command buffer proc is actually needed */
949 rc = VERR_INVALID_PARAMETER;
950 break;
951 }
952
953 const void * pvPageBuf;
954 rc = PDMDevHlpPhysGCPhys2CCPtrReadOnly(pDevIns, phPage, 0, &pvPageBuf, &Lock);
955 AssertRC(rc);
956 if (!RT_SUCCESS(rc))
957 {
958 /* @todo: if (rc == VERR_PGM_PHYS_PAGE_RESERVED) -> fall back on using PGMPhysRead ?? */
959 break;
960 }
961
962 pvBuf = (const uint8_t *)pvPageBuf;
963 pvBuf += offset;
964
965 bReleaseLocked = true;
966 }
967
968 rc = vboxVDMACmdExec(pVdma, pvBuf, pCmd->cbBuf);
969 AssertRC(rc);
970
971 if (bReleaseLocked)
972 PDMDevHlpPhysReleasePageMappingLock(pDevIns, &Lock);
973 } while (0);
974
975 pCmd->rc = rc;
976
977 rc = VBoxSHGSMICommandComplete (pHgsmi, pCmd);
978 AssertRC(rc);
979}
980
981static void vboxVDMAControlProcess(PVBOXVDMAHOST pVdma, PVBOXVDMA_CTL pCmd)
982{
983 PHGSMIINSTANCE pHgsmi = pVdma->pHgsmi;
984 pCmd->i32Result = VINF_SUCCESS;
985 int rc = VBoxSHGSMICommandComplete (pHgsmi, pCmd);
986 AssertRC(rc);
987}
988
989#ifdef VBOX_VDMA_WITH_WORKERTHREAD
990typedef struct
991{
992 struct VBOXVDMAHOST *pVdma;
993 VBOXVDMAPIPE_CMD_BODY Cmd;
994 bool bHasCmd;
995} VBOXVDMACMD_PROCESS_CONTEXT, *PVBOXVDMACMD_PROCESS_CONTEXT;
996
997static DECLCALLBACK(bool) vboxVDMACommandProcessCb(PVBOXVDMAPIPE pPipe, void *pvCallback)
998{
999 PVBOXVDMACMD_PROCESS_CONTEXT pContext = (PVBOXVDMACMD_PROCESS_CONTEXT)pvCallback;
1000 struct VBOXVDMAHOST *pVdma = pContext->pVdma;
1001 HGSMILISTENTRY *pEntry = hgsmiListRemoveHead(&pVdma->PendingList);
1002 if (pEntry)
1003 {
1004 PVBOXVDMAPIPE_CMD pPipeCmd = VBOXVDMAPIPE_CMD_FROM_ENTRY(pEntry);
1005 Assert(pPipeCmd);
1006 pContext->Cmd = pPipeCmd->Cmd;
1007 hgsmiListPrepend(&pVdma->CmdPool.List, pEntry);
1008 pContext->bHasCmd = true;
1009 return true;
1010 }
1011
1012 pContext->bHasCmd = false;
1013 return false;
1014}
1015
1016static DECLCALLBACK(int) vboxVDMAWorkerThread(RTTHREAD ThreadSelf, void *pvUser)
1017{
1018 PVBOXVDMAHOST pVdma = (PVBOXVDMAHOST)pvUser;
1019 PHGSMIINSTANCE pHgsmi = pVdma->pHgsmi;
1020 VBOXVDMACMD_PROCESS_CONTEXT Context;
1021 Context.pVdma = pVdma;
1022
1023 int rc = vboxVDMAPipeOpenServer(&pVdma->Pipe);
1024 AssertRC(rc);
1025 if (RT_SUCCESS(rc))
1026 {
1027 do
1028 {
1029 rc = vboxVDMAPipeModifyServer(&pVdma->Pipe, vboxVDMACommandProcessCb, &Context);
1030 AssertRC(rc);
1031 if (RT_SUCCESS(rc))
1032 {
1033 switch (Context.Cmd.enmType)
1034 {
1035 case VBOXVDMAPIPE_CMD_TYPE_DMACMD:
1036 {
1037 PVBOXVDMACBUF_DR pDr = Context.Cmd.u.pDr;
1038 vboxVDMACommandProcess(pVdma, pDr);
1039 break;
1040 }
1041 case VBOXVDMAPIPE_CMD_TYPE_DMACTL:
1042 {
1043 PVBOXVDMA_CTL pCtl = Context.Cmd.u.pCtl;
1044 vboxVDMAControlProcess(pVdma, pCtl);
1045 break;
1046 }
1047 default:
1048 AssertBreakpoint();
1049 break;
1050 }
1051
1052 if (rc == VINF_EOF)
1053 {
1054 rc = VINF_SUCCESS;
1055 break;
1056 }
1057 }
1058 else
1059 break;
1060 } while (1);
1061 }
1062
1063 /* always try to close the pipe to make sure the client side is notified */
1064 int tmpRc = vboxVDMAPipeCloseServer(&pVdma->Pipe);
1065 AssertRC(tmpRc);
1066 return rc;
1067}
1068#endif
1069
1070int vboxVDMAConstruct(PVGASTATE pVGAState, uint32_t cPipeElements)
1071{
1072 int rc;
1073#ifdef VBOX_VDMA_WITH_WORKERTHREAD
1074 PVBOXVDMAHOST pVdma = (PVBOXVDMAHOST)RTMemAllocZ (RT_OFFSETOF(VBOXVDMAHOST, CmdPool.aCmds[cPipeElements]));
1075#else
1076 PVBOXVDMAHOST pVdma = (PVBOXVDMAHOST)RTMemAllocZ (sizeof (*pVdma));
1077#endif
1078 Assert(pVdma);
1079 if (pVdma)
1080 {
1081 pVdma->pHgsmi = pVGAState->pHGSMI;
1082 pVdma->pVGAState = pVGAState;
1083#ifdef VBOX_VDMA_WITH_WORKERTHREAD
1084 hgsmiListInit(&pVdma->PendingList);
1085 rc = vboxVDMAPipeConstruct(&pVdma->Pipe);
1086 AssertRC(rc);
1087 if (RT_SUCCESS(rc))
1088 {
1089 rc = RTThreadCreate(&pVdma->hWorkerThread, vboxVDMAWorkerThread, pVdma, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "VDMA");
1090 AssertRC(rc);
1091 if (RT_SUCCESS(rc))
1092 {
1093 hgsmiListInit(&pVdma->CmdPool.List);
1094 pVdma->CmdPool.cCmds = cPipeElements;
1095 for (uint32_t i = 0; i < cPipeElements; ++i)
1096 {
1097 hgsmiListAppend(&pVdma->CmdPool.List, &pVdma->CmdPool.aCmds[i].Entry);
1098 }
1099# if 0 //def VBOX_WITH_CRHGSMI
1100 int tmpRc = vboxVDMACrCtlHgsmiSetup(pVdma);
1101# endif
1102#endif
1103 pVGAState->pVdma = pVdma;
1104#ifdef VBOX_WITH_CRHGSMI
1105 rc = vboxVDMACrCtlHgsmiSetup(pVdma);
1106#endif
1107 return VINF_SUCCESS;
1108#ifdef VBOX_VDMA_WITH_WORKERTHREAD
1109 }
1110
1111 int tmpRc = vboxVDMAPipeDestruct(&pVdma->Pipe);
1112 AssertRC(tmpRc);
1113 }
1114
1115 RTMemFree(pVdma);
1116#endif
1117 }
1118 else
1119 rc = VERR_OUT_OF_RESOURCES;
1120
1121 return rc;
1122}
1123
1124int vboxVDMADestruct(struct VBOXVDMAHOST *pVdma)
1125{
1126#ifdef VBOX_VDMA_WITH_WORKERTHREAD
1127 /* @todo: implement*/
1128 AssertBreakpoint();
1129#endif
1130 RTMemFree(pVdma);
1131 return VINF_SUCCESS;
1132}
1133
1134#ifdef VBOX_VDMA_WITH_WORKERTHREAD
1135typedef struct
1136{
1137 struct VBOXVDMAHOST *pVdma;
1138 VBOXVDMAPIPE_CMD_BODY Cmd;
1139 bool bQueued;
1140} VBOXVDMACMD_SUBMIT_CONTEXT, *PVBOXVDMACMD_SUBMIT_CONTEXT;
1141
1142DECLCALLBACK(bool) vboxVDMACommandSubmitCb(PVBOXVDMAPIPE pPipe, void *pvCallback)
1143{
1144 PVBOXVDMACMD_SUBMIT_CONTEXT pContext = (PVBOXVDMACMD_SUBMIT_CONTEXT)pvCallback;
1145 struct VBOXVDMAHOST *pVdma = pContext->pVdma;
1146 HGSMILISTENTRY *pEntry = hgsmiListRemoveHead(&pVdma->CmdPool.List);
1147 Assert(pEntry);
1148 if (pEntry)
1149 {
1150 PVBOXVDMAPIPE_CMD pPipeCmd = VBOXVDMAPIPE_CMD_FROM_ENTRY(pEntry);
1151 pPipeCmd->Cmd = pContext->Cmd;
1152 VBoxSHGSMICommandMarkAsynchCompletion(pContext->Cmd.u.pvCmd);
1153 pContext->bQueued = true;
1154 hgsmiListAppend(&pVdma->PendingList, pEntry);
1155 return true;
1156 }
1157
1158 /* @todo: should we try to flush some commands here? */
1159 pContext->bQueued = false;
1160 return false;
1161}
1162#endif
1163
1164int vboxVDMASaveStateExecPrep(struct VBOXVDMAHOST *pVdma, PSSMHANDLE pSSM)
1165{
1166#ifdef VBOX_WITH_CRHGSMI
1167 PVGASTATE pVGAState = pVdma->pVGAState;
1168 PVBOXVDMACMD_CHROMIUM_CTL pCmd = (PVBOXVDMACMD_CHROMIUM_CTL)vboxVDMACrCtlCreate(
1169 VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_BEGIN, sizeof (*pCmd));
1170 Assert(pCmd);
1171 if (pCmd)
1172 {
1173 int rc = vboxVDMACrCtlPost(pVGAState, pCmd);
1174 AssertRC(rc);
1175 if (RT_SUCCESS(rc))
1176 {
1177 rc = vboxVDMACrCtlGetRc(pCmd);
1178 }
1179 vboxVDMACrCtlRelease(pCmd);
1180 return rc;
1181 }
1182 return VERR_NO_MEMORY;
1183#else
1184 return VINF_SUCCESS;
1185#endif
1186}
1187
1188int vboxVDMASaveStateExecDone(struct VBOXVDMAHOST *pVdma, PSSMHANDLE pSSM)
1189{
1190#ifdef VBOX_WITH_CRHGSMI
1191 PVGASTATE pVGAState = pVdma->pVGAState;
1192 PVBOXVDMACMD_CHROMIUM_CTL pCmd = (PVBOXVDMACMD_CHROMIUM_CTL)vboxVDMACrCtlCreate(
1193 VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_END, sizeof (*pCmd));
1194 Assert(pCmd);
1195 if (pCmd)
1196 {
1197 int rc = vboxVDMACrCtlPost(pVGAState, pCmd);
1198 AssertRC(rc);
1199 if (RT_SUCCESS(rc))
1200 {
1201 rc = vboxVDMACrCtlGetRc(pCmd);
1202 }
1203 vboxVDMACrCtlRelease(pCmd);
1204 return rc;
1205 }
1206 return VERR_NO_MEMORY;
1207#else
1208 return VINF_SUCCESS;
1209#endif
1210}
1211
1212
1213void vboxVDMAControl(struct VBOXVDMAHOST *pVdma, PVBOXVDMA_CTL pCmd)
1214{
1215#if 1
1216 PHGSMIINSTANCE pIns = pVdma->pHgsmi;
1217
1218 switch (pCmd->enmCtl)
1219 {
1220 case VBOXVDMA_CTL_TYPE_ENABLE:
1221 pCmd->i32Result = VINF_SUCCESS;
1222 break;
1223 case VBOXVDMA_CTL_TYPE_DISABLE:
1224 pCmd->i32Result = VINF_SUCCESS;
1225 break;
1226 case VBOXVDMA_CTL_TYPE_FLUSH:
1227 pCmd->i32Result = VINF_SUCCESS;
1228 break;
1229 default:
1230 AssertBreakpoint();
1231 pCmd->i32Result = VERR_NOT_SUPPORTED;
1232 }
1233
1234 int rc = VBoxSHGSMICommandComplete (pIns, pCmd);
1235 AssertRC(rc);
1236#else
1237 /* test asinch completion */
1238 VBOXVDMACMD_SUBMIT_CONTEXT Context;
1239 Context.pVdma = pVdma;
1240 Context.Cmd.enmType = VBOXVDMAPIPE_CMD_TYPE_DMACTL;
1241 Context.Cmd.u.pCtl = pCmd;
1242
1243 int rc = vboxVDMAPipeModifyClient(&pVdma->Pipe, vboxVDMACommandSubmitCb, &Context);
1244 AssertRC(rc);
1245 if (RT_SUCCESS(rc))
1246 {
1247 Assert(Context.bQueued);
1248 if (Context.bQueued)
1249 {
1250 /* success */
1251 return;
1252 }
1253 rc = VERR_OUT_OF_RESOURCES;
1254 }
1255
1256 /* failure */
1257 Assert(RT_FAILURE(rc));
1258 PHGSMIINSTANCE pIns = pVdma->pHgsmi;
1259 pCmd->i32Result = rc;
1260 int tmpRc = VBoxSHGSMICommandComplete (pIns, pCmd);
1261 AssertRC(tmpRc);
1262
1263#endif
1264}
1265
1266void vboxVDMACommand(struct VBOXVDMAHOST *pVdma, PVBOXVDMACBUF_DR pCmd)
1267{
1268#ifdef VBOX_WITH_CRHGSMI
1269 /* chromium commands are processed by crhomium hgcm thread independently from our internal cmd processing pipeline
1270 * this is why we process them specially */
1271 if (vboxVDMACmdCheckCrCmd(pVdma, pCmd))
1272 return;
1273#endif
1274
1275#ifndef VBOX_VDMA_WITH_WORKERTHREAD
1276 vboxVDMACommandProcess(pVdma, pCmd);
1277#else
1278 int rc = VERR_NOT_IMPLEMENTED;
1279
1280# ifdef DEBUG_misha
1281 Assert(0);
1282# endif
1283
1284 VBOXVDMACMD_SUBMIT_CONTEXT Context;
1285 Context.pVdma = pVdma;
1286 Context.Cmd.enmType = VBOXVDMAPIPE_CMD_TYPE_DMACMD;
1287 Context.Cmd.u.pDr = pCmd;
1288
1289 rc = vboxVDMAPipeModifyClient(&pVdma->Pipe, vboxVDMACommandSubmitCb, &Context);
1290 AssertRC(rc);
1291 if (RT_SUCCESS(rc))
1292 {
1293 Assert(Context.bQueued);
1294 if (Context.bQueued)
1295 {
1296 /* success */
1297 return;
1298 }
1299 rc = VERR_OUT_OF_RESOURCES;
1300 }
1301 /* failure */
1302 Assert(RT_FAILURE(rc));
1303 PHGSMIINSTANCE pIns = pVdma->pHgsmi;
1304 pCmd->rc = rc;
1305 int tmpRc = VBoxSHGSMICommandComplete (pIns, pCmd);
1306 AssertRC(tmpRc);
1307#endif
1308}
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