VirtualBox

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

Last change on this file since 106945 was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

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