VirtualBox

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

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

dev/graphics disable unnecessary assertions

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 39.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/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 default:
677 AssertBreakpoint();
678 return VERR_INVALID_FUNCTION;
679 }
680 } while (1);
681
682 /* we should not be here */
683 AssertBreakpoint();
684 return VERR_INVALID_STATE;
685}
686
687#ifdef VBOX_VDMA_WITH_WORKERTHREAD
688
689int vboxVDMAPipeConstruct(PVBOXVDMAPIPE pPipe)
690{
691 int rc = RTSemEventCreate(&pPipe->hEvent);
692 AssertRC(rc);
693 if (RT_SUCCESS(rc))
694 {
695 rc = RTCritSectInit(&pPipe->hCritSect);
696 AssertRC(rc);
697 if (RT_SUCCESS(rc))
698 {
699 pPipe->enmState = VBOXVDMAPIPE_STATE_CREATED;
700 pPipe->bNeedNotify = true;
701 return VINF_SUCCESS;
702// RTCritSectDelete(pPipe->hCritSect);
703 }
704 RTSemEventDestroy(pPipe->hEvent);
705 }
706 return rc;
707}
708
709int vboxVDMAPipeOpenServer(PVBOXVDMAPIPE pPipe)
710{
711 int rc = RTCritSectEnter(&pPipe->hCritSect);
712 AssertRC(rc);
713 if (RT_SUCCESS(rc))
714 {
715 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CREATED);
716 switch (pPipe->enmState)
717 {
718 case VBOXVDMAPIPE_STATE_CREATED:
719 pPipe->enmState = VBOXVDMAPIPE_STATE_OPENNED;
720 pPipe->bNeedNotify = false;
721 rc = VINF_SUCCESS;
722 break;
723 case VBOXVDMAPIPE_STATE_OPENNED:
724 pPipe->bNeedNotify = false;
725 rc = VINF_ALREADY_INITIALIZED;
726 break;
727 default:
728 AssertBreakpoint();
729 rc = VERR_INVALID_STATE;
730 break;
731 }
732
733 RTCritSectLeave(&pPipe->hCritSect);
734 }
735 return rc;
736}
737
738int vboxVDMAPipeCloseServer(PVBOXVDMAPIPE pPipe)
739{
740 int rc = RTCritSectEnter(&pPipe->hCritSect);
741 AssertRC(rc);
742 if (RT_SUCCESS(rc))
743 {
744 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED
745 || pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSING);
746 switch (pPipe->enmState)
747 {
748 case VBOXVDMAPIPE_STATE_CLOSING:
749 pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSED;
750 rc = VINF_SUCCESS;
751 break;
752 case VBOXVDMAPIPE_STATE_CLOSED:
753 rc = VINF_ALREADY_INITIALIZED;
754 break;
755 default:
756 AssertBreakpoint();
757 rc = VERR_INVALID_STATE;
758 break;
759 }
760
761 RTCritSectLeave(&pPipe->hCritSect);
762 }
763 return rc;
764}
765
766int vboxVDMAPipeCloseClient(PVBOXVDMAPIPE pPipe)
767{
768 int rc = RTCritSectEnter(&pPipe->hCritSect);
769 AssertRC(rc);
770 if (RT_SUCCESS(rc))
771 {
772 bool bNeedNotify = false;
773 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED
774 || pPipe->enmState == VBOXVDMAPIPE_STATE_CREATED
775 || pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED);
776 switch (pPipe->enmState)
777 {
778 case VBOXVDMAPIPE_STATE_OPENNED:
779 pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSING;
780 bNeedNotify = pPipe->bNeedNotify;
781 pPipe->bNeedNotify = false;
782 break;
783 case VBOXVDMAPIPE_STATE_CREATED:
784 pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSED;
785 pPipe->bNeedNotify = false;
786 break;
787 case VBOXVDMAPIPE_STATE_CLOSED:
788 rc = VINF_ALREADY_INITIALIZED;
789 break;
790 default:
791 AssertBreakpoint();
792 rc = VERR_INVALID_STATE;
793 break;
794 }
795
796 RTCritSectLeave(&pPipe->hCritSect);
797
798 if (bNeedNotify)
799 {
800 rc = RTSemEventSignal(pPipe->hEvent);
801 AssertRC(rc);
802 }
803 }
804 return rc;
805}
806
807
808typedef DECLCALLBACK(bool) FNHVBOXVDMARWCB(PVBOXVDMAPIPE pPipe, void *pvCallback);
809typedef FNHVBOXVDMARWCB *PFNHVBOXVDMARWCB;
810
811int vboxVDMAPipeModifyServer(PVBOXVDMAPIPE pPipe, PFNHVBOXVDMARWCB pfnCallback, void * pvCallback)
812{
813 int rc = RTCritSectEnter(&pPipe->hCritSect);
814 AssertRC(rc);
815 if (RT_SUCCESS(rc))
816 {
817 do
818 {
819 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED
820 || pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSING);
821
822 if (pPipe->enmState >= VBOXVDMAPIPE_STATE_OPENNED)
823 {
824 bool bProcessing = pfnCallback(pPipe, pvCallback);
825 pPipe->bNeedNotify = !bProcessing;
826 if (bProcessing)
827 {
828 RTCritSectLeave(&pPipe->hCritSect);
829 rc = VINF_SUCCESS;
830 break;
831 }
832 else if (pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSING)
833 {
834 pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSED;
835 RTCritSectLeave(&pPipe->hCritSect);
836 rc = VINF_EOF;
837 break;
838 }
839 }
840 else
841 {
842 AssertBreakpoint();
843 rc = VERR_INVALID_STATE;
844 RTCritSectLeave(&pPipe->hCritSect);
845 break;
846 }
847
848 RTCritSectLeave(&pPipe->hCritSect);
849
850 rc = RTSemEventWait(pPipe->hEvent, RT_INDEFINITE_WAIT);
851 AssertRC(rc);
852 if (!RT_SUCCESS(rc))
853 break;
854
855 rc = RTCritSectEnter(&pPipe->hCritSect);
856 AssertRC(rc);
857 if (!RT_SUCCESS(rc))
858 break;
859 } while (1);
860 }
861
862 return rc;
863}
864
865int vboxVDMAPipeModifyClient(PVBOXVDMAPIPE pPipe, PFNHVBOXVDMARWCB pfnCallback, void * pvCallback)
866{
867 int rc = RTCritSectEnter(&pPipe->hCritSect);
868 AssertRC(rc);
869 if (RT_SUCCESS(rc))
870 {
871 bool bNeedNotify = false;
872 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED);
873 if (pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED)
874 {
875 bool bModified = pfnCallback(pPipe, pvCallback);
876 if (bModified)
877 {
878 bNeedNotify = pPipe->bNeedNotify;
879 pPipe->bNeedNotify = false;
880 }
881 }
882 else
883 rc = VERR_INVALID_STATE;
884
885 RTCritSectLeave(&pPipe->hCritSect);
886
887 if (bNeedNotify)
888 {
889 rc = RTSemEventSignal(pPipe->hEvent);
890 AssertRC(rc);
891 }
892 }
893 return rc;
894}
895
896int vboxVDMAPipeDestruct(PVBOXVDMAPIPE pPipe)
897{
898 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED
899 || pPipe->enmState == VBOXVDMAPIPE_STATE_CREATED);
900 /* ensure the pipe is closed */
901 vboxVDMAPipeCloseClient(pPipe);
902
903 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED);
904
905 if (pPipe->enmState != VBOXVDMAPIPE_STATE_CLOSED)
906 return VERR_INVALID_STATE;
907
908 int rc = RTCritSectDelete(&pPipe->hCritSect);
909 AssertRC(rc);
910
911 rc = RTSemEventDestroy(pPipe->hEvent);
912 AssertRC(rc);
913
914 return VINF_SUCCESS;
915}
916#endif
917
918static void vboxVDMACommandProcess(PVBOXVDMAHOST pVdma, PVBOXVDMACBUF_DR pCmd)
919{
920 PHGSMIINSTANCE pHgsmi = pVdma->pHgsmi;
921 const uint8_t * pvBuf;
922 PGMPAGEMAPLOCK Lock;
923 int rc;
924 bool bReleaseLocked = false;
925
926 do
927 {
928 PPDMDEVINS pDevIns = pVdma->pVGAState->pDevInsR3;
929
930 if (pCmd->fFlags & VBOXVDMACBUF_FLAG_BUF_FOLLOWS_DR)
931 pvBuf = VBOXVDMACBUF_DR_TAIL(pCmd, const uint8_t);
932 else if (pCmd->fFlags & VBOXVDMACBUF_FLAG_BUF_VRAM_OFFSET)
933 {
934 uint8_t * pvRam = pVdma->pVGAState->vram_ptrR3;
935 pvBuf = pvRam + pCmd->Location.offVramBuf;
936 }
937 else
938 {
939 RTGCPHYS phPage = pCmd->Location.phBuf & ~0xfffULL;
940 uint32_t offset = pCmd->Location.phBuf & 0xfff;
941 Assert(offset + pCmd->cbBuf <= 0x1000);
942 if (offset + pCmd->cbBuf > 0x1000)
943 {
944 /* @todo: more advanced mechanism of command buffer proc is actually needed */
945 rc = VERR_INVALID_PARAMETER;
946 break;
947 }
948
949 const void * pvPageBuf;
950 rc = PDMDevHlpPhysGCPhys2CCPtrReadOnly(pDevIns, phPage, 0, &pvPageBuf, &Lock);
951 AssertRC(rc);
952 if (!RT_SUCCESS(rc))
953 {
954 /* @todo: if (rc == VERR_PGM_PHYS_PAGE_RESERVED) -> fall back on using PGMPhysRead ?? */
955 break;
956 }
957
958 pvBuf = (const uint8_t *)pvPageBuf;
959 pvBuf += offset;
960
961 bReleaseLocked = true;
962 }
963
964 rc = vboxVDMACmdExec(pVdma, pvBuf, pCmd->cbBuf);
965 AssertRC(rc);
966
967 if (bReleaseLocked)
968 PDMDevHlpPhysReleasePageMappingLock(pDevIns, &Lock);
969 } while (0);
970
971 pCmd->rc = rc;
972
973 rc = VBoxSHGSMICommandComplete (pHgsmi, pCmd);
974 AssertRC(rc);
975}
976
977static void vboxVDMAControlProcess(PVBOXVDMAHOST pVdma, PVBOXVDMA_CTL pCmd)
978{
979 PHGSMIINSTANCE pHgsmi = pVdma->pHgsmi;
980 pCmd->i32Result = VINF_SUCCESS;
981 int rc = VBoxSHGSMICommandComplete (pHgsmi, pCmd);
982 AssertRC(rc);
983}
984
985#ifdef VBOX_VDMA_WITH_WORKERTHREAD
986typedef struct
987{
988 struct VBOXVDMAHOST *pVdma;
989 VBOXVDMAPIPE_CMD_BODY Cmd;
990 bool bHasCmd;
991} VBOXVDMACMD_PROCESS_CONTEXT, *PVBOXVDMACMD_PROCESS_CONTEXT;
992
993static DECLCALLBACK(bool) vboxVDMACommandProcessCb(PVBOXVDMAPIPE pPipe, void *pvCallback)
994{
995 PVBOXVDMACMD_PROCESS_CONTEXT pContext = (PVBOXVDMACMD_PROCESS_CONTEXT)pvCallback;
996 struct VBOXVDMAHOST *pVdma = pContext->pVdma;
997 HGSMILISTENTRY *pEntry = hgsmiListRemoveHead(&pVdma->PendingList);
998 if (pEntry)
999 {
1000 PVBOXVDMAPIPE_CMD pPipeCmd = VBOXVDMAPIPE_CMD_FROM_ENTRY(pEntry);
1001 Assert(pPipeCmd);
1002 pContext->Cmd = pPipeCmd->Cmd;
1003 hgsmiListPrepend(&pVdma->CmdPool.List, pEntry);
1004 pContext->bHasCmd = true;
1005 return true;
1006 }
1007
1008 pContext->bHasCmd = false;
1009 return false;
1010}
1011
1012static DECLCALLBACK(int) vboxVDMAWorkerThread(RTTHREAD ThreadSelf, void *pvUser)
1013{
1014 PVBOXVDMAHOST pVdma = (PVBOXVDMAHOST)pvUser;
1015 PHGSMIINSTANCE pHgsmi = pVdma->pHgsmi;
1016 VBOXVDMACMD_PROCESS_CONTEXT Context;
1017 Context.pVdma = pVdma;
1018
1019 int rc = vboxVDMAPipeOpenServer(&pVdma->Pipe);
1020 AssertRC(rc);
1021 if (RT_SUCCESS(rc))
1022 {
1023 do
1024 {
1025 rc = vboxVDMAPipeModifyServer(&pVdma->Pipe, vboxVDMACommandProcessCb, &Context);
1026 AssertRC(rc);
1027 if (RT_SUCCESS(rc))
1028 {
1029 switch (Context.Cmd.enmType)
1030 {
1031 case VBOXVDMAPIPE_CMD_TYPE_DMACMD:
1032 {
1033 PVBOXVDMACBUF_DR pDr = Context.Cmd.u.pDr;
1034 vboxVDMACommandProcess(pVdma, pDr);
1035 break;
1036 }
1037 case VBOXVDMAPIPE_CMD_TYPE_DMACTL:
1038 {
1039 PVBOXVDMA_CTL pCtl = Context.Cmd.u.pCtl;
1040 vboxVDMAControlProcess(pVdma, pCtl);
1041 break;
1042 }
1043 default:
1044 AssertBreakpoint();
1045 break;
1046 }
1047
1048 if (rc == VINF_EOF)
1049 {
1050 rc = VINF_SUCCESS;
1051 break;
1052 }
1053 }
1054 else
1055 break;
1056 } while (1);
1057 }
1058
1059 /* always try to close the pipe to make sure the client side is notified */
1060 int tmpRc = vboxVDMAPipeCloseServer(&pVdma->Pipe);
1061 AssertRC(tmpRc);
1062 return rc;
1063}
1064#endif
1065
1066int vboxVDMAConstruct(PVGASTATE pVGAState, uint32_t cPipeElements)
1067{
1068 int rc;
1069#ifdef VBOX_VDMA_WITH_WORKERTHREAD
1070 PVBOXVDMAHOST pVdma = (PVBOXVDMAHOST)RTMemAllocZ (RT_OFFSETOF(VBOXVDMAHOST, CmdPool.aCmds[cPipeElements]));
1071#else
1072 PVBOXVDMAHOST pVdma = (PVBOXVDMAHOST)RTMemAllocZ (sizeof (*pVdma));
1073#endif
1074 Assert(pVdma);
1075 if (pVdma)
1076 {
1077 pVdma->pHgsmi = pVGAState->pHGSMI;
1078 pVdma->pVGAState = pVGAState;
1079#ifdef VBOX_VDMA_WITH_WORKERTHREAD
1080 hgsmiListInit(&pVdma->PendingList);
1081 rc = vboxVDMAPipeConstruct(&pVdma->Pipe);
1082 AssertRC(rc);
1083 if (RT_SUCCESS(rc))
1084 {
1085 rc = RTThreadCreate(&pVdma->hWorkerThread, vboxVDMAWorkerThread, pVdma, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "VDMA");
1086 AssertRC(rc);
1087 if (RT_SUCCESS(rc))
1088 {
1089 hgsmiListInit(&pVdma->CmdPool.List);
1090 pVdma->CmdPool.cCmds = cPipeElements;
1091 for (uint32_t i = 0; i < cPipeElements; ++i)
1092 {
1093 hgsmiListAppend(&pVdma->CmdPool.List, &pVdma->CmdPool.aCmds[i].Entry);
1094 }
1095# if 0 //def VBOX_WITH_CRHGSMI
1096 int tmpRc = vboxVDMACrCtlHgsmiSetup(pVdma);
1097# endif
1098#endif
1099 pVGAState->pVdma = pVdma;
1100#ifdef VBOX_WITH_CRHGSMI
1101 rc = vboxVDMACrCtlHgsmiSetup(pVdma);
1102#endif
1103 return VINF_SUCCESS;
1104#ifdef VBOX_VDMA_WITH_WORKERTHREAD
1105 }
1106
1107 int tmpRc = vboxVDMAPipeDestruct(&pVdma->Pipe);
1108 AssertRC(tmpRc);
1109 }
1110
1111 RTMemFree(pVdma);
1112#endif
1113 }
1114 else
1115 rc = VERR_OUT_OF_RESOURCES;
1116
1117 return rc;
1118}
1119
1120int vboxVDMADestruct(struct VBOXVDMAHOST *pVdma)
1121{
1122#ifdef VBOX_VDMA_WITH_WORKERTHREAD
1123 /* @todo: implement*/
1124 AssertBreakpoint();
1125#endif
1126 RTMemFree(pVdma);
1127 return VINF_SUCCESS;
1128}
1129
1130#ifdef VBOX_VDMA_WITH_WORKERTHREAD
1131typedef struct
1132{
1133 struct VBOXVDMAHOST *pVdma;
1134 VBOXVDMAPIPE_CMD_BODY Cmd;
1135 bool bQueued;
1136} VBOXVDMACMD_SUBMIT_CONTEXT, *PVBOXVDMACMD_SUBMIT_CONTEXT;
1137
1138DECLCALLBACK(bool) vboxVDMACommandSubmitCb(PVBOXVDMAPIPE pPipe, void *pvCallback)
1139{
1140 PVBOXVDMACMD_SUBMIT_CONTEXT pContext = (PVBOXVDMACMD_SUBMIT_CONTEXT)pvCallback;
1141 struct VBOXVDMAHOST *pVdma = pContext->pVdma;
1142 HGSMILISTENTRY *pEntry = hgsmiListRemoveHead(&pVdma->CmdPool.List);
1143 Assert(pEntry);
1144 if (pEntry)
1145 {
1146 PVBOXVDMAPIPE_CMD pPipeCmd = VBOXVDMAPIPE_CMD_FROM_ENTRY(pEntry);
1147 pPipeCmd->Cmd = pContext->Cmd;
1148 VBoxSHGSMICommandMarkAsynchCompletion(pContext->Cmd.u.pvCmd);
1149 pContext->bQueued = true;
1150 hgsmiListAppend(&pVdma->PendingList, pEntry);
1151 return true;
1152 }
1153
1154 /* @todo: should we try to flush some commands here? */
1155 pContext->bQueued = false;
1156 return false;
1157}
1158#endif
1159
1160int vboxVDMASaveStateExecPrep(struct VBOXVDMAHOST *pVdma, PSSMHANDLE pSSM)
1161{
1162#ifdef VBOX_WITH_CRHGSMI
1163 PVGASTATE pVGAState = pVdma->pVGAState;
1164 PVBOXVDMACMD_CHROMIUM_CTL pCmd = (PVBOXVDMACMD_CHROMIUM_CTL)vboxVDMACrCtlCreate(
1165 VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_BEGIN, sizeof (*pCmd));
1166 Assert(pCmd);
1167 if (pCmd)
1168 {
1169 int rc = vboxVDMACrCtlPost(pVGAState, pCmd);
1170 AssertRC(rc);
1171 if (RT_SUCCESS(rc))
1172 {
1173 rc = vboxVDMACrCtlGetRc(pCmd);
1174 }
1175 vboxVDMACrCtlRelease(pCmd);
1176 return rc;
1177 }
1178 return VERR_NO_MEMORY;
1179#else
1180 return VINF_SUCCESS;
1181#endif
1182}
1183
1184int vboxVDMASaveStateExecDone(struct VBOXVDMAHOST *pVdma, PSSMHANDLE pSSM)
1185{
1186#ifdef VBOX_WITH_CRHGSMI
1187 PVGASTATE pVGAState = pVdma->pVGAState;
1188 PVBOXVDMACMD_CHROMIUM_CTL pCmd = (PVBOXVDMACMD_CHROMIUM_CTL)vboxVDMACrCtlCreate(
1189 VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_END, sizeof (*pCmd));
1190 Assert(pCmd);
1191 if (pCmd)
1192 {
1193 int rc = vboxVDMACrCtlPost(pVGAState, pCmd);
1194 AssertRC(rc);
1195 if (RT_SUCCESS(rc))
1196 {
1197 rc = vboxVDMACrCtlGetRc(pCmd);
1198 }
1199 vboxVDMACrCtlRelease(pCmd);
1200 return rc;
1201 }
1202 return VERR_NO_MEMORY;
1203#else
1204 return VINF_SUCCESS;
1205#endif
1206}
1207
1208
1209void vboxVDMAControl(struct VBOXVDMAHOST *pVdma, PVBOXVDMA_CTL pCmd)
1210{
1211#if 1
1212 PHGSMIINSTANCE pIns = pVdma->pHgsmi;
1213
1214 switch (pCmd->enmCtl)
1215 {
1216 case VBOXVDMA_CTL_TYPE_ENABLE:
1217 pCmd->i32Result = VINF_SUCCESS;
1218 break;
1219 case VBOXVDMA_CTL_TYPE_DISABLE:
1220 pCmd->i32Result = VINF_SUCCESS;
1221 break;
1222 case VBOXVDMA_CTL_TYPE_FLUSH:
1223 pCmd->i32Result = VINF_SUCCESS;
1224 break;
1225 default:
1226 AssertBreakpoint();
1227 pCmd->i32Result = VERR_NOT_SUPPORTED;
1228 }
1229
1230 int rc = VBoxSHGSMICommandComplete (pIns, pCmd);
1231 AssertRC(rc);
1232#else
1233 /* test asinch completion */
1234 VBOXVDMACMD_SUBMIT_CONTEXT Context;
1235 Context.pVdma = pVdma;
1236 Context.Cmd.enmType = VBOXVDMAPIPE_CMD_TYPE_DMACTL;
1237 Context.Cmd.u.pCtl = pCmd;
1238
1239 int rc = vboxVDMAPipeModifyClient(&pVdma->Pipe, vboxVDMACommandSubmitCb, &Context);
1240 AssertRC(rc);
1241 if (RT_SUCCESS(rc))
1242 {
1243 Assert(Context.bQueued);
1244 if (Context.bQueued)
1245 {
1246 /* success */
1247 return;
1248 }
1249 rc = VERR_OUT_OF_RESOURCES;
1250 }
1251
1252 /* failure */
1253 Assert(RT_FAILURE(rc));
1254 PHGSMIINSTANCE pIns = pVdma->pHgsmi;
1255 pCmd->i32Result = rc;
1256 int tmpRc = VBoxSHGSMICommandComplete (pIns, pCmd);
1257 AssertRC(tmpRc);
1258
1259#endif
1260}
1261
1262void vboxVDMACommand(struct VBOXVDMAHOST *pVdma, PVBOXVDMACBUF_DR pCmd)
1263{
1264#ifdef VBOX_WITH_CRHGSMI
1265 if (vboxVDMACmdCheckCrCmd(pVdma, pCmd))
1266 return;
1267#endif
1268
1269 int rc = VERR_NOT_IMPLEMENTED;
1270
1271#ifdef VBOX_VDMA_WITH_WORKERTHREAD
1272
1273#ifdef DEBUG_misha
1274 Assert(0);
1275#endif
1276
1277 VBOXVDMACMD_SUBMIT_CONTEXT Context;
1278 Context.pVdma = pVdma;
1279 Context.Cmd.enmType = VBOXVDMAPIPE_CMD_TYPE_DMACMD;
1280 Context.Cmd.u.pDr = pCmd;
1281
1282 rc = vboxVDMAPipeModifyClient(&pVdma->Pipe, vboxVDMACommandSubmitCb, &Context);
1283 AssertRC(rc);
1284 if (RT_SUCCESS(rc))
1285 {
1286 Assert(Context.bQueued);
1287 if (Context.bQueued)
1288 {
1289 /* success */
1290 return;
1291 }
1292 rc = VERR_OUT_OF_RESOURCES;
1293 }
1294#endif
1295 /* failure */
1296 Assert(RT_FAILURE(rc));
1297 PHGSMIINSTANCE pIns = pVdma->pHgsmi;
1298 pCmd->rc = rc;
1299 int tmpRc = VBoxSHGSMICommandComplete (pIns, pCmd);
1300 AssertRC(tmpRc);
1301}
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