mirror of
https://github.com/Ryujinx/Opentk.git
synced 2024-12-26 17:25:37 +00:00
223c742648
Update X11 stack to use System.Windows.Forms.XPlatUI for its Display, Screen and RootWindow. Fixed mode setting for X11GLControl. Fixed X11 shutdown (was generating X11 errors). Added DeviceContext getter to WinWindowInfo. Made IWindowInfo disposable. Added documentation to many public methods. Worked around a Mono 1.2.4 bug with Handle creation on Windows.Forms.Control. Updated GL.BuildExtensionList to correctly parse GL_VERSION when in indirect rendering mode. Fixed crash errors in X11GLContext.CreateContext and X11GraphicsMode. Added a ref overload to Glx.ChooseVisual() IGraphicsContext.MakeCurrent now takes an IWindowInfo parameter. This allows the user to change to window is context is bound to (untested). Renamed XyzWindowInfo.Handle to XyzWindowInfo.WindowHandle.
331 lines
10 KiB
C#
331 lines
10 KiB
C#
#region --- License ---
|
|
/* Copyright (c) 2007 Stefanos Apostolopoulos
|
|
* See license.txt for license info
|
|
*/
|
|
#endregion
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using System.Runtime.InteropServices;
|
|
using System.Diagnostics;
|
|
|
|
using OpenTK.Graphics.OpenGL;
|
|
using OpenTK.Graphics;
|
|
|
|
namespace OpenTK.Platform.X11
|
|
{
|
|
/// <summary>
|
|
/// Provides methods to create and control an opengl context on the X11 platform.
|
|
/// This class supports OpenTK, and is not intended for use by OpenTK programs.
|
|
/// </summary>
|
|
internal sealed class X11GLContext : IGraphicsContext, IGraphicsContextInternal
|
|
{
|
|
IntPtr context;
|
|
//X11WindowInfo window;
|
|
X11WindowInfo currentWindow;
|
|
//IntPtr visual;
|
|
bool vsync_supported;
|
|
int vsync_interval;
|
|
|
|
bool disposed;
|
|
|
|
#region --- Constructors ---
|
|
|
|
static X11GLContext()
|
|
{
|
|
// Set the GetCurrentContext implementation.
|
|
if (GraphicsContext.GetCurrentContext == null)
|
|
GraphicsContext.GetCurrentContext = X11GLContext.GetCurrentContext;
|
|
}
|
|
|
|
internal X11GLContext(GraphicsMode mode, IWindowInfo info, IGraphicsContext shared, bool directRendering)
|
|
{
|
|
//if (mode == null) mode = GraphicsMode.Default;
|
|
if (info == null) throw new ArgumentNullException("info", "Should point to a valid window.");
|
|
|
|
currentWindow = (X11WindowInfo)info;
|
|
currentWindow.VisualInfo = SelectVisual(mode, currentWindow);
|
|
|
|
Debug.Print("Chose visual: {0}", currentWindow.VisualInfo);
|
|
|
|
CreateContext(shared, directRendering, currentWindow);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region --- Private Methods ---
|
|
|
|
#region XVisualInfo SelectVisual(GraphicsMode mode, X11WindowInfo currentWindow)
|
|
|
|
XVisualInfo SelectVisual(GraphicsMode mode, X11WindowInfo currentWindow)
|
|
{
|
|
XVisualInfo info = new XVisualInfo();
|
|
info.visualid = (IntPtr)mode.Index;
|
|
info.screen = currentWindow.Screen;
|
|
int items;
|
|
IntPtr vs = Functions.XGetVisualInfo(currentWindow.Display, XVisualInfoMask.ID | XVisualInfoMask.Screen, ref info, out items);
|
|
if (items == 0)
|
|
throw new GraphicsModeException(String.Format("Invalid GraphicsMode specified ({0}).", mode));
|
|
|
|
info = (XVisualInfo)Marshal.PtrToStructure(vs, typeof(XVisualInfo));
|
|
Functions.XFree(vs);
|
|
return info;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region void CreateContext(IGraphicsContext shareContext, bool direct)
|
|
|
|
void CreateContext(IGraphicsContext shareContext, bool direct, X11WindowInfo window)
|
|
{
|
|
try
|
|
{
|
|
ContextHandle shareHandle = shareContext != null ? (shareContext as IGraphicsContextInternal).Context :
|
|
(ContextHandle)IntPtr.Zero;
|
|
|
|
Debug.Write("Creating OpenGL context: ");
|
|
Debug.Write(direct ? "direct, " : "indirect, ");
|
|
Debug.Write(shareHandle.Handle == IntPtr.Zero ? "not shared... " :
|
|
String.Format("shared with ({0})... ", shareHandle));
|
|
|
|
XVisualInfo info = window.VisualInfo; // Cannot pass a Property by reference.
|
|
context = Glx.CreateContext(window.Display, ref info, shareHandle.Handle, direct);
|
|
|
|
// Context creation succeeded, return.
|
|
if (context != IntPtr.Zero)
|
|
{
|
|
Debug.Print("done! (id: {0})", context);
|
|
return;
|
|
}
|
|
|
|
// Context creation failed. Retry with a non-shared context with the direct/indirect bit flipped.
|
|
Debug.Print("failed.");
|
|
Debug.Write(String.Format("Creating OpenGL context: {0}, not shared... ", !direct ? "direct" : "indirect"));
|
|
context = Glx.CreateContext(window.Display, ref info, IntPtr.Zero, !direct);
|
|
if (context != IntPtr.Zero)
|
|
{
|
|
Debug.Print("done! (id: {0})", context);
|
|
return;
|
|
}
|
|
|
|
Debug.Print("failed.");
|
|
throw new GraphicsModeException("Failed to create OpenGL context. Glx.CreateContext call returned 0.");
|
|
}
|
|
finally
|
|
{
|
|
Debug.Unindent();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
bool SupportsExtension(X11WindowInfo window, string e)
|
|
{
|
|
string extensions = Glx.QueryExtensionsString(window.Display, window.Screen);
|
|
return !String.IsNullOrEmpty(extensions) && extensions.Contains(e);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region --- IGraphicsContext Members ---
|
|
|
|
#region public void SwapBuffers()
|
|
|
|
public void SwapBuffers()
|
|
{
|
|
//if (window == null) throw new ArgumentNullException("window", "Must point to a valid window.");
|
|
//X11WindowInfo w = (X11WindowInfo)window;
|
|
if (currentWindow.Display == IntPtr.Zero || currentWindow.WindowHandle == IntPtr.Zero)
|
|
throw new InvalidOperationException(
|
|
String.Format("Window is invalid. Display ({0}), Handle ({1}).", currentWindow.Display, currentWindow.WindowHandle));
|
|
Glx.SwapBuffers(currentWindow.Display, currentWindow.WindowHandle);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region public void MakeCurrent(IWindowInfo window)
|
|
|
|
public void MakeCurrent(IWindowInfo window)
|
|
{
|
|
X11WindowInfo w = (X11WindowInfo)window;
|
|
bool result;
|
|
|
|
Debug.Write(String.Format("Making context {0} current on thread {1} (Display: {2}, Screen: {3}, Window: {4})... ",
|
|
context, System.Threading.Thread.CurrentThread.ManagedThreadId, w.Display, w.Screen, w.WindowHandle));
|
|
|
|
if (w.Display == IntPtr.Zero || w.WindowHandle == IntPtr.Zero || context == IntPtr.Zero)
|
|
throw new InvalidOperationException("Invalid display, window or context.");
|
|
|
|
result = Glx.MakeCurrent(w.Display, w.WindowHandle, context);
|
|
|
|
if (!result)
|
|
throw new GraphicsContextException("Failed to make context current.");
|
|
else
|
|
Debug.WriteLine("done!");
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region public bool IsCurrent
|
|
|
|
public bool IsCurrent
|
|
{
|
|
get { return Glx.GetCurrentContext() == this.context; }
|
|
//set
|
|
//{
|
|
// if (value)
|
|
// Glx.MakeCurrent(window.Display, window.Handle, context);
|
|
// else
|
|
// Glx.MakeCurrent(window.Handle, IntPtr.Zero, IntPtr.Zero);
|
|
//}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region public bool VSync
|
|
|
|
public bool VSync
|
|
{
|
|
get
|
|
{
|
|
return vsync_supported && vsync_interval > 0;
|
|
}
|
|
set
|
|
{
|
|
if (vsync_supported)
|
|
{
|
|
int error_code = Glx.Sgi.SwapInterval(value ? 1 : 0);
|
|
if (error_code != 0)
|
|
throw new GraphicsException(String.Format("Could not set vsync, error code: {0}", error_code));
|
|
vsync_interval = value ? 1 : 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
public event DestroyEvent<IGraphicsContext> Destroy;
|
|
|
|
#region public IntPtr GetAddress(string function)
|
|
|
|
public IntPtr GetAddress(string function)
|
|
{
|
|
return Glx.GetProcAddress(function);
|
|
}
|
|
|
|
#endregion
|
|
|
|
public void RegisterForDisposal(IDisposable resource)
|
|
{
|
|
throw new NotSupportedException("Use OpenTK.GraphicsContext instead.");
|
|
}
|
|
|
|
public void DisposeResources()
|
|
{
|
|
throw new NotSupportedException("Use OpenTK.GraphicsContext instead.");
|
|
}
|
|
|
|
public IEnumerable<DisplayMode> GetDisplayModes()
|
|
{
|
|
throw new Exception("The method or operation is not implemented.");
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region --- IGLContextInternal Members ---
|
|
|
|
#region void LoadAll()
|
|
|
|
void IGraphicsContextInternal.LoadAll()
|
|
{
|
|
GL.LoadAll();
|
|
Glu.LoadAll();
|
|
Glx.LoadAll();
|
|
vsync_supported = this.SupportsExtension(currentWindow, "SGI_swap_control") &&
|
|
this.GetAddress("glXSwapControlSGI") != IntPtr.Zero;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region public DisplayMode Mode
|
|
|
|
GraphicsMode IGraphicsContextInternal.GraphicsMode
|
|
{
|
|
get { return null; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IntPtr IGLContextInternal.Context
|
|
|
|
ContextHandle IGraphicsContextInternal.Context
|
|
{
|
|
get { return context; }
|
|
/*private set { context = value; }*/
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IWindowInfo IGLContextInternal.Info
|
|
|
|
//IWindowInfo IGraphicsContextInternal.Info { get { return window; } }
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region --- Methods ---
|
|
|
|
void OnDestroy()
|
|
{
|
|
if (Destroy != null)
|
|
Destroy(this, EventArgs.Empty);
|
|
}
|
|
|
|
#region static ContextHandle GetCurrentContext()
|
|
|
|
static ContextHandle GetCurrentContext()
|
|
{
|
|
return (ContextHandle)Glx.GetCurrentContext();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region --- IDisposable Members ---
|
|
|
|
public void Dispose()
|
|
{
|
|
this.Dispose(true);
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
private void Dispose(bool manuallyCalled)
|
|
{
|
|
if (!disposed)
|
|
{
|
|
// Clean unmanaged resources:
|
|
|
|
Glx.MakeCurrent(currentWindow.Display, IntPtr.Zero, IntPtr.Zero);
|
|
Glx.DestroyContext(currentWindow.Display, context);
|
|
//API.Free(visual);
|
|
|
|
if (manuallyCalled)
|
|
{
|
|
// Safe to clean managed resources, too
|
|
}
|
|
}
|
|
disposed = true;
|
|
}
|
|
|
|
~X11GLContext()
|
|
{
|
|
this.Dispose(false);
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|