VirtualBox

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

Last change on this file since 8170 was 8155, checked in by vboxsync, 16 years ago

The Big Sun Rebranding Header Change

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