update to opentk4

This commit is contained in:
emmaus 2020-09-07 18:10:41 +00:00
parent e59894411d
commit d573036187
5 changed files with 358 additions and 160 deletions

View file

@ -41,22 +41,118 @@ using OpenTK.Graphics.OpenGL;
using Gtk;
using Cairo;
using GLib;
using Gdk;
using OpenGL;
using System.Diagnostics;
using OpenTK.Mathematics;
namespace OpenTK
{
[ToolboxItem(true)]
public class GLWidget : DrawingArea
{
/// <summary>
/// Get or set the OpenGL minimum color buffer bits.
/// </summary>
[Property("color-bits")]
public uint ColorBits
{
get { return (_ColorBits); }
set { _ColorBits = value; }
}
/// <summary>
/// The OpenGL color buffer bits.
/// </summary>
private uint _ColorBits = 24;
/// <summary>
/// Get or set the OpenGL minimum depth buffer bits.
/// </summary>
[Property("depth-bits")]
public uint DepthBits
{
get { return (_DepthBits); }
set { _DepthBits = value; }
}
/// <summary>
/// The OpenGL color buffer bits.
/// </summary>
private uint _DepthBits;
/// <summary>
/// Get or set the OpenGL minimum stencil buffer bits.
/// </summary>
[Property("stencil-bits")]
public uint StencilBits
{
get { return (_StencilBits); }
set { _StencilBits = value; }
}
/// <summary>
/// The OpenGL color buffer bits.
/// </summary>
private uint _StencilBits;
/// <summary>
/// Get or set the OpenGL minimum multisample buffer "bits".
/// </summary>
[Property("multisample-bits")]
public uint MultisampleBits
{
get { return (_MultisampleBits); }
set { _MultisampleBits = value; }
}
/// <summary>
/// The OpenGL multisample buffer bits.
/// </summary>
private uint _MultisampleBits;
/// <summary>
/// Get or set the OpenGL swap buffers interval.
/// </summary>
[Property("swap-interval")]
public int SwapInterval
{
get { return (_SwapInterval); }
set { _SwapInterval = value; }
}
/// <summary>
/// The OpenGL swap buffers interval.
/// </summary>
private int _SwapInterval = 1;
/// <summary>
/// The <see cref="DevicePixelFormat"/> describing the minimum pixel format required by this control.
/// </summary>
private DevicePixelFormat ControlPixelFormat
{
get
{
DevicePixelFormat controlReqFormat = new DevicePixelFormat();
controlReqFormat.RgbaUnsigned = true;
controlReqFormat.RenderWindow = true;
controlReqFormat.ColorBits = (int)ColorBits;
controlReqFormat.DepthBits = (int)DepthBits;
controlReqFormat.StencilBits = (int)StencilBits;
controlReqFormat.MultisampleBits = (int)MultisampleBits;
controlReqFormat.DoubleBuffer = true;
return (controlReqFormat);
}
}
#region Static attrs.
private static int _graphicsContextCount;
private static bool _sharedContextInitialized;
public bool HandleRendering { get; set; } = false;
public IGraphicsContext NativeGraphicsContext { get; private set; }
#endregion
#region Attributes
@ -73,13 +169,14 @@ namespace OpenTK
/// <summary>The minor version of OpenGL to use.</summary>
public int GLVersionMinor { get; set; }
private int _framebuffer;
private int _renderbuffer;
private int _stencilbuffer;
private bool _recreateFramebuffer;
private DeviceContext _deviceContext;
private IntPtr _graphicsContext;
private int _error;
private IGraphicsContext _context;
public Gdk.GLContext GraphicsContext { get; set; }
public bool ForwardCompatible { get; }
public DeviceContext DeviceContext { get => _deviceContext; set => _deviceContext = value; }
#endregion
@ -88,7 +185,9 @@ namespace OpenTK
/// <summary>Constructs a new GLWidget</summary>
public GLWidget() : this(new Version(4, 0), true)
{
/*this.ColorBits = 32;
this.DepthBits = 24;
this.StencilBits = 8;*/
}
/// <summary>Constructs a new GLWidget</summary>
@ -110,7 +209,9 @@ namespace OpenTK
{
OnShuttingDown();
GraphicsContext.Dispose();
DeviceContext.DeleteContext(_graphicsContext);
DeviceContext.Dispose();
}
}
@ -121,25 +222,9 @@ namespace OpenTK
// Called when the first GraphicsContext is created in the case of GraphicsContext.ShareContexts == True;
public static event EventHandler GraphicsContextInitialized;
private static void OnGraphicsContextInitialized()
{
if (GraphicsContextInitialized != null)
{
GraphicsContextInitialized(null, EventArgs.Empty);
}
}
// Called when the first GraphicsContext is being destroyed in the case of GraphicsContext.ShareContexts == True;
public static event EventHandler GraphicsContextShuttingDown;
private static void OnGraphicsContextShuttingDown()
{
if (GraphicsContextShuttingDown != null)
{
GraphicsContextShuttingDown(null, EventArgs.Empty);
}
}
// Called when this GLWidget has a valid GraphicsContext
public event EventHandler Initialized;
@ -177,140 +262,177 @@ namespace OpenTK
protected override bool OnDrawn(Cairo.Context cr)
{
if (!_initialized)
System.Threading.Tasks.Task.Run(Initialize).Wait();
Initialize();
if (HandleRendering)
{
MakeCurrent();
ClearCurrent();
OnRenderFrame();
}
/*cr.SetSourceColor(new Color(0, 0, 0, 1));
cr.Paint();
var scale = this.ScaleFactor;
Gdk.CairoHelper.DrawFromGl(cr, this.Window, _renderbuffer, (int)ObjectLabelIdentifier.Renderbuffer, scale, 0, 0, AllocatedWidth, AllocatedHeight);
*/
return true;
}
public void Swapbuffers()
{
GL.Flush();
//QueueDraw();
OpenTK.GraphicsContext.GetCurrentContext(Window.Handle).SwapBuffers();
//RecreateFramebuffer();
if (!HandleRendering)
{
ClearCurrent();
}
DeviceContext?.SwapBuffers();
}
public void MakeCurrent()
{
ClearCurrent();
NativeGraphicsContext?.MakeCurrent();
GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
_context?.MakeCurrent();
_error = Marshal.GetLastWin32Error();
}
public void ClearCurrent()
{
Gdk.GLContext.ClearCurrent();
//Gdk.GLContext.ClearCurrent();
DeviceContext?.MakeCurrent(IntPtr.Zero);
}
// Called on Resize
protected override bool OnConfigureEvent(Gdk.EventConfigure evnt)
private void CreateContext()
{
if (GraphicsContext != null)
if (_graphicsContext != IntPtr.Zero)
throw new InvalidOperationException("context already created");
IntPtr sharingContext = IntPtr.Zero;
if (Gl.PlatformExtensions.CreateContext_ARB)
{
_recreateFramebuffer = true;
List<int> attributes = new List<int>();
uint contextProfile = 0, contextFlags = 0;
bool debuggerAttached = Debugger.IsAttached;
#region WGL_ARB_create_context|GLX_ARB_create_context
#endregion
#region WGL_ARB_create_context_profile|GLX_ARB_create_context_profile
if (Gl.PlatformExtensions.CreateContextProfile_ARB)
{
}
return true;
#endregion
#region WGL_ARB_create_context_robustness|GLX_ARB_create_context_robustness
if (Gl.PlatformExtensions.CreateContextRobustness_ARB)
{
}
public void RecreateFramebuffer()
{
if (!_recreateFramebuffer)
{
return;
#endregion
Debug.Assert(Wgl.CONTEXT_FLAGS_ARB == Glx.CONTEXT_FLAGS_ARB);
if (contextFlags != 0)
attributes.AddRange(new int[] { Wgl.CONTEXT_FLAGS_ARB, unchecked((int)contextFlags) });
Debug.Assert(Wgl.CONTEXT_PROFILE_MASK_ARB == Glx.CONTEXT_PROFILE_MASK_ARB);
Debug.Assert(contextProfile == 0 || Gl.PlatformExtensions.CreateContextProfile_ARB);
if (contextProfile != 0)
attributes.AddRange(new int[] { Wgl.CONTEXT_PROFILE_MASK_ARB, unchecked((int)contextProfile) });
attributes.Add(0);
if ((_graphicsContext = _deviceContext.CreateContextAttrib(sharingContext, attributes.ToArray())) == IntPtr.Zero)
throw new InvalidOperationException(String.Format("unable to create render context ({0})", Gl.GetError()));
}
_recreateFramebuffer = false;
GraphicsContext.Window.Resize(AllocatedWidth, AllocatedHeight);
DeleteBuffers();
CreateFramebuffer();
}
private void DeleteBuffers()
else
{
if (_framebuffer != 0)
{
GL.DeleteFramebuffer(_framebuffer);
GL.DeleteRenderbuffer(_renderbuffer);
// Create OpenGL context using compatibility profile
if ((_graphicsContext = _deviceContext.CreateContext(sharingContext)) == IntPtr.Zero)
throw new InvalidOperationException("unable to create render context");
}
}
private void CreateFramebuffer()
private void CreateDeviceContext(DevicePixelFormat controlReqFormat)
{
_framebuffer = GL.GenFramebuffer();
GL.BindFramebuffer(FramebufferTarget.Framebuffer, _framebuffer);
#region Create device context
_renderbuffer = GL.GenRenderbuffer();
GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, _renderbuffer);
GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer, RenderbufferStorage.Rgba8, AllocatedWidth, AllocatedHeight);
DeviceContext = DeviceContext.Create(GTKBindingHelper.GetDisplayHandle(Display.Handle), GTKBindingHelper.GetWindowHandle(Window.Handle));
DeviceContext.IncRef();
GL.FramebufferRenderbuffer(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, RenderbufferTarget.Renderbuffer, _renderbuffer);
#endregion
_stencilbuffer = GL.GenRenderbuffer();
GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, _stencilbuffer);
GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer, RenderbufferStorage.Depth24Stencil8, AllocatedWidth, AllocatedHeight);
#region Set pixel format
GL.FramebufferRenderbuffer(FramebufferTarget.Framebuffer, FramebufferAttachment.DepthStencilAttachment, RenderbufferTarget.Renderbuffer, _stencilbuffer);
DevicePixelFormatCollection pixelFormats = DeviceContext.PixelsFormats;
List<DevicePixelFormat> matchingPixelFormats = pixelFormats.Choose(controlReqFormat);
GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, 0);
var state = GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer);
if ((matchingPixelFormats.Count == 0) && controlReqFormat.MultisampleBits > 0)
{
// Try to select the maximum multisample configuration
int multisampleBits = 0;
pixelFormats.ForEach(delegate (DevicePixelFormat item) { multisampleBits = Math.Max(multisampleBits, item.MultisampleBits); });
controlReqFormat.MultisampleBits = multisampleBits;
matchingPixelFormats = pixelFormats.Choose(controlReqFormat);
}
if ((matchingPixelFormats.Count == 0) && controlReqFormat.DoubleBuffer)
{
// Try single buffered pixel formats
controlReqFormat.DoubleBuffer = false;
matchingPixelFormats = pixelFormats.Choose(controlReqFormat);
if (matchingPixelFormats.Count == 0)
throw new InvalidOperationException(String.Format("unable to find a suitable pixel format: {0}", pixelFormats.GuessChooseError(controlReqFormat)));
}
else if (matchingPixelFormats.Count == 0)
throw new InvalidOperationException(String.Format("unable to find a suitable pixel format: {0}", pixelFormats.GuessChooseError(controlReqFormat)));
DeviceContext.SetPixelFormat(matchingPixelFormats[0]);
#endregion
#region Set V-Sync
if (Gl.PlatformExtensions.SwapControl)
{
int swapInterval = SwapInterval;
// Mask value in case it is not supported
if (!Gl.PlatformExtensions.SwapControlTear && swapInterval == -1)
swapInterval = 1;
DeviceContext.SwapInterval(swapInterval);
}
#endregion
}
private void Initialize()
{
_initialized = true;
ClearCurrent();
GraphicsContext = Window.CreateGlContext();
Khronos.KhronosApi.LogEnabled = true;
Wgl.ErrorHandling = Wgl.ErrorHandlingMode.Normal;
GraphicsContext.SetRequiredVersion(GLVersionMajor, GLVersionMinor);
Window.EnsureNative();
GraphicsContext.SetUseEs(0);
CreateDeviceContext(ControlPixelFormat);
GraphicsContext.ForwardCompatible = ForwardCompatible;
CreateContext();
GraphicsContext.Realize();
DeviceContext.MakeCurrent(_graphicsContext);
GraphicsContext.MakeCurrent();
_context = GraphicsContext.GetCurrentContext(Window.Handle);
MakeCurrent();
if (!GTKBindingHelper.Loaded)
{
GTKBindingHelper.InitializeGlBindings();
}
OpenTK.GraphicsContext.Display = this.Display.Handle;
NativeGraphicsContext = OpenTK.GraphicsContext.GetCurrentContext(this.Window.Handle);
// CreateFramebuffer();
OnInitialized();
OpenTK.GraphicsContext.GetCurrentContext(Window.Handle).SwapInterval(1);
ClearCurrent();
_initialized = true;
}
}
}

View file

@ -1,13 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<TargetFramework>netcoreapp3.0</TargetFramework>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Description>GLWigdet for GTKSharp, using Opentk.</Description>
<Version>1.0.1</Version>
<Version>1.0.3-pre1</Version>
<RepositoryUrl>https://github.com/Ryujinx/GLWidget</RepositoryUrl>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="GtkSharp" Version="3.22.25.56" />
<PackageReference Include="OpenGL.Net" Version="0.8.4" />
<PackageReference Include="OpenTK.Graphics" Version="4.0.0-pre9.4" />
<PackageReference Include="OpenTK.Windowing.Common" Version="4.0.0-pre9.4" />
</ItemGroup>

View file

@ -147,6 +147,30 @@ namespace OpenTK
Loaded = true;
}
public static IntPtr GetWindowHandle(IntPtr handle)
{
if(CurrentPlatform == OSPlatform.Windows)
{
return UnsafeNativeMethods.gdk_win32_window_get_handle(handle);
}
else
{
return UnsafeNativeMethods.gdk_x11_window_get_xid(handle);
}
}
public static IntPtr GetDisplayHandle(IntPtr handle)
{
if (CurrentPlatform == OSPlatform.Windows)
{
return IntPtr.Zero;
}
else
{
return UnsafeNativeMethods.gdk_x11_display_get_xdisplay(handle);
}
}
internal static IntPtr GetLibraryHandle(string libraryPath, bool throws)
{
IntPtr libraryHandle;
@ -191,9 +215,6 @@ namespace OpenTK
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern IntPtr GetProcAddress(IntPtr handle, string funcname);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern IntPtr GetProcAddress(IntPtr handle, IntPtr funcname);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern IntPtr LoadLibrary(string dllName);
@ -224,6 +245,12 @@ namespace OpenTK
[DllImport(GlxLibrary, EntryPoint = "glXGetCurrentContext")]
public static extern IntPtr glXGetCurrentContext();
[DllImport(GlxLibrary, EntryPoint = "glXGetProcAddress")]
public static extern IntPtr glXGetProcAddress();
[DllImport(GlxLibrary, EntryPoint = "glXSwapIntervalEXT")]
public static extern IntPtr glXSwapIntervalEXT(int interval);
[DllImport(GlxLibrary, EntryPoint = "glXMakeCurrent")]
public static extern bool glXMakeCurrent(IntPtr display, IntPtr drawable, IntPtr context);
@ -246,22 +273,13 @@ namespace OpenTK
public const string GdkNativeDll = "libgdk-3-0.dll";
[DllImport(GdkNativeDll, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr gdk_win32_drawable_get_handle(IntPtr raw);
[DllImport(GdkNativeDll, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr gdk_win32_hdc_get(IntPtr drawable, IntPtr gc, int usage);
[DllImport(GdkNativeDll, CallingConvention = CallingConvention.Cdecl)]
public static extern void gdk_win32_hdc_release(IntPtr drawable, IntPtr gc, int usage);
public static extern IntPtr gdk_win32_window_get_handle(IntPtr raw);
[DllImport("libgdk-3.so.0", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr gdk_x11_display_get_xdisplay(IntPtr raw);
[DllImport("libgdk-3.so.0", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr gdk_x11_window_get_xid(IntPtr raw);
[DllImport(GdkNativeDll, CallingConvention = CallingConvention.Cdecl)]
public static extern void gdk_window_get_internal_paint_info(IntPtr raw, out IntPtr real_drawable, out int x, out int y);
}
private static class Delegates

View file

@ -1,5 +1,7 @@
using System;
using System.Runtime.InteropServices;
using OpenGL;
using static OpenTK.GTKBindingHelper;
namespace OpenTK
@ -8,8 +10,8 @@ namespace OpenTK
{
void MakeCurrent();
void SwapBuffers();
void ClearCurrent();
void SwapInterval(int interval);
}
public abstract class GraphicsContext : IGraphicsContext
@ -20,6 +22,24 @@ namespace OpenTK
public abstract void SwapBuffers();
public static void InitializeDefaults(IntPtr handle)
{
if (CurrentPlatform == OSPlatform.Windows)
{
IntPtr deviceContext = Wgl.GetDC(UnsafeNativeMethods.gdk_win32_window_get_handle(handle));
Wgl.PIXELFORMATDESCRIPTOR pfd = new Wgl.PIXELFORMATDESCRIPTOR(24);
pfd.dwFlags |= Wgl.PixelFormatDescriptorFlags.DepthDontCare | Wgl.PixelFormatDescriptorFlags.DoublebufferDontCare | Wgl.PixelFormatDescriptorFlags.StereoDontCare;
int pFormat = Wgl.ChoosePixelFormat(deviceContext, ref pfd);
bool res = Wgl.DescribePixelFormat(deviceContext, pFormat, (uint)pfd.nSize, ref pfd) != 0;
res = Wgl.SetPixelFormat(deviceContext, pFormat, ref pfd);
}
}
public static IGraphicsContext GetCurrentContext(IntPtr handle)
{
var currentPlatform = CurrentPlatform;
@ -39,10 +59,14 @@ namespace OpenTK
}
public abstract void ClearCurrent();
public abstract void SwapInterval(int interval);
}
public class WglGraphicsContext : GraphicsContext
{
private delegate int wglSwapIntervalExtDelegate(int interval);
private static wglSwapIntervalExtDelegate wglSwapIntervalExt = null;
private IntPtr _windowHandle;
private IntPtr _deviceContext;
@ -51,6 +75,14 @@ namespace OpenTK
_deviceContext = deviceContext;
_graphicsContext = graphicsContext;
_windowHandle = windowHandle;
IntPtr swapIntervalPointer = UnsafeNativeMethods.wglGetProcAddress("wglSwapIntervalEXT");
if(swapIntervalPointer != null && swapIntervalPointer != IntPtr.Zero)
{
wglSwapIntervalExt = (wglSwapIntervalExtDelegate)Marshal.GetDelegateForFunctionPointer(
swapIntervalPointer, typeof(wglSwapIntervalExtDelegate));
}
}
private IntPtr _graphicsContext;
@ -75,7 +107,12 @@ namespace OpenTK
public override void ClearCurrent()
{
throw new NotImplementedException();
UnsafeNativeMethods.WglMakeCurrent(_deviceContext, IntPtr.Zero);
}
public override void SwapInterval(int interval)
{
wglSwapIntervalExt?.Invoke(interval);
}
}
@ -83,8 +120,6 @@ namespace OpenTK
{
private IntPtr _windowHandle;
private IntPtr _drawable;
public static GlxGraphicsContext GetCurrent(IntPtr windowHandle, IntPtr display)
{
var gc = UnsafeNativeMethods.glXGetCurrentContext();
@ -116,5 +151,10 @@ namespace OpenTK
{
UnsafeNativeMethods.glXMakeCurrent(_display, _windowHandle, IntPtr.Zero);
}
public override void SwapInterval(int interval)
{
UnsafeNativeMethods.glXSwapIntervalEXT(interval);
}
}
}

View file

@ -342,7 +342,10 @@ namespace GLWidgetTestGTK3
// Add idle event handler to process rendering whenever and as long as time is available.
GLInit = true;
GLib.Idle.Add(OnIdleProcessMain);
//GLib.Idle.Add(OnIdleProcessMain);
System.Threading.Thread thread = new System.Threading.Thread(Start);
thread.Start();
}
protected void RenderFrame()
@ -449,6 +452,20 @@ namespace GLWidgetTestGTK3
//swap
MainGLWidget.Swapbuffers();
MainGLWidget.ClearCurrent();
}
public void Start()
{
System.Threading.Thread.Sleep(1000);
while (true)
{
RenderFrame();
System.Threading.Thread.Sleep(5);
}
}
protected bool OnIdleProcessMain()
@ -461,9 +478,9 @@ namespace GLWidgetTestGTK3
Stopwatch deltaTimeWatcher = new Stopwatch();
deltaTimeWatcher.Start();
System.Threading.Tasks.Task.Run(RenderFrame).Wait();
//System.Threading.Tasks.Task.Run(RenderFrame).Wait();
//RenderFrame();
RenderFrame();
// End delta time calculation
deltaTimeWatcher.Stop();