VirtualBox

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

Last change on this file was 106081, checked in by vboxsync, 8 weeks ago

Main: Fixed enabling 3D when selecting supported graphics controllers (static not needed/possible here). bugref:10749

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.8 KB
Line 
1/* $Id: GraphicsAdapterImpl.cpp 106081 2024-09-18 13:02:12Z vboxsync $ */
2/** @file
3 * Implementation of IGraphicsAdapter in VBoxSVC.
4 */
5
6/*
7 * Copyright (C) 2004-2024 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// constructor / destructor
42/////////////////////////////////////////////////////////////////////////////
43
44GraphicsAdapter::GraphicsAdapter() :
45 mParent(NULL)
46{}
47
48GraphicsAdapter::~GraphicsAdapter()
49{}
50
51HRESULT GraphicsAdapter::FinalConstruct()
52{
53 LogFlowThisFunc(("\n"));
54 return BaseFinalConstruct();
55}
56
57void GraphicsAdapter::FinalRelease()
58{
59 LogFlowThisFunc(("\n"));
60 uninit();
61 BaseFinalRelease();
62}
63
64// public initializer/uninitializer for internal purposes only
65/////////////////////////////////////////////////////////////////////////////
66
67/**
68 * Initializes the graphics adapter object.
69 *
70 * @param aParent Handle of the parent object.
71 */
72HRESULT GraphicsAdapter::init(Machine *aParent)
73{
74 LogFlowThisFunc(("aParent=%p\n", aParent));
75
76 ComAssertRet(aParent, E_INVALIDARG);
77
78 /* Enclose the state transition NotReady->InInit->Ready */
79 AutoInitSpan autoInitSpan(this);
80 AssertReturn(autoInitSpan.isOk(), E_FAIL);
81
82 unconst(mParent) = aParent;
83 /* mPeer is left null */
84
85 mData.allocate();
86
87 /* Confirm a successful initialization */
88 autoInitSpan.setSucceeded();
89
90 return S_OK;
91}
92
93/**
94 * Initializes the graphics adapter object given another graphics adapter
95 * object (a kind of copy constructor). This object shares data with
96 * the object passed as an argument.
97 *
98 * @note This object must be destroyed before the original object
99 * it shares data with is destroyed.
100 *
101 * @note Locks @a aThat object for reading.
102 */
103HRESULT GraphicsAdapter::init(Machine *aParent, GraphicsAdapter *aThat)
104{
105 LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
106
107 ComAssertRet(aParent && aThat, E_INVALIDARG);
108
109 /* Enclose the state transition NotReady->InInit->Ready */
110 AutoInitSpan autoInitSpan(this);
111 AssertReturn(autoInitSpan.isOk(), E_FAIL);
112
113 unconst(mParent) = aParent;
114 unconst(mPeer) = aThat;
115
116 AutoCaller thatCaller(aThat);
117 AssertComRCReturnRC(thatCaller.hrc());
118
119 AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
120 mData.share(aThat->mData);
121
122 /* Confirm a successful initialization */
123 autoInitSpan.setSucceeded();
124
125 return S_OK;
126}
127
128/**
129 * Initializes the graphics adapter object given another graphics adapter
130 * object (a kind of copy constructor). This object makes a private copy
131 * of data of the original object passed as an argument.
132 *
133 * @note Locks @a aThat object for reading.
134 */
135HRESULT GraphicsAdapter::initCopy(Machine *aParent, GraphicsAdapter *aThat)
136{
137 LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
138
139 ComAssertRet(aParent && aThat, E_INVALIDARG);
140
141 /* Enclose the state transition NotReady->InInit->Ready */
142 AutoInitSpan autoInitSpan(this);
143 AssertReturn(autoInitSpan.isOk(), E_FAIL);
144
145 unconst(mParent) = aParent;
146 /* mPeer is left null */
147
148 AutoCaller thatCaller(aThat);
149 AssertComRCReturnRC(thatCaller.hrc());
150
151 AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
152 mData.attachCopy(aThat->mData);
153
154 /* Confirm a successful initialization */
155 autoInitSpan.setSucceeded();
156
157 return S_OK;
158}
159
160/**
161 * Uninitializes the instance and sets the ready flag to FALSE.
162 * Called either from FinalRelease() or by the parent when it gets destroyed.
163 */
164void GraphicsAdapter::uninit()
165{
166 LogFlowThisFunc(("\n"));
167
168 /* Enclose the state transition Ready->InUninit->NotReady */
169 AutoUninitSpan autoUninitSpan(this);
170 if (autoUninitSpan.uninitDone())
171 return;
172
173 mData.free();
174
175 unconst(mPeer) = NULL;
176 unconst(mParent) = NULL;
177}
178
179// Wrapped IGraphicsAdapter properties
180/////////////////////////////////////////////////////////////////////////////
181
182HRESULT GraphicsAdapter::getGraphicsControllerType(GraphicsControllerType_T *aGraphicsControllerType)
183{
184 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
185
186 *aGraphicsControllerType = mData->graphicsControllerType;
187
188 return S_OK;
189}
190
191HRESULT GraphicsAdapter::setGraphicsControllerType(GraphicsControllerType_T aGraphicsControllerType)
192{
193 switch (aGraphicsControllerType)
194 {
195 case GraphicsControllerType_Null:
196 case GraphicsControllerType_VBoxVGA:
197#ifdef VBOX_WITH_VMSVGA
198 case GraphicsControllerType_VMSVGA:
199 case GraphicsControllerType_VBoxSVGA:
200#endif
201 case GraphicsControllerType_QemuRamFB:
202 break;
203 default:
204 return setError(E_INVALIDARG, tr("The graphics controller type (%d) is invalid"), aGraphicsControllerType);
205 }
206
207 /* the machine needs to be mutable */
208 AutoMutableStateDependency adep(mParent);
209 if (FAILED(adep.hrc())) return adep.hrc();
210
211 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
212
213 if (mData->graphicsControllerType != aGraphicsControllerType)
214 {
215 mParent->i_setModified(Machine::IsModified_GraphicsAdapter);
216 mData.backup();
217 mData->graphicsControllerType = aGraphicsControllerType;
218
219 i_updateFeatures();
220 }
221
222 return S_OK;
223}
224
225HRESULT GraphicsAdapter::getVRAMSize(ULONG *aVRAMSize)
226{
227 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
228
229 *aVRAMSize = mData->ulVRAMSizeMB;
230
231 return S_OK;
232}
233
234HRESULT GraphicsAdapter::setVRAMSize(ULONG aVRAMSize)
235{
236 /* the machine needs to be mutable */
237 AutoMutableStateDependency adep(mParent);
238 if (FAILED(adep.hrc())) return adep.hrc();
239
240 ULONG uMin, uMax;
241 HRESULT hrc = PlatformProperties::s_getSupportedVRAMRange(mData->graphicsControllerType, mData->fAccelerate3D,
242 &uMin, &uMax, NULL /* aStrideSizeMB */);
243 if (FAILED(hrc))
244 return setError(hrc,
245 tr("Error getting VRAM range for selected graphics controller"));
246
247 /* check VRAM limits */
248 if ( aVRAMSize < uMin
249 || aVRAMSize > uMax)
250 return setError(E_INVALIDARG,
251 tr("Invalid VRAM size: %lu MB (must be in range [%lu, %lu] MB)"),
252 aVRAMSize, uMin, uMax);
253
254 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
255
256 mParent->i_setModified(Machine::IsModified_GraphicsAdapter);
257 mData.backup();
258 mData->ulVRAMSizeMB = aVRAMSize;
259
260 return S_OK;
261}
262
263HRESULT GraphicsAdapter::setFeature(GraphicsFeature_T aFeature, BOOL aEnabled)
264{
265 /* the machine needs to be mutable */
266 AutoMutableStateDependency adep(mParent);
267 if (FAILED(adep.hrc())) return adep.hrc();
268
269 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
270
271 /* Validate if the given feature to be enabled is supported by this graphics controller on the given VM platform.
272 * Disabling always is allowed for all graphics controllers. */
273 if ( aEnabled
274 && !PlatformProperties::s_isGraphicsControllerFeatureSupported(mParent->i_getPlatform()->i_getArchitecture(),
275 mData->graphicsControllerType, aFeature))
276 return setError(VBOX_E_NOT_SUPPORTED, tr("The graphics controller does not support the given feature"));
277
278
279 bool *pfSetting = i_getFeatureMemberBool(aFeature);
280 if (!pfSetting)
281 return setError(E_NOTIMPL, tr("The given feature is not implemented"));
282
283 if (*pfSetting != RT_BOOL(aEnabled))
284 {
285 mParent->i_setModified(Machine::IsModified_GraphicsAdapter);
286 mData.backup();
287
288 /* Note: We have to re-evaluate the feature member here, as mData.backup() above changed the pointers. */
289 *i_getFeatureMemberBool(aFeature) = RT_BOOL(aEnabled);
290 }
291
292 return S_OK;
293}
294
295HRESULT GraphicsAdapter::isFeatureEnabled(GraphicsFeature_T aFeature, BOOL *aEnabled)
296{
297 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
298
299 bool *pfSetting = NULL;
300
301 /* If we don't support a feature with this graphics controller type, skip returning
302 * what setting we have stored for it.
303 *
304 * This could happen if loading an old(er) saved state or importing a VM where this feature (formely)
305 * was supported. PlatformProperties::s_isGraphicsControllerFeatureSupported() is the single source of truth here. */
306 if (PlatformProperties::s_isGraphicsControllerFeatureSupported(mParent->i_getPlatform()->i_getArchitecture(),
307 mData->graphicsControllerType, aFeature))
308 {
309 switch (aFeature)
310 {
311 case GraphicsFeature_Acceleration2DVideo:
312 pfSetting = &mData->fAccelerate2DVideo;
313 break;
314
315 case GraphicsFeature_Acceleration3D:
316 pfSetting = &mData->fAccelerate3D;
317 break;
318
319 default:
320 break;
321 }
322 }
323
324 *aEnabled = pfSetting ? *pfSetting : FALSE;
325
326 return S_OK;
327}
328
329HRESULT GraphicsAdapter::getMonitorCount(ULONG *aMonitorCount)
330{
331 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
332
333 *aMonitorCount = mData->cMonitors;
334
335 return S_OK;
336}
337
338HRESULT GraphicsAdapter::setMonitorCount(ULONG aMonitorCount)
339{
340 /* make sure monitor count is a sensible number */
341 if (aMonitorCount < 1 || aMonitorCount > SchemaDefs::MaxGuestMonitors)
342 return setError(E_INVALIDARG,
343 tr("Invalid monitor count: %lu (must be in range [%lu, %lu])"),
344 aMonitorCount, 1, SchemaDefs::MaxGuestMonitors);
345
346 /* the machine needs to be mutable */
347 AutoMutableStateDependency adep(mParent);
348 if (FAILED(adep.hrc())) return adep.hrc();
349
350 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
351
352 mParent->i_setModified(Machine::IsModified_GraphicsAdapter);
353 mData.backup();
354 mData->cMonitors = aMonitorCount;
355
356 return S_OK;
357}
358
359// Wrapped IGraphicsAdapter methods
360/////////////////////////////////////////////////////////////////////////////
361
362// public methods only for internal purposes
363/////////////////////////////////////////////////////////////////////////////
364
365/**
366 * Loads settings from the given machine node.
367 * May be called once right after this object creation.
368 *
369 * @param data Configuration settings.
370 *
371 * @note Locks this object for writing.
372 */
373HRESULT GraphicsAdapter::i_loadSettings(const settings::GraphicsAdapter &data)
374{
375 AutoCaller autoCaller(this);
376 AssertComRCReturnRC(autoCaller.hrc());
377
378 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
379
380 mData.assignCopy(&data);
381
382 i_updateFeatures();
383
384 return S_OK;
385}
386
387/**
388 * Saves settings to the given machine node.
389 *
390 * @param data Configuration settings.
391 *
392 * @note Locks this object for reading.
393 */
394HRESULT GraphicsAdapter::i_saveSettings(settings::GraphicsAdapter &data)
395{
396 AutoCaller autoCaller(this);
397 AssertComRCReturnRC(autoCaller.hrc());
398
399 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
400
401 data = *mData.data();
402
403 return S_OK;
404}
405
406/**
407 * @note Locks this object for writing.
408 */
409void GraphicsAdapter::i_rollback()
410{
411 /* sanity */
412 AutoCaller autoCaller(this);
413 AssertComRCReturnVoid(autoCaller.hrc());
414
415 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
416
417 mData.rollback();
418}
419
420/**
421 * @note Locks this object for writing, together with the peer object (also
422 * for writing) if there is one.
423 */
424void GraphicsAdapter::i_commit()
425{
426 /* sanity */
427 AutoCaller autoCaller(this);
428 AssertComRCReturnVoid(autoCaller.hrc());
429
430 /* sanity too */
431 AutoCaller peerCaller(mPeer);
432 AssertComRCReturnVoid(peerCaller.hrc());
433
434 /* lock both for writing since we modify both (mPeer is "master" so locked
435 * first) */
436 AutoMultiWriteLock2 alock(mPeer, this COMMA_LOCKVAL_SRC_POS);
437
438 if (mData.isBackedUp())
439 {
440 mData.commit();
441 if (mPeer)
442 {
443 /* attach new data to the peer and reshare it */
444 mPeer->mData.attach(mData);
445 }
446 }
447}
448
449/**
450 * @note Locks this object for writing, together with the peer object
451 * represented by @a aThat (locked for reading).
452 */
453void GraphicsAdapter::i_copyFrom(GraphicsAdapter *aThat)
454{
455 AssertReturnVoid(aThat != NULL);
456
457 /* sanity */
458 AutoCaller autoCaller(this);
459 AssertComRCReturnVoid(autoCaller.hrc());
460
461 /* sanity too */
462 AutoCaller thatCaller(aThat);
463 AssertComRCReturnVoid(thatCaller.hrc());
464
465 /* peer is not modified, lock it for reading (aThat is "master" so locked
466 * first) */
467 AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
468 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
469
470 /* this will back up current data */
471 mData.assignCopy(aThat->mData);
472}
473
474/**
475 * Returns the pointer to a boolean feature member of a given graphics feature.
476 *
477 * @returns Pointer to a boolean feature member of a given graphics feature, or NULL if not found / implemented.
478 * @param aFeature Graphics feature to return boolean feature member for.
479 */
480bool *GraphicsAdapter::i_getFeatureMemberBool(GraphicsFeature_T aFeature)
481{
482 switch (aFeature)
483 {
484 case GraphicsFeature_Acceleration2DVideo: return &mData->fAccelerate2DVideo;
485 case GraphicsFeature_Acceleration3D: return &mData->fAccelerate3D;
486 default:
487 break;
488 }
489
490 return NULL;
491}
492
493/**
494 * Updates all enabled features for the currently set graphics controller type.
495 *
496 * This will disable enabled features if the currently set graphics controller type does not support it.
497 */
498void GraphicsAdapter::i_updateFeatures()
499{
500 struct FEATUREMEMBER2ENUM
501 {
502 bool *pfFeatureMember;
503 GraphicsFeature_T enmFeature;
504 };
505
506 FEATUREMEMBER2ENUM aFeatures[] =
507 {
508 { &mData->fAccelerate2DVideo, GraphicsFeature_Acceleration2DVideo },
509 { &mData->fAccelerate3D, GraphicsFeature_Acceleration3D },
510 };
511
512 for (size_t i = 0; i < RT_ELEMENTS(aFeatures); i++)
513 {
514 if (*aFeatures[i].pfFeatureMember)
515 *aFeatures[i].pfFeatureMember
516 = PlatformProperties::s_isGraphicsControllerFeatureSupported(mParent->i_getPlatform()->i_getArchitecture(),
517 mData->graphicsControllerType,
518 aFeatures[i].enmFeature);
519 }
520}
521
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