Skip to content

Add WPF control #441

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
Dustray opened this issue Mar 28, 2021 · 7 comments
Open

Add WPF control #441

Dustray opened this issue Mar 28, 2021 · 7 comments
Labels
area-Windowing enhancement New feature or request
Milestone

Comments

@Dustray
Copy link

Dustray commented Mar 28, 2021

Summary of feature

I want to put it into a WPF application to run.

@Dustray Dustray added the enhancement New feature or request label Mar 28, 2021
@Perksey Perksey added this to the Future milestone May 1, 2021
@hjred
Copy link
Contributor

hjred commented May 5, 2021

For OpenGL rendering something similar to this https://github.com/opentk/GLWpfControl could be used.
This uses the NV_DX_interop OpenGL extension to share buffers between DirectX (WPF side) and OpenGL. So OpenGL renders directly to a buffer that is then given to DirectX for displaying. Despite having NV in the name, the author hints that this is supported on Intel, AMD and Nvidia GPUs.
Something similar might be possible for Vulkan as well.

@HurricanKai
Copy link
Member

Vulkan has VK_KHR_external_memory_win32
I can see us providing a WPF control in the future, but we'd have to think about what the form factor would be (-> how does one interact with this? Do we provide multiple packages Silk.NET.Extensions.WPF.DX/GL/VK?)

@Dustray Dustray closed this as completed May 18, 2021
@Perksey Perksey reopened this May 18, 2021
@Perksey Perksey changed the title Can SILK be used as a control for WPF? Add WPF control May 18, 2021
@GeorgeS2019
Copy link

@Perksey WinUI 3 has been planned. WinUI 3 control supporting project reunion can be used as control in both WinForm and WPF.

@orosbogdan
Copy link

I am planning to write a 3D game with 2D UI based on WPF's support, this would greatly help.

@Perksey Perksey modified the milestones: Future, 3.0 Mar 21, 2022
@aguerrieri82
Copy link

aguerrieri82 commented Feb 19, 2024

If somebody is still interested, i made this control for WPF

using Silk.NET.OpenGL;
using Silk.NET.Core.Contexts;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Windows.Interop;


public class RenderHost : HwndHost, INativeContext
  {
      private HwndSource? _hwndSource;
      private GL? _gl;
      private readonly nint _hLib;
      private nint _glCtx;
      private nint _hdc;

      #region NATIVE

      [DllImport("Opengl32.dll")]
      static extern IntPtr wglCreateContext(IntPtr hdc);

      [DllImport("Opengl32.dll")]
      static extern IntPtr wglDeleteContext(IntPtr hglrc);

      [DllImport("Opengl32.dll", SetLastError = true)]
      static extern IntPtr wglChoosePixelFormatARB(IntPtr hdc);

      [DllImport("Opengl32.dll", SetLastError = true)]
      static extern IntPtr wglGetProcAddress([MarshalAs(UnmanagedType.LPStr)] string unnamedParam1);

      [DllImport("Opengl32.dll", SetLastError = true)]
      static extern bool wglMakeCurrent(IntPtr hdc, IntPtr hglrc);

      [DllImport("gdi32.dll", SetLastError = true)]
      static extern int ChoosePixelFormat(IntPtr hDC,
      [In, MarshalAs(UnmanagedType.LPStruct)] PIXELFORMATDESCRIPTOR ppfd);

      [DllImport("gdi32.dll", SetLastError = true)]
      static extern bool SetPixelFormat(IntPtr hDC, int iPixelFormat,
          [In, MarshalAs(UnmanagedType.LPStruct)] PIXELFORMATDESCRIPTOR ppfd);

      [DllImport("gdi32.dll")]
      static extern int SwapBuffers(IntPtr hDC);

      [DllImport("User32.dll")]
      static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);


      [DllImport("User32.dll")]
      static extern IntPtr GetDC(IntPtr hWnd);


      [DllImport("kernel32.dll")]
      static extern IntPtr GetProcAddress(IntPtr hModule, [MarshalAs(UnmanagedType.LPStr)] string procName);

      [DllImport("kernel32.dll")]
      static extern IntPtr LoadLibraryW([MarshalAs(UnmanagedType.LPWStr)] string lpLibFileName);

      [StructLayout(LayoutKind.Explicit)]
      class PIXELFORMATDESCRIPTOR
      {
          [FieldOffset(0)]
          public UInt16 nSize;
          [FieldOffset(2)]
          public UInt16 nVersion;
          [FieldOffset(4)]
          public UInt32 dwFlags;
          [FieldOffset(8)]
          public Byte iPixelType;
          [FieldOffset(9)]
          public Byte cColorBits;
          [FieldOffset(10)]
          public Byte cRedBits;
          [FieldOffset(11)]
          public Byte cRedShift;
          [FieldOffset(12)]
          public Byte cGreenBits;
          [FieldOffset(13)]
          public Byte cGreenShift;
          [FieldOffset(14)]
          public Byte cBlueBits;
          [FieldOffset(15)]
          public Byte cBlueShift;
          [FieldOffset(16)]
          public Byte cAlphaBits;
          [FieldOffset(17)]
          public Byte cAlphaShift;
          [FieldOffset(18)]
          public Byte cAccumBits;
          [FieldOffset(19)]
          public Byte cAccumRedBits;
          [FieldOffset(20)]
          public Byte cAccumGreenBits;
          [FieldOffset(21)]
          public Byte cAccumBlueBits;
          [FieldOffset(22)]
          public Byte cAccumAlphaBits;
          [FieldOffset(23)]
          public Byte cDepthBits;
          [FieldOffset(24)]
          public Byte cStencilBits;
          [FieldOffset(25)]
          public Byte cAuxBuffers;
          [FieldOffset(26)]
          public SByte iLayerType;
          [FieldOffset(27)]
          public Byte bReserved;
          [FieldOffset(28)]
          public UInt32 dwLayerMask;
          [FieldOffset(32)]
          public UInt32 dwVisibleMask;
          [FieldOffset(36)]
          public UInt32 dwDamageMask;
      }

      const byte PFD_TYPE_RGBA = 0;
      const byte PFD_TYPE_COLORINDEX = 1;

      const uint PFD_DOUBLEBUFFER = 1;
      const uint PFD_STEREO = 2;
      const uint PFD_DRAW_TO_WINDOW = 4;
      const uint PFD_DRAW_TO_BITMAP = 8;
      const uint PFD_SUPPORT_GDI = 16;
      const uint PFD_SUPPORT_OPENGL = 32;
      const uint PFD_GENERIC_FORMAT = 64;
      const uint PFD_NEED_PALETTE = 128;
      const uint PFD_NEED_SYSTEM_PALETTE = 256;
      const uint PFD_SWAP_EXCHANGE = 512;
      const uint PFD_SWAP_COPY = 1024;
      const uint PFD_SWAP_LAYER_BUFFERS = 2048;
      const uint PFD_GENERIC_ACCELERATED = 4096;
      const uint PFD_SUPPORT_DIRECTDRAW = 8192;
      const uint PFD_DIRECT3D_ACCELERATED = 0x00004000;
      const uint PFD_SUPPORT_COMPOSITION = 0x00008000;

      const sbyte PFD_MAIN_PLANE = 0;
      const sbyte PFD_OVERLAY_PLANE = 1;
      const sbyte PFD_UNDERLAY_PLANE = -1;

      const uint WS_CHILD = 0x40000000;

      #endregion

      public RenderHost()
      {
          _hLib = LoadLibraryW("opengl32.dll");
      }

      protected unsafe override HandleRef BuildWindowCore(HandleRef hwndParent)
      {
  
            if (DesignerProperties.GetIsInDesignMode(this))
                return new HandleRef(null, 0);

            _hwndSource = new HwndSource(0, (int)WS_CHILD, 0, 0, 0, "RenderView", hwndParent.Handle);

            var handle = _hwndSource.CreateHandleRef();

            var pfd = new PIXELFORMATDESCRIPTOR
            {
                nSize = (ushort)Marshal.SizeOf<PIXELFORMATDESCRIPTOR>(),
                nVersion = 1,
                iPixelType = PFD_TYPE_RGBA,
                dwFlags = PFD_SUPPORT_OPENGL | PFD_SUPPORT_COMPOSITION | PFD_DIRECT3D_ACCELERATED | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER,
                iLayerType = PFD_MAIN_PLANE,
                cColorBits = 24,
                cDepthBits = 32
            };

            _hdc = GetDC(handle.Handle);

            var pfIndex = ChoosePixelFormat(_hdc, pfd);
            if (pfIndex <= 0)
                throw new Win32Exception();

            if (!SetPixelFormat(_hdc, pfIndex, pfd))
                throw new Win32Exception();

            _glCtx = wglCreateContext(_hdc);

            if (_glCtx == IntPtr.Zero)
                throw new Win32Exception();

            TakeContext();

            _gl = GL.GetApi(this);

            return handle;
        }

        public void SwapBuffers()
        {
            _ = SwapBuffers(_hdc);
        }

        protected override void DestroyWindowCore(HandleRef hwnd)
        {
            if (_glCtx != 0)
            {
                wglDeleteContext(_glCtx);
                _glCtx = 0;
            }

            if (_hwndSource != null)
            {
                _ = ReleaseDC(_hwndSource.Handle, _hdc);
                _hwndSource.Dispose();
                _hwndSource = null;
            }
        }

        public nint GetProcAddress(string proc, int? slot = null)
        {
            var addr = GetProcAddress(_hLib, proc);

            if (addr == 0)
            {
                addr = wglGetProcAddress(proc);
                if (addr == 0)
                    throw new NotSupportedException(proc);
            }

            return addr;
        }

        public void ReleaseContext()
        {
            if (!wglMakeCurrent(_hdc, IntPtr.Zero))
                throw new Win32Exception();
        }

        public void TakeContext()
        {
            if (!wglMakeCurrent(_hdc, _glCtx))
                throw new Win32Exception();
        }

        public bool TryGetProcAddress(string proc, out nint addr, int? slot = null)
        {
            addr = wglGetProcAddress(proc);
            return addr != 0;
        }

        public GL? Gl => _gl;

        public IntPtr Hdc => _hdc;

        public IntPtr GlCtx => _glCtx;
    }

@GeorgeS2019
Copy link

GeorgeS2019 commented Feb 19, 2024

@aguerrieri82

Recently Godot 4, top GitHub MIT Project, started to support DirectX12

Would be great we have similar Godot 4 WPF control

@Perksey
Copy link
Member

Perksey commented Feb 19, 2024

This project has nothing to do with Godot.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-Windowing enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

7 participants