VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Display/vbox.c@ 3382

Last change on this file since 3382 was 3153, checked in by vboxsync, 18 years ago

Multimonitor support.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.4 KB
Line 
1/** @file
2 *
3 * VBoxGuest -- VirtualBox Win 2000/XP guest display driver
4 *
5 * VBox support functions.
6 *
7 * Copyright (C) 2006-2007 innotek GmbH
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 as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 *
21 */
22
23#include "driver.h"
24
25#include <VBox/VBoxGuest.h>
26#include <VBox/err.h>
27#include <iprt/asm.h>
28
29/*
30 * There is a hardware ring buffer in the VBox VMMDev PCI memory space.
31 * All graphics commands go there serialized by vboxHwBufferBeginUpdate.
32 * and vboxHwBufferEndUpdate.
33 *
34 * off32Free is writing position. off32Data is reading position.
35 * off32Free == off32Data means buffer is empty.
36 * There must be always gap between off32Data and off32Free when data
37 * are in the buffer.
38 * Guest only changes off32Free, host changes off32Data.
39 */
40
41/* Forward declarations of internal functions. */
42static void vboxHwBufferFlush (PPDEV ppdev);
43static void vboxHwBufferPlaceDataAt (PPDEV ppdev, void *p, uint32_t cb, uint32_t offset);
44static BOOL vboxHwBufferWrite (PPDEV ppdev, const void *p, uint32_t cb);
45
46/*
47 * Public hardware buffer methods.
48 */
49BOOL vboxVbvaEnable (PPDEV ppdev)
50{
51 BOOL bRc = FALSE;
52
53 ULONG returnedDataLength;
54 ULONG ulEnable = TRUE;
55
56 DISPDBG((1, "VBoxDisp::vboxVbvaEnable called\n"));
57
58 if (!ghsemHwBuffer)
59 {
60 return FALSE;
61 }
62
63 if (EngDeviceIoControl(ppdev->hDriver,
64 IOCTL_VIDEO_VBVA_ENABLE,
65 &ulEnable,
66 sizeof (ulEnable),
67 &ppdev->vbva,
68 sizeof (ppdev->vbva),
69 &returnedDataLength) == 0)
70 {
71 DISPDBG((1, "VBoxDisp::vboxVbvaEnable: vbva: pVbvaMemory = %p, pfnFlush = %p, pvFlush = %p.\n",
72 ppdev->vbva.pVbvaMemory, ppdev->vbva.pfnFlush, ppdev->vbva.pvFlush));
73
74 if (ppdev->vbva.pVbvaMemory
75 && ppdev->vbva.pfnFlush
76 && ppdev->vbva.pvFlush)
77 {
78 ppdev->fHwBufferOverflow = FALSE;
79 ppdev->pRecord = NULL;
80
81 /* All have been initialized. */
82 bRc = TRUE;
83 }
84 }
85
86 if (!bRc)
87 {
88 vboxVbvaDisable (ppdev);
89 }
90
91 return bRc;
92}
93
94void vboxVbvaDisable (PPDEV ppdev)
95{
96 DISPDBG((1, "VBoxDisp::vbvaDisable called.\n"));
97
98 RtlZeroMemory (&ppdev->vbva, sizeof (ppdev->vbva));
99
100 ppdev->fHwBufferOverflow = FALSE;
101 ppdev->pRecord = NULL;
102
103 return;
104}
105
106BOOL vboxHwBufferBeginUpdate (PPDEV ppdev)
107{
108 BOOL bRc = FALSE;
109
110 VBVAMEMORY *pVbvaMemory = ppdev->vbva.pVbvaMemory;
111
112 DISPDBG((1, "VBoxDisp::vboxHwBufferBeginUpdate called flags = 0x%08X\n", pVbvaMemory? pVbvaMemory->fu32ModeFlags: -1));
113
114 if ( pVbvaMemory
115 && (pVbvaMemory->fu32ModeFlags & VBVA_F_MODE_ENABLED))
116 {
117 uint32_t indexRecordNext;
118
119 EngAcquireSemaphore (ghsemHwBuffer);
120
121 VBVA_ASSERT (!ppdev->fHwBufferOverflow);
122 VBVA_ASSERT (ppdev->pRecord == NULL);
123
124 indexRecordNext = (pVbvaMemory->indexRecordFree + 1) % VBVA_MAX_RECORDS;
125
126 if (indexRecordNext == pVbvaMemory->indexRecordFirst)
127 {
128 /* All slots in the records queue are used. */
129 vboxHwBufferFlush (ppdev);
130 }
131
132 if (indexRecordNext == pVbvaMemory->indexRecordFirst)
133 {
134 /* Even after flush there is no place. Fail the request. */
135 DISPDBG((1, "VBoxDisp::vboxHwBufferBeginUpdate no space in the queue of records!!! first %d, last %d\n",
136 pVbvaMemory->indexRecordFirst, pVbvaMemory->indexRecordFree));
137 EngReleaseSemaphore (ghsemHwBuffer);
138 }
139 else
140 {
141 /* Initialize the record. */
142 VBVARECORD *pRecord = &pVbvaMemory->aRecords[pVbvaMemory->indexRecordFree];
143
144 pRecord->cbRecord = VBVA_F_RECORD_PARTIAL;
145
146 pVbvaMemory->indexRecordFree = indexRecordNext;
147
148 DISPDBG((1, "VBoxDisp::vboxHwBufferBeginUpdate indexRecordNext = %d\n", indexRecordNext));
149
150 /* Remember which record we are using. */
151 ppdev->pRecord = pRecord;
152
153 bRc = TRUE;
154 }
155 }
156
157 return bRc;
158}
159
160void vboxHwBufferEndUpdate (PPDEV ppdev)
161{
162 VBVAMEMORY *pVbvaMemory;
163 VBVARECORD *pRecord;
164
165 DISPDBG((1, "VBoxDisp::vboxHwBufferEndUpdate called\n"));
166
167 pVbvaMemory = ppdev->vbva.pVbvaMemory;
168 VBVA_ASSERT(pVbvaMemory);
169
170 pRecord = ppdev->pRecord;
171 VBVA_ASSERT (pRecord && (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL));
172
173 /* Mark the record completed. */
174 pRecord->cbRecord &= ~VBVA_F_RECORD_PARTIAL;
175
176 ppdev->fHwBufferOverflow = FALSE;
177 ppdev->pRecord = NULL;
178
179 EngReleaseSemaphore (ghsemHwBuffer);
180
181 return;
182}
183
184/*
185 * Private operations.
186 */
187static uint32_t vboxHwBufferAvail (VBVAMEMORY *pVbvaMemory)
188{
189 int32_t i32Diff = pVbvaMemory->off32Data - pVbvaMemory->off32Free;
190
191 return i32Diff > 0? i32Diff: VBVA_RING_BUFFER_SIZE + i32Diff;
192}
193
194static void vboxHwBufferFlush (PPDEV ppdev)
195{
196 VBVAMEMORY *pVbvaMemory = ppdev->vbva.pVbvaMemory;
197
198 VBVA_ASSERT (pVbvaMemory);
199
200 ppdev->vbva.pfnFlush (ppdev->vbva.pvFlush);
201
202 return;
203}
204
205static void vboxHwBufferPlaceDataAt (PPDEV ppdev, void *p, uint32_t cb, uint32_t offset)
206{
207 VBVAMEMORY *pVbvaMemory = ppdev->vbva.pVbvaMemory;
208
209 uint32_t u32BytesTillBoundary = VBVA_RING_BUFFER_SIZE - offset;
210 uint8_t *dst = &pVbvaMemory->au8RingBuffer[offset];
211 int32_t i32Diff = cb - u32BytesTillBoundary;
212
213 if (i32Diff <= 0)
214 {
215 /* Chunk will not cross buffer boundary. */
216 memcpy (dst, p, cb);
217 }
218 else
219 {
220 /* Chunk crosses buffer boundary. */
221 memcpy (dst, p, u32BytesTillBoundary);
222 memcpy (&pVbvaMemory->au8RingBuffer[0], (uint8_t *)p + u32BytesTillBoundary, i32Diff);
223 }
224
225 return;
226}
227
228static BOOL vboxHwBufferWrite (PPDEV ppdev, const void *p, uint32_t cb)
229{
230 VBVAMEMORY *pVbvaMemory;
231 VBVARECORD *pRecord;
232 uint32_t cbHwBufferAvail;
233
234 uint32_t cbWritten = 0;
235
236 VBVA_ASSERT(ppdev);
237
238 if (ppdev->fHwBufferOverflow)
239 {
240 return FALSE;
241 }
242
243 pVbvaMemory = ppdev->vbva.pVbvaMemory;
244 VBVA_ASSERT (pVbvaMemory->indexRecordFirst != pVbvaMemory->indexRecordFree);
245
246 pRecord = ppdev->pRecord;
247 VBVA_ASSERT (pRecord && (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL));
248
249 DISPDBG((1, "VW %d\n", cb));
250
251 cbHwBufferAvail = vboxHwBufferAvail (pVbvaMemory);
252
253 while (cb > 0)
254 {
255 uint32_t cbChunk = cb;
256
257// DISPDBG((1, "VBoxDisp::vboxHwBufferWrite pVbvaMemory->off32Free %d, pRecord->cbRecord 0x%08X, cbHwBufferAvail %d, cb %d, cbWritten %d\n", pVbvaMemory->off32Free, pRecord->cbRecord, cbHwBufferAvail, cb, cbWritten));
258
259 if (cbChunk >= cbHwBufferAvail)
260 {
261 DISPDBG((1, "VBoxDisp::vboxHwBufferWrite 1) avail %d, chunk %d\n", cbHwBufferAvail, cbChunk));
262
263 vboxHwBufferFlush (ppdev);
264
265 cbHwBufferAvail = vboxHwBufferAvail (pVbvaMemory);
266
267 if (cbChunk >= cbHwBufferAvail)
268 {
269 DISPDBG((1, "VBoxDisp::vboxHwBufferWrite: no place for %d bytes. Only %d bytes available after flush. Going to partial writes.\n", cb, cbHwBufferAvail));
270
271 if (cbHwBufferAvail <= VBVA_RING_BUFFER_THRESHOLD)
272 {
273 DISPDBG((1, "VBoxDisp::vboxHwBufferWrite: Buffer overflow!!!\n"));
274 ppdev->fHwBufferOverflow = TRUE;
275 VBVA_ASSERT(FALSE);
276 return FALSE;
277 }
278
279 cbChunk = cbHwBufferAvail - VBVA_RING_BUFFER_THRESHOLD;
280 }
281 }
282
283 VBVA_ASSERT(cbChunk <= cb);
284 VBVA_ASSERT(cbChunk <= vboxHwBufferAvail (pVbvaMemory));
285
286 vboxHwBufferPlaceDataAt (ppdev, (uint8_t *)p + cbWritten, cbChunk, pVbvaMemory->off32Free);
287
288 pVbvaMemory->off32Free = (pVbvaMemory->off32Free + cbChunk) % VBVA_RING_BUFFER_SIZE;
289 pRecord->cbRecord += cbChunk;
290 cbHwBufferAvail -= cbChunk;
291
292 cb -= cbChunk;
293 cbWritten += cbChunk;
294 }
295
296 return TRUE;
297}
298
299/*
300 * Public writer to hardware buffer.
301 */
302BOOL vboxWrite (PPDEV ppdev, const void *pv, uint32_t cb)
303{
304 return vboxHwBufferWrite (ppdev, pv, cb);
305}
306
307BOOL vboxOrderSupported (PPDEV ppdev, unsigned code)
308{
309 VBVAMEMORY *pVbvaMemory;
310
311 pVbvaMemory = ppdev->vbva.pVbvaMemory;
312
313 if (pVbvaMemory->fu32ModeFlags & VBVA_F_MODE_VRDP_ORDER_MASK)
314 {
315 /* Order masking enabled. */
316 if (pVbvaMemory->fu32SupportedOrders & (1 << code))
317 {
318 return TRUE;
319 }
320 }
321
322 return FALSE;
323}
324
325void VBoxProcessDisplayInfo(PPDEV ppdev)
326{
327 DWORD returnedDataLength;
328
329 DISPDBG((1, "Process: %d,%d\n", ppdev->ptlDevOrg.x, ppdev->ptlDevOrg.y));
330
331 EngDeviceIoControl(ppdev->hDriver,
332 IOCTL_VIDEO_INTERPRET_DISPLAY_MEMORY,
333 NULL,
334 0,
335 NULL,
336 0,
337 &returnedDataLength);
338}
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