mirror of
https://github.com/Ryujinx/Opentk.git
synced 2025-01-12 05:15:33 +00:00
* Platform/Windows/WinDisplayDevice.cs:
* Platform/MacOS/QuartzDisplayDeviceDriver.cs: Updated to use the new DisplayDevice constructors. * Platform/X11/X11XrandrDisplayDevice.cs: Query Xinerama for the exact bounds of each display device, if available. Use global X lock to protect from multithreaded access.
This commit is contained in:
parent
2f3481231b
commit
139b6af9fa
|
@ -92,7 +92,7 @@ namespace OpenTK.Platform.MacOS
|
||||||
}
|
}
|
||||||
|
|
||||||
DisplayDevice opentk_dev =
|
DisplayDevice opentk_dev =
|
||||||
new DisplayDevice(opentk_dev_current_res, primary, opentk_dev_available_res);
|
new DisplayDevice(opentk_dev_current_res, primary, opentk_dev_available_res, Rectangle.Empty);
|
||||||
|
|
||||||
displayMap.Add(opentk_dev, currentDisplay);
|
displayMap.Add(opentk_dev, currentDisplay);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#region --- License ---
|
#region --- License ---
|
||||||
/* Licensed under the MIT/X11 license.
|
/* Licensed under the MIT/X11 license.
|
||||||
* Copyright (c) 2006-2008 the OpenTK team.
|
* Copyright (c) 2006-2008 the OpenTK team.
|
||||||
* This notice may not be removed.
|
* This notice may not be removed.
|
||||||
|
@ -81,7 +81,8 @@ namespace OpenTK.Platform.Windows
|
||||||
opentk_dev = new DisplayDevice(
|
opentk_dev = new DisplayDevice(
|
||||||
opentk_dev_current_res,
|
opentk_dev_current_res,
|
||||||
opentk_dev_primary,
|
opentk_dev_primary,
|
||||||
opentk_dev_available_res);
|
opentk_dev_available_res,
|
||||||
|
opentk_dev_current_res.Bounds);
|
||||||
|
|
||||||
available_device_names.Add(opentk_dev, dev1.DeviceName);
|
available_device_names.Add(opentk_dev, dev1.DeviceName);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
@ -35,17 +36,59 @@ namespace OpenTK.Platform.X11
|
||||||
|
|
||||||
static X11XrandrDisplayDevice()
|
static X11XrandrDisplayDevice()
|
||||||
{
|
{
|
||||||
// Get available resolutions. Then, for each resolution get all
|
|
||||||
// available rates.
|
|
||||||
// TODO: Global X11 lock.
|
|
||||||
// TODO: Use xinerama to get the bounds of each monitor.
|
|
||||||
for (int screen = 0; screen < API.ScreenCount; screen++)
|
|
||||||
{
|
|
||||||
IntPtr timestamp_of_last_update;
|
|
||||||
using (new XLock(API.DefaultDisplay))
|
using (new XLock(API.DefaultDisplay))
|
||||||
{
|
{
|
||||||
Functions.XRRTimes(API.DefaultDisplay, screen, out timestamp_of_last_update);
|
List<DisplayDevice> devices = new List<DisplayDevice>();
|
||||||
|
bool xinerama_supported = false;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Try to use Xinerama to obtain the geometry of all output devices.
|
||||||
|
int event_base, error_base;
|
||||||
|
if (NativeMethods.XineramaQueryExtension(API.DefaultDisplay, out event_base, out error_base) &&
|
||||||
|
NativeMethods.XineramaIsActive(API.DefaultDisplay))
|
||||||
|
{
|
||||||
|
IList<XineramaScreenInfo> screens = NativeMethods.XineramaQueryScreens(API.DefaultDisplay);
|
||||||
|
bool first = true;
|
||||||
|
foreach (XineramaScreenInfo screen in screens)
|
||||||
|
{
|
||||||
|
DisplayDevice dev = new DisplayDevice();
|
||||||
|
dev.Bounds = new Rectangle(screen.X, screen.Y, screen.Width, screen.Height);
|
||||||
|
if (first)
|
||||||
|
{
|
||||||
|
// We consider the first device returned by Xinerama as the primary one.
|
||||||
|
// Makes sense conceptually, but is there a way to verify this?
|
||||||
|
dev.IsPrimary = true;
|
||||||
|
first = false;
|
||||||
}
|
}
|
||||||
|
devices.Add(dev);
|
||||||
|
// It seems that all X screens are equal to 0 is Xinerama is enabled, at least on Nvidia (verify?)
|
||||||
|
deviceToScreen.Add(dev, 0 /*screen.ScreenNumber*/);
|
||||||
|
xinerama_supported = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { Debug.Print("Xinerama query failed."); }
|
||||||
|
|
||||||
|
if (!xinerama_supported)
|
||||||
|
{
|
||||||
|
// We assume that devices are equivalent to the number of available screens.
|
||||||
|
// Note: this won't work correctly in the case of distinct X servers.
|
||||||
|
for (int i = 0; i < API.ScreenCount; i++)
|
||||||
|
{
|
||||||
|
DisplayDevice dev = new DisplayDevice();
|
||||||
|
dev.IsPrimary = i == Functions.XDefaultScreen(API.DefaultDisplay);
|
||||||
|
devices.Add(dev);
|
||||||
|
deviceToScreen.Add(dev, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get available resolutions. Then, for each resolution get all available rates.
|
||||||
|
foreach (DisplayDevice dev in devices)
|
||||||
|
{
|
||||||
|
int screen = deviceToScreen[dev];
|
||||||
|
|
||||||
|
IntPtr timestamp_of_last_update;
|
||||||
|
Functions.XRRTimes(API.DefaultDisplay, screen, out timestamp_of_last_update);
|
||||||
lastConfigUpdate.Add(timestamp_of_last_update);
|
lastConfigUpdate.Add(timestamp_of_last_update);
|
||||||
|
|
||||||
List<DisplayResolution> available_res = new List<DisplayResolution>();
|
List<DisplayResolution> available_res = new List<DisplayResolution>();
|
||||||
|
@ -64,10 +107,7 @@ namespace OpenTK.Platform.X11
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
short[] rates = null;
|
short[] rates = null;
|
||||||
using (new XLock(API.DefaultDisplay))
|
|
||||||
{
|
|
||||||
rates = Functions.XRRRates(API.DefaultDisplay, screen, resolution_count);
|
rates = Functions.XRRRates(API.DefaultDisplay, screen, resolution_count);
|
||||||
}
|
|
||||||
|
|
||||||
// It seems that XRRRates returns 0 for modes that are larger than the screen
|
// It seems that XRRRates returns 0 for modes that are larger than the screen
|
||||||
// can support, as well as for all supported modes. On Ubuntu 7.10 the tool
|
// can support, as well as for all supported modes. On Ubuntu 7.10 the tool
|
||||||
|
@ -82,8 +122,15 @@ namespace OpenTK.Platform.X11
|
||||||
}
|
}
|
||||||
// Keep the index of this resolution - we will need it for resolution changes later.
|
// Keep the index of this resolution - we will need it for resolution changes later.
|
||||||
foreach (int depth in depths)
|
foreach (int depth in depths)
|
||||||
screenResolutionToIndex[screen].Add(new DisplayResolution(0, 0, size.Width, size.Height, depth, 0),
|
{
|
||||||
resolution_count);
|
// Note that Xinerama may return multiple devices for a single screen. XRandR will
|
||||||
|
// not distinguish between the two as far as resolutions are supported (since XRandR
|
||||||
|
// operates on X screens, not display devices) - we need to be careful not to add the
|
||||||
|
// same resolution twice!
|
||||||
|
DisplayResolution res = new DisplayResolution(0, 0, size.Width, size.Height, depth, 0);
|
||||||
|
if (!screenResolutionToIndex[screen].ContainsKey(res))
|
||||||
|
screenResolutionToIndex[screen].Add(res, resolution_count);
|
||||||
|
}
|
||||||
|
|
||||||
++resolution_count;
|
++resolution_count;
|
||||||
}
|
}
|
||||||
|
@ -98,16 +145,14 @@ namespace OpenTK.Platform.X11
|
||||||
ushort current_rotation; // Not needed.
|
ushort current_rotation; // Not needed.
|
||||||
int current_resolution_index = Functions.XRRConfigCurrentConfiguration(screen_config, out current_rotation);
|
int current_resolution_index = Functions.XRRConfigCurrentConfiguration(screen_config, out current_rotation);
|
||||||
|
|
||||||
DisplayDevice current_device = new DisplayDevice(
|
if (dev.Bounds == Rectangle.Empty)
|
||||||
new DisplayResolution(
|
dev.Bounds = new Rectangle(0, 0, available_res[current_resolution_index].Width, available_res[current_resolution_index].Height);
|
||||||
0, 0,
|
dev.BitsPerPixel = current_depth;
|
||||||
available_res[current_resolution_index].Width, available_res[current_resolution_index].Height,
|
dev.RefreshRate = current_refresh_rate;
|
||||||
current_depth, current_refresh_rate),
|
dev.AvailableResolutions = available_res;
|
||||||
screen == Functions.XDefaultScreen(API.DefaultDisplay),
|
|
||||||
available_res);
|
|
||||||
|
|
||||||
deviceToScreen.Add(current_device, screen);
|
deviceToDefaultResolution.Add(dev, current_resolution_index);
|
||||||
deviceToDefaultResolution.Add(current_device, current_resolution_index);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,12 +165,9 @@ namespace OpenTK.Platform.X11
|
||||||
#region static int[] FindAvailableDepths(int screen)
|
#region static int[] FindAvailableDepths(int screen)
|
||||||
|
|
||||||
static int[] FindAvailableDepths(int screen)
|
static int[] FindAvailableDepths(int screen)
|
||||||
{
|
|
||||||
using (new XLock(API.DefaultDisplay))
|
|
||||||
{
|
{
|
||||||
return Functions.XListDepths(API.DefaultDisplay, screen);
|
return Functions.XListDepths(API.DefaultDisplay, screen);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
@ -134,10 +176,7 @@ namespace OpenTK.Platform.X11
|
||||||
static XRRScreenSize[] FindAvailableResolutions(int screen)
|
static XRRScreenSize[] FindAvailableResolutions(int screen)
|
||||||
{
|
{
|
||||||
XRRScreenSize[] resolutions = null;
|
XRRScreenSize[] resolutions = null;
|
||||||
using (new XLock(API.DefaultDisplay))
|
|
||||||
{
|
|
||||||
resolutions = Functions.XRRSizes(API.DefaultDisplay, screen);
|
resolutions = Functions.XRRSizes(API.DefaultDisplay, screen);
|
||||||
}
|
|
||||||
if (resolutions == null)
|
if (resolutions == null)
|
||||||
throw new NotSupportedException("XRandR extensions not available.");
|
throw new NotSupportedException("XRandR extensions not available.");
|
||||||
return resolutions;
|
return resolutions;
|
||||||
|
@ -150,14 +189,11 @@ namespace OpenTK.Platform.X11
|
||||||
static float FindCurrentRefreshRate(int screen)
|
static float FindCurrentRefreshRate(int screen)
|
||||||
{
|
{
|
||||||
short rate = 0;
|
short rate = 0;
|
||||||
using (new XLock(API.DefaultDisplay))
|
|
||||||
{
|
|
||||||
IntPtr screen_config = Functions.XRRGetScreenInfo(API.DefaultDisplay, Functions.XRootWindow(API.DefaultDisplay, screen));
|
IntPtr screen_config = Functions.XRRGetScreenInfo(API.DefaultDisplay, Functions.XRootWindow(API.DefaultDisplay, screen));
|
||||||
ushort rotation = 0;
|
ushort rotation = 0;
|
||||||
int size = Functions.XRRConfigCurrentConfiguration(screen_config, out rotation);
|
int size = Functions.XRRConfigCurrentConfiguration(screen_config, out rotation);
|
||||||
rate = Functions.XRRConfigCurrentRate(screen_config);
|
rate = Functions.XRRConfigCurrentRate(screen_config);
|
||||||
Functions.XRRFreeScreenConfigInfo(screen_config);
|
Functions.XRRFreeScreenConfigInfo(screen_config);
|
||||||
}
|
|
||||||
return (float)rate;
|
return (float)rate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,12 +202,9 @@ namespace OpenTK.Platform.X11
|
||||||
#region private static int FindCurrentDepth(int screen)
|
#region private static int FindCurrentDepth(int screen)
|
||||||
|
|
||||||
private static int FindCurrentDepth(int screen)
|
private static int FindCurrentDepth(int screen)
|
||||||
{
|
|
||||||
using (new XLock(API.DefaultDisplay))
|
|
||||||
{
|
{
|
||||||
return (int)Functions.XDefaultDepth(API.DefaultDisplay, screen);
|
return (int)Functions.XDefaultDepth(API.DefaultDisplay, screen);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
@ -181,7 +214,7 @@ namespace OpenTK.Platform.X11
|
||||||
|
|
||||||
public bool TryChangeResolution(DisplayDevice device, DisplayResolution resolution)
|
public bool TryChangeResolution(DisplayDevice device, DisplayResolution resolution)
|
||||||
{
|
{
|
||||||
// If resolution == null, restore to default resolution (new_resolution_index = 0).
|
// If resolution is null, restore the default resolution (new_resolution_index = 0).
|
||||||
|
|
||||||
using (new XLock(API.DefaultDisplay))
|
using (new XLock(API.DefaultDisplay))
|
||||||
{
|
{
|
||||||
|
@ -213,5 +246,55 @@ namespace OpenTK.Platform.X11
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region NativeMethods
|
||||||
|
|
||||||
|
static class NativeMethods
|
||||||
|
{
|
||||||
|
const string Xinerama = "libXinerama";
|
||||||
|
|
||||||
|
[DllImport(Xinerama)]
|
||||||
|
public static extern bool XineramaQueryExtension(IntPtr dpy, out int event_basep, out int error_basep);
|
||||||
|
|
||||||
|
[DllImport(Xinerama)]
|
||||||
|
public static extern int XineramaQueryVersion (IntPtr dpy, out int major_versionp, out int minor_versionp);
|
||||||
|
|
||||||
|
[DllImport(Xinerama)]
|
||||||
|
public static extern bool XineramaIsActive(IntPtr dpy);
|
||||||
|
|
||||||
|
[DllImport(Xinerama)]
|
||||||
|
static extern IntPtr XineramaQueryScreens(IntPtr dpy, out int number);
|
||||||
|
|
||||||
|
public static IList<XineramaScreenInfo> XineramaQueryScreens(IntPtr dpy)
|
||||||
|
{
|
||||||
|
int number;
|
||||||
|
IntPtr screen_ptr = XineramaQueryScreens(dpy, out number);
|
||||||
|
List<XineramaScreenInfo> screens = new List<XineramaScreenInfo>(number);
|
||||||
|
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
XineramaScreenInfo* ptr = (XineramaScreenInfo*)screen_ptr;
|
||||||
|
while (--number >= 0)
|
||||||
|
{
|
||||||
|
screens.Add(*ptr);
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return screens;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
|
struct XineramaScreenInfo
|
||||||
|
{
|
||||||
|
public int ScreenNumber;
|
||||||
|
public short X;
|
||||||
|
public short Y;
|
||||||
|
public short Width;
|
||||||
|
public short Height;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue