VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Miniport/wddm/VBoxVideoVbva.cpp@ 33226

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

Additions/WINNT/Graphics: more refactoring

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.0 KB
Line 
1/** @file
2 *
3 * VirtualBox Windows Wddm guest video driver
4 *
5 * VBVA dirty rectangles calculations.
6 *
7 * Copyright (C) 2010 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include "../VBoxVideo.h"
19#include "../Helper.h"
20
21static int vboxVBVAInformHost (PDEVICE_EXTENSION pDevExt, VBOXVBVAINFO * pVbva, BOOL bEnable)
22{
23 int rc = VERR_NO_MEMORY;
24 void *p = vboxHGSMIBufferAlloc (commonFromDeviceExt(pDevExt),
25 sizeof (VBVAENABLE_EX),
26 HGSMI_CH_VBVA,
27 VBVA_ENABLE);
28 Assert(p);
29 if (!p)
30 {
31 drprintf((__FUNCTION__":vboxVBVAInformHost: HGSMIHeapAlloc failed\n"));
32 rc = VERR_NO_MEMORY;
33 }
34 else
35 {
36 VBVAENABLE_EX *pEnableEx = (VBVAENABLE_EX *)p;
37 pEnableEx->u32ScreenId = pVbva->srcId;
38
39 VBVAENABLE *pEnable = &pEnableEx->Base;
40 pEnable->u32Flags = bEnable? VBVA_F_ENABLE: VBVA_F_DISABLE;
41 pEnable->u32Flags |= VBVA_F_EXTENDED | VBVA_F_ABSOFFSET;
42 pEnable->u32Offset = (uint32_t)pVbva->offVBVA;
43 pEnable->i32Result = VERR_NOT_SUPPORTED;
44
45 vboxHGSMIBufferSubmit (commonFromDeviceExt(pDevExt), p);
46
47 if (bEnable)
48 {
49 rc = pEnable->i32Result;
50 AssertRC(rc);
51 }
52 else
53 rc = VINF_SUCCESS;
54
55 vboxHGSMIBufferFree (commonFromDeviceExt(pDevExt), p);
56 }
57 return rc;
58}
59
60/*
61 * Public hardware buffer methods.
62 */
63int vboxVbvaEnable (PDEVICE_EXTENSION pDevExt, VBOXVBVAINFO *pVbva)
64{
65 VBVABUFFER *pVBVA = pVbva->pVBVA;
66
67// DISPDBG((1, "VBoxDisp::vboxVbvaEnable screen %p vbva off 0x%x\n", ppdev->pjScreen, ppdev->layout.offVBVABuffer));
68
69 pVBVA->hostFlags.u32HostEvents = 0;
70 pVBVA->hostFlags.u32SupportedOrders = 0;
71 pVBVA->off32Data = 0;
72 pVBVA->off32Free = 0;
73 RtlZeroMemory (pVBVA->aRecords, sizeof (pVBVA->aRecords));
74 pVBVA->indexRecordFirst = 0;
75 pVBVA->indexRecordFree = 0;
76 pVBVA->cbPartialWriteThreshold = 256;
77 pVBVA->cbData = pVbva->cbVBVA - sizeof (VBVABUFFER) + sizeof (pVBVA->au8Data);
78
79 pVbva->fHwBufferOverflow = FALSE;
80 pVbva->pRecord = NULL;
81
82 int rc = vboxVBVAInformHost (pDevExt, pVbva, TRUE);
83 AssertRC(rc);
84
85 if (!RT_SUCCESS(rc))
86 vboxVbvaDisable (pDevExt, pVbva);
87
88 return rc;
89}
90
91int vboxVbvaDisable (PDEVICE_EXTENSION pDevExt, VBOXVBVAINFO *pVbva)
92{
93// DISPDBG((1, "VBoxDisp::vbvaDisable called.\n"));
94
95 pVbva->fHwBufferOverflow = FALSE;
96 pVbva->pRecord = NULL;
97// ppdev->pVBVA = NULL;
98
99 return vboxVBVAInformHost (pDevExt, pVbva, FALSE);
100}
101
102int vboxVbvaCreate(PDEVICE_EXTENSION pDevExt, VBOXVBVAINFO *pVbva, ULONG offBuffer, ULONG cbBuffer, D3DDDI_VIDEO_PRESENT_SOURCE_ID srcId)
103{
104 memset(pVbva, 0, sizeof(VBOXVBVAINFO));
105
106 KeInitializeSpinLock(&pVbva->Lock);
107
108 int rc = VBoxMapAdapterMemory (commonFromDeviceExt(pDevExt),
109 (void**)&pVbva->pVBVA,
110 offBuffer,
111 cbBuffer);
112 AssertRC(rc);
113 if (RT_SUCCESS(rc))
114 {
115 Assert(pVbva->pVBVA);
116 pVbva->offVBVA = offBuffer;
117 pVbva->cbVBVA = cbBuffer;
118 pVbva->srcId = srcId;
119 }
120
121 return rc;
122}
123
124int vboxVbvaDestroy(PDEVICE_EXTENSION pDevExt, VBOXVBVAINFO *pVbva)
125{
126 int rc = VINF_SUCCESS;
127 /*rc = */VBoxUnmapAdapterMemory(pDevExt, (void**)&pVbva->pVBVA, pVbva->cbVBVA);
128/*
129 AssertRC(rc);
130 if (RT_SUCCESS(rc))
131*/
132 memset(pVbva, 0, sizeof(VBOXVBVAINFO));
133/*
134 else
135 drprintf((__FUNCTION__": VBoxUnmapAdapterMemory failed, rc (%d)\n", rc));
136*/
137 return rc;
138}
139
140/*
141 * Private operations.
142 */
143static uint32_t vboxHwBufferAvail (const VBVABUFFER *pVBVA)
144{
145 int32_t i32Diff = pVBVA->off32Data - pVBVA->off32Free;
146
147 return i32Diff > 0? i32Diff: pVBVA->cbData + i32Diff;
148}
149
150static void vboxHwBufferFlush (PDEVICE_EXTENSION pDevExt, VBOXVBVAINFO *pVbva)
151{
152 /* Issue the flush command. */
153 void *p = vboxHGSMIBufferAlloc (commonFromDeviceExt(pDevExt),
154 sizeof (VBVAFLUSH),
155 HGSMI_CH_VBVA,
156 VBVA_FLUSH);
157 Assert(p);
158 if (!p)
159 {
160 drprintf((__FUNCTION__":vboxHwBufferFlush: HGSMIHeapAlloc failed\n"));
161 }
162 else
163 {
164 VBVAFLUSH *pFlush = (VBVAFLUSH *)p;
165
166 pFlush->u32Reserved = 0;
167
168 vboxHGSMIBufferSubmit (commonFromDeviceExt(pDevExt), p);
169
170 vboxHGSMIBufferFree (commonFromDeviceExt(pDevExt), p);
171 }
172
173 return;
174}
175
176static void vboxHwBufferPlaceDataAt (VBVABUFFER *pVBVA, const void *p, uint32_t cb, uint32_t offset)
177{
178 uint32_t u32BytesTillBoundary = pVBVA->cbData - offset;
179 uint8_t *dst = &pVBVA->au8Data[offset];
180 int32_t i32Diff = cb - u32BytesTillBoundary;
181
182 if (i32Diff <= 0)
183 {
184 /* Chunk will not cross buffer boundary. */
185 memcpy (dst, p, cb);
186 }
187 else
188 {
189 /* Chunk crosses buffer boundary. */
190 memcpy (dst, p, u32BytesTillBoundary);
191 memcpy (&pVBVA->au8Data[0], (uint8_t *)p + u32BytesTillBoundary, i32Diff);
192 }
193
194 return;
195}
196
197BOOL vboxVbvaBufferBeginUpdate (PDEVICE_EXTENSION pDevExt, VBOXVBVAINFO *pVbva)
198{
199 BOOL bRc = FALSE;
200
201 // DISPDBG((1, "VBoxDisp::vboxHwBufferBeginUpdate called flags = 0x%08X\n",
202 // ppdev->pVBVA? ppdev->pVBVA->u32HostEvents: -1));
203
204 if ( pVbva->pVBVA
205 && (pVbva->pVBVA->hostFlags.u32HostEvents & VBVA_F_MODE_ENABLED))
206 {
207 uint32_t indexRecordNext;
208
209 Assert (!pVbva->fHwBufferOverflow);
210 Assert (pVbva->pRecord == NULL);
211
212 indexRecordNext = (pVbva->pVBVA->indexRecordFree + 1) % VBVA_MAX_RECORDS;
213
214 if (indexRecordNext == pVbva->pVBVA->indexRecordFirst)
215 {
216 /* All slots in the records queue are used. */
217 vboxHwBufferFlush (pDevExt, pVbva);
218 }
219
220 if (indexRecordNext == pVbva->pVBVA->indexRecordFirst)
221 {
222// /* Even after flush there is no place. Fail the request. */
223// DISPDBG((1, "VBoxDisp::vboxHwBufferBeginUpdate no space in the queue of records!!! first %d, last %d\n",
224// ppdev->pVBVA->indexRecordFirst, ppdev->pVBVA->indexRecordFree));
225 }
226 else
227 {
228 /* Initialize the record. */
229 VBVARECORD *pRecord = &pVbva->pVBVA->aRecords[pVbva->pVBVA->indexRecordFree];
230
231 pRecord->cbRecord = VBVA_F_RECORD_PARTIAL;
232
233 pVbva->pVBVA->indexRecordFree = indexRecordNext;
234
235 // DISPDBG((1, "VBoxDisp::vboxHwBufferBeginUpdate indexRecordNext = %d\n", indexRecordNext));
236
237 /* Remember which record we are using. */
238 pVbva->pRecord = pRecord;
239
240 bRc = TRUE;
241 }
242 }
243
244 return bRc;
245}
246
247void vboxVbvaBufferEndUpdate (PDEVICE_EXTENSION pDevExt, VBOXVBVAINFO *pVbva)
248{
249 VBVARECORD *pRecord;
250
251 // DISPDBG((1, "VBoxDisp::vboxHwBufferEndUpdate called\n"));
252
253 Assert(pVbva->pVBVA);
254
255 pRecord = pVbva->pRecord;
256 Assert (pRecord && (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL));
257
258 /* Mark the record completed. */
259 pRecord->cbRecord &= ~VBVA_F_RECORD_PARTIAL;
260
261 pVbva->fHwBufferOverflow = FALSE;
262 pVbva->pRecord = NULL;
263
264 return;
265}
266
267static int vboxHwBufferWrite (PDEVICE_EXTENSION pDevExt, VBOXVBVAINFO *pVbva, const void *p, uint32_t cb)
268{
269 VBVARECORD *pRecord;
270 uint32_t cbHwBufferAvail;
271
272 uint32_t cbWritten = 0;
273
274 VBVABUFFER *pVBVA = pVbva->pVBVA;
275 Assert(pVBVA);
276
277 if (!pVBVA || pVbva->fHwBufferOverflow)
278 {
279 return VERR_INVALID_STATE;
280 }
281
282 Assert (pVBVA->indexRecordFirst != pVBVA->indexRecordFree);
283
284 pRecord = pVbva->pRecord;
285 Assert (pRecord && (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL));
286
287// dfprintf((__FUNCTION__": VW %d\n", cb));
288
289 cbHwBufferAvail = vboxHwBufferAvail (pVBVA);
290
291 while (cb > 0)
292 {
293 uint32_t cbChunk = cb;
294
295 // DISPDBG((1, "VBoxDisp::vboxHwBufferWrite pVBVA->off32Free %d, pRecord->cbRecord 0x%08X, cbHwBufferAvail %d, cb %d, cbWritten %d\n",
296 // pVBVA->off32Free, pRecord->cbRecord, cbHwBufferAvail, cb, cbWritten));
297
298 if (cbChunk >= cbHwBufferAvail)
299 {
300 dfprintf((__FUNCTION__": 1) avail %d, chunk %d\n", cbHwBufferAvail, cbChunk));
301
302 vboxHwBufferFlush (pDevExt, pVbva);
303
304 cbHwBufferAvail = vboxHwBufferAvail (pVBVA);
305
306 if (cbChunk >= cbHwBufferAvail)
307 {
308 dprintf((__FUNCTION__": no place for %d bytes. Only %d bytes available after flush. Going to partial writes.\n",
309 cb, cbHwBufferAvail));
310
311 if (cbHwBufferAvail <= pVBVA->cbPartialWriteThreshold)
312 {
313 drprintf((__FUNCTION__": Buffer overflow!!!\n"));
314 pVbva->fHwBufferOverflow = TRUE;
315 Assert(FALSE);
316 return VERR_NO_MEMORY;
317 }
318
319 cbChunk = cbHwBufferAvail - pVBVA->cbPartialWriteThreshold;
320 }
321 }
322
323 Assert(cbChunk <= cb);
324 Assert(cbChunk <= vboxHwBufferAvail (pVBVA));
325
326 vboxHwBufferPlaceDataAt (pVbva->pVBVA, (uint8_t *)p + cbWritten, cbChunk, pVBVA->off32Free);
327
328 pVBVA->off32Free = (pVBVA->off32Free + cbChunk) % pVBVA->cbData;
329 pRecord->cbRecord += cbChunk;
330 cbHwBufferAvail -= cbChunk;
331
332 cb -= cbChunk;
333 cbWritten += cbChunk;
334 }
335
336 return VINF_SUCCESS;
337}
338
339/*
340 * Public writer to the hardware buffer.
341 */
342int vboxWrite (PDEVICE_EXTENSION pDevExt, VBOXVBVAINFO *pVbva, const void *pv, uint32_t cb)
343{
344 return vboxHwBufferWrite (pDevExt, pVbva, pv, cb);
345}
346
347
348int vboxVbvaReportDirtyRect (PDEVICE_EXTENSION pDevExt, PVBOXWDDM_SOURCE pSrc, RECT *pRectOrig)
349{
350 VBVACMDHDR hdr;
351
352 RECT rect = *pRectOrig;
353
354// if (rect.left < 0) rect.left = 0;
355// if (rect.top < 0) rect.top = 0;
356// if (rect.right > (int)ppdev->cxScreen) rect.right = ppdev->cxScreen;
357// if (rect.bottom > (int)ppdev->cyScreen) rect.bottom = ppdev->cyScreen;
358
359 hdr.x = (int16_t)rect.left;
360 hdr.y = (int16_t)rect.top;
361 hdr.w = (uint16_t)(rect.right - rect.left);
362 hdr.h = (uint16_t)(rect.bottom - rect.top);
363
364 hdr.x += (int16_t)pSrc->VScreenPos.x;
365 hdr.y += (int16_t)pSrc->VScreenPos.y;
366
367 return vboxWrite (pDevExt, &pSrc->Vbva, &hdr, sizeof(hdr));
368}
369
370#ifdef VBOXVDMA_WITH_VBVA
371int vboxVbvaReportCmdOffset (PDEVICE_EXTENSION pDevExt, VBOXVBVAINFO *pVbva, uint32_t offCmd)
372{
373 VBOXVDMAVBVACMD cmd;
374 cmd.offCmd = offCmd;
375 return vboxWrite (pDevExt, pVbva, &cmd, sizeof(cmd));
376}
377#endif
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