2007-07-23 00:15:18 +00:00
#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 ;
2008-02-02 00:58:26 +00:00
using OpenTK.Graphics.OpenGL ;
2008-01-31 14:22:37 +00:00
using OpenTK.Graphics ;
2007-07-23 00:15:18 +00:00
namespace OpenTK.Platform.X11
{
2007-08-05 13:42:31 +00:00
/// <summary>
2007-09-09 11:52:09 +00:00
/// Provides methods to create and control an opengl context on the X11 platform.
2007-12-09 18:15:51 +00:00
/// This class supports OpenTK, and is not intended for use by OpenTK programs.
2007-08-05 13:42:31 +00:00
/// </summary>
2008-01-31 13:17:42 +00:00
internal sealed class X11GLContext : IGraphicsContext , IGLContextInternal , IGLContextCreationHack
2007-07-23 00:15:18 +00:00
{
2008-01-23 00:18:52 +00:00
IntPtr context ;
DisplayMode mode ;
2008-02-28 13:57:07 +00:00
X11WindowInfo windowInfo = new X11WindowInfo ( ) ;
GraphicsFormat format ;
2008-01-23 00:18:52 +00:00
IntPtr visual ;
bool vsync_supported ;
int vsync_interval ;
2007-07-23 00:15:18 +00:00
2008-01-23 00:18:52 +00:00
bool disposed ;
2007-07-23 00:15:18 +00:00
2007-09-09 11:52:09 +00:00
#region - - - Constructors - - -
2007-07-23 00:15:18 +00:00
2008-01-31 13:15:17 +00:00
static X11GLContext ( )
{
// Set the GetCurrentContext implementation.
2008-01-31 14:39:54 +00:00
if ( GraphicsContext . GetCurrentContext = = null )
GraphicsContext . GetCurrentContext = X11GLContext . GetCurrentContext ;
2008-01-31 13:15:17 +00:00
}
/// <private />
/// <summary>Constructs a new X11GLContext object.</summary>
2008-01-11 20:23:41 +00:00
public X11GLContext ( ) { }
2007-09-09 11:52:09 +00:00
#endregion
2008-01-11 20:23:41 +00:00
#region - - - IGLContextCreationHack Members - - -
2007-08-20 12:25:48 +00:00
2008-01-11 20:23:41 +00:00
#region bool IGLContextCreationHack . SelectDisplayMode ( DisplayMode mode , IWindowInfo info )
/// <summary>
/// HACK! This function will be removed in 0.3.15
/// Checks if the specified OpenTK.Platform.DisplayMode is available, and selects it if it is.
/// </summary>
/// <param name="mode">The OpenTK.Platform.DisplayMode to select.</param>
/// <param name="info">The OpenTK.Platform.IWindowInfo that describes the display to use. Note: a window handle is not necessary for this function!</param>
/// <returns>True if the DisplayMode is available, false otherwise.</returns>
bool IGLContextCreationHack . SelectDisplayMode ( DisplayMode mode , IWindowInfo info )
2007-08-20 12:25:48 +00:00
{
List < int > visualAttributes = new List < int > ( ) ;
2007-08-21 10:48:32 +00:00
2007-11-04 15:37:41 +00:00
// TODO: Improve modesetting code.
if ( mode = = null | | mode . Color . BitsPerPixel = = 0 )
2007-08-21 10:48:32 +00:00
{
// Define the bare essentials - needed for compatibility with Mono's System.Windows.Forms
Debug . Print ( "Preparing visual for System.Windows.Forms (compatibility mode)" ) ;
2007-09-02 22:52:00 +00:00
2007-08-21 10:48:32 +00:00
visualAttributes . Add ( ( int ) Glx . Enums . GLXAttribute . RGBA ) ;
2007-11-11 19:28:55 +00:00
/ * visualAttributes . Add ( ( int ) Glx . Enums . GLXAttribute . RED_SIZE ) ;
2007-11-04 15:37:41 +00:00
visualAttributes . Add ( ( int ) 1 ) ;
visualAttributes . Add ( ( int ) Glx . Enums . GLXAttribute . GREEN_SIZE ) ;
visualAttributes . Add ( ( int ) 1 ) ;
visualAttributes . Add ( ( int ) Glx . Enums . GLXAttribute . BLUE_SIZE ) ;
2007-11-11 19:28:55 +00:00
visualAttributes . Add ( ( int ) 1 ) ; * /
2007-08-21 10:48:32 +00:00
visualAttributes . Add ( ( int ) Glx . Enums . GLXAttribute . DEPTH_SIZE ) ;
visualAttributes . Add ( ( int ) 1 ) ;
visualAttributes . Add ( ( int ) Glx . Enums . GLXAttribute . DOUBLEBUFFER ) ;
visualAttributes . Add ( ( int ) 0 ) ;
}
else
{
Debug . Print ( "Preparing visual for DisplayMode: {0}" , mode . ToString ( ) ) ;
visualAttributes . Add ( ( int ) Glx . Enums . GLXAttribute . RGBA ) ;
visualAttributes . Add ( ( int ) Glx . Enums . GLXAttribute . RED_SIZE ) ;
visualAttributes . Add ( ( int ) mode . Color . Red ) ;
visualAttributes . Add ( ( int ) Glx . Enums . GLXAttribute . GREEN_SIZE ) ;
visualAttributes . Add ( ( int ) mode . Color . Green ) ;
visualAttributes . Add ( ( int ) Glx . Enums . GLXAttribute . BLUE_SIZE ) ;
visualAttributes . Add ( ( int ) mode . Color . Blue ) ;
visualAttributes . Add ( ( int ) Glx . Enums . GLXAttribute . ALPHA_SIZE ) ;
visualAttributes . Add ( ( int ) mode . Color . Alpha ) ;
visualAttributes . Add ( ( int ) Glx . Enums . GLXAttribute . DEPTH_SIZE ) ;
2008-01-31 13:15:17 +00:00
visualAttributes . Add ( ( int ) mode . DepthBits ) ;
2007-08-21 10:48:32 +00:00
visualAttributes . Add ( ( int ) Glx . Enums . GLXAttribute . DOUBLEBUFFER ) ;
visualAttributes . Add ( ( int ) 0 ) ;
}
2008-01-15 10:59:36 +00:00
2008-02-28 13:57:07 +00:00
//windowInfo.CopyInfoFrom(info);
2008-01-15 12:32:38 +00:00
visual = Glx . ChooseVisual ( windowInfo . Display , windowInfo . Screen , visualAttributes . ToArray ( ) ) ;
2007-08-20 12:25:48 +00:00
if ( visual = = IntPtr . Zero )
2008-01-11 20:23:41 +00:00
return false ;
2007-08-20 12:25:48 +00:00
else
{
2007-11-04 15:37:41 +00:00
windowInfo . VisualInfo = ( XVisualInfo ) Marshal . PtrToStructure ( visual ,
typeof ( XVisualInfo ) ) ;
Debug . Print ( "Chose visual {0}" , windowInfo . VisualInfo . ToString ( ) ) ;
2007-08-20 12:25:48 +00:00
}
2008-01-11 20:23:41 +00:00
return true ;
}
#endregion
void IGLContextCreationHack . SetWindowHandle ( IntPtr handle )
{
this . windowInfo . Handle = handle ;
2007-08-20 12:25:48 +00:00
}
#endregion
2008-01-31 13:17:42 +00:00
#region - - - IGraphicsContext Members - - -
2007-09-09 15:10:21 +00:00
2008-01-31 13:15:17 +00:00
#region public void CreateContext ( )
2007-09-09 15:10:21 +00:00
public void CreateContext ( )
{
this . CreateContext ( true , null ) ;
}
2008-01-31 13:15:17 +00:00
#endregion
#region public void CreateContext ( bool direct )
2007-09-09 15:10:21 +00:00
public void CreateContext ( bool direct )
{
this . CreateContext ( direct , null ) ;
}
2008-01-31 13:15:17 +00:00
#endregion
2008-01-31 13:17:42 +00:00
#region public void CreateContext ( bool direct , IGraphicsContext shareContext )
2007-09-09 15:10:21 +00:00
2008-01-31 13:17:42 +00:00
public void CreateContext ( bool direct , IGraphicsContext shareContext )
2007-09-09 15:10:21 +00:00
{
try
2007-08-20 12:25:48 +00:00
{
2007-09-09 15:10:21 +00:00
Debug . WriteLine ( "Creating opengl context." ) ;
Debug . Indent ( ) ;
2008-01-15 12:47:51 +00:00
ContextHandle shareHandle = shareContext ! = null ? ( shareContext as IGLContextInternal ) . Context : ( ContextHandle ) IntPtr . Zero ;
2007-09-09 15:10:21 +00:00
Debug . Write ( direct ? "Context is direct, " : "Context is indirect, " ) ;
2008-01-15 12:47:51 +00:00
Debug . WriteLine ( shareHandle . Handle = = IntPtr . Zero ? "not shared." :
2007-09-09 15:10:21 +00:00
String . Format ( "shared with ({0})." , shareHandle ) ) ;
// Try to call Glx.CreateContext with the specified parameters.
2008-01-15 12:47:51 +00:00
context = Glx . CreateContext ( windowInfo . Display , visual , shareHandle . Handle , direct ) ;
2007-09-09 15:10:21 +00:00
// Context creation succeeded, return.
if ( context ! = IntPtr . Zero )
{
Debug . Print ( "New opengl context created. (id: {0})" , context ) ;
2007-11-04 15:37:41 +00:00
this . MakeCurrent ( ) ;
GL . LoadAll ( ) ;
Glu . LoadAll ( ) ;
2008-01-23 00:18:52 +00:00
Glx . LoadAll ( ) ;
2007-09-09 15:10:21 +00:00
return ;
}
// Context creation failed. Retry with a non-shared context with the
// direct/indirect rendering mode flipped.
Debug . Print ( "Cotnext creation failed, retrying with a non-shared, {0} context." ,
! direct ? "direct" : "indirect" ) ;
context = Glx . CreateContext ( windowInfo . Display , visual , IntPtr . Zero , ! direct ) ;
if ( context ! = IntPtr . Zero )
{
Debug . Print ( "New opengl context created. (id: {0})" , context ) ;
2007-11-04 15:37:41 +00:00
this . MakeCurrent ( ) ;
GL . LoadAll ( ) ;
Glu . LoadAll ( ) ;
2008-01-23 00:18:52 +00:00
Glx . LoadAll ( ) ;
2007-11-04 15:37:41 +00:00
2007-09-09 15:10:21 +00:00
return ;
}
2008-01-23 00:18:52 +00:00
vsync_supported = Glx . SupportsExtension ( "glxSwapControlSGI" ) ;
2007-08-20 12:25:48 +00:00
throw new ApplicationException ( "Glx.CreateContext call failed (returned 0)." ) ;
}
2007-09-09 15:10:21 +00:00
finally
{
Debug . Unindent ( ) ;
}
2007-08-20 12:25:48 +00:00
}
#endregion
2007-07-23 00:15:18 +00:00
#region public void SwapBuffers ( )
public void SwapBuffers ( )
{
2007-08-05 13:42:31 +00:00
Glx . SwapBuffers ( windowInfo . Display , windowInfo . Handle ) ;
2007-07-23 00:15:18 +00:00
}
#endregion
#region public void MakeCurrent ( )
2007-08-20 12:25:48 +00:00
bool result ;
2007-07-23 00:15:18 +00:00
public void MakeCurrent ( )
{
2007-08-20 12:25:48 +00:00
Debug . Write ( String . Format ( "Making context {0} current on thread {1} (Display: {2}, Screen: {3}, Window: {4})... " ,
context , System . Threading . Thread . CurrentThread . ManagedThreadId , windowInfo . Display , windowInfo . Screen , windowInfo . Handle ) ) ;
if ( windowInfo . Display ! = IntPtr . Zero & & windowInfo . Handle ! = IntPtr . Zero & & context ! = IntPtr . Zero )
2007-07-23 00:15:18 +00:00
{
2007-08-20 12:25:48 +00:00
result = Glx . MakeCurrent ( windowInfo . Display , windowInfo . Handle , context ) ;
if ( ! result )
{
Debug . WriteLine ( "failed." ) ;
// probably need to recreate context here.
//throw new ApplicationException(String.Format("Failed to make context {0} current on thread {1}.",
// context, System.Threading.Thread.CurrentThread.ManagedThreadId));
}
else
{
Debug . WriteLine ( "done!" ) ;
}
2007-07-23 00:15:18 +00:00
}
}
#endregion
2008-01-15 12:47:51 +00:00
#region public bool IsCurrent
2007-12-09 18:15:51 +00:00
public bool IsCurrent
2007-07-23 00:15:18 +00:00
{
2008-01-15 12:47:51 +00:00
get { return Glx . GetCurrentContext ( ) = = this . context ; }
2008-01-31 13:15:17 +00:00
set
{
if ( value )
Glx . MakeCurrent ( windowInfo . Display , windowInfo . Handle , context ) ;
else
Glx . MakeCurrent ( windowInfo . Handle , IntPtr . Zero , IntPtr . Zero ) ;
}
2007-12-09 18:15:51 +00:00
}
2008-01-15 12:47:51 +00:00
#endregion
2007-07-23 00:15:18 +00:00
2008-01-23 00:18:52 +00:00
#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
2008-01-31 13:17:42 +00:00
public event DestroyEvent < IGraphicsContext > Destroy ;
2007-12-09 18:15:51 +00:00
2007-07-23 00:15:18 +00:00
#region public IntPtr GetAddress ( string function )
public IntPtr GetAddress ( string function )
{
return Glx . GetProcAddress ( function ) ;
}
#endregion
2007-12-09 18:15:51 +00:00
public void RegisterForDisposal ( IDisposable resource )
{
2008-01-31 14:39:54 +00:00
throw new NotSupportedException ( "Use OpenTK.GraphicsContext instead." ) ;
2007-12-09 18:15:51 +00:00
}
public void DisposeResources ( )
{
2008-01-31 14:39:54 +00:00
throw new NotSupportedException ( "Use OpenTK.GraphicsContext instead." ) ;
2007-12-09 18:15:51 +00:00
}
2007-07-23 00:15:18 +00:00
public IEnumerable < DisplayMode > GetDisplayModes ( )
{
throw new Exception ( "The method or operation is not implemented." ) ;
}
#endregion
2008-01-15 12:47:51 +00:00
#region - - - IGLContextInternal Members - - -
2008-02-28 13:57:07 +00:00
#region public DisplayMode Mode
GraphicsFormat IGLContextInternal . GraphicsFormat
{
get { return format ; }
}
#endregion
2008-01-15 12:47:51 +00:00
#region IntPtr IGLContextInternal . Context
ContextHandle IGLContextInternal . Context
{
get { return context ; }
/*private set { context = value; }*/
}
#endregion
#region IWindowInfo IGLContextInternal . Info
IWindowInfo IGLContextInternal . Info { get { return windowInfo ; } }
#endregion
#endregion
2008-01-31 13:15:17 +00:00
#region - - - Methods - - -
2008-01-20 19:29:42 +00:00
void OnDestroy ( )
{
if ( Destroy ! = null )
Destroy ( this , EventArgs . Empty ) ;
}
2008-01-31 13:15:17 +00:00
#region static ContextHandle GetCurrentContext ( )
static ContextHandle GetCurrentContext ( )
{
return ( ContextHandle ) Glx . GetCurrentContext ( ) ;
}
#endregion
2008-01-20 19:29:42 +00:00
#endregion
2007-07-23 00:15:18 +00:00
#region - - - IDisposable Members - - -
public void Dispose ( )
{
this . Dispose ( true ) ;
GC . SuppressFinalize ( this ) ;
}
private void Dispose ( bool manuallyCalled )
{
if ( ! disposed )
{
// Clean unmanaged resources:
2007-08-20 12:25:48 +00:00
Glx . MakeCurrent ( windowInfo . Display , IntPtr . Zero , IntPtr . Zero ) ;
Glx . DestroyContext ( windowInfo . Display , context ) ;
2007-07-23 00:15:18 +00:00
API . Free ( visual ) ;
if ( manuallyCalled )
{
// Safe to clean managed resources, too
}
}
disposed = true ;
}
~ X11GLContext ( )
{
this . Dispose ( false ) ;
}
#endregion
}
}