mirror of
https://github.com/Ryujinx/Opentk.git
synced 2025-03-29 18:06:52 +00:00
Merge branch 'develop' into linux_joystick
This commit is contained in:
commit
f3036e5f10
|
@ -25,9 +25,23 @@ namespace Examples.Tests
|
||||||
int texture;
|
int texture;
|
||||||
bool mouse_in_window = false;
|
bool mouse_in_window = false;
|
||||||
bool viewport_changed = true;
|
bool viewport_changed = true;
|
||||||
|
|
||||||
|
// time drift
|
||||||
Stopwatch watch = new Stopwatch();
|
Stopwatch watch = new Stopwatch();
|
||||||
double update_time, render_time;
|
double update_time, render_time;
|
||||||
|
|
||||||
|
// timing information
|
||||||
|
double timestamp;
|
||||||
|
int update_count;
|
||||||
|
int update_fps;
|
||||||
|
int render_count;
|
||||||
|
int render_fps;
|
||||||
|
|
||||||
|
// position of moving objects on screen
|
||||||
|
double variable_update_timestep_pos = -1;
|
||||||
|
double variable_refresh_timestep_pos = -1;
|
||||||
|
double fixed_update_timestep_pos = -1;
|
||||||
|
|
||||||
public GameWindowStates()
|
public GameWindowStates()
|
||||||
: base(800, 600, GraphicsMode.Default)
|
: base(800, 600, GraphicsMode.Default)
|
||||||
{
|
{
|
||||||
|
@ -35,10 +49,10 @@ namespace Examples.Tests
|
||||||
Keyboard.KeyRepeat = true;
|
Keyboard.KeyRepeat = true;
|
||||||
KeyDown += KeyDownHandler;
|
KeyDown += KeyDownHandler;
|
||||||
KeyPress += KeyPressHandler;
|
KeyPress += KeyPressHandler;
|
||||||
|
|
||||||
MouseEnter += delegate { mouse_in_window = true; };
|
MouseEnter += delegate { mouse_in_window = true; };
|
||||||
MouseLeave += delegate { mouse_in_window = false; };
|
MouseLeave += delegate { mouse_in_window = false; };
|
||||||
|
|
||||||
Mouse.Move += MouseMoveHandler;
|
Mouse.Move += MouseMoveHandler;
|
||||||
Mouse.ButtonDown += MouseButtonHandler;
|
Mouse.ButtonDown += MouseButtonHandler;
|
||||||
Mouse.ButtonUp += MouseButtonHandler;
|
Mouse.ButtonUp += MouseButtonHandler;
|
||||||
|
@ -110,7 +124,7 @@ namespace Examples.Tests
|
||||||
{
|
{
|
||||||
return val > max ? max : val < min ? min : val;
|
return val > max ? max : val < min ? min : val;
|
||||||
}
|
}
|
||||||
|
|
||||||
static float DrawString(Graphics gfx, string str, int line)
|
static float DrawString(Graphics gfx, string str, int line)
|
||||||
{
|
{
|
||||||
return DrawString(gfx, str, line, 0);
|
return DrawString(gfx, str, line, 0);
|
||||||
|
@ -217,6 +231,8 @@ namespace Examples.Tests
|
||||||
{
|
{
|
||||||
double clock_time = watch.Elapsed.TotalSeconds;
|
double clock_time = watch.Elapsed.TotalSeconds;
|
||||||
update_time += e.Time;
|
update_time += e.Time;
|
||||||
|
timestamp += e.Time;
|
||||||
|
update_count++;
|
||||||
|
|
||||||
using (Graphics gfx = Graphics.FromImage(TextBitmap))
|
using (Graphics gfx = Graphics.FromImage(TextBitmap))
|
||||||
{
|
{
|
||||||
|
@ -247,22 +263,47 @@ namespace Examples.Tests
|
||||||
// Timing information
|
// Timing information
|
||||||
line++;
|
line++;
|
||||||
DrawString(gfx, "Timing:", line++);
|
DrawString(gfx, "Timing:", line++);
|
||||||
DrawString(gfx, String.Format("Frequency: update ({0:f2}/{1:f2}); render ({2:f2}/{3:f2})",
|
DrawString(gfx,
|
||||||
UpdateFrequency, TargetUpdateFrequency, RenderFrequency, TargetRenderFrequency), line++);
|
String.Format("Frequency: update {4} ({0:f2}/{1:f2}); render {5} ({2:f2}/{3:f2})",
|
||||||
DrawString(gfx, String.Format("Period: update ({0:f4}/{1:f4}); render ({2:f4}/{3:f4})",
|
UpdateFrequency, TargetUpdateFrequency,
|
||||||
UpdatePeriod, TargetUpdatePeriod, RenderPeriod, TargetRenderPeriod), line++);
|
RenderFrequency, TargetRenderFrequency,
|
||||||
|
update_fps, render_fps),
|
||||||
|
line++);
|
||||||
|
DrawString(gfx,
|
||||||
|
String.Format("Period: update {4:N4} ({0:f4}/{1:f4}); render {5:N4} ({2:f4}/{3:f4})",
|
||||||
|
UpdatePeriod, TargetUpdatePeriod,
|
||||||
|
RenderPeriod, TargetRenderPeriod,
|
||||||
|
1.0 / update_fps, 1.0 / render_fps),
|
||||||
|
line++);
|
||||||
DrawString(gfx, String.Format("Time: update {0:f4}; render {1:f4}",
|
DrawString(gfx, String.Format("Time: update {0:f4}; render {1:f4}",
|
||||||
UpdateTime, RenderTime), line++);
|
UpdateTime, RenderTime), line++);
|
||||||
DrawString(gfx, String.Format("Drift: clock {0:f4}; update {1:f4}; render {2:f4}",
|
DrawString(gfx, String.Format("Drift: clock {0:f4}; update {1:f4}; render {2:f4}",
|
||||||
clock_time, clock_time - update_time, clock_time - render_time), line++);
|
clock_time, clock_time - update_time, clock_time - render_time), line++);
|
||||||
DrawString(gfx, String.Format("Text: {0}", TypedText.ToString()), line++);
|
DrawString(gfx, String.Format("Text: {0}", TypedText.ToString()), line++);
|
||||||
|
|
||||||
|
if (timestamp >= 1)
|
||||||
|
{
|
||||||
|
timestamp -= 1;
|
||||||
|
update_fps = update_count;
|
||||||
|
render_fps = render_count;
|
||||||
|
update_count = 0;
|
||||||
|
render_count = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// Input information
|
// Input information
|
||||||
line = DrawKeyboards(gfx, line);
|
line = DrawKeyboards(gfx, line);
|
||||||
line = DrawMice(gfx, line);
|
line = DrawMice(gfx, line);
|
||||||
line = DrawJoysticks(gfx, line);
|
line = DrawJoysticks(gfx, line);
|
||||||
line = DrawLegacyJoysticks(gfx, Joysticks, line);
|
line = DrawLegacyJoysticks(gfx, Joysticks, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fixed_update_timestep_pos += TargetUpdatePeriod;
|
||||||
|
variable_update_timestep_pos += e.Time;
|
||||||
|
if (fixed_update_timestep_pos >= 1)
|
||||||
|
fixed_update_timestep_pos -= 2;
|
||||||
|
if (variable_update_timestep_pos >= 1)
|
||||||
|
variable_update_timestep_pos -= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
int DrawJoysticks(Graphics gfx, int line)
|
int DrawJoysticks(Graphics gfx, int line)
|
||||||
|
@ -323,7 +364,31 @@ namespace Examples.Tests
|
||||||
protected override void OnRenderFrame(FrameEventArgs e)
|
protected override void OnRenderFrame(FrameEventArgs e)
|
||||||
{
|
{
|
||||||
render_time += e.Time;
|
render_time += e.Time;
|
||||||
|
render_count++;
|
||||||
|
|
||||||
|
GL.Clear(ClearBufferMask.ColorBufferBit);
|
||||||
|
|
||||||
|
if (viewport_changed)
|
||||||
|
{
|
||||||
|
viewport_changed = false;
|
||||||
|
GL.Viewport(0, 0, Width, Height);
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawText();
|
||||||
|
|
||||||
|
DrawMovingObjects();
|
||||||
|
|
||||||
|
variable_refresh_timestep_pos += e.Time;
|
||||||
|
if (variable_refresh_timestep_pos >= 1)
|
||||||
|
variable_refresh_timestep_pos -= 2;
|
||||||
|
|
||||||
|
SwapBuffers();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uploads our text Bitmap to an OpenGL texture
|
||||||
|
// and displays is to screen.
|
||||||
|
private void DrawText()
|
||||||
|
{
|
||||||
System.Drawing.Imaging.BitmapData data = TextBitmap.LockBits(
|
System.Drawing.Imaging.BitmapData data = TextBitmap.LockBits(
|
||||||
new System.Drawing.Rectangle(0, 0, TextBitmap.Width, TextBitmap.Height),
|
new System.Drawing.Rectangle(0, 0, TextBitmap.Width, TextBitmap.Height),
|
||||||
System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
|
System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
|
||||||
|
@ -331,29 +396,63 @@ namespace Examples.Tests
|
||||||
PixelType.UnsignedByte, data.Scan0);
|
PixelType.UnsignedByte, data.Scan0);
|
||||||
TextBitmap.UnlockBits(data);
|
TextBitmap.UnlockBits(data);
|
||||||
|
|
||||||
if (viewport_changed)
|
Matrix4 text_projection = Matrix4.CreateOrthographicOffCenter(0, Width, Height, 0, -1, 1);
|
||||||
{
|
GL.MatrixMode(MatrixMode.Projection);
|
||||||
viewport_changed = false;
|
GL.LoadMatrix(ref text_projection);
|
||||||
|
GL.MatrixMode(MatrixMode.Modelview);
|
||||||
GL.Viewport(0, 0, Width, Height);
|
GL.LoadIdentity();
|
||||||
|
|
||||||
Matrix4 ortho_projection = Matrix4.CreateOrthographicOffCenter(0, Width, Height, 0, -1, 1);
|
|
||||||
GL.MatrixMode(MatrixMode.Projection);
|
|
||||||
GL.LoadMatrix(ref ortho_projection);
|
|
||||||
}
|
|
||||||
|
|
||||||
GL.Clear(ClearBufferMask.ColorBufferBit);
|
|
||||||
|
|
||||||
|
GL.Color4(Color4.White);
|
||||||
|
GL.Enable(EnableCap.Texture2D);
|
||||||
GL.Begin(PrimitiveType.Quads);
|
GL.Begin(PrimitiveType.Quads);
|
||||||
|
|
||||||
GL.TexCoord2(0, 0); GL.Vertex2(0, 0);
|
GL.TexCoord2(0, 0); GL.Vertex2(0, 0);
|
||||||
GL.TexCoord2(1, 0); GL.Vertex2(TextBitmap.Width, 0);
|
GL.TexCoord2(1, 0); GL.Vertex2(TextBitmap.Width, 0);
|
||||||
GL.TexCoord2(1, 1); GL.Vertex2(TextBitmap.Width, TextBitmap.Height);
|
GL.TexCoord2(1, 1); GL.Vertex2(TextBitmap.Width, TextBitmap.Height);
|
||||||
GL.TexCoord2(0, 1); GL.Vertex2(0, TextBitmap.Height);
|
GL.TexCoord2(0, 1); GL.Vertex2(0, TextBitmap.Height);
|
||||||
|
|
||||||
GL.End();
|
GL.End();
|
||||||
|
GL.Disable(EnableCap.Texture2D);
|
||||||
|
}
|
||||||
|
|
||||||
SwapBuffers();
|
// Draws three moving objects, using three different timing methods:
|
||||||
|
// 1. fixed framerate based on TargetUpdatePeriod
|
||||||
|
// 2. variable framerate based on UpdateFrame e.Time
|
||||||
|
// 3. variable framerate based on RenderFrame e.Time
|
||||||
|
// If the timing implementation is correct, all three objects
|
||||||
|
// should be moving at the same speed, regardless of the current
|
||||||
|
// UpdatePeriod and RenderPeriod.
|
||||||
|
void DrawMovingObjects()
|
||||||
|
{
|
||||||
|
Matrix4 thing_projection = Matrix4.CreateOrthographic(2, 2, -1, 1);
|
||||||
|
GL.MatrixMode(MatrixMode.Projection);
|
||||||
|
GL.LoadMatrix(ref thing_projection);
|
||||||
|
|
||||||
|
GL.MatrixMode(MatrixMode.Modelview);
|
||||||
|
GL.LoadIdentity();
|
||||||
|
GL.Translate(fixed_update_timestep_pos, -0.2, 0);
|
||||||
|
GL.Color4(Color4.Red);
|
||||||
|
DrawRectangle();
|
||||||
|
|
||||||
|
GL.MatrixMode(MatrixMode.Modelview);
|
||||||
|
GL.LoadIdentity();
|
||||||
|
GL.Translate(variable_update_timestep_pos, -0.4, 0);
|
||||||
|
GL.Color4(Color4.DarkGoldenrod);
|
||||||
|
DrawRectangle();
|
||||||
|
|
||||||
|
GL.MatrixMode(MatrixMode.Modelview);
|
||||||
|
GL.LoadIdentity();
|
||||||
|
GL.Translate(variable_refresh_timestep_pos, -0.8, 0);
|
||||||
|
GL.Color4(Color4.DarkGreen);
|
||||||
|
DrawRectangle();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawRectangle()
|
||||||
|
{
|
||||||
|
GL.Begin(PrimitiveType.Quads);
|
||||||
|
GL.Vertex2(-0.05, -0.05);
|
||||||
|
GL.Vertex2(+0.05, -0.05);
|
||||||
|
GL.Vertex2(+0.05, +0.05);
|
||||||
|
GL.Vertex2(-0.05, +0.05);
|
||||||
|
GL.End();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Main()
|
public static void Main()
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Security;
|
using System.Security;
|
||||||
|
|
||||||
|
@ -262,7 +263,13 @@ namespace OpenTK.Audio.OpenAL
|
||||||
/// <returns>A string containing the name of the Device.</returns>
|
/// <returns>A string containing the name of the Device.</returns>
|
||||||
public static string GetString(IntPtr device, AlcGetString param)
|
public static string GetString(IntPtr device, AlcGetString param)
|
||||||
{
|
{
|
||||||
return Marshal.PtrToStringAnsi(GetStringPrivate(device, param));
|
IntPtr pstr = GetStringPrivate(device, param);
|
||||||
|
string str = String.Empty;
|
||||||
|
if (pstr != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
str = Marshal.PtrToStringAnsi(pstr);
|
||||||
|
}
|
||||||
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>This function returns a List of strings related to the context.</summary>
|
/// <summary>This function returns a List of strings related to the context.</summary>
|
||||||
|
@ -277,26 +284,54 @@ namespace OpenTK.Audio.OpenAL
|
||||||
public static IList<string> GetString(IntPtr device, AlcGetStringList param)
|
public static IList<string> GetString(IntPtr device, AlcGetStringList param)
|
||||||
{
|
{
|
||||||
List<string> result = new List<string>();
|
List<string> result = new List<string>();
|
||||||
IntPtr t = GetStringPrivate(IntPtr.Zero, (AlcGetString)param);
|
|
||||||
System.Text.StringBuilder sb = new System.Text.StringBuilder();
|
|
||||||
byte b;
|
|
||||||
int offset = 0;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
b = Marshal.ReadByte(t, offset++);
|
|
||||||
if (b != 0)
|
|
||||||
sb.Append((char)b);
|
|
||||||
if (b == 0)
|
|
||||||
{
|
|
||||||
result.Add(sb.ToString());
|
|
||||||
if (Marshal.ReadByte(t, offset) == 0) // offset already properly increased through ++
|
|
||||||
break; // 2x null
|
|
||||||
else
|
|
||||||
sb.Remove(0, sb.Length); // 1x null
|
|
||||||
}
|
|
||||||
} while (true);
|
|
||||||
|
|
||||||
return (IList<string>)result;
|
// We cannot use Marshal.PtrToStringAnsi(),
|
||||||
|
// because alcGetString is defined to return either a nul-terminated string,
|
||||||
|
// or an array of nul-terminated strings terminated by an extra nul.
|
||||||
|
// Marshal.PtrToStringAnsi() will fail in the latter case (it will only
|
||||||
|
// return the very first string in the array.)
|
||||||
|
// We'll have to marshal this ourselves.
|
||||||
|
IntPtr t = GetStringPrivate(device, (AlcGetString)param);
|
||||||
|
if (t != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
System.Text.StringBuilder sb = new System.Text.StringBuilder();
|
||||||
|
byte b;
|
||||||
|
int offset = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
b = Marshal.ReadByte(t, offset++);
|
||||||
|
if (b != 0)
|
||||||
|
{
|
||||||
|
sb.Append((char)b);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// One string from the array is complete
|
||||||
|
result.Add(sb.ToString());
|
||||||
|
|
||||||
|
// Check whether the array has finished
|
||||||
|
// Note: offset already been increased through offset++ above
|
||||||
|
if (Marshal.ReadByte(t, offset) == 0)
|
||||||
|
{
|
||||||
|
// 2x consecutive nuls, we've read the whole array
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Another string is starting, clear the StringBuilder
|
||||||
|
sb.Remove(0, sb.Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.Print("[Audio] Alc.GetString({0}, {1}) returned null.",
|
||||||
|
device, param);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
[DllImport(Alc.Lib, EntryPoint = "alcGetIntegerv", ExactSpelling = true, CallingConvention = Alc.Style, CharSet = CharSet.Ansi), SuppressUnmanagedCodeSecurity()]
|
[DllImport(Alc.Lib, EntryPoint = "alcGetIntegerv", ExactSpelling = true, CallingConvention = Alc.Style, CharSet = CharSet.Ansi), SuppressUnmanagedCodeSecurity()]
|
||||||
|
|
|
@ -75,6 +75,8 @@ namespace OpenTK
|
||||||
{
|
{
|
||||||
#region --- Fields ---
|
#region --- Fields ---
|
||||||
|
|
||||||
|
const double MaxFrequency = 500.0; // Frequency cap for Update/RenderFrame events
|
||||||
|
|
||||||
readonly Stopwatch watch = new Stopwatch();
|
readonly Stopwatch watch = new Stopwatch();
|
||||||
|
|
||||||
IGraphicsContext glContext;
|
IGraphicsContext glContext;
|
||||||
|
@ -90,6 +92,10 @@ namespace OpenTK
|
||||||
double update_timestamp; // timestamp of last UpdateFrame event
|
double update_timestamp; // timestamp of last UpdateFrame event
|
||||||
double render_timestamp; // timestamp of last RenderFrame event
|
double render_timestamp; // timestamp of last RenderFrame event
|
||||||
|
|
||||||
|
double update_epsilon; // quantization error for UpdateFrame events
|
||||||
|
|
||||||
|
bool is_running_slowly; // true, when UpdatePeriod cannot reach TargetUpdatePeriod
|
||||||
|
|
||||||
VSyncMode vsync;
|
VSyncMode vsync;
|
||||||
|
|
||||||
FrameEventArgs update_args = new FrameEventArgs();
|
FrameEventArgs update_args = new FrameEventArgs();
|
||||||
|
@ -431,63 +437,84 @@ namespace OpenTK
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double ClampElapsed(double elapsed)
|
||||||
|
{
|
||||||
|
return MathHelper.Clamp(elapsed, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
void DispatchUpdateAndRenderFrame(object sender, EventArgs e)
|
void DispatchUpdateAndRenderFrame(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
const int max_frameskip = 10;
|
int is_running_slowly_retries = 4;
|
||||||
int frameskip = 0;
|
|
||||||
double timestamp = watch.Elapsed.TotalSeconds;
|
double timestamp = watch.Elapsed.TotalSeconds;
|
||||||
|
double elapsed = 0;
|
||||||
|
|
||||||
do
|
elapsed = ClampElapsed(timestamp - update_timestamp);
|
||||||
|
while (elapsed > 0 && elapsed + update_epsilon >= TargetUpdatePeriod)
|
||||||
{
|
{
|
||||||
// Raise UpdateFrame events until we catch up with our target update rate.
|
RaiseUpdateFrame(elapsed, ref timestamp);
|
||||||
double update_elapsed = MathHelper.Clamp(timestamp - update_timestamp, 0.0, 1.0);
|
|
||||||
if (RaiseUpdateFrame(update_elapsed))
|
// Calculate difference (positive or negative) between
|
||||||
|
// actual elapsed time and target elapsed time. We must
|
||||||
|
// compensate for this difference.
|
||||||
|
update_epsilon += elapsed - TargetUpdatePeriod;
|
||||||
|
|
||||||
|
// Prepare for next loop
|
||||||
|
elapsed = ClampElapsed(timestamp - update_timestamp);
|
||||||
|
|
||||||
|
if (TargetUpdatePeriod <= Double.Epsilon)
|
||||||
{
|
{
|
||||||
update_period = update_elapsed;
|
// According to the TargetUpdatePeriod documentation,
|
||||||
update_timestamp = timestamp;
|
// a TargetUpdatePeriod of zero means we will raise
|
||||||
timestamp = watch.Elapsed.TotalSeconds;
|
// UpdateFrame events as fast as possible (one event
|
||||||
update_time = timestamp - update_timestamp;
|
// per ProcessEvents() call)
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// We have executed enough UpdateFrame events to catch up.
|
|
||||||
// Break and issue a RenderFrame event.
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while (++frameskip < max_frameskip);
|
|
||||||
|
|
||||||
|
is_running_slowly = update_epsilon >= TargetUpdatePeriod;
|
||||||
|
if (is_running_slowly && --is_running_slowly_retries == 0)
|
||||||
|
{
|
||||||
|
// If UpdateFrame consistently takes longer than TargetUpdateFrame
|
||||||
|
// stop raising events to avoid hanging inside the UpdateFrame loop.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
elapsed = ClampElapsed(timestamp - render_timestamp);
|
||||||
|
if (elapsed > 0 && elapsed >= TargetRenderPeriod)
|
||||||
|
{
|
||||||
|
RaiseRenderFrame(elapsed, ref timestamp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RaiseUpdateFrame(double elapsed, ref double timestamp)
|
||||||
|
{
|
||||||
|
// Raise UpdateFrame event
|
||||||
|
update_args.Time = elapsed;
|
||||||
|
OnUpdateFrameInternal(update_args);
|
||||||
|
|
||||||
|
// Update UpdatePeriod/UpdateFrequency properties
|
||||||
|
update_period = elapsed;
|
||||||
|
|
||||||
|
// Update UpdateTime property
|
||||||
|
update_timestamp = timestamp;
|
||||||
timestamp = watch.Elapsed.TotalSeconds;
|
timestamp = watch.Elapsed.TotalSeconds;
|
||||||
double render_elapsed = MathHelper.Clamp(timestamp - render_timestamp, 0.0, 1.0);
|
update_time = timestamp - update_timestamp;
|
||||||
if (RaiseRenderFrame(render_elapsed))
|
|
||||||
{
|
|
||||||
render_period = render_elapsed;
|
|
||||||
render_timestamp = timestamp;
|
|
||||||
timestamp = watch.Elapsed.TotalSeconds;
|
|
||||||
render_time = timestamp - render_timestamp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RaiseUpdateFrame(double time)
|
|
||||||
{
|
|
||||||
if (time > 0 && time >= TargetUpdatePeriod)
|
|
||||||
{
|
|
||||||
update_args.Time = time;
|
|
||||||
OnUpdateFrameInternal(update_args);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool RaiseRenderFrame(double time)
|
void RaiseRenderFrame(double elapsed, ref double timestamp)
|
||||||
{
|
{
|
||||||
if (time > 0 && time >= TargetRenderPeriod)
|
// Raise RenderFrame event
|
||||||
{
|
render_args.Time = elapsed;
|
||||||
render_args.Time = time;
|
OnRenderFrameInternal(render_args);
|
||||||
OnRenderFrameInternal(render_args);
|
|
||||||
return true;
|
// Update RenderPeriod/UpdateFrequency properties
|
||||||
}
|
render_period = elapsed;
|
||||||
return false;
|
|
||||||
|
// Update RenderTime property
|
||||||
|
render_timestamp = timestamp;
|
||||||
|
timestamp = watch.Elapsed.TotalSeconds;
|
||||||
|
render_time = timestamp - render_timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -656,7 +683,7 @@ namespace OpenTK
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// <para>A value of 0.0 indicates that RenderFrame events are generated at the maximum possible frequency (i.e. only limited by the hardware's capabilities).</para>
|
/// <para>A value of 0.0 indicates that RenderFrame events are generated at the maximum possible frequency (i.e. only limited by the hardware's capabilities).</para>
|
||||||
/// <para>Values lower than 1.0Hz are clamped to 1.0Hz. Values higher than 200.0Hz are clamped to 200.0Hz.</para>
|
/// <para>Values lower than 1.0Hz are clamped to 0.0. Values higher than 500.0Hz are clamped to 200.0Hz.</para>
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public double TargetRenderFrequency
|
public double TargetRenderFrequency
|
||||||
{
|
{
|
||||||
|
@ -674,11 +701,11 @@ namespace OpenTK
|
||||||
{
|
{
|
||||||
TargetRenderPeriod = 0.0;
|
TargetRenderPeriod = 0.0;
|
||||||
}
|
}
|
||||||
else if (value <= 200.0)
|
else if (value <= MaxFrequency)
|
||||||
{
|
{
|
||||||
TargetRenderPeriod = 1.0 / value;
|
TargetRenderPeriod = 1.0 / value;
|
||||||
}
|
}
|
||||||
else Debug.Print("Target render frequency clamped to 200.0Hz."); // TODO: Where is it actually performed?
|
else Debug.Print("Target render frequency clamped to {0}Hz.", MaxFrequency);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -691,7 +718,7 @@ namespace OpenTK
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// <para>A value of 0.0 indicates that RenderFrame events are generated at the maximum possible frequency (i.e. only limited by the hardware's capabilities).</para>
|
/// <para>A value of 0.0 indicates that RenderFrame events are generated at the maximum possible frequency (i.e. only limited by the hardware's capabilities).</para>
|
||||||
/// <para>Values lower than 0.005 seconds (200Hz) are clamped to 0.0. Values higher than 1.0 seconds (1Hz) are clamped to 1.0.</para>
|
/// <para>Values lower than 0.002 seconds (500Hz) are clamped to 0.0. Values higher than 1.0 seconds (1Hz) are clamped to 1.0.</para>
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public double TargetRenderPeriod
|
public double TargetRenderPeriod
|
||||||
{
|
{
|
||||||
|
@ -703,7 +730,7 @@ namespace OpenTK
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
EnsureUndisposed();
|
EnsureUndisposed();
|
||||||
if (value <= 0.005)
|
if (value <= 1 / MaxFrequency)
|
||||||
{
|
{
|
||||||
target_render_period = 0.0;
|
target_render_period = 0.0;
|
||||||
}
|
}
|
||||||
|
@ -724,7 +751,7 @@ namespace OpenTK
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// <para>A value of 0.0 indicates that UpdateFrame events are generated at the maximum possible frequency (i.e. only limited by the hardware's capabilities).</para>
|
/// <para>A value of 0.0 indicates that UpdateFrame events are generated at the maximum possible frequency (i.e. only limited by the hardware's capabilities).</para>
|
||||||
/// <para>Values lower than 1.0Hz are clamped to 1.0Hz. Values higher than 200.0Hz are clamped to 200.0Hz.</para>
|
/// <para>Values lower than 1.0Hz are clamped to 0.0. Values higher than 500.0Hz are clamped to 500.0Hz.</para>
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public double TargetUpdateFrequency
|
public double TargetUpdateFrequency
|
||||||
{
|
{
|
||||||
|
@ -742,11 +769,11 @@ namespace OpenTK
|
||||||
{
|
{
|
||||||
TargetUpdatePeriod = 0.0;
|
TargetUpdatePeriod = 0.0;
|
||||||
}
|
}
|
||||||
else if (value <= 200.0)
|
else if (value <= MaxFrequency)
|
||||||
{
|
{
|
||||||
TargetUpdatePeriod = 1.0 / value;
|
TargetUpdatePeriod = 1.0 / value;
|
||||||
}
|
}
|
||||||
else Debug.Print("Target update frequency clamped to 200.0Hz."); // TODO: Where is it actually performed?
|
else Debug.Print("Target render frequency clamped to {0}Hz.", MaxFrequency);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -759,7 +786,7 @@ namespace OpenTK
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// <para>A value of 0.0 indicates that UpdateFrame events are generated at the maximum possible frequency (i.e. only limited by the hardware's capabilities).</para>
|
/// <para>A value of 0.0 indicates that UpdateFrame events are generated at the maximum possible frequency (i.e. only limited by the hardware's capabilities).</para>
|
||||||
/// <para>Values lower than 0.005 seconds (200Hz) are clamped to 0.0. Values higher than 1.0 seconds (1Hz) are clamped to 1.0.</para>
|
/// <para>Values lower than 0.002 seconds (500Hz) are clamped to 0.0. Values higher than 1.0 seconds (1Hz) are clamped to 1.0.</para>
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public double TargetUpdatePeriod
|
public double TargetUpdatePeriod
|
||||||
{
|
{
|
||||||
|
@ -771,7 +798,7 @@ namespace OpenTK
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
EnsureUndisposed();
|
EnsureUndisposed();
|
||||||
if (value <= 0.005)
|
if (value <= 1 / MaxFrequency)
|
||||||
{
|
{
|
||||||
target_update_period = 0.0;
|
target_update_period = 0.0;
|
||||||
}
|
}
|
||||||
|
@ -779,7 +806,7 @@ namespace OpenTK
|
||||||
{
|
{
|
||||||
target_update_period = value;
|
target_update_period = value;
|
||||||
}
|
}
|
||||||
else Debug.Print("Target update period clamped to 1.0 seconds."); // TODO: Where is it actually performed?
|
else Debug.Print("Target update period clamped to 1.0 seconds.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -94,7 +94,6 @@ namespace OpenTK.Platform.SDL2
|
||||||
[SuppressUnmanagedCodeSecurity]
|
[SuppressUnmanagedCodeSecurity]
|
||||||
[DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_CreateWindow", ExactSpelling = true)]
|
[DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_CreateWindow", ExactSpelling = true)]
|
||||||
public static extern IntPtr CreateWindow(string title, int x, int y, int w, int h, WindowFlags flags);
|
public static extern IntPtr CreateWindow(string title, int x, int y, int w, int h, WindowFlags flags);
|
||||||
//public static extern IntPtr SDL_CreateWindow(string title, int x, int y, int w, int h, WindowFlags flags);
|
|
||||||
|
|
||||||
[SuppressUnmanagedCodeSecurity]
|
[SuppressUnmanagedCodeSecurity]
|
||||||
[DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_CreateWindowFrom", ExactSpelling = true)]
|
[DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_CreateWindowFrom", ExactSpelling = true)]
|
||||||
|
@ -420,6 +419,34 @@ namespace OpenTK.Platform.SDL2
|
||||||
[DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_WarpMouseInWindow", ExactSpelling = true)]
|
[DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_WarpMouseInWindow", ExactSpelling = true)]
|
||||||
public static extern void WarpMouseInWindow(IntPtr window, int x, int y);
|
public static extern void WarpMouseInWindow(IntPtr window, int x, int y);
|
||||||
|
|
||||||
|
#region SysWM
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves driver-dependent window information.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="window">
|
||||||
|
/// The window about which information is being requested.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="info">
|
||||||
|
/// Returns driver-dependent information about the specified window.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>
|
||||||
|
/// True, if the function is implemented and the version number of the info struct is valid;
|
||||||
|
/// false, otherwise.
|
||||||
|
/// </returns>
|
||||||
|
public static bool GetWindowWMInfo(IntPtr window, out SysWMInfo info)
|
||||||
|
{
|
||||||
|
info = new SysWMInfo();
|
||||||
|
info.Version = GetVersion();
|
||||||
|
return GetWindowWMInfoInternal(window, ref info);
|
||||||
|
}
|
||||||
|
|
||||||
|
[SuppressUnmanagedCodeSecurity]
|
||||||
|
[DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GetWindowWMInfo", ExactSpelling = true)]
|
||||||
|
static extern bool GetWindowWMInfoInternal(IntPtr window, ref SysWMInfo info);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
public partial class GL
|
public partial class GL
|
||||||
{
|
{
|
||||||
[SuppressUnmanagedCodeSecurity]
|
[SuppressUnmanagedCodeSecurity]
|
||||||
|
@ -1200,6 +1227,17 @@ namespace OpenTK.Platform.SDL2
|
||||||
JOYSTICK | HAPTIC | GAMECONTROLLER
|
JOYSTICK | HAPTIC | GAMECONTROLLER
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum SysWMType
|
||||||
|
{
|
||||||
|
Unknown = 0,
|
||||||
|
Windows,
|
||||||
|
X11,
|
||||||
|
Wayland,
|
||||||
|
DirectFB,
|
||||||
|
Cocoa,
|
||||||
|
UIKit,
|
||||||
|
}
|
||||||
|
|
||||||
enum WindowEventID : byte
|
enum WindowEventID : byte
|
||||||
{
|
{
|
||||||
NONE,
|
NONE,
|
||||||
|
@ -1517,6 +1555,65 @@ namespace OpenTK.Platform.SDL2
|
||||||
public int Height;
|
public int Height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct SysWMInfo
|
||||||
|
{
|
||||||
|
public Version Version;
|
||||||
|
public SysWMType Subsystem;
|
||||||
|
public SysInfo Info;
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
|
public struct SysInfo
|
||||||
|
{
|
||||||
|
[FieldOffset(0)]
|
||||||
|
public WindowsInfo Windows;
|
||||||
|
[FieldOffset(0)]
|
||||||
|
public X11Info X11;
|
||||||
|
[FieldOffset(0)]
|
||||||
|
public WaylandInfo Wayland;
|
||||||
|
[FieldOffset(0)]
|
||||||
|
public DirectFBInfo DirectFB;
|
||||||
|
[FieldOffset(0)]
|
||||||
|
public CocoaInfo Cocoa;
|
||||||
|
[FieldOffset(0)]
|
||||||
|
public UIKitInfo UIKit;
|
||||||
|
|
||||||
|
public struct WindowsInfo
|
||||||
|
{
|
||||||
|
public IntPtr Window;
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct X11Info
|
||||||
|
{
|
||||||
|
public IntPtr Display;
|
||||||
|
public IntPtr Window;
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct WaylandInfo
|
||||||
|
{
|
||||||
|
public IntPtr Display;
|
||||||
|
public IntPtr Surface;
|
||||||
|
public IntPtr ShellSurface;
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct DirectFBInfo
|
||||||
|
{
|
||||||
|
public IntPtr Dfb;
|
||||||
|
public IntPtr Window;
|
||||||
|
public IntPtr Surface;
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct CocoaInfo
|
||||||
|
{
|
||||||
|
public IntPtr Window;
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct UIKitInfo
|
||||||
|
{
|
||||||
|
public IntPtr Window;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct TextEditingEvent
|
struct TextEditingEvent
|
||||||
{
|
{
|
||||||
public const int TextSize = 32;
|
public const int TextSize = 32;
|
||||||
|
|
|
@ -157,6 +157,8 @@ namespace OpenTK.Platform.SDL2
|
||||||
int major, int minor,
|
int major, int minor,
|
||||||
GraphicsContextFlags flags)
|
GraphicsContextFlags flags)
|
||||||
{
|
{
|
||||||
|
ContextProfileFlags cpflags = 0;
|
||||||
|
|
||||||
if (mode.AccumulatorFormat.BitsPerPixel > 0)
|
if (mode.AccumulatorFormat.BitsPerPixel > 0)
|
||||||
{
|
{
|
||||||
SDL.GL.SetAttribute(ContextAttribute.ACCUM_ALPHA_SIZE, mode.AccumulatorFormat.Alpha);
|
SDL.GL.SetAttribute(ContextAttribute.ACCUM_ALPHA_SIZE, mode.AccumulatorFormat.Alpha);
|
||||||
|
@ -203,6 +205,15 @@ namespace OpenTK.Platform.SDL2
|
||||||
{
|
{
|
||||||
SDL.GL.SetAttribute(ContextAttribute.CONTEXT_MAJOR_VERSION, major);
|
SDL.GL.SetAttribute(ContextAttribute.CONTEXT_MAJOR_VERSION, major);
|
||||||
SDL.GL.SetAttribute(ContextAttribute.CONTEXT_MINOR_VERSION, minor);
|
SDL.GL.SetAttribute(ContextAttribute.CONTEXT_MINOR_VERSION, minor);
|
||||||
|
|
||||||
|
// Workaround for https://github.com/opentk/opentk/issues/44
|
||||||
|
// Mac OS X desktop OpenGL 3.x/4.x contexts require require
|
||||||
|
// ContextProfileFlags.Core, otherwise they will fail to construct.
|
||||||
|
if (Configuration.RunningOnMacOS && major >= 3 &&
|
||||||
|
(flags & GraphicsContextFlags.Embedded) == 0)
|
||||||
|
{
|
||||||
|
cpflags |= ContextProfileFlags.CORE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((flags & GraphicsContextFlags.Debug) != 0)
|
if ((flags & GraphicsContextFlags.Debug) != 0)
|
||||||
|
@ -223,7 +234,6 @@ namespace OpenTK.Platform.SDL2
|
||||||
*/
|
*/
|
||||||
|
|
||||||
{
|
{
|
||||||
ContextProfileFlags cpflags = 0;
|
|
||||||
if ((flags & GraphicsContextFlags.Embedded) != 0)
|
if ((flags & GraphicsContextFlags.Embedded) != 0)
|
||||||
{
|
{
|
||||||
cpflags |= ContextProfileFlags.ES;
|
cpflags |= ContextProfileFlags.ES;
|
||||||
|
|
|
@ -301,7 +301,7 @@ namespace OpenTK.Platform
|
||||||
public static IWindowInfo CreateSdl2WindowInfo(IntPtr windowHandle)
|
public static IWindowInfo CreateSdl2WindowInfo(IntPtr windowHandle)
|
||||||
{
|
{
|
||||||
return new OpenTK.Platform.SDL2.Sdl2WindowInfo(
|
return new OpenTK.Platform.SDL2.Sdl2WindowInfo(
|
||||||
SDL2.SDL.CreateWindowFrom(windowHandle), null);
|
windowHandle, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
|
@ -34,6 +35,9 @@ namespace OpenTK.Platform.Windows
|
||||||
|
|
||||||
internal const string Library = "OPENGL32.DLL";
|
internal const string Library = "OPENGL32.DLL";
|
||||||
|
|
||||||
|
readonly static Dictionary<string, bool> extensions =
|
||||||
|
new Dictionary<string, bool>();
|
||||||
|
|
||||||
private static Assembly assembly;
|
private static Assembly assembly;
|
||||||
private static Type wglClass;
|
private static Type wglClass;
|
||||||
private static Type delegatesClass;
|
private static Type delegatesClass;
|
||||||
|
@ -121,43 +125,61 @@ namespace OpenTK.Platform.Windows
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region public static partial class Arb
|
public static bool SupportsExtension(string name)
|
||||||
|
|
||||||
/// <summary>Contains ARB extensions for WGL.</summary>
|
|
||||||
public static partial class Arb
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
return SupportsExtension(Wgl.GetCurrentDC(), name);
|
||||||
/// Checks if a Wgl extension is supported by the given context.
|
}
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The device context.</param>
|
/// <summary>
|
||||||
/// <param name="ext">The extension to check.</param>
|
/// Checks if a Wgl extension is supported by the given context.
|
||||||
/// <returns>True if the extension is supported by the given context, false otherwise</returns>
|
/// </summary>
|
||||||
public static bool SupportsExtension(WinGLContext context, string ext)
|
/// <param name="context">The device context.</param>
|
||||||
|
/// <param name="ext">The extension to check.</param>
|
||||||
|
/// <returns>True if the extension is supported by the given context, false otherwise</returns>
|
||||||
|
public static bool SupportsExtension(IntPtr dc, string name)
|
||||||
|
{
|
||||||
|
if (extensions.Count == 0)
|
||||||
{
|
{
|
||||||
// We cache this locally, as another thread might create a context which doesn't support this method.
|
// We cache this locally, as another thread might create a context which doesn't support this method.
|
||||||
// The design is far from ideal, but there's no good solution to this issue as long as we are using
|
// The design is far from ideal, but there's no good solution to this issue as long as we are using
|
||||||
// static WGL/GL classes. Fortunately, this issue is extremely unlikely to arise in practice, as you'd
|
// static WGL/GL classes. Fortunately, this issue is extremely unlikely to arise in practice, as you'd
|
||||||
// have to create one accelerated and one non-accelerated context in the same application, with the
|
// have to create one accelerated and one non-accelerated context in the same application, with the
|
||||||
// non-accelerated context coming second.
|
// non-accelerated context coming second.
|
||||||
Wgl.Delegates.GetExtensionsStringARB get = Wgl.Delegates.wglGetExtensionsStringARB;
|
Wgl.Delegates.GetExtensionsStringARB get_arb = Wgl.Delegates.wglGetExtensionsStringARB;
|
||||||
|
Wgl.Delegates.GetExtensionsStringEXT get_ext = Wgl.Delegates.wglGetExtensionsStringEXT;
|
||||||
|
IntPtr str_ptr =
|
||||||
|
get_arb != null ? get_arb(dc) :
|
||||||
|
get_ext != null ? get_ext() :
|
||||||
|
IntPtr.Zero;
|
||||||
|
|
||||||
if (get != null)
|
if (str_ptr != IntPtr.Zero)
|
||||||
{
|
{
|
||||||
string[] extensions = null;
|
string str;
|
||||||
|
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
extensions = new string((sbyte*)get(context.DeviceContext))
|
str = new string((sbyte*)str_ptr);
|
||||||
.Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
|
|
||||||
}
|
}
|
||||||
if (extensions == null || extensions.Length == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
foreach (string s in extensions)
|
foreach (string ext in str.Split(' '))
|
||||||
if (s == ext)
|
{
|
||||||
return true;
|
extensions.Add(ext, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (extensions.Count > 0)
|
||||||
|
{
|
||||||
|
return extensions.ContainsKey(name);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region public static partial class Arb
|
||||||
|
|
||||||
|
/// <summary>Contains ARB extensions for WGL.</summary>
|
||||||
|
public static partial class Arb
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -167,27 +189,6 @@ namespace OpenTK.Platform.Windows
|
||||||
/// <summary>Contains EXT extensions for WGL.</summary>
|
/// <summary>Contains EXT extensions for WGL.</summary>
|
||||||
public static partial class Ext
|
public static partial class Ext
|
||||||
{
|
{
|
||||||
private static string[] extensions;
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if a Wgl extension is supported by the given context.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="ext">The extension to check.</param>
|
|
||||||
/// <returns>True if the extension is supported by the given context, false otherwise</returns>
|
|
||||||
public static bool SupportsExtension(string ext)
|
|
||||||
{
|
|
||||||
if (Wgl.Delegates.wglGetExtensionsStringEXT != null)
|
|
||||||
{
|
|
||||||
if (extensions == null || rebuildExtensionList)
|
|
||||||
{
|
|
||||||
extensions = Wgl.Ext.GetExtensionsString().Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
|
|
||||||
Array.Sort(extensions);
|
|
||||||
rebuildExtensionList = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Array.BinarySearch(extensions, ext) != -1;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
|
@ -31,6 +31,7 @@ namespace OpenTK.Platform.Windows
|
||||||
|
|
||||||
IntPtr device_context;
|
IntPtr device_context;
|
||||||
bool vsync_supported;
|
bool vsync_supported;
|
||||||
|
bool vsync_tear_supported;
|
||||||
|
|
||||||
readonly WinGraphicsMode ModeSelector;
|
readonly WinGraphicsMode ModeSelector;
|
||||||
|
|
||||||
|
@ -325,7 +326,13 @@ namespace OpenTK.Platform.Windows
|
||||||
lock (LoadLock)
|
lock (LoadLock)
|
||||||
{
|
{
|
||||||
if (vsync_supported)
|
if (vsync_supported)
|
||||||
|
{
|
||||||
|
if (value < 0 && !vsync_tear_supported)
|
||||||
|
{
|
||||||
|
value = 1;
|
||||||
|
}
|
||||||
Wgl.Ext.SwapInterval(value);
|
Wgl.Ext.SwapInterval(value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -339,8 +346,11 @@ namespace OpenTK.Platform.Windows
|
||||||
lock (LoadLock)
|
lock (LoadLock)
|
||||||
{
|
{
|
||||||
Wgl.LoadAll();
|
Wgl.LoadAll();
|
||||||
vsync_supported = Wgl.Arb.SupportsExtension(this, "WGL_EXT_swap_control") &&
|
vsync_supported =
|
||||||
|
Wgl.SupportsExtension(DeviceContext, "WGL_EXT_swap_control") &&
|
||||||
Wgl.Load("wglGetSwapIntervalEXT") && Wgl.Load("wglSwapIntervalEXT");
|
Wgl.Load("wglGetSwapIntervalEXT") && Wgl.Load("wglSwapIntervalEXT");
|
||||||
|
vsync_tear_supported =
|
||||||
|
Wgl.SupportsExtension(DeviceContext, "WGL_EXT_swap_tear");
|
||||||
}
|
}
|
||||||
|
|
||||||
base.LoadAll();
|
base.LoadAll();
|
||||||
|
|
|
@ -99,7 +99,8 @@ namespace OpenTK.Platform.Windows
|
||||||
GraphicsMode ChoosePixelFormatARB(IntPtr device, GraphicsMode mode)
|
GraphicsMode ChoosePixelFormatARB(IntPtr device, GraphicsMode mode)
|
||||||
{
|
{
|
||||||
GraphicsMode created_mode = null;
|
GraphicsMode created_mode = null;
|
||||||
if (Wgl.Delegates.wglChoosePixelFormatARB != null)
|
if (Wgl.SupportsExtension("WGL_ARB_pixel_format") &&
|
||||||
|
Wgl.Delegates.wglChoosePixelFormatARB != null)
|
||||||
{
|
{
|
||||||
List<int> attributes = new List<int>();
|
List<int> attributes = new List<int>();
|
||||||
attributes.Add((int)WGL_ARB_pixel_format.AccelerationArb);
|
attributes.Add((int)WGL_ARB_pixel_format.AccelerationArb);
|
||||||
|
@ -168,7 +169,8 @@ namespace OpenTK.Platform.Windows
|
||||||
attributes.Add(mode.AccumulatorFormat.Alpha);
|
attributes.Add(mode.AccumulatorFormat.Alpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode.Samples > 0)
|
if (mode.Samples > 0 &&
|
||||||
|
Wgl.SupportsExtension("WGL_ARB_multisample"))
|
||||||
{
|
{
|
||||||
attributes.Add((int)WGL_ARB_multisample.SampleBuffersArb);
|
attributes.Add((int)WGL_ARB_multisample.SampleBuffersArb);
|
||||||
attributes.Add(1);
|
attributes.Add(1);
|
||||||
|
@ -193,7 +195,8 @@ namespace OpenTK.Platform.Windows
|
||||||
|
|
||||||
int[] format = new int[1];
|
int[] format = new int[1];
|
||||||
int count;
|
int count;
|
||||||
if (Wgl.Arb.ChoosePixelFormat(device, attributes.ToArray(), null, format.Length, format, out count))
|
if (Wgl.Arb.ChoosePixelFormat(device, attributes.ToArray(), null, format.Length, format, out count)
|
||||||
|
&& count > 0)
|
||||||
{
|
{
|
||||||
created_mode = DescribePixelFormatARB(device, format[0]);
|
created_mode = DescribePixelFormatARB(device, format[0]);
|
||||||
}
|
}
|
||||||
|
@ -271,13 +274,6 @@ namespace OpenTK.Platform.Windows
|
||||||
{
|
{
|
||||||
flags |= PixelFormatDescriptorFlags.STEREO;
|
flags |= PixelFormatDescriptorFlags.STEREO;
|
||||||
}
|
}
|
||||||
if (mode.Buffers > 1)
|
|
||||||
{
|
|
||||||
// On Win7 64bit + Nvidia 650M, no pixel format advertises DOUBLEBUFFER.
|
|
||||||
// Adding this check here causes mode selection to fail.
|
|
||||||
// Does not appear to be supported by DescribePixelFormat
|
|
||||||
//flags |= PixelFormatDescriptorFlags.DOUBLEBUFFER;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (System.Environment.OSVersion.Version.Major >= 6 &&
|
if (System.Environment.OSVersion.Version.Major >= 6 &&
|
||||||
requested_acceleration_type != AccelerationType.None)
|
requested_acceleration_type != AccelerationType.None)
|
||||||
|
@ -304,6 +300,9 @@ namespace OpenTK.Platform.Windows
|
||||||
valid &= GetAccelerationType(ref pfd) == requested_acceleration_type;
|
valid &= GetAccelerationType(ref pfd) == requested_acceleration_type;
|
||||||
valid &= (pfd.Flags & flags) == flags;
|
valid &= (pfd.Flags & flags) == flags;
|
||||||
valid &= pfd.PixelType == PixelType.RGBA; // indexed modes not currently supported
|
valid &= pfd.PixelType == PixelType.RGBA; // indexed modes not currently supported
|
||||||
|
// heavily penalize single-buffered modes when the user requests double buffering
|
||||||
|
if ((pfd.Flags & PixelFormatDescriptorFlags.DOUBLEBUFFER) == 0 && mode.Buffers > 1)
|
||||||
|
dist += 1000;
|
||||||
valid &= Compare(pfd.ColorBits, mode.ColorFormat.BitsPerPixel, ref dist);
|
valid &= Compare(pfd.ColorBits, mode.ColorFormat.BitsPerPixel, ref dist);
|
||||||
valid &= Compare(pfd.RedBits, mode.ColorFormat.Red, ref dist);
|
valid &= Compare(pfd.RedBits, mode.ColorFormat.Red, ref dist);
|
||||||
valid &= Compare(pfd.GreenBits, mode.ColorFormat.Green, ref dist);
|
valid &= Compare(pfd.GreenBits, mode.ColorFormat.Green, ref dist);
|
||||||
|
|
Loading…
Reference in a new issue