package org.ovirt.engine.core.bll.utils;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import org.ovirt.engine.core.common.businessentities.DisplayType;
import org.ovirt.engine.core.common.businessentities.VM;
import org.ovirt.engine.core.common.businessentities.VmBase;
import org.ovirt.engine.core.common.osinfo.OsRepository;
import org.ovirt.engine.core.common.utils.CompatibilityVersionUtils;
import org.ovirt.engine.core.common.utils.SimpleDependencyInjector;
import org.ovirt.engine.core.compat.Version;
import org.ovirt.engine.core.vdsbroker.vdsbroker.VdsProperties;
public class VideoDeviceSettings {
/**
* Video settings for clusters 3.6 and newer (they may change in future versions).
*/
private static class VgamemVideoSettings {
// Displays up to 4 Mpix fit into this; higher resolutions are currently
// not supported by the drivers.
private static final int BASE_RAM_SIZE = 16384; // KB
private static final int DEFAULT_VRAM_SIZE = 8192; // KB
private static final int RAM_MULTIPLIER = 4;
/**
* Returns video device settings for QXL devices.
*
* @return a map of device settings
*/
public static Map<String, Integer> getQxlVideoDeviceSettings(VmBase vmBase) {
// Things are likely to completely change in future, so let's keep this
// computation as simple as possible for now.
Map<String, Integer> settings = new HashMap<>();
int heads = vmBase.getSingleQxlPci() ? vmBase.getNumOfMonitors() : 1;
int vgamem = BASE_RAM_SIZE * heads;
int vramMultiplier = getVramMultiplier(vmBase);
int vram = vramMultiplier == 0 ? DEFAULT_VRAM_SIZE : vramMultiplier * vgamem;
settings.put(VdsProperties.VIDEO_HEADS, heads);
settings.put(VdsProperties.VIDEO_VGAMEM, vgamem);
settings.put(VdsProperties.VIDEO_RAM, RAM_MULTIPLIER * vgamem);
settings.put(VdsProperties.VIDEO_VRAM, vram);
return settings;
}
/**
* Returns video device settings for VGA and Cirrus devices.
*
* @return a map of device settings
*/
public static Map<String, Integer> getVgaVideoDeviceSettings() {
// No multihead, no special driver requirements, the base value should
// just work. Except for high resolutions on Wayland (requires twice
// as much video RAM as other systems due to page flipping); not likely
// to be used with vga or cirrus so we don't care about that here.
return Collections.singletonMap(VdsProperties.VIDEO_VRAM, BASE_RAM_SIZE);
}
private static int getVramMultiplier(VmBase vmBase) {
OsRepository osRepository = SimpleDependencyInjector.getInstance().get(OsRepository.class);
return osRepository.getVramMultiplier(vmBase.getOsId());
}
}
/**
* Legacy video settings, for clusters older than 3.6.
* Not necesessarily correct but this is what the engine used to send to the hosts,
* so it's best to reuse the values in order not to break old setups.
*/
private static class LegacyVideoSettings {
private static final int BASE_RAM_SIZE = 65536; // KB
private static final int VRAM_SIZE = 32768; // KB
public static Map<String, Integer> getVideoDeviceSettings(VmBase vmBase) {
Map<String, Integer> settings = new HashMap<>();
boolean singleQxlPci = vmBase.getSingleQxlPci();
int numOfMonitors = vmBase.getNumOfMonitors();
int heads = singleQxlPci ? numOfMonitors : 1;
settings.put(VdsProperties.VIDEO_HEADS, heads);
settings.put(VdsProperties.VIDEO_VRAM, VRAM_SIZE);
if (singleQxlPci) {
settings.put(VdsProperties.VIDEO_RAM, BASE_RAM_SIZE * heads);
}
return settings;
}
}
private static Map<String, Integer> getVideoDeviceSettings(VmBase vmBase) {
Version vmVersion = vmBase.getCustomCompatibilityVersion();
Supplier<Version> clusterVersionSupplier = () -> ClusterUtils.getCompatibilityVersion(vmBase);
if (CompatibilityVersionUtils.getEffective(vmVersion, clusterVersionSupplier).greaterOrEquals(Version.v3_6)) {
if (vmBase.getDefaultDisplayType() == DisplayType.qxl) {
return VgamemVideoSettings.getQxlVideoDeviceSettings(vmBase);
} else {
return VgamemVideoSettings.getVgaVideoDeviceSettings();
}
} else {
return LegacyVideoSettings.getVideoDeviceSettings(vmBase);
}
}
/**
* Returns video device spec params.
*
* @return a map of device parameters
*/
public static Map<String, Object> getVideoDeviceSpecParams(VmBase vmBase) {
return getVideoDeviceSettings(vmBase).entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, e -> String.valueOf(e.getValue())));
}
/**
* Returns total video RAM size to be allocated for the given VM.
*
* @param vm the VM to compute the video RAM size for
* @return size of the video RAM in MiB
*/
public static int totalVideoRAMSizeMb(VM vm) {
Map<String, Integer> settings = getVideoDeviceSettings(vm.getStaticData());
return (settings.getOrDefault(VdsProperties.VIDEO_RAM, 0) +
settings.getOrDefault(VdsProperties.VIDEO_VRAM, 0) + 1023) / 1024;
}
}