VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxVideo/VBVABase.cpp@ 34497

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

Additions/WINNT/Graphics and Additions/common/VBoxVideo: move the base VBVA support functions into the common driver code

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.7 KB
Line 
1/* $Id: VBVABase.cpp 34440 2010-11-28 22:12:07Z vboxsync $ */
2/** @file
3 * VirtualBox Video driver, common code - VBVA initialisation and helper
4 * functions.
5 */
6
7/*
8 * Copyright (C) 2006-2010 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19#include <VBox/VBoxVideoGuest.h>
20#include <VBox/VBoxVideo.h>
21#include <VBox/err.h>
22#include <VBox/log.h>
23#include <iprt/assert.h>
24
25#include <string.h>
26
27/*
28 * There is a hardware ring buffer in the graphics device video RAM, formerly
29 * in the VBox VMMDev PCI memory space.
30 * All graphics commands go there serialized by VBoxVBVABufferBeginUpdate.
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(PHGSMIGUESTCOMMANDCONTEXT pCtx);
42static void vboxHwBufferPlaceDataAt(PVBVABUFFERCONTEXT pCtx, const void *p,
43 uint32_t cb, uint32_t offset);
44static bool vboxHwBufferWrite(PVBVABUFFERCONTEXT pCtx,
45 PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx,
46 const void *p, uint32_t cb);
47
48
49static bool vboxVBVAInformHost(PVBVABUFFERCONTEXT pCtx,
50 PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx,
51 bool bEnable)
52{
53 bool bRc = false;
54
55#if 0 /* All callers check this */
56 if (ppdev->bHGSMISupported)
57#endif
58 {
59 void *p = VBoxHGSMIBufferAlloc(pHGSMICtx,
60 sizeof (VBVAENABLE),
61 HGSMI_CH_VBVA,
62 VBVA_ENABLE);
63 if (!p)
64 {
65 LogFunc(("HGSMIHeapAlloc failed\n"));
66 }
67 else
68 {
69 VBVAENABLE *pEnable = (VBVAENABLE *)p;
70
71 pEnable->u32Flags = bEnable? VBVA_F_ENABLE: VBVA_F_DISABLE;
72 pEnable->u32Offset = pCtx->offVRAMBuffer;
73 pEnable->i32Result = VERR_NOT_SUPPORTED;
74
75 VBoxHGSMIBufferSubmit(pHGSMICtx, p);
76
77 if (bEnable)
78 {
79 bRc = RT_SUCCESS(pEnable->i32Result);
80 }
81 else
82 {
83 bRc = true;
84 }
85
86 VBoxHGSMIBufferFree(pHGSMICtx, p);
87 }
88 }
89
90 return bRc;
91}
92
93/*
94 * Public hardware buffer methods.
95 */
96RTDECL(bool) VBoxVBVAEnable(PVBVABUFFERCONTEXT pCtx,
97 PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx,
98 VBVABUFFER *pVBVA)
99{
100 bool bRc = false;
101
102 LogFlowFunc(("pVBVA %p\n", pVBVA));
103
104#if 0 /* All callers check this */
105 if (ppdev->bHGSMISupported)
106#endif
107 {
108 LogFunc(("pVBVA %p vbva off 0x%x\n", pVBVA, pCtx->offVRAMBuffer));
109
110 pVBVA->hostFlags.u32HostEvents = 0;
111 pVBVA->hostFlags.u32SupportedOrders = 0;
112 pVBVA->off32Data = 0;
113 pVBVA->off32Free = 0;
114 memset(pVBVA->aRecords, 0, sizeof (pVBVA->aRecords));
115 pVBVA->indexRecordFirst = 0;
116 pVBVA->indexRecordFree = 0;
117 pVBVA->cbPartialWriteThreshold = 256;
118 pVBVA->cbData = pCtx->cbBuffer - sizeof (VBVABUFFER) + sizeof (pVBVA->au8Data);
119
120 pCtx->fHwBufferOverflow = false;
121 pCtx->pRecord = NULL;
122 pCtx->pVBVA = pVBVA;
123
124 bRc = vboxVBVAInformHost(pCtx, pHGSMICtx, true);
125 }
126
127 if (!bRc)
128 {
129 VBoxVBVADisable(pCtx, pHGSMICtx);
130 }
131
132 return bRc;
133}
134
135RTDECL(void) VBoxVBVADisable(PVBVABUFFERCONTEXT pCtx,
136 PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx)
137{
138 LogFlowFunc(("\n"));
139
140 pCtx->fHwBufferOverflow = false;
141 pCtx->pRecord = NULL;
142 pCtx->pVBVA = NULL;
143
144 vboxVBVAInformHost(pCtx, pHGSMICtx, false);
145
146 return;
147}
148
149RTDECL(bool) VBoxVBVABufferBeginUpdate(PVBVABUFFERCONTEXT pCtx,
150 PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx)
151{
152 bool bRc = false;
153
154 // LogFunc(("flags = 0x%08X\n", pCtx->pVBVA? pCtx->pVBVA->u32HostEvents: -1));
155
156 if ( pCtx->pVBVA
157 && (pCtx->pVBVA->hostFlags.u32HostEvents & VBVA_F_MODE_ENABLED))
158 {
159 uint32_t indexRecordNext;
160
161 Assert(!pCtx->fHwBufferOverflow);
162 Assert(pCtx->pRecord == NULL);
163
164 indexRecordNext = (pCtx->pVBVA->indexRecordFree + 1) % VBVA_MAX_RECORDS;
165
166 if (indexRecordNext == pCtx->pVBVA->indexRecordFirst)
167 {
168 /* All slots in the records queue are used. */
169 vboxHwBufferFlush (pHGSMICtx);
170 }
171
172 if (indexRecordNext == pCtx->pVBVA->indexRecordFirst)
173 {
174 /* Even after flush there is no place. Fail the request. */
175 LogFunc(("no space in the queue of records!!! first %d, last %d\n",
176 pCtx->pVBVA->indexRecordFirst, pCtx->pVBVA->indexRecordFree));
177 }
178 else
179 {
180 /* Initialize the record. */
181 VBVARECORD *pRecord = &pCtx->pVBVA->aRecords[pCtx->pVBVA->indexRecordFree];
182
183 pRecord->cbRecord = VBVA_F_RECORD_PARTIAL;
184
185 pCtx->pVBVA->indexRecordFree = indexRecordNext;
186
187 // LogFunc(("indexRecordNext = %d\n", indexRecordNext));
188
189 /* Remember which record we are using. */
190 pCtx->pRecord = pRecord;
191
192 bRc = true;
193 }
194 }
195
196 return bRc;
197}
198
199RTDECL(void) VBoxVBVABufferEndUpdate(PVBVABUFFERCONTEXT pCtx)
200{
201 VBVARECORD *pRecord;
202
203 // LogFunc(("\n"));
204
205 Assert(pCtx->pVBVA);
206
207 pRecord = pCtx->pRecord;
208 Assert(pRecord && (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL));
209
210 /* Mark the record completed. */
211 pRecord->cbRecord &= ~VBVA_F_RECORD_PARTIAL;
212
213 pCtx->fHwBufferOverflow = false;
214 pCtx->pRecord = NULL;
215
216 return;
217}
218
219/*
220 * Private operations.
221 */
222static uint32_t vboxHwBufferAvail (const VBVABUFFER *pVBVA)
223{
224 int32_t i32Diff = pVBVA->off32Data - pVBVA->off32Free;
225
226 return i32Diff > 0? i32Diff: pVBVA->cbData + i32Diff;
227}
228
229static void vboxHwBufferFlush(PHGSMIGUESTCOMMANDCONTEXT pCtx)
230{
231 /* Issue the flush command. */
232 void *p = VBoxHGSMIBufferAlloc(pCtx,
233 sizeof (VBVAFLUSH),
234 HGSMI_CH_VBVA,
235 VBVA_FLUSH);
236 if (!p)
237 {
238 LogFunc(("HGSMIHeapAlloc failed\n"));
239 }
240 else
241 {
242 VBVAFLUSH *pFlush = (VBVAFLUSH *)p;
243
244 pFlush->u32Reserved = 0;
245
246 VBoxHGSMIBufferSubmit(pCtx, p);
247
248 VBoxHGSMIBufferSubmit(pCtx, p);
249 }
250
251 return;
252}
253
254static void vboxHwBufferPlaceDataAt(PVBVABUFFERCONTEXT pCtx, const void *p,
255 uint32_t cb, uint32_t offset)
256{
257 VBVABUFFER *pVBVA = pCtx->pVBVA;
258 uint32_t u32BytesTillBoundary = pVBVA->cbData - offset;
259 uint8_t *dst = &pVBVA->au8Data[offset];
260 int32_t i32Diff = cb - u32BytesTillBoundary;
261
262 if (i32Diff <= 0)
263 {
264 /* Chunk will not cross buffer boundary. */
265 memcpy (dst, p, cb);
266 }
267 else
268 {
269 /* Chunk crosses buffer boundary. */
270 memcpy (dst, p, u32BytesTillBoundary);
271 memcpy (&pVBVA->au8Data[0], (uint8_t *)p + u32BytesTillBoundary, i32Diff);
272 }
273
274 return;
275}
276
277static bool vboxHwBufferWrite(PVBVABUFFERCONTEXT pCtx,
278 PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx,
279 const void *p, uint32_t cb)
280{
281 VBVARECORD *pRecord;
282 uint32_t cbHwBufferAvail;
283
284 uint32_t cbWritten = 0;
285
286 VBVABUFFER *pVBVA = pCtx->pVBVA;
287 Assert(pVBVA);
288
289 if (!pVBVA || pCtx->fHwBufferOverflow)
290 {
291 return false;
292 }
293
294 Assert(pVBVA->indexRecordFirst != pVBVA->indexRecordFree);
295
296 pRecord = pCtx->pRecord;
297 Assert(pRecord && (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL));
298
299 LogFunc(("%d\n", cb));
300
301 cbHwBufferAvail = vboxHwBufferAvail (pVBVA);
302
303 while (cb > 0)
304 {
305 uint32_t cbChunk = cb;
306
307 // LogFunc(("pVBVA->off32Free %d, pRecord->cbRecord 0x%08X, cbHwBufferAvail %d, cb %d, cbWritten %d\n",
308 // pVBVA->off32Free, pRecord->cbRecord, cbHwBufferAvail, cb, cbWritten));
309
310 if (cbChunk >= cbHwBufferAvail)
311 {
312 LogFunc(("1) avail %d, chunk %d\n", cbHwBufferAvail, cbChunk));
313
314 vboxHwBufferFlush (pHGSMICtx);
315
316 cbHwBufferAvail = vboxHwBufferAvail (pVBVA);
317
318 if (cbChunk >= cbHwBufferAvail)
319 {
320 LogFunc(("no place for %d bytes. Only %d bytes available after flush. Going to partial writes.\n",
321 cb, cbHwBufferAvail));
322
323 if (cbHwBufferAvail <= pVBVA->cbPartialWriteThreshold)
324 {
325 LogFunc(("Buffer overflow!!!\n"));
326 pCtx->fHwBufferOverflow = true;
327 Assert(false);
328 return false;
329 }
330
331 cbChunk = cbHwBufferAvail - pVBVA->cbPartialWriteThreshold;
332 }
333 }
334
335 Assert(cbChunk <= cb);
336 Assert(cbChunk <= vboxHwBufferAvail (pVBVA));
337
338 vboxHwBufferPlaceDataAt (pCtx, (uint8_t *)p + cbWritten, cbChunk, pVBVA->off32Free);
339
340 pVBVA->off32Free = (pVBVA->off32Free + cbChunk) % pVBVA->cbData;
341 pRecord->cbRecord += cbChunk;
342 cbHwBufferAvail -= cbChunk;
343
344 cb -= cbChunk;
345 cbWritten += cbChunk;
346 }
347
348 return true;
349}
350
351/*
352 * Public writer to the hardware buffer.
353 */
354RTDECL(bool) VBoxVBVAWrite(PVBVABUFFERCONTEXT pCtx,
355 PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx,
356 const void *pv, uint32_t cb)
357{
358 return vboxHwBufferWrite (pCtx, pHGSMICtx, pv, cb);
359}
360
361RTDECL(bool) VBoxVBVAOrderSupported(PVBVABUFFERCONTEXT pCtx, unsigned code)
362{
363 VBVABUFFER *pVBVA = pCtx->pVBVA;
364
365 if (!pVBVA)
366 {
367 return false;
368 }
369
370 if (pVBVA->hostFlags.u32SupportedOrders & (1 << code))
371 {
372 return true;
373 }
374
375 return false;
376}
377
378RTDECL(void) VBoxHGSMIProcessDisplayInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx,
379 uint32_t cDisplay,
380 int32_t cOriginX,
381 int32_t cOriginY,
382 uint32_t offStart,
383 uint32_t cbPitch,
384 uint32_t cWidth,
385 uint32_t cHeight,
386 uint16_t cBPP)
387{
388 /* Issue the screen info command. */
389 void *p = VBoxHGSMIBufferAlloc(pCtx,
390 sizeof (VBVAINFOSCREEN),
391 HGSMI_CH_VBVA,
392 VBVA_INFO_SCREEN);
393 if (!p)
394 {
395 LogFunc(("HGSMIHeapAlloc failed\n"));
396 }
397 else
398 {
399 VBVAINFOSCREEN *pScreen = (VBVAINFOSCREEN *)p;
400
401 pScreen->u32ViewIndex = cDisplay;
402 pScreen->i32OriginX = cOriginX;
403 pScreen->i32OriginY = cOriginY;
404 pScreen->u32StartOffset = offStart;
405 pScreen->u32LineSize = cbPitch;
406 pScreen->u32Width = cWidth;
407 pScreen->u32Height = cHeight;
408 pScreen->u16BitsPerPixel = cBPP;
409 pScreen->u16Flags = VBVA_SCREEN_F_ACTIVE;
410
411 VBoxHGSMIBufferSubmit(pCtx, p);
412
413 VBoxHGSMIBufferFree(pCtx, p);
414 }
415}
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