VirtualBox

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

Last change on this file since 65661 was 65381, checked in by vboxsync, 8 years ago

bugref:8282: Additions/linux: submit DRM driver to the Linux kernel: move all graphics device-related header files to a separate sub-directory and add that to the include path where they are needed. The intention is too be able to remove the VBox/ include folder in the DRM driver package.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.9 KB
Line 
1/* $Id: VBVABase.cpp 65381 2017-01-20 09:23:53Z vboxsync $ */
2/** @file
3 * VirtualBox Video driver, common code - VBVA initialisation and helper
4 * functions.
5 */
6
7/*
8 * Copyright (C) 2006-2016 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 <VBoxVideoGuest.h>
20#include <VBox/err.h>
21// #include <VBox/log.h>
22#include <iprt/string.h>
23
24/*
25 * There is a hardware ring buffer in the graphics device video RAM, formerly
26 * in the VBox VMMDev PCI memory space.
27 * All graphics commands go there serialized by VBoxVBVABufferBeginUpdate.
28 * and vboxHwBufferEndUpdate.
29 *
30 * off32Free is writing position. off32Data is reading position.
31 * off32Free == off32Data means buffer is empty.
32 * There must be always gap between off32Data and off32Free when data
33 * are in the buffer.
34 * Guest only changes off32Free, host changes off32Data.
35 */
36
37/* Forward declarations of internal functions. */
38static void vboxHwBufferFlush(PHGSMIGUESTCOMMANDCONTEXT pCtx);
39static void vboxHwBufferPlaceDataAt(PVBVABUFFERCONTEXT pCtx, const void *p,
40 uint32_t cb, uint32_t offset);
41static bool vboxHwBufferWrite(PVBVABUFFERCONTEXT pCtx,
42 PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx,
43 const void *p, uint32_t cb);
44
45
46static bool vboxVBVAInformHost(PVBVABUFFERCONTEXT pCtx,
47 PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx,
48 int32_t cScreen, bool bEnable)
49{
50 bool bRc = false;
51
52#if 0 /* All callers check this */
53 if (ppdev->bHGSMISupported)
54#endif
55 {
56 void *p = VBoxHGSMIBufferAlloc(pHGSMICtx,
57 sizeof (VBVAENABLE_EX),
58 HGSMI_CH_VBVA,
59 VBVA_ENABLE);
60 if (!p)
61 {
62 // LogFunc(("HGSMIHeapAlloc failed\n"));
63 }
64 else
65 {
66 VBVAENABLE_EX *pEnable = (VBVAENABLE_EX *)p;
67
68 pEnable->Base.u32Flags = bEnable? VBVA_F_ENABLE: VBVA_F_DISABLE;
69 pEnable->Base.u32Offset = pCtx->offVRAMBuffer;
70 pEnable->Base.i32Result = VERR_NOT_SUPPORTED;
71 if (cScreen >= 0)
72 {
73 pEnable->Base.u32Flags |= VBVA_F_EXTENDED | VBVA_F_ABSOFFSET;
74 pEnable->u32ScreenId = cScreen;
75 }
76
77 VBoxHGSMIBufferSubmit(pHGSMICtx, p);
78
79 if (bEnable)
80 {
81 bRc = RT_SUCCESS(pEnable->Base.i32Result);
82 }
83 else
84 {
85 bRc = true;
86 }
87
88 VBoxHGSMIBufferFree(pHGSMICtx, p);
89 }
90 }
91
92 return bRc;
93}
94
95/*
96 * Public hardware buffer methods.
97 */
98DECLHIDDEN(bool) VBoxVBVAEnable(PVBVABUFFERCONTEXT pCtx,
99 PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx,
100 VBVABUFFER *pVBVA, int32_t cScreen)
101{
102 bool bRc = false;
103
104 // LogFlowFunc(("pVBVA %p\n", pVBVA));
105
106#if 0 /* All callers check this */
107 if (ppdev->bHGSMISupported)
108#endif
109 {
110 // LogFunc(("pVBVA %p vbva off 0x%x\n", pVBVA, pCtx->offVRAMBuffer));
111
112 pVBVA->hostFlags.u32HostEvents = 0;
113 pVBVA->hostFlags.u32SupportedOrders = 0;
114 pVBVA->off32Data = 0;
115 pVBVA->off32Free = 0;
116 memset(pVBVA->aRecords, 0, sizeof (pVBVA->aRecords));
117 pVBVA->indexRecordFirst = 0;
118 pVBVA->indexRecordFree = 0;
119 pVBVA->cbPartialWriteThreshold = 256;
120 pVBVA->cbData = pCtx->cbBuffer - sizeof (VBVABUFFER) + sizeof (pVBVA->au8Data);
121
122 pCtx->fHwBufferOverflow = false;
123 pCtx->pRecord = NULL;
124 pCtx->pVBVA = pVBVA;
125
126 bRc = vboxVBVAInformHost(pCtx, pHGSMICtx, cScreen, true);
127 }
128
129 if (!bRc)
130 {
131 VBoxVBVADisable(pCtx, pHGSMICtx, cScreen);
132 }
133
134 return bRc;
135}
136
137DECLHIDDEN(void) VBoxVBVADisable(PVBVABUFFERCONTEXT pCtx,
138 PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx,
139 int32_t cScreen)
140{
141 // LogFlowFunc(("\n"));
142
143 pCtx->fHwBufferOverflow = false;
144 pCtx->pRecord = NULL;
145 pCtx->pVBVA = NULL;
146
147 vboxVBVAInformHost(pCtx, pHGSMICtx, cScreen, false);
148
149 return;
150}
151
152DECLHIDDEN(bool) VBoxVBVABufferBeginUpdate(PVBVABUFFERCONTEXT pCtx,
153 PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx)
154{
155 bool bRc = false;
156
157 // LogFunc(("flags = 0x%08X\n", pCtx->pVBVA? pCtx->pVBVA->u32HostEvents: -1));
158
159 if ( pCtx->pVBVA
160 && (pCtx->pVBVA->hostFlags.u32HostEvents & VBVA_F_MODE_ENABLED))
161 {
162 uint32_t indexRecordNext;
163
164 VBVOAssert(!pCtx->fHwBufferOverflow);
165 VBVOAssert(pCtx->pRecord == NULL);
166
167 indexRecordNext = (pCtx->pVBVA->indexRecordFree + 1) % VBVA_MAX_RECORDS;
168
169 if (indexRecordNext == pCtx->pVBVA->indexRecordFirst)
170 {
171 /* All slots in the records queue are used. */
172 vboxHwBufferFlush (pHGSMICtx);
173 }
174
175 if (indexRecordNext == pCtx->pVBVA->indexRecordFirst)
176 {
177 /* Even after flush there is no place. Fail the request. */
178 // LogFunc(("no space in the queue of records!!! first %d, last %d\n",
179 // pCtx->pVBVA->indexRecordFirst, pCtx->pVBVA->indexRecordFree));
180 }
181 else
182 {
183 /* Initialize the record. */
184 VBVARECORD *pRecord = &pCtx->pVBVA->aRecords[pCtx->pVBVA->indexRecordFree];
185
186 pRecord->cbRecord = VBVA_F_RECORD_PARTIAL;
187
188 pCtx->pVBVA->indexRecordFree = indexRecordNext;
189
190 // LogFunc(("indexRecordNext = %d\n", indexRecordNext));
191
192 /* Remember which record we are using. */
193 pCtx->pRecord = pRecord;
194
195 bRc = true;
196 }
197 }
198
199 return bRc;
200}
201
202DECLHIDDEN(void) VBoxVBVABufferEndUpdate(PVBVABUFFERCONTEXT pCtx)
203{
204 VBVARECORD *pRecord;
205
206 // LogFunc(("\n"));
207
208 VBVOAssert(pCtx->pVBVA);
209
210 pRecord = pCtx->pRecord;
211 VBVOAssert(pRecord && (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL));
212
213 /* Mark the record completed. */
214 pRecord->cbRecord &= ~VBVA_F_RECORD_PARTIAL;
215
216 pCtx->fHwBufferOverflow = false;
217 pCtx->pRecord = NULL;
218
219 return;
220}
221
222/*
223 * Private operations.
224 */
225static uint32_t vboxHwBufferAvail (const VBVABUFFER *pVBVA)
226{
227 int32_t i32Diff = pVBVA->off32Data - pVBVA->off32Free;
228
229 return i32Diff > 0? i32Diff: pVBVA->cbData + i32Diff;
230}
231
232static void vboxHwBufferFlush(PHGSMIGUESTCOMMANDCONTEXT pCtx)
233{
234 /* Issue the flush command. */
235 void *p = VBoxHGSMIBufferAlloc(pCtx,
236 sizeof (VBVAFLUSH),
237 HGSMI_CH_VBVA,
238 VBVA_FLUSH);
239 if (!p)
240 {
241 // LogFunc(("HGSMIHeapAlloc failed\n"));
242 }
243 else
244 {
245 VBVAFLUSH *pFlush = (VBVAFLUSH *)p;
246
247 pFlush->u32Reserved = 0;
248
249 VBoxHGSMIBufferSubmit(pCtx, p);
250
251 VBoxHGSMIBufferFree(pCtx, p);
252 }
253
254 return;
255}
256
257static void vboxHwBufferPlaceDataAt(PVBVABUFFERCONTEXT pCtx, const void *p,
258 uint32_t cb, uint32_t offset)
259{
260 VBVABUFFER *pVBVA = pCtx->pVBVA;
261 uint32_t u32BytesTillBoundary = pVBVA->cbData - offset;
262 uint8_t *dst = &pVBVA->au8Data[offset];
263 int32_t i32Diff = cb - u32BytesTillBoundary;
264
265 if (i32Diff <= 0)
266 {
267 /* Chunk will not cross buffer boundary. */
268 memcpy (dst, p, cb);
269 }
270 else
271 {
272 /* Chunk crosses buffer boundary. */
273 memcpy (dst, p, u32BytesTillBoundary);
274 memcpy (&pVBVA->au8Data[0], (uint8_t *)p + u32BytesTillBoundary, i32Diff);
275 }
276
277 return;
278}
279
280static bool vboxHwBufferWrite(PVBVABUFFERCONTEXT pCtx,
281 PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx,
282 const void *p, uint32_t cb)
283{
284 VBVARECORD *pRecord;
285 uint32_t cbHwBufferAvail;
286
287 uint32_t cbWritten = 0;
288
289 VBVABUFFER *pVBVA = pCtx->pVBVA;
290 VBVOAssert(pVBVA);
291
292 if (!pVBVA || pCtx->fHwBufferOverflow)
293 {
294 return false;
295 }
296
297 VBVOAssert(pVBVA->indexRecordFirst != pVBVA->indexRecordFree);
298
299 pRecord = pCtx->pRecord;
300 VBVOAssert(pRecord && (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL));
301
302 // LogFunc(("%d\n", cb));
303
304 cbHwBufferAvail = vboxHwBufferAvail (pVBVA);
305
306 while (cb > 0)
307 {
308 uint32_t cbChunk = cb;
309
310 // LogFunc(("pVBVA->off32Free %d, pRecord->cbRecord 0x%08X, cbHwBufferAvail %d, cb %d, cbWritten %d\n",
311 // pVBVA->off32Free, pRecord->cbRecord, cbHwBufferAvail, cb, cbWritten));
312
313 if (cbChunk >= cbHwBufferAvail)
314 {
315 // LogFunc(("1) avail %d, chunk %d\n", cbHwBufferAvail, cbChunk));
316
317 vboxHwBufferFlush (pHGSMICtx);
318
319 cbHwBufferAvail = vboxHwBufferAvail (pVBVA);
320
321 if (cbChunk >= cbHwBufferAvail)
322 {
323 // LogFunc(("no place for %d bytes. Only %d bytes available after flush. Going to partial writes.\n",
324 // cb, cbHwBufferAvail));
325
326 if (cbHwBufferAvail <= pVBVA->cbPartialWriteThreshold)
327 {
328 // LogFunc(("Buffer overflow!!!\n"));
329 pCtx->fHwBufferOverflow = true;
330 VBVOAssert(false);
331 return false;
332 }
333
334 cbChunk = cbHwBufferAvail - pVBVA->cbPartialWriteThreshold;
335 }
336 }
337
338 VBVOAssert(cbChunk <= cb);
339 VBVOAssert(cbChunk <= vboxHwBufferAvail (pVBVA));
340
341 vboxHwBufferPlaceDataAt (pCtx, (uint8_t *)p + cbWritten, cbChunk, pVBVA->off32Free);
342
343 pVBVA->off32Free = (pVBVA->off32Free + cbChunk) % pVBVA->cbData;
344 pRecord->cbRecord += cbChunk;
345 cbHwBufferAvail -= cbChunk;
346
347 cb -= cbChunk;
348 cbWritten += cbChunk;
349 }
350
351 return true;
352}
353
354/*
355 * Public writer to the hardware buffer.
356 */
357DECLHIDDEN(bool) VBoxVBVAWrite(PVBVABUFFERCONTEXT pCtx,
358 PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx,
359 const void *pv, uint32_t cb)
360{
361 return vboxHwBufferWrite (pCtx, pHGSMICtx, pv, cb);
362}
363
364DECLHIDDEN(bool) VBoxVBVAOrderSupported(PVBVABUFFERCONTEXT pCtx, unsigned code)
365{
366 VBVABUFFER *pVBVA = pCtx->pVBVA;
367
368 if (!pVBVA)
369 {
370 return false;
371 }
372
373 if (pVBVA->hostFlags.u32SupportedOrders & (1 << code))
374 {
375 return true;
376 }
377
378 return false;
379}
380
381DECLHIDDEN(void) VBoxVBVASetupBufferContext(PVBVABUFFERCONTEXT pCtx,
382 uint32_t offVRAMBuffer,
383 uint32_t cbBuffer)
384{
385 pCtx->offVRAMBuffer = offVRAMBuffer;
386 pCtx->cbBuffer = cbBuffer;
387}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette