Search Unity

Mesh shaders support?

Discussion in 'Graphics Experimental Previews' started by tswierkot, Sep 19, 2018.

  1. tswierkot

    tswierkot

    Joined:
    Feb 15, 2017
    Posts:
    25
    grizzly likes this.
  2. neoshaman

    neoshaman

    Joined:
    Feb 11, 2011
    Posts:
    4,985
  3. Tim-C

    Tim-C

    Unity Technologies

    Joined:
    Feb 6, 2010
    Posts:
    2,116
    They are really cool... but no roadmap or anything yet. So many new gfx stuff to implement this year! :confused:
     
    Ruberta and hippocoder like this.
  4. recursive

    recursive

    Joined:
    Jul 12, 2012
    Posts:
    640
    So this is an effective replacement for vtx/geom/tes shaders, based more on modern compute capabilities?

    Forget raytracing this is way more interesting for some of the experiments I've been tinkering with.
     
  5. hippocoder

    hippocoder

    Digital Ape Moderator

    Joined:
    Apr 11, 2010
    Posts:
    26,434
    I think it would be wiser for HDRP to look into acceptable compute shader equivalents that are comparable - for example geometry shaders are a bad design and a couple of compute shaders to replace it scales better, performs better, works on metal and any compute hardware... just an example.

    Seems time consuming to make but I see some AAA studios making noise in that direction so it seems like something more practical than getting locked into supporting a single GPU company.
     
    ParovozVR likes this.
  6. Przemyslaw_Zaworski

    Przemyslaw_Zaworski

    Joined:
    Jun 9, 2017
    Posts:
    187
    I made a plugin with simple example of NVIDIA Mesh Shader working with Unity OpenGL 4.5:

    upload_2019-7-8_17-52-10.png


    Source code:
    MeshShaderPlugin.cs
    Code (CSharp):
    1. using UnityEngine;
    2. using System;
    3. using System.Collections;
    4. using System.Runtime.InteropServices;
    5.  
    6. public class MeshShaderPlugin : MonoBehaviour
    7. {
    8.     [DllImport("MeshShaderPlugin")]
    9.     static extern IntPtr Execute();
    10.  
    11.     IEnumerator Start()
    12.     {
    13.         yield return StartCoroutine("CallNativePlugin");
    14.     }
    15.  
    16.     IEnumerator CallNativePlugin()
    17.     {
    18.         while (true)
    19.         {
    20.             yield return new WaitForEndOfFrame();
    21.             GL.IssuePluginEvent(Execute(), 1);
    22.         }
    23.     }
    24. }
    MeshShaderPlugin.cpp
    Code (CSharp):
    1. // For x64 Visual Studio command line:  cl.exe /LD MeshShaderPlugin.cpp opengl32.lib
    2. #include <windows.h>
    3. #include <GL/gl.h>
    4.  
    5. typedef GLuint(WINAPI *PFNGLCREATEPROGRAMPROC) ();
    6. typedef GLuint(WINAPI *PFNGLCREATESHADERPROC) (GLenum t);
    7. typedef void(WINAPI *PFNGLSHADERSOURCEPROC) (GLuint s, GLsizei c, const char*const*string, const GLint* i);
    8. typedef void(WINAPI *PFNGLCOMPILESHADERPROC) (GLuint s);
    9. typedef void(WINAPI *PFNGLATTACHSHADERPROC) (GLuint p, GLuint s);
    10. typedef void(WINAPI *PFNGLLINKPROGRAMPROC) (GLuint p);
    11. typedef void(WINAPI *PFNGLUSEPROGRAMPROC) (GLuint p);
    12. typedef void(WINAPI *PFNGLGETSHADERIVPROC) (GLuint s, GLenum v, GLint *p);
    13. typedef void(WINAPI *PFNGLGETSHADERINFOLOGPROC) (GLuint s, GLsizei b, GLsizei *l, char *i);
    14. typedef void(WINAPI *PFNGLDRAWMESHTASKSNVPROC) (GLuint f, GLuint c);
    15.  
    16. unsigned int PS;
    17.  
    18. static const char* MeshShader = \
    19.     "#version 450 \n"
    20.     "#extension GL_NV_mesh_shader : enable\n"
    21.     "layout(local_size_x = 3) in;"
    22.     "layout(max_vertices = 64) out;"
    23.     "layout(max_primitives = 126) out;"
    24.     "layout(triangles) out;"
    25.     "const vec3 vertices[3] = {vec3(-1,-1,0), vec3(1,-1,0), vec3(0,1,0)};"
    26.     "void main()"
    27.     "{"
    28.         "uint id = gl_LocalInvocationID.x;"
    29.         "gl_MeshVerticesNV[id].gl_Position = vec4(vertices[id], 2);"
    30.         "gl_PrimitiveIndicesNV[id] = id;"
    31.         "gl_PrimitiveCountNV = 1;"
    32.     "}";
    33.    
    34. static const char* FragmentShader = \
    35.     "#version 450 \n"
    36.     "#extension GL_NV_fragment_shader_barycentric : enable\n"
    37.     "out vec4 color;"
    38.     "void main()"
    39.     "{"  
    40.         "color = vec4(gl_BaryCoordNV, 1.0);"
    41.     "}";
    42.  
    43. int MakeShaders(const char* MS, const char* FS)
    44. {
    45.     int p = ((PFNGLCREATEPROGRAMPROC)wglGetProcAddress("glCreateProgram"))();
    46.     int sm = ((PFNGLCREATESHADERPROC)wglGetProcAddress("glCreateShader"))(0x9559);  
    47.     int sf = ((PFNGLCREATESHADERPROC)wglGetProcAddress("glCreateShader"))(0x8B30);  
    48.     ((PFNGLSHADERSOURCEPROC)wglGetProcAddress("glShaderSource"))(sm,1,&MS,0);
    49.     ((PFNGLSHADERSOURCEPROC)wglGetProcAddress("glShaderSource"))(sf,1,&FS,0);  
    50.     ((PFNGLCOMPILESHADERPROC)wglGetProcAddress("glCompileShader"))(sm);
    51.     ((PFNGLCOMPILESHADERPROC)wglGetProcAddress("glCompileShader"))(sf);  
    52.     ((PFNGLATTACHSHADERPROC)wglGetProcAddress("glAttachShader"))(p,sm);
    53.     ((PFNGLATTACHSHADERPROC)wglGetProcAddress("glAttachShader"))(p,sf);  
    54.     ((PFNGLLINKPROGRAMPROC)wglGetProcAddress("glLinkProgram"))(p);
    55.     return p;
    56. }
    57.  
    58. void Rendering()
    59. {
    60.     glDisable(GL_CULL_FACE);
    61.     glDisable(GL_BLEND);
    62.     glDepthFunc(GL_LEQUAL);
    63.     glEnable(GL_DEPTH_TEST);
    64.     glDepthMask(GL_FALSE);
    65.     ((PFNGLUSEPROGRAMPROC)wglGetProcAddress("glUseProgram"))(PS);
    66.     ((PFNGLDRAWMESHTASKSNVPROC)wglGetProcAddress("glDrawMeshTasksNV"))(0,1);
    67. }
    68.  
    69. typedef enum UnityGfxRenderer
    70. {
    71.     kUnityGfxRendererNull = 4,
    72.     kUnityGfxRendererOpenGLCore = 17,
    73. } UnityGfxRenderer;
    74.  
    75. typedef enum UnityGfxDeviceEventType
    76. {
    77.     kUnityGfxDeviceEventInitialize = 0,
    78.     kUnityGfxDeviceEventShutdown = 1,
    79.     kUnityGfxDeviceEventBeforeReset = 2,
    80.     kUnityGfxDeviceEventAfterReset = 3,
    81. } UnityGfxDeviceEventType;
    82.    
    83. struct UnityInterfaceGUID
    84. {
    85.     UnityInterfaceGUID(unsigned long long high, unsigned long long low) : m_GUIDHigh(high) , m_GUIDLow(low) { }
    86.     unsigned long long m_GUIDHigh;
    87.     unsigned long long m_GUIDLow;
    88. };
    89.  
    90. struct IUnityInterface {};
    91. typedef void (__stdcall * IUnityGraphicsDeviceEventCallback)(UnityGfxDeviceEventType eventType);
    92.  
    93. struct IUnityInterfaces
    94. {
    95.     IUnityInterface* (__stdcall* GetInterface)(UnityInterfaceGUID guid);
    96.     void(__stdcall* RegisterInterface)(UnityInterfaceGUID guid, IUnityInterface * ptr);
    97.     template<typename INTERFACE>
    98.     INTERFACE* Get()
    99.     {
    100.         return static_cast<INTERFACE*>(GetInterface(UnityInterfaceGUID(0x7CBA0A9CA4DDB544ULL, 0x8C5AD4926EB17B11ULL)));
    101.     }
    102.     void Register(IUnityInterface* ptr)
    103.     {
    104.         RegisterInterface(UnityInterfaceGUID(0x7CBA0A9CA4DDB544ULL, 0x8C5AD4926EB17B11ULL), ptr);
    105.     }
    106. };
    107.  
    108. struct IUnityGraphics : IUnityInterface
    109. {
    110.     void(__stdcall* RegisterDeviceEventCallback)(IUnityGraphicsDeviceEventCallback callback);
    111. };
    112.  
    113. typedef void (__stdcall* UnityRenderingEvent)(int eventId);
    114. typedef void(__stdcall* UnregisterDeviceEventCallback)(IUnityGraphicsDeviceEventCallback callback);
    115. static UnityGfxRenderer DeviceType = kUnityGfxRendererNull;
    116.  
    117. static void __stdcall OnGraphicsDeviceEvent(UnityGfxDeviceEventType eventType)
    118. {
    119.     if (eventType == kUnityGfxDeviceEventInitialize)
    120.     {
    121.         DeviceType = kUnityGfxRendererOpenGLCore;
    122.         PS = MakeShaders(MeshShader,FragmentShader);
    123.     }
    124.     if (eventType == kUnityGfxDeviceEventShutdown)
    125.     {
    126.         DeviceType = kUnityGfxRendererNull;
    127.     }
    128. }
    129.  
    130. static void __stdcall OnRenderEvent(int eventID)
    131. {
    132.     Rendering();
    133. }
    134.  
    135. extern "C" void    __declspec(dllexport) __stdcall UnityPluginLoad(IUnityInterfaces* unityInterfaces)
    136. {
    137.     IUnityInterfaces* s_UnityInterfaces = unityInterfaces;
    138.     IUnityGraphics* s_Graphics = s_UnityInterfaces->Get<IUnityGraphics>();
    139.     s_Graphics->RegisterDeviceEventCallback(OnGraphicsDeviceEvent);
    140.     OnGraphicsDeviceEvent(kUnityGfxDeviceEventInitialize);
    141. }
    142.  
    143. extern "C" void __declspec(dllexport) __stdcall UnityPluginUnload()
    144. {
    145.     UnregisterDeviceEventCallback(OnGraphicsDeviceEvent);  
    146. }
    147.  
    148. extern "C" UnityRenderingEvent __declspec(dllexport) __stdcall Execute()
    149. {
    150.     return OnRenderEvent;
    151. }
    upload_2019-7-8_18-0-20.png


    Copy compiled DLL file to Assets/Plugins, reload project and include MeshShaderPlugin.cs to camera. Play.
     
    mgear, ekakiya and Invertex like this.
  7. Przemyslaw_Zaworski

    Przemyslaw_Zaworski

    Joined:
    Jun 9, 2017
    Posts:
    187
    Update to the previous post:
    This is a second version of CS script for situation, when we don't want to render output directly to screen, but to Render Texture:

    Code (CSharp):
    1. using UnityEngine;
    2. using System;
    3. using System.Collections;
    4. using System.Runtime.InteropServices;
    5.  
    6. public class MeshShaderPlugin : MonoBehaviour
    7. {
    8.     [DllImport("MeshShaderPlugin")]
    9.     static extern IntPtr Execute();
    10.  
    11.     public RenderTexture RT;
    12.     private Material InternalMaterial;
    13.  
    14.     void Awake()
    15.     {
    16.         InternalMaterial = new Material(Shader.Find("Sprites/Default"));
    17.     }
    18.  
    19.     void RenderToBuffer(RenderTexture destination, Material material)
    20.     {
    21.         RenderTexture.active = destination;
    22.         GL.PushMatrix();
    23.         GL.LoadOrtho();
    24.         material.SetPass(0);
    25.         GL.Begin(GL.QUADS);
    26.         GL.MultiTexCoord2(0, 0.0f, 0.0f);
    27.         GL.Vertex3(0.0f, 0.0f, 0.0f);
    28.         GL.MultiTexCoord2(0, 1.0f, 0.0f);
    29.         GL.Vertex3(1.0f, 0.0f, 0.0f);
    30.         GL.MultiTexCoord2(0, 1.0f, 1.0f);
    31.         GL.Vertex3(1.0f, 1.0f, 0.0f);
    32.         GL.MultiTexCoord2(0, 0.0f, 1.0f);
    33.         GL.Vertex3(0.0f, 1.0f, 0.0f);
    34.         GL.End();
    35.         GL.Clear(false, true, Color.black);
    36.         GL.IssuePluginEvent(Execute(), 1);
    37.         GL.PopMatrix();
    38.     }
    39.  
    40.     void Update()
    41.     {
    42.         RenderToBuffer(RT,InternalMaterial);
    43.     }
    44. }
     
  8. landonth

    landonth

    Joined:
    Dec 3, 2018
    Posts:
    3
    Once Microsoft adds Mesh Shaders to DirectX 12 then it will be a shoo-in for Unity to add support. Vulkan and OpenGL also already have preliminary Mesh Shader support (as an extension but presumably will be rolled into the main specifications.) After the graphics APIs have standardised Mesh Shaders, AMD and any other GPU vendors just need to implement driver and hardware support for the latest API features like AMD is already working on for Real-time Raytracing support.

    More details:
    https://devblogs.microsoft.com/directx/dev-preview-of-new-directx-12-features/
    https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/chap24.html
     
    hippocoder likes this.
unityunity