VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/GraphicsAdapterImpl.cpp@ 105865

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

Main: Added API for querying graphics features (2D Video / 3D Acceleration) of a specific graphics controller for a given platform and revamped the graphics controller attributes for 2D / 3D setters/getters to also use the new graphics features enumeration. Also, the system properties also now contain a dedicated API to query for graphics features (very basic for now, needs to be stuffed out). See SDK changelog for details. Added validation code when setting a specific graphics feature (which we never did before) [build fix]. bugref:10749

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.7 KB
Line 
1/* $Id: GraphicsAdapterImpl.cpp 105865 2024-08-26 20:37:09Z vboxsync $ */
2/** @file
3 * Implementation of IGraphicsAdapter in VBoxSVC.
4 */
5
6/*
7 * Copyright (C) 2004-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28#define LOG_GROUP LOG_GROUP_MAIN_GRAPHICSADAPTER
29
30#include "LoggingNew.h"
31
32#include "GraphicsAdapterImpl.h"
33#include "MachineImpl.h"
34
35#include "AutoStateDep.h"
36#include "AutoCaller.h"
37
38#include <iprt/cpp/utils.h>
39
40
41/** @def MY_VECTOR_ASSIGN_ARRAY
42 * Safe way to copy an array (static + const) into a vector w/ minimal typing.
43 *
44 * @param a_rVector The destination vector reference.
45 * @param a_aSrcArray The source array to assign to the vector.
46 */
47#if RT_GNUC_PREREQ(13, 0) && !RT_GNUC_PREREQ(14, 0) && defined(VBOX_WITH_GCC_SANITIZER)
48/* Workaround for g++ 13.2 incorrectly failing on arrays with a single entry in ASAN builds.
49 This is restricted to [13.0, 14.0), assuming the issue was introduced in the 13 cycle
50 and will be fixed by the time 14 is done. If 14 doesn't fix it, extend the range
51 version by version till it is fixed. */
52# define MY_VECTOR_ASSIGN_ARRAY(a_rVector, a_aSrcArray) do { \
53 _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wstringop-overread\""); \
54 (a_rVector).assign(&a_aSrcArray[0], &a_aSrcArray[RT_ELEMENTS(a_aSrcArray)]); \
55 _Pragma("GCC diagnostic pop"); \
56 } while (0)
57#else
58# define MY_VECTOR_ASSIGN_ARRAY(a_rVector, a_aSrcArray) do { \
59 (a_rVector).assign(&a_aSrcArray[0], &a_aSrcArray[RT_ELEMENTS(a_aSrcArray)]); \
60 } while (0)
61#endif
62
63
64// constructor / destructor
65/////////////////////////////////////////////////////////////////////////////
66
67GraphicsAdapter::GraphicsAdapter() :
68 mParent(NULL)
69{}
70
71GraphicsAdapter::~GraphicsAdapter()
72{}
73
74HRESULT GraphicsAdapter::FinalConstruct()
75{
76 LogFlowThisFunc(("\n"));
77 return BaseFinalConstruct();
78}
79
80void GraphicsAdapter::FinalRelease()
81{
82 LogFlowThisFunc(("\n"));
83 uninit();
84 BaseFinalRelease();
85}
86
87// public initializer/uninitializer for internal purposes only
88/////////////////////////////////////////////////////////////////////////////
89
90/**
91 * Initializes the graphics adapter object.
92 *
93 * @param aParent Handle of the parent object.
94 */
95HRESULT GraphicsAdapter::init(Machine *aParent)
96{
97 LogFlowThisFunc(("aParent=%p\n", aParent));
98
99 ComAssertRet(aParent, E_INVALIDARG);
100
101 /* Enclose the state transition NotReady->InInit->Ready */
102 AutoInitSpan autoInitSpan(this);
103 AssertReturn(autoInitSpan.isOk(), E_FAIL);
104
105 unconst(mParent) = aParent;
106 /* mPeer is left null */
107
108 mData.allocate();
109
110 /* Confirm a successful initialization */
111 autoInitSpan.setSucceeded();
112
113 return S_OK;
114}
115
116/**
117 * Initializes the graphics adapter object given another graphics adapter
118 * object (a kind of copy constructor). This object shares data with
119 * the object passed as an argument.
120 *
121 * @note This object must be destroyed before the original object
122 * it shares data with is destroyed.
123 *
124 * @note Locks @a aThat object for reading.
125 */
126HRESULT GraphicsAdapter::init(Machine *aParent, GraphicsAdapter *aThat)
127{
128 LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
129
130 ComAssertRet(aParent && aThat, E_INVALIDARG);
131
132 /* Enclose the state transition NotReady->InInit->Ready */
133 AutoInitSpan autoInitSpan(this);
134 AssertReturn(autoInitSpan.isOk(), E_FAIL);
135
136 unconst(mParent) = aParent;
137 unconst(mPeer) = aThat;
138
139 AutoCaller thatCaller(aThat);
140 AssertComRCReturnRC(thatCaller.hrc());
141
142 AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
143 mData.share(aThat->mData);
144
145 /* Confirm a successful initialization */
146 autoInitSpan.setSucceeded();
147
148 return S_OK;
149}
150
151/**
152 * Initializes the graphics adapter object given another graphics adapter
153 * object (a kind of copy constructor). This object makes a private copy
154 * of data of the original object passed as an argument.
155 *
156 * @note Locks @a aThat object for reading.
157 */
158HRESULT GraphicsAdapter::initCopy(Machine *aParent, GraphicsAdapter *aThat)
159{
160 LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
161
162 ComAssertRet(aParent && aThat, E_INVALIDARG);
163
164 /* Enclose the state transition NotReady->InInit->Ready */
165 AutoInitSpan autoInitSpan(this);
166 AssertReturn(autoInitSpan.isOk(), E_FAIL);
167
168 unconst(mParent) = aParent;
169 /* mPeer is left null */
170
171 AutoCaller thatCaller(aThat);
172 AssertComRCReturnRC(thatCaller.hrc());
173
174 AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
175 mData.attachCopy(aThat->mData);
176
177 /* Confirm a successful initialization */
178 autoInitSpan.setSucceeded();
179
180 return S_OK;
181}
182
183/**
184 * Uninitializes the instance and sets the ready flag to FALSE.
185 * Called either from FinalRelease() or by the parent when it gets destroyed.
186 */
187void GraphicsAdapter::uninit()
188{
189 LogFlowThisFunc(("\n"));
190
191 /* Enclose the state transition Ready->InUninit->NotReady */
192 AutoUninitSpan autoUninitSpan(this);
193 if (autoUninitSpan.uninitDone())
194 return;
195
196 mData.free();
197
198 unconst(mPeer) = NULL;
199 unconst(mParent) = NULL;
200}
201
202// Wrapped IGraphicsAdapter properties
203/////////////////////////////////////////////////////////////////////////////
204
205HRESULT GraphicsAdapter::getGraphicsControllerType(GraphicsControllerType_T *aGraphicsControllerType)
206{
207 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
208
209 *aGraphicsControllerType = mData->graphicsControllerType;
210
211 return S_OK;
212}
213
214HRESULT GraphicsAdapter::setGraphicsControllerType(GraphicsControllerType_T aGraphicsControllerType)
215{
216 switch (aGraphicsControllerType)
217 {
218 case GraphicsControllerType_Null:
219 case GraphicsControllerType_VBoxVGA:
220#ifdef VBOX_WITH_VMSVGA
221 case GraphicsControllerType_VMSVGA:
222 case GraphicsControllerType_VBoxSVGA:
223#endif
224 case GraphicsControllerType_QemuRamFB:
225 break;
226 default:
227 return setError(E_INVALIDARG, tr("The graphics controller type (%d) is invalid"), aGraphicsControllerType);
228 }
229
230 /* the machine needs to be mutable */
231 AutoMutableStateDependency adep(mParent);
232 if (FAILED(adep.hrc())) return adep.hrc();
233
234 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
235
236 mParent->i_setModified(Machine::IsModified_GraphicsAdapter);
237 mData.backup();
238 mData->graphicsControllerType = aGraphicsControllerType;
239
240 return S_OK;
241}
242
243HRESULT GraphicsAdapter::getVRAMSize(ULONG *aVRAMSize)
244{
245 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
246
247 *aVRAMSize = mData->ulVRAMSizeMB;
248
249 return S_OK;
250}
251
252HRESULT GraphicsAdapter::setVRAMSize(ULONG aVRAMSize)
253{
254 /* the machine needs to be mutable */
255 AutoMutableStateDependency adep(mParent);
256 if (FAILED(adep.hrc())) return adep.hrc();
257
258 ULONG uMin, uMax;
259 HRESULT hrc = PlatformProperties::s_getSupportedVRAMRange(mData->graphicsControllerType, mData->fAccelerate3D,
260 &uMin, &uMax, NULL /* aStrideSizeMB */);
261 if (FAILED(hrc))
262 return setError(hrc,
263 tr("Error getting VRAM range for selected graphics controller"));
264
265 /* check VRAM limits */
266 if ( aVRAMSize < uMin
267 || aVRAMSize > uMax)
268 return setError(E_INVALIDARG,
269 tr("Invalid VRAM size: %lu MB (must be in range [%lu, %lu] MB)"),
270 aVRAMSize, uMin, uMax);
271
272 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
273
274 mParent->i_setModified(Machine::IsModified_GraphicsAdapter);
275 mData.backup();
276 mData->ulVRAMSizeMB = aVRAMSize;
277
278 return S_OK;
279}
280
281HRESULT GraphicsAdapter::setFeature(GraphicsFeature_T aFeature, BOOL aEnabled)
282{
283 /* the machine needs to be mutable */
284 AutoMutableStateDependency adep(mParent);
285 if (FAILED(adep.hrc())) return adep.hrc();
286
287 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
288
289 /* Validate if the given feature is supported by this graphics controller. */
290 if (!PlatformProperties::s_isGraphicsControllerFeatureSupported(mData->graphicsControllerType, aFeature))
291 return setError(VBOX_E_NOT_SUPPORTED, tr("The graphics controller does not support the given feature"));
292
293 bool *pfSetting = NULL;
294 switch (aFeature)
295 {
296 case GraphicsFeature_Acceleration2DVideo:
297 pfSetting = &mData->fAccelerate2DVideo;
298 break;
299
300 case GraphicsFeature_Acceleration3D:
301 pfSetting = &mData->fAccelerate3D;
302 break;
303
304 default:
305 break;
306 }
307
308 if (!pfSetting)
309 return setError(E_NOTIMPL, tr("The given feature is not implemented"));
310
311 if (*pfSetting != RT_BOOL(aEnabled))
312 {
313 mParent->i_setModified(Machine::IsModified_GraphicsAdapter);
314 mData.backup();
315
316 *pfSetting = RT_BOOL(aEnabled);
317 }
318
319 return S_OK;
320}
321
322HRESULT GraphicsAdapter::isFeatureEnabled(GraphicsFeature_T aFeature, BOOL *aEnabled)
323{
324 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
325
326 bool *pfSetting = NULL;
327
328 switch (aFeature)
329 {
330#ifndef VBOX_WITH_VIRT_ARMV8 /* On macOS (ARM) we don't support any 2D/3D acceleration for now. */
331 case GraphicsFeature_Acceleration2DVideo:
332 pfSetting = &mData->fAccelerate2DVideo;
333 *pfSetting = false; /* @bugref{9691} -- The legacy VHWA acceleration has been disabled completely. */
334 break;
335
336 case GraphicsFeature_Acceleration3D:
337 pfSetting = &mData->fAccelerate3D;
338 break;
339#endif
340 default:
341 break;
342 }
343
344 if (!pfSetting)
345 return VBOX_E_NOT_SUPPORTED;
346
347 *aEnabled = *pfSetting;
348
349 return S_OK;
350}
351
352HRESULT GraphicsAdapter::getMonitorCount(ULONG *aMonitorCount)
353{
354 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
355
356 *aMonitorCount = mData->cMonitors;
357
358 return S_OK;
359}
360
361HRESULT GraphicsAdapter::setMonitorCount(ULONG aMonitorCount)
362{
363 /* make sure monitor count is a sensible number */
364 if (aMonitorCount < 1 || aMonitorCount > SchemaDefs::MaxGuestMonitors)
365 return setError(E_INVALIDARG,
366 tr("Invalid monitor count: %lu (must be in range [%lu, %lu])"),
367 aMonitorCount, 1, SchemaDefs::MaxGuestMonitors);
368
369 /* the machine needs to be mutable */
370 AutoMutableStateDependency adep(mParent);
371 if (FAILED(adep.hrc())) return adep.hrc();
372
373 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
374
375 mParent->i_setModified(Machine::IsModified_GraphicsAdapter);
376 mData.backup();
377 mData->cMonitors = aMonitorCount;
378
379 return S_OK;
380}
381
382// Wrapped IGraphicsAdapter methods
383/////////////////////////////////////////////////////////////////////////////
384
385// public methods only for internal purposes
386/////////////////////////////////////////////////////////////////////////////
387
388/**
389 * Loads settings from the given machine node.
390 * May be called once right after this object creation.
391 *
392 * @param data Configuration settings.
393 *
394 * @note Locks this object for writing.
395 */
396HRESULT GraphicsAdapter::i_loadSettings(const settings::GraphicsAdapter &data)
397{
398 AutoCaller autoCaller(this);
399 AssertComRCReturnRC(autoCaller.hrc());
400
401 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
402
403 mData.assignCopy(&data);
404
405 return S_OK;
406}
407
408/**
409 * Saves settings to the given machine node.
410 *
411 * @param data Configuration settings.
412 *
413 * @note Locks this object for reading.
414 */
415HRESULT GraphicsAdapter::i_saveSettings(settings::GraphicsAdapter &data)
416{
417 AutoCaller autoCaller(this);
418 AssertComRCReturnRC(autoCaller.hrc());
419
420 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
421
422 data = *mData.data();
423
424 return S_OK;
425}
426
427/**
428 * @note Locks this object for writing.
429 */
430void GraphicsAdapter::i_rollback()
431{
432 /* sanity */
433 AutoCaller autoCaller(this);
434 AssertComRCReturnVoid(autoCaller.hrc());
435
436 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
437
438 mData.rollback();
439}
440
441/**
442 * @note Locks this object for writing, together with the peer object (also
443 * for writing) if there is one.
444 */
445void GraphicsAdapter::i_commit()
446{
447 /* sanity */
448 AutoCaller autoCaller(this);
449 AssertComRCReturnVoid(autoCaller.hrc());
450
451 /* sanity too */
452 AutoCaller peerCaller(mPeer);
453 AssertComRCReturnVoid(peerCaller.hrc());
454
455 /* lock both for writing since we modify both (mPeer is "master" so locked
456 * first) */
457 AutoMultiWriteLock2 alock(mPeer, this COMMA_LOCKVAL_SRC_POS);
458
459 if (mData.isBackedUp())
460 {
461 mData.commit();
462 if (mPeer)
463 {
464 /* attach new data to the peer and reshare it */
465 mPeer->mData.attach(mData);
466 }
467 }
468}
469
470/**
471 * @note Locks this object for writing, together with the peer object
472 * represented by @a aThat (locked for reading).
473 */
474void GraphicsAdapter::i_copyFrom(GraphicsAdapter *aThat)
475{
476 AssertReturnVoid(aThat != NULL);
477
478 /* sanity */
479 AutoCaller autoCaller(this);
480 AssertComRCReturnVoid(autoCaller.hrc());
481
482 /* sanity too */
483 AutoCaller thatCaller(aThat);
484 AssertComRCReturnVoid(thatCaller.hrc());
485
486 /* peer is not modified, lock it for reading (aThat is "master" so locked
487 * first) */
488 AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
489 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
490
491 /* this will back up current data */
492 mData.assignCopy(aThat->mData);
493}
494/* vi: set tabstop=4 shiftwidth=4 expandtab: */
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