2019-12-26 15:32:37 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2020-01-24 18:07:01 -05:00
// ..
2014-07-02 11:08:24 -04:00
2016-11-23 15:48:37 -05:00
# include "CoreMinimal.h"
# include "HAL/FileManager.h"
# include "Misc/FileHelper.h"
# include "Misc/Paths.h"
# include "Serialization/MemoryWriter.h"
2016-08-18 10:28:43 -04:00
# include "ShaderFormatOpenGL.h"
2021-01-27 17:53:40 -04:00
# include "HlslccHeaderWriter.h"
2021-04-08 10:09:56 -04:00
# include "SpirvReflectCommon.h"
2022-06-21 10:49:56 -04:00
# include "ShaderParameterParser.h"
2021-09-08 13:00:48 -04:00
# include <algorithm>
# include <regex>
2014-03-14 14:13:41 -04:00
# if PLATFORM_WINDOWS
2018-01-20 11:19:29 -05:00
# include "Windows/AllowWindowsPlatformTypes.h"
2014-03-14 14:13:41 -04:00
# include "Windows/PreWindowsApi.h"
# include <objbase.h>
# include <assert.h>
# include <stdio.h>
# include "Windows/PostWindowsApi.h"
# include "Windows/MinWindows.h"
2018-01-20 11:19:29 -05:00
# include "Windows/HideWindowsPlatformTypes.h"
2014-03-14 14:13:41 -04:00
# endif
2016-11-23 15:48:37 -05:00
# include "ShaderCore.h"
2014-06-05 16:38:54 -04:00
# include "ShaderPreprocessor.h"
# include "ShaderCompilerCommon.h"
2014-09-25 18:03:18 -04:00
# include "GlslBackend.h"
2014-03-14 14:13:41 -04:00
# if PLATFORM_WINDOWS
2018-01-20 11:19:29 -05:00
# include "Windows/AllowWindowsPlatformTypes.h"
2022-09-13 21:48:33 -04:00
# include <GL/glcorearb.h>
# include <GL/glext.h>
# include <GL/wglext.h>
2018-01-20 11:19:29 -05:00
# include "Windows/HideWindowsPlatformTypes.h"
2014-06-05 17:11:45 -04:00
# elif PLATFORM_LINUX
2022-09-13 21:48:33 -04:00
# include <GL/glcorearb.h>
# include <GL/glext.h>
2014-08-04 18:28:10 -04:00
# include "SDL.h"
2020-10-09 22:42:26 -04:00
# include <stdio.h>
# include <wchar.h>
2014-08-04 18:28:10 -04:00
typedef SDL_Window * SDL_HWindow ;
typedef SDL_GLContext SDL_HGLContext ;
struct FPlatformOpenGLContext
{
SDL_HWindow hWnd ;
SDL_HGLContext hGLContext ; // this is a (void*) pointer
} ;
2014-03-14 14:13:41 -04:00
# elif PLATFORM_MAC
# include <OpenGL/OpenGL.h>
# include <OpenGL/gl3.h>
# include <OpenGL/gl3ext.h>
# ifndef GL_COMPUTE_SHADER
# define GL_COMPUTE_SHADER 0x91B9
# endif
# ifndef GL_TESS_EVALUATION_SHADER
# define GL_TESS_EVALUATION_SHADER 0x8E87
2017-08-21 15:05:19 -04:00
# endif
2014-03-14 14:13:41 -04:00
# ifndef GL_TESS_CONTROL_SHADER
# define GL_TESS_CONTROL_SHADER 0x8E88
# endif
# endif
2014-07-15 13:25:14 -04:00
# include "OpenGLUtil.h"
2014-03-14 14:13:41 -04:00
# include "OpenGLShaderResources.h"
2020-10-09 22:42:26 -04:00
# ifndef DXC_SUPPORTED
# define DXC_SUPPORTED (PLATFORM_MAC || PLATFORM_WINDOWS || PLATFORM_LINUX)
2019-09-14 09:45:25 -04:00
# endif
2020-10-09 22:42:26 -04:00
# if DXC_SUPPORTED
2019-09-14 09:45:25 -04:00
THIRD_PARTY_INCLUDES_START
# include "spirv_reflect.h"
# include <map>
THIRD_PARTY_INCLUDES_END
2020-10-09 22:42:26 -04:00
# endif // DXC_SUPPORTED
2019-09-14 09:45:25 -04:00
2017-08-21 15:05:19 -04:00
DEFINE_LOG_CATEGORY_STATIC ( LogOpenGLShaderCompiler , Log , All ) ;
2014-03-14 14:13:41 -04:00
2014-09-18 17:49:40 -04:00
# define VALIDATE_GLSL_WITH_DRIVER 0
2014-03-14 14:13:41 -04:00
# define ENABLE_IMAGINATION_COMPILER 1
2020-01-24 18:07:01 -05:00
static FORCEINLINE bool IsPCESPlatform ( GLSLVersion Version )
2014-03-14 14:13:41 -04:00
{
2020-01-24 18:07:01 -05:00
return ( Version = = GLSL_150_ES3_1 ) ;
2014-03-14 14:13:41 -04:00
}
/*------------------------------------------------------------------------------
Shader compiling.
------------------------------------------------------------------------------*/
# if PLATFORM_WINDOWS
/** List all OpenGL entry points needed for shader compilation. */
# define ENUM_GL_ENTRYPOINTS(EnumMacro) \
EnumMacro(PFNGLCOMPILESHADERPROC,glCompileShader) \
EnumMacro(PFNGLCREATESHADERPROC,glCreateShader) \
EnumMacro(PFNGLDELETESHADERPROC,glDeleteShader) \
EnumMacro(PFNGLGETSHADERIVPROC,glGetShaderiv) \
EnumMacro(PFNGLGETSHADERINFOLOGPROC,glGetShaderInfoLog) \
EnumMacro(PFNGLSHADERSOURCEPROC,glShaderSource) \
EnumMacro(PFNGLDELETEBUFFERSPROC,glDeleteBuffers)
/** Define all GL functions. */
# define DEFINE_GL_ENTRYPOINTS(Type,Func) static Type Func = NULL;
ENUM_GL_ENTRYPOINTS ( DEFINE_GL_ENTRYPOINTS ) ;
/** This function is handled separately because it is used to get a real context. */
static PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB ;
/** Platform specific OpenGL context. */
struct FPlatformOpenGLContext
{
HWND WindowHandle ;
HDC DeviceContext ;
HGLRC OpenGLContext ;
} ;
/**
2014-06-05 16:38:54 -04:00
* A dummy wndproc.
2014-03-14 14:13:41 -04:00
*/
static LRESULT CALLBACK PlatformDummyGLWndproc ( HWND hWnd , uint32 Message , WPARAM wParam , LPARAM lParam )
{
return DefWindowProc ( hWnd , Message , wParam , lParam ) ;
}
/**
* Initialize a pixel format descriptor for the given window handle.
*/
static void PlatformInitPixelFormatForDevice ( HDC DeviceContext )
{
// Pixel format descriptor for the context.
PIXELFORMATDESCRIPTOR PixelFormatDesc ;
2015-01-14 04:21:10 -05:00
FMemory : : Memzero ( PixelFormatDesc ) ;
2014-03-14 14:13:41 -04:00
PixelFormatDesc . nSize = sizeof ( PIXELFORMATDESCRIPTOR ) ;
PixelFormatDesc . nVersion = 1 ;
PixelFormatDesc . dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER ;
PixelFormatDesc . iPixelType = PFD_TYPE_RGBA ;
PixelFormatDesc . cColorBits = 32 ;
PixelFormatDesc . cDepthBits = 0 ;
PixelFormatDesc . cStencilBits = 0 ;
PixelFormatDesc . iLayerType = PFD_MAIN_PLANE ;
// Set the pixel format and create the context.
int32 PixelFormat = ChoosePixelFormat ( DeviceContext , & PixelFormatDesc ) ;
if ( ! PixelFormat | | ! SetPixelFormat ( DeviceContext , PixelFormat , & PixelFormatDesc ) )
{
UE_LOG ( LogOpenGLShaderCompiler , Fatal , TEXT ( " Failed to set pixel format for device context. " ) ) ;
}
}
/**
* Create a dummy window used to construct OpenGL contexts.
*/
static void PlatformCreateDummyGLWindow ( FPlatformOpenGLContext * OutContext )
{
const TCHAR * WindowClassName = TEXT ( " DummyGLToolsWindow " ) ;
// Register a dummy window class.
static bool bInitializedWindowClass = false ;
if ( ! bInitializedWindowClass )
{
WNDCLASS wc ;
bInitializedWindowClass = true ;
2015-01-14 04:21:10 -05:00
FMemory : : Memzero ( wc ) ;
2014-03-14 14:13:41 -04:00
wc . style = CS_OWNDC ;
wc . lpfnWndProc = PlatformDummyGLWndproc ;
wc . cbClsExtra = 0 ;
wc . cbWndExtra = 0 ;
wc . hInstance = NULL ;
wc . hIcon = NULL ;
wc . hCursor = NULL ;
wc . hbrBackground = ( HBRUSH ) ( COLOR_MENUTEXT ) ;
wc . lpszMenuName = NULL ;
wc . lpszClassName = WindowClassName ;
ATOM ClassAtom = : : RegisterClass ( & wc ) ;
check ( ClassAtom ) ;
}
// Create a dummy window.
OutContext - > WindowHandle = CreateWindowEx (
WS_EX_WINDOWEDGE ,
WindowClassName ,
NULL ,
WS_POPUP ,
CW_USEDEFAULT , CW_USEDEFAULT , CW_USEDEFAULT , CW_USEDEFAULT ,
NULL , NULL , NULL , NULL ) ;
check ( OutContext - > WindowHandle ) ;
// Get the device context.
OutContext - > DeviceContext = GetDC ( OutContext - > WindowHandle ) ;
check ( OutContext - > DeviceContext ) ;
PlatformInitPixelFormatForDevice ( OutContext - > DeviceContext ) ;
}
/**
* Create a core profile OpenGL context.
*/
static void PlatformCreateOpenGLContextCore ( FPlatformOpenGLContext * OutContext , int MajorVersion , int MinorVersion , HGLRC InParentContext )
{
check ( wglCreateContextAttribsARB ) ;
check ( OutContext ) ;
check ( OutContext - > DeviceContext ) ;
int AttribList [ ] =
{
WGL_CONTEXT_MAJOR_VERSION_ARB , MajorVersion ,
WGL_CONTEXT_MINOR_VERSION_ARB , MinorVersion ,
WGL_CONTEXT_FLAGS_ARB , WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB | WGL_CONTEXT_DEBUG_BIT_ARB ,
WGL_CONTEXT_PROFILE_MASK_ARB , WGL_CONTEXT_CORE_PROFILE_BIT_ARB ,
0
} ;
OutContext - > OpenGLContext = wglCreateContextAttribsARB ( OutContext - > DeviceContext , InParentContext , AttribList ) ;
check ( OutContext - > OpenGLContext ) ;
}
/**
* Make the context current.
*/
static void PlatformMakeGLContextCurrent ( FPlatformOpenGLContext * Context )
{
check ( Context & & Context - > OpenGLContext & & Context - > DeviceContext ) ;
wglMakeCurrent ( Context - > DeviceContext , Context - > OpenGLContext ) ;
}
/**
* Initialize an OpenGL context so that shaders can be compiled.
*/
static void PlatformInitOpenGL ( void * & ContextPtr , void * & PrevContextPtr , int InMajorVersion , int InMinorVersion )
{
static FPlatformOpenGLContext ShaderCompileContext = { 0 } ;
ContextPtr = ( void * ) wglGetCurrentDC ( ) ;
PrevContextPtr = ( void * ) wglGetCurrentContext ( ) ;
if ( ShaderCompileContext . OpenGLContext = = NULL & & InMajorVersion & & InMinorVersion )
{
PlatformCreateDummyGLWindow ( & ShaderCompileContext ) ;
// Disable warning C4191: 'type cast' : unsafe conversion from 'PROC' to 'XXX' while getting GL entry points.
# pragma warning(push)
# pragma warning(disable:4191)
if ( wglCreateContextAttribsARB = = NULL )
{
// Create a dummy context so that wglCreateContextAttribsARB can be initialized.
ShaderCompileContext . OpenGLContext = wglCreateContext ( ShaderCompileContext . DeviceContext ) ;
check ( ShaderCompileContext . OpenGLContext ) ;
PlatformMakeGLContextCurrent ( & ShaderCompileContext ) ;
wglCreateContextAttribsARB = ( PFNWGLCREATECONTEXTATTRIBSARBPROC ) wglGetProcAddress ( " wglCreateContextAttribsARB " ) ;
check ( wglCreateContextAttribsARB ) ;
wglDeleteContext ( ShaderCompileContext . OpenGLContext ) ;
}
// Create a context so that remaining GL function pointers can be initialized.
PlatformCreateOpenGLContextCore ( & ShaderCompileContext , InMajorVersion , InMinorVersion , /*InParentContext=*/ NULL ) ;
check ( ShaderCompileContext . OpenGLContext ) ;
PlatformMakeGLContextCurrent ( & ShaderCompileContext ) ;
if ( glCreateShader = = NULL )
{
// Initialize all entry points.
# define GET_GL_ENTRYPOINTS(Type,Func) Func = (Type)wglGetProcAddress(#Func);
ENUM_GL_ENTRYPOINTS ( GET_GL_ENTRYPOINTS ) ;
// Check that all of the entry points have been initialized.
bool bFoundAllEntryPoints = true ;
# define CHECK_GL_ENTRYPOINTS(Type,Func) if (Func == NULL) { bFoundAllEntryPoints = false; UE_LOG(LogOpenGLShaderCompiler, Warning, TEXT("Failed to find entry point for %s"), TEXT(#Func)); }
ENUM_GL_ENTRYPOINTS ( CHECK_GL_ENTRYPOINTS ) ;
checkf ( bFoundAllEntryPoints , TEXT ( " Failed to find all OpenGL entry points. " ) ) ;
}
// Restore warning C4191.
# pragma warning(pop)
}
PlatformMakeGLContextCurrent ( & ShaderCompileContext ) ;
}
static void PlatformReleaseOpenGL ( void * ContextPtr , void * PrevContextPtr )
{
wglMakeCurrent ( ( HDC ) ContextPtr , ( HGLRC ) PrevContextPtr ) ;
}
2014-06-05 17:11:45 -04:00
# elif PLATFORM_LINUX
2019-06-04 15:42:48 -04:00
/** List all OpenGL entry points needed for shader compilation. */
# define ENUM_GL_ENTRYPOINTS(EnumMacro) \
EnumMacro(PFNGLCOMPILESHADERPROC,glCompileShader) \
EnumMacro(PFNGLCREATESHADERPROC,glCreateShader) \
EnumMacro(PFNGLDELETESHADERPROC,glDeleteShader) \
EnumMacro(PFNGLGETSHADERIVPROC,glGetShaderiv) \
EnumMacro(PFNGLGETSHADERINFOLOGPROC,glGetShaderInfoLog) \
EnumMacro(PFNGLSHADERSOURCEPROC,glShaderSource) \
EnumMacro(PFNGLDELETEBUFFERSPROC,glDeleteBuffers)
/** Define all GL functions. */
// We need to make pointer names different from GL functions otherwise we may end up getting
// addresses of those symbols when looking for extensions.
namespace GLFuncPointers
{
# define DEFINE_GL_ENTRYPOINTS(Type,Func) static Type Func = NULL;
ENUM_GL_ENTRYPOINTS ( DEFINE_GL_ENTRYPOINTS ) ;
} ;
using namespace GLFuncPointers ;
2014-08-04 18:28:10 -04:00
static void _PlatformCreateDummyGLWindow ( FPlatformOpenGLContext * OutContext )
{
static bool bInitializedWindowClass = false ;
// Create a dummy window.
OutContext - > hWnd = SDL_CreateWindow ( NULL ,
0 , 0 , 1 , 1 ,
2015-09-20 18:16:58 -04:00
SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOW_HIDDEN | SDL_WINDOW_SKIP_TASKBAR ) ;
2014-08-04 18:28:10 -04:00
}
static void _PlatformCreateOpenGLContextCore ( FPlatformOpenGLContext * OutContext )
{
check ( OutContext ) ;
SDL_HWindow PrevWindow = SDL_GL_GetCurrentWindow ( ) ;
SDL_HGLContext PrevContext = SDL_GL_GetCurrentContext ( ) ;
OutContext - > hGLContext = SDL_GL_CreateContext ( OutContext - > hWnd ) ;
SDL_GL_MakeCurrent ( PrevWindow , PrevContext ) ;
}
static void _ContextMakeCurrent ( SDL_HWindow hWnd , SDL_HGLContext hGLDC )
{
GLint Result = SDL_GL_MakeCurrent ( hWnd , hGLDC ) ;
check ( ! Result ) ;
}
2014-06-05 17:11:45 -04:00
static void PlatformInitOpenGL ( void * & ContextPtr , void * & PrevContextPtr , int InMajorVersion , int InMinorVersion )
{
2014-08-04 18:28:10 -04:00
static bool bInitialized = ( SDL_GL_GetCurrentWindow ( ) ! = NULL ) & & ( SDL_GL_GetCurrentContext ( ) ! = NULL ) ;
if ( ! bInitialized )
{
check ( InMajorVersion > 3 | | ( InMajorVersion = = 3 & & InMinorVersion > = 2 ) ) ;
if ( SDL_WasInit ( 0 ) = = 0 )
{
SDL_Init ( SDL_INIT_VIDEO ) ;
}
else
{
Uint32 InitializedSubsystemsMask = SDL_WasInit ( SDL_INIT_EVERYTHING ) ;
if ( ( InitializedSubsystemsMask & SDL_INIT_VIDEO ) = = 0 )
{
SDL_InitSubSystem ( SDL_INIT_VIDEO ) ;
}
}
if ( SDL_GL_LoadLibrary ( NULL ) )
{
UE_LOG ( LogOpenGLShaderCompiler , Fatal , TEXT ( " Unable to dynamically load libGL: %s " ) , ANSI_TO_TCHAR ( SDL_GetError ( ) ) ) ;
}
2019-06-04 15:42:48 -04:00
if ( glCreateShader = = nullptr )
{
// Initialize all entry points.
# define GET_GL_ENTRYPOINTS(Type,Func) GLFuncPointers::Func = reinterpret_cast<Type>(SDL_GL_GetProcAddress(#Func));
ENUM_GL_ENTRYPOINTS ( GET_GL_ENTRYPOINTS ) ;
// Check that all of the entry points have been initialized.
bool bFoundAllEntryPoints = true ;
# define CHECK_GL_ENTRYPOINTS(Type,Func) if (Func == nullptr) { bFoundAllEntryPoints = false; UE_LOG(LogOpenGLShaderCompiler, Warning, TEXT("Failed to find entry point for %s"), TEXT(#Func)); }
ENUM_GL_ENTRYPOINTS ( CHECK_GL_ENTRYPOINTS ) ;
checkf ( bFoundAllEntryPoints , TEXT ( " Failed to find all OpenGL entry points. " ) ) ;
}
2014-08-04 18:28:10 -04:00
if ( SDL_GL_SetAttribute ( SDL_GL_CONTEXT_MAJOR_VERSION , InMajorVersion ) )
{
UE_LOG ( LogOpenGLShaderCompiler , Fatal , TEXT ( " Failed to set GL major version: %s " ) , ANSI_TO_TCHAR ( SDL_GetError ( ) ) ) ;
}
if ( SDL_GL_SetAttribute ( SDL_GL_CONTEXT_MINOR_VERSION , InMinorVersion ) )
{
UE_LOG ( LogOpenGLShaderCompiler , Fatal , TEXT ( " Failed to set GL minor version: %s " ) , ANSI_TO_TCHAR ( SDL_GetError ( ) ) ) ;
}
if ( SDL_GL_SetAttribute ( SDL_GL_CONTEXT_FLAGS , SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG ) )
{
UE_LOG ( LogOpenGLShaderCompiler , Fatal , TEXT ( " Failed to set GL flags: %s " ) , ANSI_TO_TCHAR ( SDL_GetError ( ) ) ) ;
}
if ( SDL_GL_SetAttribute ( SDL_GL_CONTEXT_PROFILE_MASK , SDL_GL_CONTEXT_PROFILE_CORE ) )
{
UE_LOG ( LogOpenGLShaderCompiler , Fatal , TEXT ( " Failed to set GL mask/profile: %s " ) , ANSI_TO_TCHAR ( SDL_GetError ( ) ) ) ;
}
// Create a dummy context to verify opengl support.
FPlatformOpenGLContext DummyContext ;
_PlatformCreateDummyGLWindow ( & DummyContext ) ;
_PlatformCreateOpenGLContextCore ( & DummyContext ) ;
if ( DummyContext . hGLContext )
{
_ContextMakeCurrent ( DummyContext . hWnd , DummyContext . hGLContext ) ;
}
else
{
UE_LOG ( LogOpenGLShaderCompiler , Fatal , TEXT ( " OpenGL %d.%d not supported by driver " ) , InMajorVersion , InMinorVersion ) ;
return ;
}
PrevContextPtr = NULL ;
ContextPtr = DummyContext . hGLContext ;
bInitialized = true ;
}
PrevContextPtr = reinterpret_cast < void * > ( SDL_GL_GetCurrentContext ( ) ) ;
SDL_HGLContext NewContext = SDL_GL_CreateContext ( SDL_GL_GetCurrentWindow ( ) ) ;
SDL_GL_MakeCurrent ( SDL_GL_GetCurrentWindow ( ) , NewContext ) ;
ContextPtr = reinterpret_cast < void * > ( NewContext ) ;
2014-06-05 17:11:45 -04:00
}
2014-08-04 18:28:10 -04:00
2014-06-05 17:11:45 -04:00
static void PlatformReleaseOpenGL ( void * ContextPtr , void * PrevContextPtr )
{
2014-08-04 18:28:10 -04:00
SDL_GL_MakeCurrent ( SDL_GL_GetCurrentWindow ( ) , reinterpret_cast < SDL_HGLContext > ( PrevContextPtr ) ) ;
SDL_GL_DeleteContext ( reinterpret_cast < SDL_HGLContext > ( ContextPtr ) ) ;
2014-06-05 17:11:45 -04:00
}
2014-03-14 14:13:41 -04:00
# elif PLATFORM_MAC
static void PlatformInitOpenGL ( void * & ContextPtr , void * & PrevContextPtr , int InMajorVersion , int InMinorVersion )
{
check ( InMajorVersion > 3 | | ( InMajorVersion = = 3 & & InMinorVersion > = 2 ) ) ;
CGLPixelFormatAttribute AttribList [ ] =
{
kCGLPFANoRecovery ,
kCGLPFAAccelerated ,
kCGLPFAOpenGLProfile ,
( CGLPixelFormatAttribute ) kCGLOGLPVersion_3_2_Core ,
( CGLPixelFormatAttribute ) 0
} ;
CGLPixelFormatObj PixelFormat ;
GLint NumFormats = 0 ;
CGLError Error = CGLChoosePixelFormat ( AttribList , & PixelFormat , & NumFormats ) ;
check ( Error = = kCGLNoError ) ;
CGLContextObj ShaderCompileContext ;
Error = CGLCreateContext ( PixelFormat , NULL , & ShaderCompileContext ) ;
check ( Error = = kCGLNoError ) ;
Error = CGLDestroyPixelFormat ( PixelFormat ) ;
check ( Error = = kCGLNoError ) ;
PrevContextPtr = ( void * ) CGLGetCurrentContext ( ) ;
Error = CGLSetCurrentContext ( ShaderCompileContext ) ;
check ( Error = = kCGLNoError ) ;
ContextPtr = ( void * ) ShaderCompileContext ;
}
static void PlatformReleaseOpenGL ( void * ContextPtr , void * PrevContextPtr )
{
CGLContextObj ShaderCompileContext = ( CGLContextObj ) ContextPtr ;
CGLContextObj PreviousShaderCompileContext = ( CGLContextObj ) PrevContextPtr ;
CGLError Error ;
Error = CGLSetCurrentContext ( PreviousShaderCompileContext ) ;
check ( Error = = kCGLNoError ) ;
Error = CGLDestroyContext ( ShaderCompileContext ) ;
check ( Error = = kCGLNoError ) ;
}
# endif
/** Map shader frequency -> GL shader type. */
GLenum GLFrequencyTable [ ] =
{
GL_VERTEX_SHADER , // SF_Vertex
2021-03-18 18:42:49 -04:00
GLenum ( 0 ) , // SF_Mesh
GLenum ( 0 ) , // SF_Amplification
2014-03-14 14:13:41 -04:00
GL_FRAGMENT_SHADER , // SF_Pixel
GL_GEOMETRY_SHADER , // SF_Geometry
GL_COMPUTE_SHADER , // SF_Compute
2018-12-18 21:41:17 -05:00
// Ray tracing shaders are not supported in OpenGL
GLenum ( 0 ) , // SF_RayGen
GLenum ( 0 ) , // SF_RayMiss
GLenum ( 0 ) , // SF_RayHitGroup (closest hit, any hit, intersection)
2019-06-11 18:27:07 -04:00
GLenum ( 0 ) , // SF_RayCallable
2014-03-14 14:13:41 -04:00
} ;
2019-09-28 08:19:35 -04:00
static_assert ( UE_ARRAY_COUNT ( GLFrequencyTable ) = = SF_NumFrequencies , " Frequency table size mismatch. " ) ;
2014-03-14 14:13:41 -04:00
2017-03-21 17:46:52 -04:00
static inline bool IsDigit ( TCHAR Char )
{
return Char > = ' 0 ' & & Char < = ' 9 ' ;
}
2014-03-14 14:13:41 -04:00
/**
* Parse a GLSL error.
* @param OutErrors - Storage for shader compiler errors.
* @param InLine - A single line from the compile error log.
*/
void ParseGlslError ( TArray < FShaderCompilerError > & OutErrors , const FString & InLine )
{
const TCHAR * ErrorPrefix = TEXT ( " error: 0: " ) ;
const TCHAR * p = * InLine ;
if ( FCString : : Strnicmp ( p , ErrorPrefix , 9 ) = = 0 )
{
FString ErrorMsg ;
int32 LineNumber = 0 ;
p + = FCString : : Strlen ( ErrorPrefix ) ;
// Skip to a number, take that to be the line number.
2017-03-21 17:46:52 -04:00
while ( * p & & ! IsDigit ( * p ) ) { p + + ; }
while ( * p & & IsDigit ( * p ) )
2014-03-14 14:13:41 -04:00
{
LineNumber = 10 * LineNumber + ( * p + + - TEXT ( ' 0 ' ) ) ;
}
// Skip to the next alphanumeric value, treat that as the error message.
while ( * p & & ! FChar : : IsAlnum ( * p ) ) { p + + ; }
ErrorMsg = p ;
// Generate a compiler error.
if ( ErrorMsg . Len ( ) > 0 )
{
// Note that no mapping exists from the GLSL source to the original
// HLSL source.
FShaderCompilerError * CompilerError = new ( OutErrors ) FShaderCompilerError ;
CompilerError - > StrippedErrorMessage = FString : : Printf (
TEXT ( " driver compile error(%d): %s " ) ,
LineNumber ,
* ErrorMsg
) ;
}
}
}
2015-07-02 11:52:03 -04:00
static TArray < ANSICHAR > ParseIdentifierANSI ( const FString & Str )
2015-02-25 08:13:48 -05:00
{
TArray < ANSICHAR > Result ;
2015-07-02 11:52:03 -04:00
Result . Reserve ( Str . Len ( ) ) ;
for ( int32 Index = 0 ; Index < Str . Len ( ) ; + + Index )
2015-02-25 08:13:48 -05:00
{
2015-07-02 11:52:03 -04:00
Result . Add ( FChar : : ToLower ( ( ANSICHAR ) Str [ Index ] ) ) ;
2015-02-25 08:13:48 -05:00
}
Result . Add ( ' \0 ' ) ;
2014-03-14 14:13:41 -04:00
return Result ;
}
2015-07-02 11:52:03 -04:00
static uint32 ParseNumber ( const TCHAR * Str )
2014-03-14 14:13:41 -04:00
{
uint32 Num = 0 ;
2017-03-21 17:46:52 -04:00
while ( * Str & & IsDigit ( * Str ) )
2014-03-14 14:13:41 -04:00
{
Num = Num * 10 + * Str + + - ' 0 ' ;
}
return Num ;
}
2016-09-30 21:21:09 -04:00
static ANSICHAR TranslateFrequencyToCrossCompilerPrefix ( int32 Frequency )
{
switch ( Frequency )
{
case SF_Vertex : return ' v ' ;
case SF_Pixel : return ' p ' ;
case SF_Geometry : return ' g ' ;
case SF_Compute : return ' c ' ;
}
return ' \0 ' ;
}
static TCHAR * SetIndex ( TCHAR * Str , int32 Offset , int32 Index )
{
check ( Index > = 0 & & Index < 100 ) ;
Str + = Offset ;
if ( Index > = 10 )
{
* Str + + = ' 0 ' + ( TCHAR ) ( Index / 10 ) ;
}
* Str + + = ' 0 ' + ( TCHAR ) ( Index % 10 ) ;
* Str = ' \0 ' ;
return Str ;
}
2014-03-14 14:13:41 -04:00
/**
* Construct the final microcode from the compiled and verified shader source.
* @param ShaderOutput - Where to store the microcode and parameter map.
* @param InShaderSource - GLSL source with input/output signature.
* @param SourceLen - The length of the GLSL source code.
*/
2016-09-30 21:21:09 -04:00
void FOpenGLFrontend : : BuildShaderOutput (
2014-03-14 14:13:41 -04:00
FShaderCompilerOutput & ShaderOutput ,
2017-08-21 15:05:19 -04:00
const FShaderCompilerInput & ShaderInput ,
2014-03-14 14:13:41 -04:00
const ANSICHAR * InShaderSource ,
int32 SourceLen ,
GLSLVersion Version
)
{
2015-07-02 11:52:03 -04:00
const ANSICHAR * USFSource = InShaderSource ;
CrossCompiler : : FHlslccHeader CCHeader ;
if ( ! CCHeader . Read ( USFSource , SourceLen ) )
{
UE_LOG ( LogOpenGLShaderCompiler , Error , TEXT ( " Bad hlslcc header found " ) ) ;
}
2017-08-21 15:05:19 -04:00
2015-07-02 11:52:03 -04:00
if ( * USFSource ! = ' # ' )
{
UE_LOG ( LogOpenGLShaderCompiler , Error , TEXT ( " Bad hlslcc header found! Missing '#'! " ) ) ;
}
2014-03-14 14:13:41 -04:00
FOpenGLCodeHeader Header = { 0 } ;
FShaderParameterMap & ParameterMap = ShaderOutput . ParameterMap ;
EShaderFrequency Frequency = ( EShaderFrequency ) ShaderOutput . Target . Frequency ;
2014-06-05 16:38:54 -04:00
TBitArray < > UsedUniformBufferSlots ;
2015-07-02 11:52:03 -04:00
UsedUniformBufferSlots . Init ( false , 32 ) ;
2014-06-05 16:38:54 -04:00
2014-03-14 14:13:41 -04:00
// Write out the magic markers.
Header . GlslMarker = 0x474c534c ;
switch ( Frequency )
{
case SF_Vertex :
Header . FrequencyMarker = 0x5653 ;
break ;
case SF_Pixel :
Header . FrequencyMarker = 0x5053 ;
break ;
case SF_Geometry :
Header . FrequencyMarker = 0x4753 ;
break ;
case SF_Compute :
Header . FrequencyMarker = 0x4353 ;
break ;
default :
UE_LOG ( LogOpenGLShaderCompiler , Fatal , TEXT ( " Invalid shader frequency: %d " ) , ( int32 ) Frequency ) ;
}
2015-07-02 11:52:03 -04:00
static const FString AttributePrefix = TEXT ( " in_ATTRIBUTE " ) ;
2019-09-14 09:45:25 -04:00
static const FString AttributeVarPrefix = TEXT ( " in_var_ATTRIBUTE " ) ;
2015-07-02 11:52:03 -04:00
static const FString GL_Prefix = TEXT ( " gl_ " ) ;
for ( auto & Input : CCHeader . Inputs )
2014-03-14 14:13:41 -04:00
{
2015-07-02 11:52:03 -04:00
// Only process attributes for vertex shaders.
if ( Frequency = = SF_Vertex & & Input . Name . StartsWith ( AttributePrefix ) )
{
int32 AttributeIndex = ParseNumber ( * Input . Name + AttributePrefix . Len ( ) ) ;
2021-03-08 13:24:59 -04:00
Header . Bindings . InOutMask . EnableField ( AttributeIndex ) ;
2015-07-02 11:52:03 -04:00
}
2019-09-14 09:45:25 -04:00
else if ( Frequency = = SF_Vertex & & Input . Name . StartsWith ( AttributeVarPrefix ) )
{
int32 AttributeIndex = ParseNumber ( * Input . Name + AttributeVarPrefix . Len ( ) ) ;
2021-03-08 13:24:59 -04:00
Header . Bindings . InOutMask . EnableField ( AttributeIndex ) ;
2019-09-14 09:45:25 -04:00
}
2015-07-02 11:52:03 -04:00
// Record user-defined input varyings
else if ( ! Input . Name . StartsWith ( GL_Prefix ) )
{
FOpenGLShaderVarying Var ;
Var . Location = Input . Index ;
Var . Varying = ParseIdentifierANSI ( Input . Name ) ;
Header . Bindings . InputVaryings . Add ( Var ) ;
}
2014-03-14 14:13:41 -04:00
}
2015-07-02 11:52:03 -04:00
static const FString TargetPrefix = " out_Target " ;
static const FString GL_FragDepth = " gl_FragDepth " ;
for ( auto & Output : CCHeader . Outputs )
2014-03-14 14:13:41 -04:00
{
2017-03-21 17:46:52 -04:00
// Only targets for pixel shaders must be tracked.
if ( Frequency = = SF_Pixel & & Output . Name . StartsWith ( TargetPrefix ) )
{
2015-07-02 11:52:03 -04:00
uint8 TargetIndex = ParseNumber ( * Output . Name + TargetPrefix . Len ( ) ) ;
2021-03-08 13:24:59 -04:00
Header . Bindings . InOutMask . EnableField ( TargetIndex ) ;
2017-03-21 17:46:52 -04:00
}
// Only depth writes for pixel shaders must be tracked.
else if ( Frequency = = SF_Pixel & & Output . Name . Equals ( GL_FragDepth ) )
{
2021-03-08 13:24:59 -04:00
Header . Bindings . InOutMask . EnableField ( CrossCompiler : : FShaderBindingInOutMask : : DepthStencilMaskIndex ) ;
2017-03-21 17:46:52 -04:00
}
// Record user-defined output varyings
else if ( ! Output . Name . StartsWith ( GL_Prefix ) )
{
FOpenGLShaderVarying Var ;
Var . Location = Output . Index ;
Var . Varying = ParseIdentifierANSI ( Output . Name ) ;
Header . Bindings . OutputVaryings . Add ( Var ) ;
}
2014-03-14 14:13:41 -04:00
}
2016-09-30 21:21:09 -04:00
// general purpose binding name
TCHAR BindingName [ ] = TEXT ( " XYZ \0 \0 \0 \0 \0 \0 \0 \0 " ) ;
BindingName [ 0 ] = TranslateFrequencyToCrossCompilerPrefix ( Frequency ) ;
TMap < FString , FString > BindingNameMap ;
2014-03-14 14:13:41 -04:00
// Then 'normal' uniform buffers.
2015-07-02 11:52:03 -04:00
for ( auto & UniformBlock : CCHeader . UniformBlocks )
2014-03-14 14:13:41 -04:00
{
2015-07-02 11:52:03 -04:00
uint16 UBIndex = UniformBlock . Index ;
2021-09-03 04:01:32 -04:00
UsedUniformBufferSlots [ UBIndex ] = true ;
2021-08-11 07:11:25 -04:00
2016-09-30 21:21:09 -04:00
if ( OutputTrueParameterNames ( ) )
{
// make the final name this will be in the shader
BindingName [ 1 ] = ' b ' ;
SetIndex ( BindingName , 2 , UBIndex ) ;
BindingNameMap . Add ( BindingName , UniformBlock . Name ) ;
}
else
{
2022-04-14 15:46:20 -04:00
HandleReflectedUniformBuffer ( UniformBlock . Name , UBIndex , ShaderOutput ) ;
2016-09-30 21:21:09 -04:00
}
Header . Bindings . NumUniformBuffers + + ;
2014-03-14 14:13:41 -04:00
}
const uint16 BytesPerComponent = 4 ;
2021-08-11 07:11:25 -04:00
FString GlobalIgnoreStrings [ ] =
{
TEXT ( " gl_LastFragDepthARM " ) ,
TEXT ( " ARM_shader_framebuffer_fetch_depth_stencil " ) ,
} ;
2014-03-14 14:13:41 -04:00
// Packed global uniforms
TMap < ANSICHAR , uint16 > PackedGlobalArraySize ;
2015-07-02 11:52:03 -04:00
for ( auto & PackedGlobal : CCHeader . PackedGlobals )
2014-03-14 14:13:41 -04:00
{
2021-08-11 07:11:25 -04:00
bool bIgnore = false ;
for ( uint32_t i = 0 ; i < UE_ARRAY_COUNT ( GlobalIgnoreStrings ) ; + + i )
{
if ( PackedGlobal . Name . StartsWith ( GlobalIgnoreStrings [ i ] ) )
{
bIgnore = true ;
break ;
}
}
if ( bIgnore )
continue ;
2022-04-14 15:46:20 -04:00
HandleReflectedGlobalConstantBufferMember (
PackedGlobal . Name ,
2015-07-02 11:52:03 -04:00
PackedGlobal . PackedType ,
2022-04-14 15:46:20 -04:00
PackedGlobal . Offset * BytesPerComponent ,
PackedGlobal . Count * BytesPerComponent ,
ShaderOutput
) ;
2014-03-14 14:13:41 -04:00
2015-07-02 11:52:03 -04:00
uint16 & Size = PackedGlobalArraySize . FindOrAdd ( PackedGlobal . PackedType ) ;
Size = FMath : : Max < uint16 > ( BytesPerComponent * ( PackedGlobal . Offset + PackedGlobal . Count ) , Size ) ;
2014-03-14 14:13:41 -04:00
}
// Packed Uniform Buffers
TMap < int , TMap < ANSICHAR , uint16 > > PackedUniformBuffersSize ;
2015-07-02 11:52:03 -04:00
for ( auto & PackedUB : CCHeader . PackedUBs )
2014-03-14 14:13:41 -04:00
{
2016-09-30 21:21:09 -04:00
checkf ( OutputTrueParameterNames ( ) = = false , TEXT ( " Unexpected Packed UBs used with a shader format that needs true parameter names - If this is hit, we need to figure out how to handle them " ) ) ;
2015-07-02 11:52:03 -04:00
UsedUniformBufferSlots [ PackedUB . Attribute . Index ] = true ;
2016-09-30 21:21:09 -04:00
if ( OutputTrueParameterNames ( ) )
{
BindingName [ 1 ] = ' b ' ;
// ???
}
else
{
2022-04-14 15:46:20 -04:00
HandleReflectedUniformBuffer ( PackedUB . Attribute . Name , PackedUB . Attribute . Index , ShaderOutput ) ;
2016-09-30 21:21:09 -04:00
}
Header . Bindings . NumUniformBuffers + + ;
2014-03-14 14:13:41 -04:00
2015-07-02 11:52:03 -04:00
// Nothing else...
//for (auto& Member : PackedUB.Members)
//{
//}
2014-03-14 14:13:41 -04:00
}
// Packed Uniform Buffers copy lists & setup sizes for each UB/Precision entry
enum EFlattenUBState
{
Unknown ,
GroupedUBs ,
FlattenedUBs ,
} ;
EFlattenUBState UBState = Unknown ;
2015-07-02 11:52:03 -04:00
for ( auto & PackedUBCopy : CCHeader . PackedUBCopies )
2014-03-14 14:13:41 -04:00
{
2015-07-02 11:52:03 -04:00
CrossCompiler : : FUniformBufferCopyInfo CopyInfo ;
CopyInfo . SourceUBIndex = PackedUBCopy . SourceUB ;
CopyInfo . SourceOffsetInFloats = PackedUBCopy . SourceOffset ;
CopyInfo . DestUBIndex = PackedUBCopy . DestUB ;
CopyInfo . DestUBTypeName = PackedUBCopy . DestPackedType ;
CopyInfo . DestUBTypeIndex = CrossCompiler : : PackedTypeNameToTypeIndex ( CopyInfo . DestUBTypeName ) ;
CopyInfo . DestOffsetInFloats = PackedUBCopy . DestOffset ;
CopyInfo . SizeInFloats = PackedUBCopy . Count ;
2014-03-14 14:13:41 -04:00
2015-07-02 11:52:03 -04:00
Header . UniformBuffersCopyInfo . Add ( CopyInfo ) ;
2014-03-14 14:13:41 -04:00
2015-07-02 11:52:03 -04:00
auto & UniformBufferSize = PackedUniformBuffersSize . FindOrAdd ( CopyInfo . DestUBIndex ) ;
uint16 & Size = UniformBufferSize . FindOrAdd ( CopyInfo . DestUBTypeName ) ;
Size = FMath : : Max < uint16 > ( BytesPerComponent * ( CopyInfo . DestOffsetInFloats + CopyInfo . SizeInFloats ) , Size ) ;
2014-03-14 14:13:41 -04:00
2015-07-02 11:52:03 -04:00
check ( UBState = = Unknown | | UBState = = GroupedUBs ) ;
2014-03-14 14:13:41 -04:00
UBState = GroupedUBs ;
}
2015-07-02 11:52:03 -04:00
for ( auto & PackedUBCopy : CCHeader . PackedUBGlobalCopies )
2014-03-14 14:13:41 -04:00
{
2015-07-02 11:52:03 -04:00
CrossCompiler : : FUniformBufferCopyInfo CopyInfo ;
CopyInfo . SourceUBIndex = PackedUBCopy . SourceUB ;
CopyInfo . SourceOffsetInFloats = PackedUBCopy . SourceOffset ;
CopyInfo . DestUBIndex = PackedUBCopy . DestUB ;
CopyInfo . DestUBTypeName = PackedUBCopy . DestPackedType ;
CopyInfo . DestUBTypeIndex = CrossCompiler : : PackedTypeNameToTypeIndex ( CopyInfo . DestUBTypeName ) ;
CopyInfo . DestOffsetInFloats = PackedUBCopy . DestOffset ;
CopyInfo . SizeInFloats = PackedUBCopy . Count ;
2014-03-14 14:13:41 -04:00
2015-07-02 11:52:03 -04:00
Header . UniformBuffersCopyInfo . Add ( CopyInfo ) ;
2014-03-14 14:13:41 -04:00
2015-07-02 11:52:03 -04:00
uint16 & Size = PackedGlobalArraySize . FindOrAdd ( CopyInfo . DestUBTypeName ) ;
Size = FMath : : Max < uint16 > ( BytesPerComponent * ( CopyInfo . DestOffsetInFloats + CopyInfo . SizeInFloats ) , Size ) ;
2014-03-14 14:13:41 -04:00
2015-07-02 11:52:03 -04:00
check ( UBState = = Unknown | | UBState = = FlattenedUBs ) ;
2014-03-14 14:13:41 -04:00
UBState = FlattenedUBs ;
}
Header . Bindings . bFlattenUB = ( UBState = = FlattenedUBs ) ;
// Setup Packed Array info
Header . Bindings . PackedGlobalArrays . Reserve ( PackedGlobalArraySize . Num ( ) ) ;
for ( auto Iterator = PackedGlobalArraySize . CreateIterator ( ) ; Iterator ; + + Iterator )
{
ANSICHAR TypeName = Iterator . Key ( ) ;
uint16 Size = Iterator . Value ( ) ;
Size = ( Size + 0xf ) & ( ~ 0xf ) ;
2014-07-15 13:25:14 -04:00
CrossCompiler : : FPackedArrayInfo Info ;
2014-03-14 14:13:41 -04:00
Info . Size = Size ;
Info . TypeName = TypeName ;
2014-07-15 13:25:14 -04:00
Info . TypeIndex = CrossCompiler : : PackedTypeNameToTypeIndex ( TypeName ) ;
2014-03-14 14:13:41 -04:00
Header . Bindings . PackedGlobalArrays . Add ( Info ) ;
}
// Setup Packed Uniform Buffers info
Header . Bindings . PackedUniformBuffers . Reserve ( PackedUniformBuffersSize . Num ( ) ) ;
for ( auto Iterator = PackedUniformBuffersSize . CreateIterator ( ) ; Iterator ; + + Iterator )
{
int BufferIndex = Iterator . Key ( ) ;
auto & ArraySizes = Iterator . Value ( ) ;
2014-07-15 13:25:14 -04:00
TArray < CrossCompiler : : FPackedArrayInfo > InfoArray ;
2014-03-14 14:13:41 -04:00
InfoArray . Reserve ( ArraySizes . Num ( ) ) ;
for ( auto IterSizes = ArraySizes . CreateIterator ( ) ; IterSizes ; + + IterSizes )
{
ANSICHAR TypeName = IterSizes . Key ( ) ;
uint16 Size = IterSizes . Value ( ) ;
Size = ( Size + 0xf ) & ( ~ 0xf ) ;
2014-07-15 13:25:14 -04:00
CrossCompiler : : FPackedArrayInfo Info ;
2014-03-14 14:13:41 -04:00
Info . Size = Size ;
Info . TypeName = TypeName ;
2014-07-15 13:25:14 -04:00
Info . TypeIndex = CrossCompiler : : PackedTypeNameToTypeIndex ( TypeName ) ;
2014-03-14 14:13:41 -04:00
InfoArray . Add ( Info ) ;
}
2020-02-22 17:01:54 -05:00
// Sort by TypeIndex as expected by eUB uloading code
InfoArray . Sort ( [ ] ( const CrossCompiler : : FPackedArrayInfo & A , const CrossCompiler : : FPackedArrayInfo & B )
{
return A . TypeIndex < B . TypeIndex ;
} ) ;
2014-03-14 14:13:41 -04:00
Header . Bindings . PackedUniformBuffers . Add ( InfoArray ) ;
}
// Then samplers.
2015-07-02 11:52:03 -04:00
for ( auto & Sampler : CCHeader . Samplers )
2014-03-14 14:13:41 -04:00
{
2016-09-30 21:21:09 -04:00
if ( OutputTrueParameterNames ( ) )
{
BindingName [ 1 ] = ' s ' ;
SetIndex ( BindingName , 2 , Sampler . Offset ) ;
BindingNameMap . Add ( BindingName , Sampler . Name ) ;
}
else
{
2022-04-14 15:46:20 -04:00
HandleReflectedShaderResource ( Sampler . Name , Sampler . Offset , Sampler . Count , ShaderOutput ) ;
2016-09-30 21:21:09 -04:00
}
2014-03-14 14:13:41 -04:00
2015-07-02 11:52:03 -04:00
Header . Bindings . NumSamplers = FMath : : Max < uint8 > (
Header . Bindings . NumSamplers ,
Sampler . Offset + Sampler . Count
) ;
for ( auto & SamplerState : Sampler . SamplerStates )
2014-03-14 14:13:41 -04:00
{
2016-09-30 21:21:09 -04:00
if ( OutputTrueParameterNames ( ) )
{
// add an entry for the sampler parameter as well
BindingNameMap . Add ( FString ( BindingName ) + TEXT ( " _samp " ) , SamplerState ) ;
}
else
{
2022-04-14 15:46:20 -04:00
HandleReflectedShaderSampler ( SamplerState , Sampler . Offset , Sampler . Count , ShaderOutput ) ;
2017-08-21 15:05:19 -04:00
}
2014-03-14 14:13:41 -04:00
}
2017-08-21 15:05:19 -04:00
}
2014-03-14 14:13:41 -04:00
// Then UAVs (images in GLSL)
2015-07-02 11:52:03 -04:00
for ( auto & UAV : CCHeader . UAVs )
2014-03-14 14:13:41 -04:00
{
2016-09-30 21:21:09 -04:00
if ( OutputTrueParameterNames ( ) )
{
// make the final name this will be in the shader
BindingName [ 1 ] = ' i ' ;
SetIndex ( BindingName , 2 , UAV . Offset ) ;
BindingNameMap . Add ( BindingName , UAV . Name ) ;
}
else
{
2022-04-14 15:46:20 -04:00
HandleReflectedShaderUAV ( UAV . Name , UAV . Offset , UAV . Count , ShaderOutput ) ;
2016-09-30 21:21:09 -04:00
}
2014-03-14 14:13:41 -04:00
2015-07-02 11:52:03 -04:00
Header . Bindings . NumUAVs = FMath : : Max < uint8 > (
Header . Bindings . NumSamplers ,
UAV . Offset + UAV . Count
) ;
2014-03-14 14:13:41 -04:00
}
2015-08-26 06:02:24 -04:00
Header . ShaderName = CCHeader . Name ;
2015-07-02 11:52:03 -04:00
2016-09-30 21:21:09 -04:00
// perform any post processing this frontend class may need to do
2017-06-09 17:44:13 -04:00
ShaderOutput . bSucceeded = PostProcessShaderSource ( Version , Frequency , USFSource , SourceLen + 1 - ( USFSource - InShaderSource ) , ParameterMap , BindingNameMap , ShaderOutput . Errors , ShaderInput ) ;
2016-09-30 21:21:09 -04:00
2014-06-05 16:38:54 -04:00
// Build the SRT for this shader.
{
// Build the generic SRT for this shader.
2015-10-06 15:59:09 -04:00
FShaderCompilerResourceTable GenericSRT ;
2020-12-07 17:42:32 -04:00
BuildResourceTableMapping ( ShaderInput . Environment . ResourceTableMap , ShaderInput . Environment . UniformBufferMap , UsedUniformBufferSlots , ShaderOutput . ParameterMap , GenericSRT ) ;
CullGlobalUniformBuffers ( ShaderInput . Environment . UniformBufferMap , ShaderOutput . ParameterMap ) ;
2014-06-05 16:38:54 -04:00
// Copy over the bits indicating which resource tables are active.
Header . Bindings . ShaderResourceTable . ResourceTableBits = GenericSRT . ResourceTableBits ;
Header . Bindings . ShaderResourceTable . ResourceTableLayoutHashes = GenericSRT . ResourceTableLayoutHashes ;
// Now build our token streams.
BuildResourceTableTokenStream ( GenericSRT . TextureMap , GenericSRT . MaxBoundResourceTable , Header . Bindings . ShaderResourceTable . TextureMap ) ;
BuildResourceTableTokenStream ( GenericSRT . ShaderResourceViewMap , GenericSRT . MaxBoundResourceTable , Header . Bindings . ShaderResourceTable . ShaderResourceViewMap ) ;
BuildResourceTableTokenStream ( GenericSRT . SamplerMap , GenericSRT . MaxBoundResourceTable , Header . Bindings . ShaderResourceTable . SamplerMap ) ;
BuildResourceTableTokenStream ( GenericSRT . UnorderedAccessViewMap , GenericSRT . MaxBoundResourceTable , Header . Bindings . ShaderResourceTable . UnorderedAccessViewMap ) ;
}
2016-09-30 21:21:09 -04:00
const int32 MaxSamplers = GetMaxSamplers ( Version ) ;
2014-03-14 14:13:41 -04:00
if ( Header . Bindings . NumSamplers > MaxSamplers )
{
ShaderOutput . bSucceeded = false ;
FShaderCompilerError * NewError = new ( ShaderOutput . Errors ) FShaderCompilerError ( ) ;
NewError - > StrippedErrorMessage =
FString : : Printf ( TEXT ( " shader uses %d samplers exceeding the limit of %d " ) ,
Header . Bindings . NumSamplers , MaxSamplers ) ;
}
2016-09-30 21:21:09 -04:00
else if ( ShaderOutput . bSucceeded )
2014-03-14 14:13:41 -04:00
{
2016-09-30 21:21:09 -04:00
// Write out the header
2015-09-25 17:34:00 -04:00
FMemoryWriter Ar ( ShaderOutput . ShaderCode . GetWriteAccess ( ) , true ) ;
2014-03-14 14:13:41 -04:00
Ar < < Header ;
2016-09-16 17:07:30 -04:00
2016-09-30 21:21:09 -04:00
if ( OptionalSerializeOutputAndReturnIfSerialized ( Ar ) = = false )
{
2018-06-26 08:42:47 -04:00
Ar . Serialize ( ( void * ) USFSource , SourceLen + 1 - ( USFSource - InShaderSource ) ) ;
2016-09-30 21:21:09 -04:00
ShaderOutput . bSucceeded = true ;
}
2017-08-21 15:05:19 -04:00
2018-06-26 08:42:47 -04:00
// extract final source code as requested by the Material Editor
if ( ShaderInput . ExtraSettings . bExtractShaderSource )
{
TArray < ANSICHAR > GlslCodeOriginal ;
GlslCodeOriginal . Append ( USFSource , FCStringAnsi : : Strlen ( USFSource ) + 1 ) ;
ShaderOutput . OptionalFinalShaderSource = FString ( GlslCodeOriginal . GetData ( ) ) ;
}
2021-08-16 23:18:23 -04:00
if ( ShaderInput . Environment . CompilerFlags . Contains ( CFLAG_ExtraShaderData ) )
2020-12-03 00:55:36 -04:00
{
ShaderOutput . ShaderCode . AddOptionalData ( FShaderCodeName : : Key , TCHAR_TO_UTF8 ( * ShaderInput . GenerateShaderName ( ) ) ) ;
}
2018-06-26 08:42:47 -04:00
// if available, attempt run an offline compilation and extract statistics
if ( ShaderInput . ExtraSettings . OfflineCompilerPath . Len ( ) > 0 )
{
CompileOffline ( ShaderInput , ShaderOutput , Version , USFSource ) ;
}
else
{
ShaderOutput . NumInstructions = 0 ;
}
2014-03-14 14:13:41 -04:00
ShaderOutput . NumTextureSamplers = Header . Bindings . NumSamplers ;
}
}
2016-09-30 21:21:09 -04:00
void FOpenGLFrontend : : ConvertOpenGLVersionFromGLSLVersion ( GLSLVersion InVersion , int & OutMajorVersion , int & OutMinorVersion )
2014-03-14 14:13:41 -04:00
{
switch ( InVersion )
{
2015-04-13 18:00:32 -04:00
case GLSL_150_ES3_1 :
2014-03-14 14:13:41 -04:00
OutMajorVersion = 3 ;
OutMinorVersion = 2 ;
break ;
2016-07-19 19:13:01 -04:00
case GLSL_ES3_1_ANDROID :
2014-03-14 14:13:41 -04:00
OutMajorVersion = 0 ;
OutMinorVersion = 0 ;
break ;
default :
// Invalid enum
check ( 0 ) ;
OutMajorVersion = 0 ;
OutMinorVersion = 0 ;
break ;
}
}
/**
* Precompile a GLSL shader.
* @param ShaderOutput - The precompiled shader.
* @param ShaderInput - The shader input.
* @param InPreprocessedShader - The preprocessed source code.
*/
2016-09-30 21:21:09 -04:00
void FOpenGLFrontend : : PrecompileShader ( FShaderCompilerOutput & ShaderOutput , const FShaderCompilerInput & ShaderInput , const ANSICHAR * ShaderSource , GLSLVersion Version , EHlslShaderFrequency Frequency )
2014-03-14 14:13:41 -04:00
{
check ( ShaderInput . Target . Frequency < SF_NumFrequencies ) ;
// Lookup the GL shader type.
GLenum GLFrequency = GLFrequencyTable [ ShaderInput . Target . Frequency ] ;
if ( GLFrequency = = GL_NONE )
{
ShaderOutput . bSucceeded = false ;
FShaderCompilerError * NewError = new ( ShaderOutput . Errors ) FShaderCompilerError ( ) ;
2015-07-02 11:52:03 -04:00
NewError - > StrippedErrorMessage = FString : : Printf ( TEXT ( " %s shaders not supported for use in OpenGL. " ) , CrossCompiler : : GetFrequencyName ( ( EShaderFrequency ) ShaderInput . Target . Frequency ) ) ;
2014-03-14 14:13:41 -04:00
return ;
}
2020-02-12 13:27:19 -05:00
// Create the shader with the preprocessed source code.
void * ContextPtr ;
void * PrevContextPtr ;
int MajorVersion = 0 ;
int MinorVersion = 0 ;
ConvertOpenGLVersionFromGLSLVersion ( Version , MajorVersion , MinorVersion ) ;
PlatformInitOpenGL ( ContextPtr , PrevContextPtr , MajorVersion , MinorVersion ) ;
GLint SourceLen = FCStringAnsi : : Strlen ( ShaderSource ) ;
GLuint Shader = glCreateShader ( GLFrequency ) ;
2014-03-14 14:13:41 -04:00
{
2020-02-12 13:27:19 -05:00
const GLchar * SourcePtr = ShaderSource ;
glShaderSource ( Shader , 1 , & SourcePtr , & SourceLen ) ;
2014-03-14 14:13:41 -04:00
}
2020-02-12 13:27:19 -05:00
// Compile and get results.
glCompileShader ( Shader ) ;
2014-03-14 14:13:41 -04:00
{
2020-02-12 13:27:19 -05:00
GLint CompileStatus ;
glGetShaderiv ( Shader , GL_COMPILE_STATUS , & CompileStatus ) ;
if ( CompileStatus = = GL_TRUE )
2014-03-14 14:13:41 -04:00
{
2020-02-12 13:27:19 -05:00
ShaderOutput . Target = ShaderInput . Target ;
BuildShaderOutput (
ShaderOutput ,
ShaderInput ,
ShaderSource ,
( int32 ) SourceLen ,
Version
) ;
2014-03-14 14:13:41 -04:00
}
2020-02-12 13:27:19 -05:00
else
2014-03-14 14:13:41 -04:00
{
2020-02-12 13:27:19 -05:00
GLint LogLength ;
glGetShaderiv ( Shader , GL_INFO_LOG_LENGTH , & LogLength ) ;
if ( LogLength > 1 )
2014-03-14 14:13:41 -04:00
{
2020-02-12 13:27:19 -05:00
TArray < ANSICHAR > RawCompileLog ;
FString CompileLog ;
TArray < FString > LogLines ;
RawCompileLog . Empty ( LogLength ) ;
RawCompileLog . AddZeroed ( LogLength ) ;
glGetShaderInfoLog ( Shader , LogLength , /*OutLength=*/ NULL , RawCompileLog . GetData ( ) ) ;
CompileLog = ANSI_TO_TCHAR ( RawCompileLog . GetData ( ) ) ;
CompileLog . ParseIntoArray ( LogLines , TEXT ( " \n " ) , true ) ;
for ( int32 Line = 0 ; Line < LogLines . Num ( ) ; + + Line )
{
ParseGlslError ( ShaderOutput . Errors , LogLines [ Line ] ) ;
}
if ( ShaderOutput . Errors . Num ( ) = = 0 )
{
FShaderCompilerError * NewError = new ( ShaderOutput . Errors ) FShaderCompilerError ( ) ;
NewError - > StrippedErrorMessage = FString : : Printf (
TEXT ( " GLSL source: \n %sGL compile log: %s \n " ) ,
ANSI_TO_TCHAR ( ShaderSource ) ,
ANSI_TO_TCHAR ( RawCompileLog . GetData ( ) )
) ;
}
2014-03-14 14:13:41 -04:00
}
else
{
2020-02-12 13:27:19 -05:00
FShaderCompilerError * NewError = new ( ShaderOutput . Errors ) FShaderCompilerError ( ) ;
NewError - > StrippedErrorMessage = TEXT ( " Shader compile failed without errors. " ) ;
2014-03-14 14:13:41 -04:00
}
2020-02-12 13:27:19 -05:00
ShaderOutput . bSucceeded = false ;
2014-03-14 14:13:41 -04:00
}
}
2020-02-12 13:27:19 -05:00
glDeleteShader ( Shader ) ;
PlatformReleaseOpenGL ( ContextPtr , PrevContextPtr ) ;
2014-03-14 14:13:41 -04:00
}
2016-09-30 21:21:09 -04:00
void FOpenGLFrontend : : SetupPerVersionCompilationEnvironment ( GLSLVersion Version , FShaderCompilerDefinitions & AdditionalDefines , EHlslCompileTarget & HlslCompilerTarget )
2020-10-29 13:38:15 -04:00
{
2014-03-14 14:13:41 -04:00
switch ( Version )
{
2016-07-19 19:13:01 -04:00
case GLSL_ES3_1_ANDROID :
AdditionalDefines . SetDefine ( TEXT ( " COMPILER_GLSL_ES3_1 " ) , 1 ) ;
AdditionalDefines . SetDefine ( TEXT ( " ES3_1_PROFILE " ) , 1 ) ;
HlslCompilerTarget = HCT_FeatureLevelES3_1 ;
break ;
2015-04-13 18:00:32 -04:00
case GLSL_150_ES3_1 :
AdditionalDefines . SetDefine ( TEXT ( " COMPILER_GLSL " ) , 1 ) ;
AdditionalDefines . SetDefine ( TEXT ( " ES3_1_PROFILE " ) , 1 ) ;
2019-05-23 00:36:32 -04:00
HlslCompilerTarget = HCT_FeatureLevelES3_1 ;
2015-04-13 18:00:32 -04:00
AdditionalDefines . SetDefine ( TEXT ( " row_major " ) , TEXT ( " " ) ) ;
break ;
2014-03-14 14:13:41 -04:00
default :
check ( 0 ) ;
}
2018-05-01 10:36:33 -04:00
AdditionalDefines . SetDefine ( TEXT ( " OPENGL_PROFILE " ) , 1 ) ;
2016-09-30 21:21:09 -04:00
}
uint32 FOpenGLFrontend : : GetMaxSamplers ( GLSLVersion Version )
{
2020-10-29 13:38:15 -04:00
return 16 ;
2016-09-30 21:21:09 -04:00
}
2021-11-07 23:43:01 -05:00
uint32 FOpenGLFrontend : : CalculateCrossCompilerFlags ( GLSLVersion Version , const bool bFullPrecisionInPS , const FShaderCompilerFlags & CompilerFlags )
2016-09-30 21:21:09 -04:00
{
2018-12-14 14:51:12 -05:00
uint32 CCFlags = HLSLCC_NoPreprocess | HLSLCC_PackUniforms | HLSLCC_DX11ClipSpace | HLSLCC_RetainSizes ;
2016-09-30 21:21:09 -04:00
2021-11-03 11:57:39 -04:00
if ( bFullPrecisionInPS )
2020-03-13 11:36:26 -04:00
{
CCFlags | = HLSLCC_UseFullPrecisionInPS ;
}
2020-09-24 00:43:27 -04:00
if ( CompilerFlags . Contains ( CFLAG_UseEmulatedUB ) )
2016-09-30 21:21:09 -04:00
{
CCFlags | = HLSLCC_FlattenUniformBuffers | HLSLCC_FlattenUniformBufferStructures ;
2019-03-21 14:30:39 -04:00
// Enabling HLSLCC_GroupFlattenedUniformBuffers, see FORT-159483.
CCFlags | = HLSLCC_GroupFlattenedUniformBuffers ;
2018-09-25 10:11:35 -04:00
CCFlags | = HLSLCC_ExpandUBMemberArrays ;
2016-09-30 21:21:09 -04:00
}
2018-09-25 10:11:35 -04:00
if ( CompilerFlags . Contains ( CFLAG_UsesExternalTexture ) )
2017-11-22 16:42:04 -05:00
{
CCFlags | = HLSLCC_UsesExternalTexture ;
}
2016-09-30 21:21:09 -04:00
return CCFlags ;
}
FGlslCodeBackend * FOpenGLFrontend : : CreateBackend ( GLSLVersion Version , uint32 CCFlags , EHlslCompileTarget HlslCompilerTarget )
{
2020-02-12 13:27:19 -05:00
return new FGlslCodeBackend ( CCFlags , HlslCompilerTarget ) ;
2016-09-30 21:21:09 -04:00
}
2020-06-23 18:40:00 -04:00
class FGlsl430LanguageSpec : public FGlslLanguageSpec
{
public :
FGlsl430LanguageSpec ( bool bInDefaultPrecisionIsHalf )
: FGlslLanguageSpec ( bInDefaultPrecisionIsHalf )
{ }
virtual bool EmulateStructuredWithTypedBuffers ( ) const override { return false ; }
} ;
2020-03-13 11:36:26 -04:00
FGlslLanguageSpec * FOpenGLFrontend : : CreateLanguageSpec ( GLSLVersion Version , bool bDefaultPrecisionIsHalf )
{
return new FGlslLanguageSpec ( bDefaultPrecisionIsHalf ) ;
2016-09-30 21:21:09 -04:00
}
2020-10-09 22:42:26 -04:00
# if DXC_SUPPORTED
2021-09-02 16:41:03 -04:00
static const ANSICHAR * GetFrequencyPrefix ( EShaderFrequency Frequency )
2019-09-14 09:45:25 -04:00
{
2020-10-09 22:42:26 -04:00
switch ( Frequency )
{
2021-09-02 16:41:03 -04:00
case SF_Vertex : return " v " ;
case SF_Pixel : return " p " ;
case SF_Geometry : return " g " ;
case SF_Compute : return " c " ;
default : return " " ;
2020-10-09 22:42:26 -04:00
}
}
2019-09-14 09:45:25 -04:00
2021-08-11 07:11:25 -04:00
struct PackedUBMemberInfo
{
std : : string Name ;
2021-09-08 13:00:48 -04:00
std : : string SanitizedName ;
2021-08-11 07:11:25 -04:00
std : : string TypeQualifier ;
uint32_t SrcOffset ;
uint32_t DestOffset ;
uint32_t SrcSizeInFloats ;
uint32_t DestSizeInFloats ;
} ;
void WritePackedUBHeader ( CrossCompiler : : FHlslccHeaderWriter & CCHeaderWriter , const TMap < uint32_t , TArray < PackedUBMemberInfo > > & UBMemberInfo , const TMap < uint32 , std : : string > & UBNames )
{
bool bFirst = true ;
bool bNeedsHeader = true ;
2021-08-11 07:39:01 -04:00
for ( const auto & Pair : UBNames )
2021-08-11 07:11:25 -04:00
{
FString Name ( Pair . Value . c_str ( ) ) ;
CCHeaderWriter . WritePackedUB ( Name , Pair . Key ) ;
}
2021-08-11 07:39:01 -04:00
for ( const auto & Pair : UBMemberInfo )
2021-08-11 07:11:25 -04:00
{
FString UBName ( UBNames [ Pair . Key ] . c_str ( ) ) ;
for ( const PackedUBMemberInfo & MemberInfo : UBMemberInfo [ Pair . Key ] )
{
2021-09-08 13:00:48 -04:00
CCHeaderWriter . WritePackedUBField ( UBName , UTF8_TO_TCHAR ( MemberInfo . SanitizedName . c_str ( ) ) , MemberInfo . SrcOffset , MemberInfo . DestSizeInFloats * sizeof ( float ) ) ;
CCHeaderWriter . WritePackedUBCopy ( Pair . Key , MemberInfo . SrcOffset / sizeof ( float ) , Pair . Key , MemberInfo . TypeQualifier [ 0 ] , MemberInfo . DestOffset / sizeof ( float ) , MemberInfo . DestSizeInFloats , true ) ;
2021-08-11 07:11:25 -04:00
}
}
}
void GetSpvVarQualifier ( const SpvReflectBlockVariable & Member , FString & Out )
{
auto const type = * Member . type_description ;
const uint32 MbrSize = Member . size / sizeof ( float ) ;
FString TypeQualifier ;
uint32_t masked_type = type . type_flags & 0xF ;
switch ( masked_type )
{
default : checkf ( false , TEXT ( " unsupported component type %d " ) , masked_type ) ; break ;
case SPV_REFLECT_TYPE_FLAG_BOOL :
case SPV_REFLECT_TYPE_FLAG_INT :
Out = ( type . traits . numeric . scalar . signedness ? TEXT ( " i " ) : TEXT ( " u " ) ) ;
break ;
case SPV_REFLECT_TYPE_FLAG_FLOAT :
2021-11-03 09:25:57 -04:00
if ( Member . decoration_flags & SPV_REFLECT_DECORATION_RELAXED_PRECISION )
{
Out = TEXT ( " m " ) ;
}
else
{
Out = TEXT ( " h " ) ;
}
2021-08-11 07:11:25 -04:00
break ;
}
}
// Adds a member to ne included in the PackedUB structures and generates the #define for readability in glsl
2022-02-09 18:32:08 -05:00
void AddMemberToPackedUB ( const std : : string & FrequencyPrefix ,
const SpvReflectBlockVariable & Member ,
const std : : string & UBName ,
int32_t Index ,
TMap < FString , uint32 > & Offsets ,
TArray < PackedUBMemberInfo > & MemberInfos ,
TArray < std : : string > & Remap ,
TArray < std : : string > & Arrays )
2021-08-11 07:11:25 -04:00
{
std : : string ArrayName ;
const uint32 MbrSize = Member . size / sizeof ( float ) ;
FString TypeQualifier ;
GetSpvVarQualifier ( Member , TypeQualifier ) ;
2021-09-08 13:00:48 -04:00
std : : string SanitizedName = Member . name ;
std : : replace ( SanitizedName . begin ( ) , SanitizedName . end ( ) , ' . ' , ' _ ' ) ;
2021-08-11 07:11:25 -04:00
uint32 & Offset = Offsets . FindOrAdd ( TypeQualifier ) ;
2022-02-09 18:32:08 -05:00
2021-08-11 07:11:25 -04:00
auto const type = * Member . type_description ;
bool const bArray = type . traits . array . dims_count > 0 ;
bool const bGlobals = Index = = - 1 ;
std : : string Name = " #define " ;
if ( bGlobals )
{
Name + = " _Globals_ " ;
}
std : : string OffsetString = std : : to_string ( Offset ) ;
2021-09-08 13:00:48 -04:00
Name + = SanitizedName ;
2021-08-11 07:11:25 -04:00
PackedUBMemberInfo & MemberInfo = MemberInfos . AddDefaulted_GetRef ( ) ;
MemberInfo . Name = Member . name ;
2021-09-08 13:00:48 -04:00
MemberInfo . SanitizedName = SanitizedName ;
2021-08-11 07:11:25 -04:00
MemberInfo . TypeQualifier = TCHAR_TO_UTF8 ( * TypeQualifier ) ;
MemberInfo . SrcOffset = Member . offset ;
MemberInfo . DestOffset = Offset * 4 * sizeof ( float ) ;
MemberInfo . SrcSizeInFloats = Member . size / sizeof ( float ) ;
2022-02-09 18:32:08 -05:00
MemberInfo . DestSizeInFloats = Member . size / sizeof ( float ) ;
2021-08-11 07:11:25 -04:00
if ( bArray )
{
if ( bGlobals )
{
2021-09-08 13:00:48 -04:00
ArrayName = UBName + SanitizedName ;
2021-08-11 07:11:25 -04:00
}
else
{
2021-09-08 13:00:48 -04:00
ArrayName = SanitizedName ;
2021-08-11 07:11:25 -04:00
}
Name + = " (Offset) " ;
2021-10-12 10:56:02 -04:00
if ( type . op = = SpvOpTypeMatrix | | ( type . traits . numeric . matrix . column_count = = 4 & & type . traits . numeric . matrix . row_count = = 4 ) )
2021-08-11 07:11:25 -04:00
{
OffsetString + = " + (int(Offset) * 4) " ;
}
else
{
OffsetString + = " + int(Offset) " ;
}
}
Name + = " ( " ;
std : : string UniformPrefix = FrequencyPrefix ;
if ( ! bGlobals )
{
UniformPrefix + = std : : string ( " c " ) + std : : to_string ( Index ) ;
}
else
{
UniformPrefix + = " u " ;
}
2021-10-12 10:56:02 -04:00
if ( type . op = = SpvOpTypeMatrix | | ( type . traits . numeric . matrix . column_count = = 4 & & type . traits . numeric . matrix . row_count = = 4 ) )
2021-08-11 07:11:25 -04:00
{
if ( ( type . traits . numeric . matrix . column_count = = 4 & & type . traits . numeric . matrix . row_count = = 4 ) )
{
Name + = " mat4( " ;
}
else
{
2021-08-11 07:55:27 -04:00
std : : string Buff = " mat " + std : : to_string ( type . traits . numeric . matrix . column_count ) + " x " + std : : to_string ( type . traits . numeric . matrix . row_count ) + " ( " ;
Name + = Buff ;
2021-08-11 07:11:25 -04:00
}
2022-05-31 09:21:55 -04:00
for ( uint32_t i = 0 ; i < type . traits . numeric . matrix . column_count ; + + i )
2021-08-11 07:11:25 -04:00
{
if ( i > 0 )
{
Name + = " , " ;
}
Name + = UniformPrefix ;
Name + = " _ " ;
Name + = TCHAR_TO_UTF8 ( * TypeQualifier ) ;
2021-08-11 07:55:27 -04:00
std : : string Buff = " [ " + OffsetString + " + " + std : : to_string ( i ) + " ] " ;
Name + = Buff ;
2021-08-11 07:11:25 -04:00
2022-05-31 09:21:55 -04:00
switch ( type . traits . numeric . matrix . row_count )
2021-08-11 07:11:25 -04:00
{
case 0 :
case 1 :
Name + = " .x " ;
break ;
case 2 :
Name + = " .xy " ;
break ;
case 3 :
Name + = " .xyz " ;
break ;
case 4 :
default :
Name + = " .xyzw " ;
break ;
}
}
Name + = " ) " ;
}
else
{
Name + = UniformPrefix ;
Name + = " _ " ;
Name + = TCHAR_TO_UTF8 ( * TypeQualifier ) ;
Name + = " [ " ;
Name + = OffsetString ;
2022-02-09 18:32:08 -05:00
Name + = " ] " ;
2021-08-11 07:11:25 -04:00
switch ( type . traits . numeric . vector . component_count )
{
case 0 :
case 1 :
2022-02-09 18:32:08 -05:00
Name + = " .x " ;
2021-08-11 07:11:25 -04:00
break ;
case 2 :
2022-02-09 18:32:08 -05:00
Name + = " .xy " ;
2021-08-11 07:11:25 -04:00
break ;
case 3 :
2022-02-09 18:32:08 -05:00
Name + = " .xyz " ;
2021-08-11 07:11:25 -04:00
break ;
case 4 :
default :
break ;
}
}
Name + = " ) \n " ;
if ( bArray )
{
Arrays . Add ( ArrayName ) ;
}
Remap . Add ( Name ) ;
Offset + = Align ( MbrSize , 4 ) / 4 ;
}
2022-02-09 18:32:08 -05:00
void GetPackedUniformString ( std : : string & OutputString , const std : : string & UniformPrefix , const FString & Key , uint32_t Index )
2021-09-08 13:00:48 -04:00
{
if ( Key = = TEXT ( " u " ) )
{
OutputString = " uniform uvec4 " ;
OutputString + = UniformPrefix ;
OutputString + = " _u[ " ;
OutputString + = std : : to_string ( Index ) ;
OutputString + = " ]; \n " ;
}
else if ( Key = = TEXT ( " i " ) )
{
OutputString = " uniform ivec4 " ;
OutputString + = UniformPrefix ;
OutputString + = " _i[ " ;
OutputString + = std : : to_string ( Index ) ;
OutputString + = " ]; \n " ;
}
else if ( Key = = TEXT ( " h " ) )
{
OutputString = " uniform highp vec4 " ;
OutputString + = UniformPrefix ;
OutputString + = " _h[ " ;
OutputString + = std : : to_string ( Index ) ;
OutputString + = " ]; \n " ;
}
2021-11-03 09:25:57 -04:00
else if ( Key = = TEXT ( " m " ) )
{
OutputString = " uniform mediump vec4 " ;
OutputString + = UniformPrefix ;
OutputString + = " _m[ " ;
OutputString + = std : : to_string ( Index ) ;
OutputString + = " ]; \n " ;
}
2021-09-08 13:00:48 -04:00
}
2022-02-09 18:32:08 -05:00
struct ReflectionData
{
TArray < FString > Textures ;
TArray < FString > Samplers ;
TArray < std : : string > UAVs ;
TArray < std : : string > StructuredBuffers ;
std : : map < std : : string , std : : string > UniformVarNames ;
2022-03-02 15:20:27 -05:00
std : : map < std : : string , std : : vector < std : : string > > UniformVarMemberNames ;
2022-02-09 18:32:08 -05:00
TMap < FString , uint32 > GlobalOffsets ;
TArray < std : : string > GlobalRemap ;
TArray < std : : string > GlobalArrays ;
TArray < PackedUBMemberInfo > GlobalMemberInfos ;
TMap < uint32 , TMap < FString , uint32 > > PackedUBOffsets ;
TMap < uint32 , TArray < std : : string > > PackedUBRemap ;
TMap < uint32 , TArray < std : : string > > PackedUBArrays ;
TMap < uint32 , TArray < PackedUBMemberInfo > > PackedUBMemberInfos ;
TMap < uint32 , std : : string > PackedUBNames ;
TArray < FString > InputVarNames ;
TArray < FString > OutputVarNames ;
} ;
2022-03-02 15:20:27 -05:00
void ParseReflectionData ( const FShaderCompilerInput & ShaderInput , CrossCompiler : : FHlslccHeaderWriter & CCHeaderWriter , ReflectionData & ReflectionOut , TArray < uint32 > & SpirvData ,
spv_reflect : : ShaderModule & Reflection , const ANSICHAR * SPIRV_DummySamplerName , const EShaderFrequency Frequency , bool bEmulatedUBs )
2022-02-09 18:32:08 -05:00
{
const ANSICHAR * FrequencyPrefix = GetFrequencyPrefix ( Frequency ) ;
check ( Reflection . GetResult ( ) = = SPV_REFLECT_RESULT_SUCCESS ) ;
SpvReflectResult SPVRResult = SPV_REFLECT_RESULT_NOT_READY ;
TArray < SpvReflectBlockVariable * > ConstantBindings ;
const uint32 GlobalSetId = 32 ;
FSpirvReflectBindings ReflectionBindings ;
ReflectionBindings . GatherDescriptorBindings ( Reflection ) ;
uint32 BufferIndices = 0xffffffff ;
uint32 UAVIndices = 0xffffffff ;
uint32 TextureIndices = 0xffffffff ;
uint32 UBOIndices = 0xffffffff ;
uint32 SamplerIndices = 0xffffffff ;
uint32_t PackedUBIndex = 0 ;
for ( auto const & Binding : ReflectionBindings . TBufferUAVs )
{
check ( UAVIndices ) ;
uint32 Index = FPlatformMath : : CountTrailingZeros ( UAVIndices ) ;
// UAVs always claim all slots so we don't have conflicts as D3D expects 0-7
BufferIndices & = ~ ( 1 < < Index ) ;
TextureIndices & = ~ ( 1llu < < uint64 ( Index ) ) ;
UAVIndices & = ~ ( 1 < < Index ) ;
CCHeaderWriter . WriteUAV ( UTF8_TO_TCHAR ( Binding - > name ) , Index ) ;
SPVRResult = Reflection . ChangeDescriptorBindingNumbers ( Binding , Index , GlobalSetId ) ;
check ( SPVRResult = = SPV_REFLECT_RESULT_SUCCESS ) ;
ReflectionOut . UAVs . Add ( Binding - > name ) ;
}
for ( auto const & Binding : ReflectionBindings . SBufferUAVs )
{
check ( UAVIndices ) ;
uint32 Index = FPlatformMath : : CountTrailingZeros ( UAVIndices ) ;
// UAVs always claim all slots so we don't have conflicts as D3D expects 0-7
BufferIndices & = ~ ( 1 < < Index ) ;
TextureIndices & = ~ ( 1llu < < uint64 ( Index ) ) ;
UAVIndices & = ~ ( 1 < < Index ) ;
CCHeaderWriter . WriteUAV ( UTF8_TO_TCHAR ( Binding - > name ) , Index ) ;
ReflectionOut . StructuredBuffers . Add ( Binding - > name ) ;
SPVRResult = Reflection . ChangeDescriptorBindingNumbers ( Binding , Index , GlobalSetId ) ;
check ( SPVRResult = = SPV_REFLECT_RESULT_SUCCESS ) ;
}
for ( auto const & Binding : ReflectionBindings . TextureUAVs )
{
check ( UAVIndices ) ;
uint32 Index = FPlatformMath : : CountTrailingZeros ( UAVIndices ) ;
// UAVs always claim all slots so we don't have conflicts as D3D expects 0-7
// For texture2d this allows us to emulate atomics with buffers
BufferIndices & = ~ ( 1 < < Index ) ;
TextureIndices & = ~ ( 1llu < < uint64 ( Index ) ) ;
UAVIndices & = ~ ( 1 < < Index ) ;
CCHeaderWriter . WriteUAV ( UTF8_TO_TCHAR ( Binding - > name ) , Index ) ;
SPVRResult = Reflection . ChangeDescriptorBindingNumbers ( Binding , Index , GlobalSetId ) ;
check ( SPVRResult = = SPV_REFLECT_RESULT_SUCCESS ) ;
ReflectionOut . UAVs . Add ( Binding - > name ) ;
}
for ( auto const & Binding : ReflectionBindings . TBufferSRVs )
{
check ( TextureIndices ) ;
uint32 Index = FPlatformMath : : CountTrailingZeros ( TextureIndices ) ;
// No support for 3-component types in dxc/SPIRV/MSL - need to expose my workarounds there too
TextureIndices & = ~ ( 1llu < < uint64 ( Index ) ) ;
ReflectionOut . Textures . Add ( UTF8_TO_TCHAR ( Binding - > name ) ) ;
SPVRResult = Reflection . ChangeDescriptorBindingNumbers ( Binding , Index , GlobalSetId ) ;
check ( SPVRResult = = SPV_REFLECT_RESULT_SUCCESS ) ;
}
for ( int32_t SBufferIndex = ReflectionBindings . SBufferSRVs . Num ( ) - 1 ; SBufferIndex > = 0 ; SBufferIndex - - )
{
auto Binding = ReflectionBindings . SBufferSRVs [ SBufferIndex ] ;
check ( BufferIndices ) ;
uint32 Index = FPlatformMath : : CountTrailingZeros ( BufferIndices ) ;
BufferIndices & = ~ ( 1 < < Index ) ;
SPVRResult = Reflection . ChangeDescriptorBindingNumbers ( Binding , Index , GlobalSetId ) ;
check ( SPVRResult = = SPV_REFLECT_RESULT_SUCCESS ) ;
CCHeaderWriter . WriteUAV ( UTF8_TO_TCHAR ( Binding - > name ) , Index ) ;
ReflectionOut . StructuredBuffers . Add ( Binding - > name ) ;
}
2022-03-02 15:20:27 -05:00
TArray < const SpvReflectDescriptorBinding * > RealUniformBuffers ;
2022-02-09 18:32:08 -05:00
for ( auto const & Binding : ReflectionBindings . UniformBuffers )
{
// Global uniform buffer - handled specially as we care about the internal layout
if ( strstr ( Binding - > name , " $Globals " ) )
{
TMap < FString , uint32_t > GlobalOffsetSizes ;
for ( uint32 i = 0 ; i < Binding - > block . member_count ; i + + )
{
SpvReflectBlockVariable & member = Binding - > block . members [ i ] ;
FString TypeQualifier ;
GetSpvVarQualifier ( member , TypeQualifier ) ;
uint32_t & GlobalOffsetSize = GlobalOffsetSizes . FindOrAdd ( TypeQualifier ) ;
if ( strstr ( member . name , " gl_ " ) | | ! strcmp ( member . name , " ARM_shader_framebuffer_fetch " ) | | ! strcmp ( member . name , " ARM_shader_framebuffer_fetch_depth_stencil " ) )
{
continue ;
}
bool bHalfPrecision = member . decoration_flags & SPV_REFLECT_DECORATION_RELAXED_PRECISION ;
CCHeaderWriter . WritePackedGlobal ( ANSI_TO_TCHAR ( member . name ) , CrossCompiler : : FHlslccHeaderWriter : : EncodePackedGlobalType ( * ( member . type_description ) , bHalfPrecision ) , GlobalOffsetSize , member . size ) ;
GlobalOffsetSize + = Align ( member . size , 16 ) ;
AddMemberToPackedUB ( FrequencyPrefix ,
member ,
" _Globals_ " ,
- 1 ,
ReflectionOut . GlobalOffsets ,
ReflectionOut . GlobalMemberInfos ,
ReflectionOut . GlobalRemap ,
ReflectionOut . GlobalArrays ) ;
}
}
else
{
2022-04-12 08:41:13 -04:00
const FUniformBufferEntry * UniformBufferEntry = ShaderInput . Environment . UniformBufferMap . Find ( Binding - > name ) ;
if ( bEmulatedUBs & & ( UniformBufferEntry = = nullptr | | ! UniformBufferEntry - > bNoEmulatedUniformBuffer ) )
2022-02-09 18:32:08 -05:00
{
2022-03-02 15:20:27 -05:00
check ( UBOIndices ) ;
uint32 Index = FPlatformMath : : CountTrailingZeros ( UBOIndices ) ;
UBOIndices & = ~ ( 1 < < Index ) ;
2022-02-09 18:32:08 -05:00
2022-03-02 15:20:27 -05:00
ReflectionOut . PackedUBOffsets . Add ( Index ) ;
ReflectionOut . PackedUBRemap . Add ( Index ) ;
ReflectionOut . PackedUBArrays . Add ( Index ) ;
ReflectionOut . PackedUBMemberInfos . Add ( Index ) ;
ReflectionOut . PackedUBNames . Add ( Index , std : : string ( Binding - > name ) ) ;
2022-02-09 18:32:08 -05:00
for ( uint32 i = 0 ; i < Binding - > block . member_count ; i + + )
{
SpvReflectBlockVariable & member = Binding - > block . members [ i ] ;
std : : string UBName = " _ " + std : : string ( Binding - > name ) + " _ " ;
if ( member . type_description - > type_flags & SPV_REFLECT_TYPE_FLAG_STRUCT )
{
for ( uint32 n = 0 ; n < member . member_count ; n + + )
{
// Clone struct member and rename it for struct
SpvReflectBlockVariable StructMember = member . members [ n ] ;
std : : string StructMemberName = std : : string ( member . name ) + " . " + std : : string ( StructMember . name ) ;
StructMember . name = StructMemberName . c_str ( ) ;
AddMemberToPackedUB ( FrequencyPrefix ,
StructMember ,
UBName ,
2022-03-02 15:20:27 -05:00
Index ,
ReflectionOut . PackedUBOffsets [ Index ] ,
ReflectionOut . PackedUBMemberInfos [ Index ] ,
ReflectionOut . PackedUBRemap [ Index ] ,
ReflectionOut . PackedUBArrays [ Index ] ) ;
2022-02-09 18:32:08 -05:00
}
}
else
{
AddMemberToPackedUB ( FrequencyPrefix ,
member ,
UBName ,
2022-03-02 15:20:27 -05:00
Index ,
ReflectionOut . PackedUBOffsets [ Index ] ,
ReflectionOut . PackedUBMemberInfos [ Index ] ,
ReflectionOut . PackedUBRemap [ Index ] ,
ReflectionOut . PackedUBArrays [ Index ] ) ;
2022-02-09 18:32:08 -05:00
}
}
2022-03-02 15:20:27 -05:00
SPVRResult = Reflection . ChangeDescriptorBindingNumbers ( Binding , Index , GlobalSetId ) ;
check ( SPVRResult = = SPV_REFLECT_RESULT_SUCCESS ) ;
2022-02-09 18:32:08 -05:00
}
else
{
2022-03-02 15:20:27 -05:00
RealUniformBuffers . Add ( Binding ) ;
2022-02-09 18:32:08 -05:00
}
}
2022-03-02 15:20:27 -05:00
}
//Always write the real uniform buffers after the emulated because OpenGLShaders expects emulated to be in consecutive slots
for ( auto const & Binding : RealUniformBuffers )
{
uint32 Index = FPlatformMath : : CountTrailingZeros ( UBOIndices ) ;
UBOIndices & = ~ ( 1 < < Index ) ;
std : : string OldName = Binding - > name ;
std : : string NewName = FrequencyPrefix ;
NewName + = " b " ;
NewName + = std : : to_string ( Index ) ;
ReflectionOut . UniformVarNames [ OldName ] = NewName ;
// Regular uniform buffer - we only care about the binding index
CCHeaderWriter . WriteUniformBlock ( UTF8_TO_TCHAR ( Binding - > name ) , Index ) ;
ReflectionOut . UniformVarMemberNames . insert ( { OldName , { } } ) ;
for ( uint32 i = 0 ; i < Binding - > block . member_count ; i + + )
{
SpvReflectBlockVariable & member = Binding - > block . members [ i ] ;
ReflectionOut . UniformVarMemberNames [ OldName ] . push_back ( member . name ) ;
}
2022-02-09 18:32:08 -05:00
SPVRResult = Reflection . ChangeDescriptorBindingNumbers ( Binding , Index , GlobalSetId ) ;
check ( SPVRResult = = SPV_REFLECT_RESULT_SUCCESS ) ;
}
WritePackedUBHeader ( CCHeaderWriter , ReflectionOut . PackedUBMemberInfos , ReflectionOut . PackedUBNames ) ;
for ( auto const & Binding : ReflectionBindings . TextureSRVs )
{
check ( TextureIndices ) ;
uint32 Index = FPlatformMath : : CountTrailingZeros64 ( TextureIndices ) ;
TextureIndices & = ~ ( 1llu < < uint64 ( Index ) ) ;
ReflectionOut . Textures . Add ( UTF8_TO_TCHAR ( Binding - > name ) ) ;
SPVRResult = Reflection . ChangeDescriptorBindingNumbers ( Binding , Index , GlobalSetId ) ;
check ( SPVRResult = = SPV_REFLECT_RESULT_SUCCESS ) ;
}
for ( auto const & Binding : ReflectionBindings . Samplers )
{
check ( SamplerIndices ) ;
uint32 Index = FPlatformMath : : CountTrailingZeros ( SamplerIndices ) ;
SamplerIndices & = ~ ( 1 < < Index ) ;
ReflectionOut . Samplers . Add ( UTF8_TO_TCHAR ( Binding - > name ) ) ;
SPVRResult = Reflection . ChangeDescriptorBindingNumbers ( Binding , Index , GlobalSetId ) ;
check ( SPVRResult = = SPV_REFLECT_RESULT_SUCCESS ) ;
}
// Spirv-cross can add a dummy sampler for glsl which isn't in the reflection bindings
ReflectionOut . Samplers . Add ( SPIRV_DummySamplerName ) ;
{
uint32 Count = 0 ;
SPVRResult = Reflection . EnumeratePushConstantBlocks ( & Count , nullptr ) ;
check ( SPVRResult = = SPV_REFLECT_RESULT_SUCCESS ) ;
ConstantBindings . SetNum ( Count ) ;
SPVRResult = Reflection . EnumeratePushConstantBlocks ( & Count , ConstantBindings . GetData ( ) ) ;
check ( SPVRResult = = SPV_REFLECT_RESULT_SUCCESS ) ;
if ( Count > 0 )
{
for ( auto const & Var : ConstantBindings )
{
// Global uniform buffer - handled specially as we care about the internal layout
if ( strstr ( Var - > name , " $Globals " ) )
{
TMap < FString , uint32_t > GlobalOffsetSizes ;
for ( uint32 i = 0 ; i < Var - > member_count ; i + + )
{
SpvReflectBlockVariable & member = Var - > members [ i ] ;
FString TypeQualifier ;
GetSpvVarQualifier ( member , TypeQualifier ) ;
uint32_t & GlobalOffsetSize = GlobalOffsetSizes . FindOrAdd ( TypeQualifier ) ;
if ( ! strcmp ( member . name , " gl_FragColor " ) | | ! strcmp ( member . name , " gl_LastFragColorARM " ) | | ! strcmp ( member . name , " gl_LastFragDepthARM " ) | | ! strcmp ( member . name , " ARM_shader_framebuffer_fetch " ) | | ! strcmp ( member . name , " ARM_shader_framebuffer_fetch_depth_stencil " ) )
{
continue ;
}
bool bHalfPrecision = member . decoration_flags & SPV_REFLECT_DECORATION_RELAXED_PRECISION ;
CCHeaderWriter . WritePackedGlobal ( ANSI_TO_TCHAR ( member . name ) , CrossCompiler : : FHlslccHeaderWriter : : EncodePackedGlobalType ( * ( member . type_description ) , bHalfPrecision ) , GlobalOffsetSize , member . size ) ;
GlobalOffsetSize + = Align ( member . size , 16 ) ;
AddMemberToPackedUB ( FrequencyPrefix ,
member ,
" _Globals_ " ,
- 1 ,
ReflectionOut . GlobalOffsets ,
ReflectionOut . GlobalMemberInfos ,
ReflectionOut . GlobalRemap ,
ReflectionOut . GlobalArrays ) ;
}
}
}
}
}
{
uint32 AssignedInputs = 0 ;
ReflectionBindings . GatherOutputAttributes ( Reflection ) ;
for ( SpvReflectInterfaceVariable * Var : ReflectionBindings . OutputAttributes )
{
if ( Var - > storage_class = = SpvStorageClassOutput & & Var - > built_in = = - 1 & & ! CrossCompiler : : FShaderConductorContext : : IsIntermediateSpirvOutputVariable ( Var - > name ) )
{
if ( Frequency = = SF_Pixel & & strstr ( Var - > name , " SV_Target " ) )
{
FString TypeQualifier ;
auto const type = * Var - > type_description ;
uint32_t masked_type = type . type_flags & 0xF ;
switch ( masked_type ) {
default : checkf ( false , TEXT ( " unsupported component type %d " ) , masked_type ) ; break ;
case SPV_REFLECT_TYPE_FLAG_BOOL : TypeQualifier = TEXT ( " b " ) ; break ;
case SPV_REFLECT_TYPE_FLAG_INT : TypeQualifier = ( type . traits . numeric . scalar . signedness ? TEXT ( " i " ) : TEXT ( " u " ) ) ; break ;
case SPV_REFLECT_TYPE_FLAG_FLOAT : TypeQualifier = ( type . traits . numeric . scalar . width = = 32 ? TEXT ( " f " ) : TEXT ( " h " ) ) ; break ;
}
if ( type . type_flags & SPV_REFLECT_TYPE_FLAG_MATRIX )
{
TypeQualifier + = FString : : Printf ( TEXT ( " %d%d " ) , type . traits . numeric . matrix . row_count , type . traits . numeric . matrix . column_count ) ;
}
else if ( type . type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR )
{
TypeQualifier + = FString : : Printf ( TEXT ( " %d " ) , type . traits . numeric . vector . component_count ) ;
}
else
{
TypeQualifier + = TEXT ( " 1 " ) ;
}
FString Name = ANSI_TO_TCHAR ( Var - > name ) ;
Name . ReplaceInline ( TEXT ( " . " ) , TEXT ( " _ " ) ) ;
ReflectionOut . OutputVarNames . Add ( Name ) ;
CCHeaderWriter . WriteOutputAttribute ( TEXT ( " out_Target " ) , * TypeQualifier , Var - > location , /*bLocationPrefix:*/ true , /*bLocationSuffix:*/ true ) ;
}
else
{
unsigned Location = Var - > location ;
unsigned SemanticIndex = Location ;
check ( Var - > semantic ) ;
unsigned i = ( unsigned ) strlen ( Var - > semantic ) ;
check ( i ) ;
while ( isdigit ( ( unsigned char ) ( Var - > semantic [ i - 1 ] ) ) )
{
i - - ;
}
if ( i < strlen ( Var - > semantic ) )
{
SemanticIndex = ( unsigned ) atoi ( Var - > semantic + i ) ;
if ( Location ! = SemanticIndex )
{
Location = SemanticIndex ;
}
}
while ( ( 1 < < Location ) & AssignedInputs )
{
Location + + ;
}
if ( Location ! = Var - > location )
{
SPVRResult = Reflection . ChangeOutputVariableLocation ( Var , Location ) ;
check ( SPVRResult = = SPV_REFLECT_RESULT_SUCCESS ) ;
}
uint32 ArrayCount = 1 ;
for ( uint32 Dim = 0 ; Dim < Var - > array . dims_count ; Dim + + )
{
ArrayCount * = Var - > array . dims [ Dim ] ;
}
FString TypeQualifier ;
auto const type = * Var - > type_description ;
uint32_t masked_type = type . type_flags & 0xF ;
switch ( masked_type ) {
default : checkf ( false , TEXT ( " unsupported component type %d " ) , masked_type ) ; break ;
case SPV_REFLECT_TYPE_FLAG_BOOL : TypeQualifier = TEXT ( " b " ) ; break ;
case SPV_REFLECT_TYPE_FLAG_INT : TypeQualifier = ( type . traits . numeric . scalar . signedness ? TEXT ( " i " ) : TEXT ( " u " ) ) ; break ;
case SPV_REFLECT_TYPE_FLAG_FLOAT : TypeQualifier = ( type . traits . numeric . scalar . width = = 32 ? TEXT ( " f " ) : TEXT ( " h " ) ) ; break ;
}
if ( type . type_flags & SPV_REFLECT_TYPE_FLAG_MATRIX )
{
TypeQualifier + = FString : : Printf ( TEXT ( " %d%d " ) , type . traits . numeric . matrix . row_count , type . traits . numeric . matrix . column_count ) ;
}
else if ( type . type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR )
{
TypeQualifier + = FString : : Printf ( TEXT ( " %d " ) , type . traits . numeric . vector . component_count ) ;
}
else
{
TypeQualifier + = TEXT ( " 1 " ) ;
}
for ( uint32 j = 0 ; j < ArrayCount ; j + + )
{
AssignedInputs | = ( 1 < < ( Location + j ) ) ;
}
FString Name = ANSI_TO_TCHAR ( Var - > name ) ;
Name . ReplaceInline ( TEXT ( " . " ) , TEXT ( " _ " ) ) ;
CCHeaderWriter . WriteOutputAttribute ( * Name , * TypeQualifier , Location , /*bLocationPrefix:*/ true , /*bLocationSuffix:*/ false ) ;
}
}
}
}
{
uint32 AssignedInputs = 0 ;
ReflectionBindings . GatherInputAttributes ( Reflection ) ;
for ( SpvReflectInterfaceVariable * Var : ReflectionBindings . InputAttributes )
{
if ( Var - > storage_class = = SpvStorageClassInput & & Var - > built_in = = - 1 )
{
unsigned Location = Var - > location ;
unsigned SemanticIndex = Location ;
check ( Var - > semantic ) ;
unsigned i = ( unsigned ) strlen ( Var - > semantic ) ;
check ( i ) ;
while ( isdigit ( ( unsigned char ) ( Var - > semantic [ i - 1 ] ) ) )
{
i - - ;
}
if ( i < strlen ( Var - > semantic ) )
{
SemanticIndex = ( unsigned ) atoi ( Var - > semantic + i ) ;
if ( Location ! = SemanticIndex )
{
Location = SemanticIndex ;
}
}
while ( ( 1 < < Location ) & AssignedInputs )
{
Location + + ;
}
if ( Location ! = Var - > location )
{
SPVRResult = Reflection . ChangeInputVariableLocation ( Var , Location ) ;
check ( SPVRResult = = SPV_REFLECT_RESULT_SUCCESS ) ;
}
uint32 ArrayCount = 1 ;
for ( uint32 Dim = 0 ; Dim < Var - > array . dims_count ; Dim + + )
{
ArrayCount * = Var - > array . dims [ Dim ] ;
}
FString TypeQualifier ;
auto const type = * Var - > type_description ;
uint32_t masked_type = type . type_flags & 0xF ;
switch ( masked_type ) {
default : checkf ( false , TEXT ( " unsupported component type %d " ) , masked_type ) ; break ;
case SPV_REFLECT_TYPE_FLAG_BOOL : TypeQualifier = TEXT ( " b " ) ; break ;
case SPV_REFLECT_TYPE_FLAG_INT : TypeQualifier = ( type . traits . numeric . scalar . signedness ? TEXT ( " i " ) : TEXT ( " u " ) ) ; break ;
case SPV_REFLECT_TYPE_FLAG_FLOAT : TypeQualifier = ( type . traits . numeric . scalar . width = = 32 ? TEXT ( " f " ) : TEXT ( " h " ) ) ; break ;
}
if ( type . type_flags & SPV_REFLECT_TYPE_FLAG_MATRIX )
{
TypeQualifier + = FString : : Printf ( TEXT ( " %d%d " ) , type . traits . numeric . matrix . row_count , type . traits . numeric . matrix . column_count ) ;
}
else if ( type . type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR )
{
TypeQualifier + = FString : : Printf ( TEXT ( " %d " ) , type . traits . numeric . vector . component_count ) ;
}
else
{
TypeQualifier + = TEXT ( " 1 " ) ;
}
for ( uint32 j = 0 ; j < ArrayCount ; j + + )
{
AssignedInputs | = ( 1 < < ( Location + j ) ) ;
}
FString Name = ANSI_TO_TCHAR ( Var - > name ) ;
Name . ReplaceInline ( TEXT ( " . " ) , TEXT ( " _ " ) ) ;
ReflectionOut . InputVarNames . Add ( Name ) ;
CCHeaderWriter . WriteInputAttribute ( * Name , * TypeQualifier , Location , /*bLocationPrefix:*/ true , /*bLocationSuffix:*/ false ) ;
}
}
}
}
static void ConvertToEmulatedUBs ( std : : string & GlslSource , const ReflectionData & ReflectData , const EShaderFrequency Frequency )
{
const ANSICHAR * FrequencyPrefix = GetFrequencyPrefix ( Frequency ) ;
2022-03-02 15:20:27 -05:00
2022-02-09 18:32:08 -05:00
for ( const auto & PackedUBNamePair : ReflectData . PackedUBNames )
{
bool bIsLayout = true ;
std : : string UBSearchString = " layout \\ (.* \\ ) uniform type_ " + PackedUBNamePair . Value + " $ " ;
std : : smatch RegexMatch ;
std : : regex_search ( GlslSource , RegexMatch , std : : regex ( UBSearchString ) ) ;
for ( auto Match : RegexMatch )
{
UBSearchString = Match ;
break ;
}
size_t UBPos = GlslSource . find ( UBSearchString ) ;
if ( UBPos = = std : : string : : npos )
{
UBSearchString = " struct type_ " + PackedUBNamePair . Value ;
UBPos = GlslSource . find ( UBSearchString ) ;
bIsLayout = false ;
}
if ( UBPos ! = std : : string : : npos )
{
std : : string UBEndSearchString ;
if ( bIsLayout )
{
UBEndSearchString = " } " + PackedUBNamePair . Value + " ; " ;
}
else
{
UBEndSearchString = " uniform type_ " + PackedUBNamePair . Value + " " + PackedUBNamePair . Value + " ; " ;
}
size_t UBEndPos = GlslSource . find ( UBEndSearchString ) ;
if ( UBEndPos ! = std : : string : : npos )
{
GlslSource . erase ( UBPos , UBEndPos - UBPos + UBEndSearchString . length ( ) ) ;
size_t UBVarPos = 0 ;
for ( const PackedUBMemberInfo & MemberInfo : ReflectData . PackedUBMemberInfos [ PackedUBNamePair . Key ] )
{
std : : string UBVarString = PackedUBNamePair . Value + " . " + MemberInfo . Name ;
UBVarPos = GlslSource . find ( UBVarString ) ;
while ( UBVarPos ! = std : : string : : npos )
{
GlslSource . erase ( UBVarPos , PackedUBNamePair . Value . length ( ) + 1 ) ;
GlslSource . replace ( UBVarPos , MemberInfo . Name . size ( ) , MemberInfo . SanitizedName ) ;
for ( std : : string const & SearchString : ReflectData . PackedUBArrays [ PackedUBNamePair . Key ] )
{
if ( ! GlslSource . compare ( UBVarPos , SearchString . length ( ) , SearchString ) )
{
GlslSource . replace ( UBVarPos + SearchString . length ( ) , 1 , " ( " ) ;
size_t ClosingBrace = GlslSource . find ( " ] " , UBVarPos + SearchString . length ( ) ) ;
if ( ClosingBrace ! = std : : string : : npos )
GlslSource . replace ( ClosingBrace , 1 , " ) " ) ;
}
}
UBVarPos = GlslSource . find ( UBVarString ) ;
}
}
for ( auto const & Pair : ReflectData . PackedUBOffsets [ PackedUBNamePair . Key ] )
{
if ( Pair . Value > 0 )
{
std : : string NewUniforms ;
std : : string UniformPrefix = FrequencyPrefix + std : : string ( " c " ) + std : : to_string ( PackedUBNamePair . Key ) ;
GetPackedUniformString ( NewUniforms , UniformPrefix , Pair . Key , Pair . Value ) ;
GlslSource . insert ( UBPos , NewUniforms ) ;
}
}
for ( std : : string const & Define : ReflectData . PackedUBRemap [ PackedUBNamePair . Key ] )
{
GlslSource . insert ( UBPos , Define ) ;
}
}
}
}
}
const ANSICHAR * GlslFrameBufferExtensions =
" \n \n #ifdef GL_ARM_shader_framebuffer_fetch_depth_stencil \n "
" \t #extension GL_ARM_shader_framebuffer_fetch_depth_stencil : enable \n "
" #elif defined(GL_EXT_shader_framebuffer_fetch) \n "
" \t #extension GL_EXT_shader_framebuffer_fetch : enable \n "
" \t #define FBF_STORAGE_QUALIFIER inout \n "
" #endif \n "
" #extension GL_EXT_texture_buffer : enable \n "
" // end extensions " ;
// GLSL framebuffer macro definitions. Used to patch GLSL output source.
const ANSICHAR * GlslFrameBufferDefines =
" \n \n #ifdef UE_EXT_shader_framebuffer_fetch \n "
" #define _Globals_ARM_shader_framebuffer_fetch 0 \n "
" #define FRAME_BUFFERFETCH_STORAGE_QUALIFIER inout \n "
" #define _Globals_gl_FragColor out_var_SV_Target0 \n "
" #define _Globals_gl_LastFragColorARM vec4(0.0, 0.0, 0.0, 0.0) \n "
" #elif defined( GL_ARM_shader_framebuffer_fetch) \n "
" #define _Globals_ARM_shader_framebuffer_fetch 1 \n "
" #define FRAME_BUFFERFETCH_STORAGE_QUALIFIER out \n "
" #define _Globals_gl_FragColor vec4(0.0, 0.0, 0.0, 0.0) \n "
" #define _Globals_gl_LastFragColorARM gl_LastFragDepthARM \n "
" #else \n "
" #define FRAME_BUFFERFETCH_STORAGE_QUALIFIER out \n "
" #define _Globals_ARM_shader_framebuffer_fetch 0 \n "
" #define _Globals_gl_FragColor vec4(0.0, 0.0, 0.0, 0.0) \n "
" #define _Globals_gl_LastFragColorARM vec4(0.0, 0.0, 0.0, 0.0) \n "
" #endif \n "
" #ifdef GL_ARM_shader_framebuffer_fetch_depth_stencil \n "
" #define _Globals_ARM_shader_framebuffer_fetch_depth_stencil 1u \n "
" #else \n "
" #define _Globals_ARM_shader_framebuffer_fetch_depth_stencil 0u \n "
" #endif \n " ;
struct GLSLCompileParameters
{
CrossCompiler : : FShaderConductorContext * CompilerContext ;
CrossCompiler : : FHlslccHeaderWriter * CCHeaderWriter ;
CrossCompiler : : FShaderConductorTarget * TargetDesc ;
CrossCompiler : : FShaderConductorOptions * Options ;
FShaderCompilerOutput * Output ;
TArray < uint32 > * SpirvData ;
EShaderFrequency Frequency ;
const ANSICHAR * SPIRV_DummySamplerName ;
} ;
bool GenerateGlslShader ( std : : string & OutString , GLSLCompileParameters & GLSLCompileParams , ReflectionData & ReflectData , bool bWriteToCCHeader , bool bIsDeferred , bool bEmulatedUBs )
{
const bool bGlslSourceCompileSucceeded = GLSLCompileParams . CompilerContext - > CompileSpirvToSourceBuffer (
* GLSLCompileParams . Options , * GLSLCompileParams . TargetDesc , GLSLCompileParams . SpirvData - > GetData ( ) , GLSLCompileParams . SpirvData - > Num ( ) * sizeof ( uint32 ) ,
[ & OutString ] ( const void * Data , uint32 Size )
{
OutString = std : : string ( reinterpret_cast < const ANSICHAR * > ( Data ) , Size ) ;
}
) ;
if ( ! bGlslSourceCompileSucceeded )
{
GLSLCompileParams . CompilerContext - > FlushErrors ( GLSLCompileParams . Output - > Errors ) ;
return false ;
}
const ANSICHAR * FrequencyPrefix = GetFrequencyPrefix ( GLSLCompileParams . Frequency ) ;
std : : string LayoutString = " #extension " ;
size_t LayoutPos = OutString . find ( LayoutString ) ;
if ( LayoutPos ! = std : : string : : npos )
{
for ( FString Name : ReflectData . InputVarNames )
{
std : : string DefineString = " #define " ;
DefineString + = TCHAR_TO_ANSI ( * Name ) ;
DefineString + = " " ;
DefineString + = TCHAR_TO_ANSI ( * Name . Replace ( TEXT ( " in_var_ " ) , TEXT ( " in_ " ) ) ) ;
DefineString + = " \n " ;
OutString . insert ( LayoutPos , DefineString ) ;
}
for ( FString Name : ReflectData . OutputVarNames )
{
std : : string DefineString = " #define " ;
DefineString + = TCHAR_TO_ANSI ( * Name ) ;
DefineString + = " " ;
DefineString + = TCHAR_TO_ANSI ( * Name . Replace ( TEXT ( " out_var_SV_ " ) , TEXT ( " out_ " ) ) ) ;
DefineString + = " \n " ;
OutString . insert ( LayoutPos , DefineString ) ;
}
}
// Perform FBF replacements
{
size_t MainPos = OutString . find ( " #version 320 es " ) ;
// Fallback if the shader is 310
if ( MainPos = = std : : string : : npos )
{
MainPos = OutString . find ( " #version 310 es " ) ;
}
if ( MainPos ! = std : : string : : npos )
{
MainPos + = strlen ( " #version 320 es " ) ;
}
// Framebuffer Depth Fetch
{
std : : string FBDFString = " _Globals.ARM_shader_framebuffer_fetch_depth_stencil " ;
2022-03-02 15:20:27 -05:00
std : : string FBDFReplaceString = " 1u " ;
2022-02-09 18:32:08 -05:00
std : : string FBFString = " _Globals.ARM_shader_framebuffer_fetch " ;
std : : string FBFReplaceString = " _Globals_ARM_shader_framebuffer_fetch " ;
bool UsesFramebufferDepthFetch = GLSLCompileParams . Frequency = = SF_Pixel & & OutString . find ( FBDFString ) ! = std : : string : : npos ;
bool UsesFramebufferFetch = GLSLCompileParams . Frequency = = SF_Pixel & & OutString . find ( FBFString ) ! = std : : string : : npos ;
if ( UsesFramebufferDepthFetch | | UsesFramebufferFetch )
{
OutString . insert ( MainPos , GlslFrameBufferDefines ) ;
OutString . insert ( MainPos , GlslFrameBufferExtensions ) ;
size_t FramebufferDepthFetchPos = OutString . find ( FBDFString ) ;
OutString . erase ( FramebufferDepthFetchPos , FBDFString . length ( ) ) ;
OutString . insert ( FramebufferDepthFetchPos , FBDFReplaceString ) ;
std : : string LastFragDepthARMString = " _Globals._RESERVED_IDENTIFIER_FIXUP_gl_LastFragDepthARM " ;
2022-03-02 15:20:27 -05:00
std : : string LastFragDepthARMReplaceString = " GLFetchDepthBuffer() " ;
2022-02-09 18:32:08 -05:00
size_t LastFragDepthARMStringPos = OutString . find ( LastFragDepthARMString ) ;
2022-03-02 15:20:27 -05:00
while ( LastFragDepthARMStringPos ! = std : : string : : npos )
{
OutString . erase ( LastFragDepthARMStringPos , LastFragDepthARMString . length ( ) ) ;
OutString . insert ( LastFragDepthARMStringPos , LastFragDepthARMReplaceString ) ;
2022-02-09 18:32:08 -05:00
2022-03-02 15:20:27 -05:00
LastFragDepthARMStringPos = OutString . find ( LastFragDepthARMString ) ;
}
2022-02-09 18:32:08 -05:00
MainPos = OutString . find ( " void main() " ) ;
// Add support for framebuffer fetch depth when ARM extension is not supported
if ( MainPos ! = std : : string : : npos )
{
std : : string DepthBufferIndex = bIsDeferred ? " 4 " : " 1 " ;
std : : string DepthBufferOutVarString = " out_var_SV_Target " + DepthBufferIndex ;
2022-03-15 14:33:37 -04:00
// Insert function declaration to handle retrieving depth
2022-02-09 18:32:08 -05:00
OutString . insert ( MainPos , " float GLFetchDepthBuffer() \n "
" { \n "
2022-03-15 14:33:37 -04:00
" \t #if defined(GL_ARM_shader_framebuffer_fetch_depth_stencil) \n "
2022-02-09 18:32:08 -05:00
" \t return gl_LastFragDepthARM; \n "
2022-03-15 14:33:37 -04:00
" \t #elif defined(GL_EXT_shader_framebuffer_fetch) \n "
2022-02-09 18:32:08 -05:00
" \t return " + DepthBufferOutVarString + " .x; \n "
2022-03-15 14:33:37 -04:00
" \t #else \n "
" \t return 0.0f; \n "
2022-02-09 18:32:08 -05:00
" \t #endif \n "
" } \n " ) ;
2022-03-15 14:33:37 -04:00
// If SceneDepthAux is not declared then declare it, otherwise modify so that we only enable it on devices that don't support
// GL_ARM_shader_framebuffer_fetch_depth_stencil and do support GL_EXT_shader_framebuffer_fetch
2022-02-09 18:32:08 -05:00
size_t DepthBufferOutVarPos = OutString . find ( DepthBufferOutVarString + " ; " ) ;
2022-03-15 14:33:37 -04:00
std : : string DepthBufferDeclString = " layout(location = " + DepthBufferIndex + " ) inout highp vec4 " + DepthBufferOutVarString + " ; \n " ;
std : : string DepthBufferOutString = " \n #if !defined(GL_ARM_shader_framebuffer_fetch_depth_stencil) && defined(GL_EXT_shader_framebuffer_fetch) \n " +
DepthBufferDeclString +
" #endif \n " ;
// If we cannot find a declararation of out_var_SV_Target(n) in the shader, insert one
2022-02-09 18:32:08 -05:00
if ( DepthBufferOutVarPos = = std : : string : : npos )
{
2022-03-15 14:33:37 -04:00
OutString . insert ( MainPos , DepthBufferOutString ) ;
2022-02-09 18:32:08 -05:00
}
2022-03-15 14:33:37 -04:00
else
2022-02-09 18:32:08 -05:00
{
2022-03-15 14:33:37 -04:00
// If we have a declaration, replace with one that will be stripped if GL_ARM_shader_framebuffer_fetch_depth_stencil is enabled
size_t StringStartPos = OutString . rfind ( " layout " , DepthBufferOutVarPos - 1 ) ;
size_t StringEndPos = OutString . find ( " ; " , StringStartPos ) ;
OutString . erase ( StringStartPos , ( StringEndPos + 1 ) - StringStartPos ) ;
OutString . insert ( StringStartPos , DepthBufferOutString ) ;
}
// Make SceneDepthAux assignment conditional
// We only need to write the depth when we don't support GL_ARM_shader_framebuffer_fetch_depth_stencil
std : : string DepthBufferAssignment = DepthBufferOutVarString + " = " ;
size_t DepthBufferAssignmentPos = OutString . find ( DepthBufferAssignment ) ;
if ( DepthBufferAssignmentPos ! = std : : string : : npos )
{
size_t LineEnd = OutString . find_first_of ( " ; " , DepthBufferAssignmentPos ) ;
uint32_t AssignmentValueStart = DepthBufferAssignmentPos + DepthBufferAssignment . size ( ) ;
std : : string AssignmentValue = OutString . substr ( AssignmentValueStart + 1 , LineEnd - AssignmentValueStart ) ;
if ( LineEnd ! = std : : string : : npos )
{
OutString . erase ( DepthBufferAssignmentPos , LineEnd + 1 - DepthBufferAssignmentPos ) ;
OutString . insert ( DepthBufferAssignmentPos , std : : string ( " #if !defined(GL_ARM_shader_framebuffer_fetch_depth_stencil) && defined(GL_EXT_shader_framebuffer_fetch) \n " ) + DepthBufferAssignment + AssignmentValue + std : : string ( " \n #endif \n " ) ) ;
}
2022-02-09 18:32:08 -05:00
}
2022-03-02 15:20:27 -05:00
}
}
}
}
2022-02-09 18:32:08 -05:00
2022-03-15 14:33:37 -04:00
// If we are rendering deferred, then we only need SceneDepthAux on devices that don't support framebuffer fetch depth
2022-10-30 08:26:11 -04:00
/*
2022-03-02 15:20:27 -05:00
if (bIsDeferred)
{
std::string SceneDepthAux = "layout(location = 4) out highp float out_var_SV_Target4;";
size_t SceneDepthAuxPos = OutString.find(SceneDepthAux);
if (SceneDepthAuxPos != std::string::npos)
{
OutString.insert(SceneDepthAuxPos + SceneDepthAux.size(), "\n#endif\n");
OutString.insert(SceneDepthAuxPos, "\n#ifndef GL_ARM_shader_framebuffer_fetch_depth_stencil\n");
2022-02-09 18:32:08 -05:00
2022-03-02 15:20:27 -05:00
std::string SceneDepthAuxAssignment = "out_var_SV_Target4 =";
size_t SceneDepthAuxAssignmentPos = OutString.find(SceneDepthAuxAssignment);
if (SceneDepthAuxAssignmentPos != std::string::npos)
{
size_t LineEnd = OutString.find_first_of(";", SceneDepthAuxAssignmentPos);
uint32_t AssignmentValueStart = SceneDepthAuxAssignmentPos + SceneDepthAuxAssignment.size();
std::string AssignmentValue = OutString.substr(AssignmentValueStart + 1, LineEnd - AssignmentValueStart);
if (LineEnd != std::string::npos)
{
OutString.erase(SceneDepthAuxAssignmentPos, LineEnd + 1 - SceneDepthAuxAssignmentPos);
OutString.insert(SceneDepthAuxAssignmentPos, std::string("#ifndef GL_ARM_shader_framebuffer_fetch_depth_stencil\n") + SceneDepthAuxAssignment + AssignmentValue + std::string("\n#endif\n"));
}
}
}
}
2022-10-30 08:26:11 -04:00
*/
2022-03-02 15:20:27 -05:00
// Fixup packed globals
{
bool bIsLayout = true ;
std : : string GlobalsSearchString = " layout \\ (.* \\ ) uniform type_Globals$ " ;
std : : smatch RegexMatch ;
std : : regex_search ( OutString , RegexMatch , std : : regex ( GlobalsSearchString ) ) ;
for ( auto Match : RegexMatch )
{
GlobalsSearchString = Match ;
break ;
}
size_t GlobalPos = OutString . find ( GlobalsSearchString ) ;
if ( GlobalPos = = std : : string : : npos )
{
GlobalsSearchString = " struct type_Globals " ;
GlobalPos = OutString . find ( GlobalsSearchString ) ;
bIsLayout = false ;
}
if ( GlobalPos ! = std : : string : : npos )
{
std : : string GlobalsEndSearchString ;
if ( bIsLayout )
{
GlobalsEndSearchString = " } _Globals; " ;
}
else
{
GlobalsEndSearchString = " uniform type_Globals _Globals; " ;
}
size_t GlobalEndPos = OutString . find ( GlobalsEndSearchString ) ;
if ( GlobalEndPos ! = std : : string : : npos )
{
OutString . erase ( GlobalPos , GlobalEndPos - GlobalPos + GlobalsEndSearchString . length ( ) ) ;
std : : string GlobalVarString = " _Globals. " ;
size_t GlobalVarPos = 0 ;
do
{
GlobalVarPos = OutString . find ( GlobalVarString , GlobalVarPos ) ;
if ( GlobalVarPos ! = std : : string : : npos )
2022-02-09 18:32:08 -05:00
{
2022-03-02 15:20:27 -05:00
OutString . replace ( GlobalVarPos , GlobalVarString . length ( ) , " _Globals_ " ) ;
for ( std : : string const & SearchString : ReflectData . GlobalArrays )
{
if ( ! OutString . compare ( GlobalVarPos , SearchString . length ( ) , SearchString ) )
{
OutString . replace ( GlobalVarPos + SearchString . length ( ) , 1 , " ( " ) ;
size_t ClosingBrace = OutString . find ( " ] " , GlobalVarPos + SearchString . length ( ) ) ;
if ( ClosingBrace ! = std : : string : : npos )
OutString . replace ( ClosingBrace , 1 , " ) " ) ;
}
}
2022-02-09 18:32:08 -05:00
}
2022-03-02 15:20:27 -05:00
} while ( GlobalVarPos ! = std : : string : : npos ) ;
for ( auto const & Pair : ReflectData . GlobalOffsets )
{
if ( Pair . Value > 0 )
{
std : : string NewUniforms ;
GetPackedUniformString ( NewUniforms , FrequencyPrefix + std : : string ( " u " ) , Pair . Key , Pair . Value ) ;
OutString . insert ( GlobalPos , NewUniforms ) ;
}
}
for ( std : : string const & Define : ReflectData . GlobalRemap )
{
OutString . insert ( GlobalPos , Define ) ;
}
bool UsesFramebufferFetch = GLSLCompileParams . Frequency = = SF_Pixel & & OutString . find ( " _Globals.ARM_shader_framebuffer_fetch " ) ! = std : : string : : npos ;
if ( UsesFramebufferFetch )
{
size_t OutColor = OutString . find ( " 0) out " ) ;
if ( OutColor ! = std : : string : : npos )
OutString . replace ( OutColor , 7 , " 0) FRAME_BUFFERFETCH_STORAGE_QUALIFIER " ) ;
2022-02-09 18:32:08 -05:00
}
}
}
}
if ( bEmulatedUBs )
{
ConvertToEmulatedUBs ( OutString , ReflectData , GLSLCompileParams . Frequency ) ;
}
const size_t GlslSourceLen = OutString . length ( ) ;
if ( GlslSourceLen > 0 )
{
uint32 TextureIndex = 0 ;
for ( const FString & Texture : ReflectData . Textures )
{
const size_t SamplerPos = OutString . find ( " \n uniform " ) ;
TArray < FString > UsedSamplers ;
FString SamplerString ;
for ( const FString & Sampler : ReflectData . Samplers )
{
std : : string SamplerName = " SPIRV_Cross_Combined " ;
SamplerName + = TCHAR_TO_ANSI ( * ( Texture + Sampler ) ) ;
size_t FindCombinedSampler = OutString . find ( SamplerName . c_str ( ) ) ;
if ( FindCombinedSampler ! = std : : string : : npos )
{
checkf ( SamplerPos ! = std : : string : : npos , TEXT ( " Generated GLSL shader is expected to have combined sampler '%s:%s' but no appropriate 'uniform' declaration could be found " ) , * Texture , * Sampler ) ;
uint32 NewIndex = TextureIndex + UsedSamplers . Num ( ) ;
std : : string NewDefine = " #define " ;
NewDefine + = SamplerName ;
NewDefine + = " " ;
NewDefine + = FrequencyPrefix ;
NewDefine + = " s " ;
NewDefine + = std : : to_string ( NewIndex ) ;
NewDefine + = " \n " ;
OutString . insert ( SamplerPos + 1 , NewDefine ) ;
// Do not add an entry for the dummy sampler as it will throw errors in the runtime checks
if ( Sampler ! = GLSLCompileParams . SPIRV_DummySamplerName )
{
UsedSamplers . Add ( Sampler ) ;
}
SamplerString + = FString : : Printf ( TEXT ( " %s%s " ) , SamplerString . Len ( ) ? TEXT ( " , " ) : TEXT ( " " ) , * Sampler ) ;
}
}
// Rename texture buffers
std : : string SamplerBufferName = std : : string ( " samplerBuffer " ) + TCHAR_TO_ANSI ( * Texture ) ;
size_t SamplerBufferPos = OutString . find ( SamplerBufferName ) ;
if ( SamplerBufferPos ! = std : : string : : npos )
{
std : : string NewSamplerBufferName = std : : string ( FrequencyPrefix ) + " s " + std : : to_string ( TextureIndex ) ;
OutString . erase ( SamplerBufferPos + SamplerBufferName . size ( ) - Texture . Len ( ) , Texture . Len ( ) ) ;
OutString . insert ( SamplerBufferPos + SamplerBufferName . size ( ) - Texture . Len ( ) , NewSamplerBufferName ) ;
2022-03-07 15:53:15 -05:00
std : : string SamplerTexFetchExpression = std : : string ( " texelFetch \\ ( \\ s? " ) + TCHAR_TO_ANSI ( * Texture ) + " \\ s?, " ;
std : : regex SamplerTexFetchPattern ( SamplerTexFetchExpression ) ;
OutString = std : : regex_replace ( OutString , SamplerTexFetchPattern , std : : string ( " texelFetch( " ) + NewSamplerBufferName + " , " ) ;
2022-02-09 18:32:08 -05:00
}
const uint32 SamplerCount = FMath : : Max ( 1 , UsedSamplers . Num ( ) ) ;
if ( bWriteToCCHeader )
{
GLSLCompileParams . CCHeaderWriter - > WriteSRV ( * Texture , TextureIndex , SamplerCount , UsedSamplers ) ;
}
TextureIndex + = SamplerCount ;
}
// UAVS, rename as ci0 format
uint32_t UAVIndex = 0 ;
for ( const std : : string & UAV : ReflectData . UAVs )
{
std : : string NewUAVName = FrequencyPrefix + std : : string ( " i " ) + std : : to_string ( UAVIndex ) ;
// Find instances of UAVs
std : : string RegexExpression = " (?:^| \\ W| \\ S) " + UAV + " (?:$| \\ W) " ;
std : : cmatch RegexMatch ;
std : : vector < std : : string > RegexMatches ;
const char * TempString = OutString . c_str ( ) ;
while ( std : : regex_search ( TempString , RegexMatch , std : : regex ( RegexExpression ) ) )
{
RegexMatches . push_back ( RegexMatch . str ( ) ) ;
TempString = RegexMatch . suffix ( ) . first ;
}
for ( const auto & Match : RegexMatches )
{
size_t MatchOffset = Match . find_first_of ( UAV ) ;
size_t MatchPos = OutString . find ( Match ) ;
OutString . replace ( MatchPos + MatchOffset , UAV . size ( ) , NewUAVName ) ;
}
UAVIndex + + ;
}
// StructuredBuffers, rename as ci0 format
for ( const std : : string & SBuffer : ReflectData . StructuredBuffers )
{
std : : string NewSBufferName = FrequencyPrefix + std : : string ( " i " ) + std : : to_string ( UAVIndex ) ;
std : : string NewSBufferVarName = NewSBufferName + std : : string ( " _VAR " ) ;
std : : string SearchString = " } " + SBuffer ;
size_t SBufferPos = OutString . find ( SearchString ) ;
size_t SBufferEndPos = OutString . find ( " ; " , SBufferPos ) ;
std : : string ReplacementSubStr = OutString . substr ( SBufferPos + 2 , SBufferEndPos - SBufferPos - 2 ) ;
OutString . erase ( SBufferPos + 1 , SBufferEndPos - SBufferPos - 1 ) ;
const std : : string SBufferData = " _m0 " ;
size_t SBufferDataPos = OutString . rfind ( SBufferData , SBufferPos ) ;
OutString . replace ( SBufferDataPos , SBufferData . size ( ) , NewSBufferName ) ;
const std : : string BufferString = " buffer " ;
size_t BufferNamePos = OutString . rfind ( BufferString , SBufferPos ) ;
size_t BufferLineEndPos = OutString . find ( " \n " , BufferNamePos ) ;
size_t ReplacePos = BufferNamePos + BufferString . size ( ) ;
OutString . replace ( ReplacePos , BufferLineEndPos - ReplacePos , NewSBufferVarName ) ;
// Replace the usage of StructuredBuffer with new name
size_t CurPos = OutString . find ( ReplacementSubStr + " . " ) ;
while ( CurPos ! = std : : string : : npos )
{
// Offset by 4 to account for ._m0
OutString . replace ( CurPos , ReplacementSubStr . size ( ) + 4 , NewSBufferName ) ;
CurPos = OutString . find ( ReplacementSubStr + " . " ) ;
}
UAVIndex + + ;
}
for ( const auto & pair : ReflectData . UniformVarNames )
{
2022-03-02 15:20:27 -05:00
std : : string OldUniformTypeName = " uniform type_ " + pair . first + " " + pair . first + " ; " ;
2022-02-09 18:32:08 -05:00
size_t UniformTypePos = OutString . find ( OldUniformTypeName ) ;
if ( UniformTypePos ! = std : : string : : npos )
{
OutString . erase ( UniformTypePos , OldUniformTypeName . length ( ) ) ;
2022-03-02 15:20:27 -05:00
}
// Replace struct type with layout, for compatibility
std : : string OldStructTypeName = " struct type_ " + pair . first + " \n " ;
std : : string NewStructTypeName = " layout(std140) uniform " + pair . second + " \n " ;
size_t StructTypePos = OutString . find ( OldStructTypeName ) ;
if ( StructTypePos ! = std : : string : : npos )
{
OutString . erase ( StructTypePos , OldStructTypeName . length ( ) ) ;
OutString . insert ( StructTypePos , NewStructTypeName ) ;
}
// Append the uniform buffer name i.e. pb0 to ensure variable names are unique across shaders
std : : vector < std : : string > & MemberNames = ReflectData . UniformVarMemberNames [ pair . first ] ;
for ( const std : : string & uniform_member_name : MemberNames )
{
std : : string OldVarName = uniform_member_name ;
std : : string NewVarName = uniform_member_name + pair . second ;
size_t OldVarNamePos = OutString . find ( OldVarName ) ;
OutString . erase ( OldVarNamePos , OldVarName . length ( ) ) ;
OutString . insert ( OldVarNamePos , NewVarName ) ;
}
// Sort the member names by length so that we don't accidently replace a partial string
std : : sort ( MemberNames . begin ( ) , MemberNames . end ( ) , [ ] ( const std : : string & a , const std : : string & b ) {
return a . length ( ) > b . length ( ) ;
} ) ;
// Replace uniform member names in the glsl
for ( const std : : string & uniform_member_name : MemberNames )
{
std : : string OldUniformBufferAccessor = pair . first + " . " + uniform_member_name ;
std : : string NewUniformBufferAccessor = uniform_member_name + pair . second ;
size_t OldAccessorPos = OutString . find ( OldUniformBufferAccessor ) ;
while ( OldAccessorPos ! = std : : string : : npos )
{
OutString . erase ( OldAccessorPos , OldUniformBufferAccessor . length ( ) ) ;
OutString . insert ( OldAccessorPos , NewUniformBufferAccessor ) ;
OldAccessorPos = OutString . find ( OldUniformBufferAccessor ) ;
}
}
// Rename the padding variables to stop conflicts between shaders
std : : string OldPaddingName = " type_ " + pair . first + " _pad " ;
std : : string NewPaddingName = pair . second + " _pad " ;
size_t OldPaddingPos = OutString . find ( OldPaddingName ) ;
while ( OldPaddingPos ! = std : : string : : npos )
{
OutString . erase ( OldPaddingPos , OldPaddingName . length ( ) ) ;
OutString . insert ( OldPaddingPos , NewPaddingName ) ;
OldPaddingPos = OutString . find ( OldPaddingName ) ;
2022-02-09 18:32:08 -05:00
}
}
}
return true ;
}
2022-05-03 09:54:19 -04:00
enum EDecalBlendFlags
{
DecalOut_MRT0 = 1 ,
DecalOut_MRT1 = 1 < < 1 ,
DecalOut_MRT2 = 1 < < 2 ,
DecalOut_MRT3 = 1 < < 3 ,
Translucent = 1 < < 4 ,
AlphaComposite = 1 < < 5 ,
Modulate = 1 < < 6 ,
} ;
2022-11-10 05:06:00 -05:00
bool EnvironmentHasMatchingKeyValue ( const TMap < FString , FString > & Definitions , const FString & Key , const FString & Value )
{
const FString * MatchedKey = Definitions . Find ( Key ) ;
if ( MatchedKey )
{
return * MatchedKey = = Value ;
}
return false ;
}
uint32_t GetDecalBlendFlags ( const FShaderCompilerInput & Input )
2022-05-03 09:54:19 -04:00
{
uint32_t Flags = 0 ;
2022-11-10 05:06:00 -05:00
const TMap < FString , FString > & Definitions = Input . Environment . GetDefinitions ( ) ;
if ( EnvironmentHasMatchingKeyValue ( Definitions , TEXT ( " DECAL_OUT_MRT0 " ) , TEXT ( " 1 " ) ) )
2022-05-03 09:54:19 -04:00
{
Flags | = EDecalBlendFlags : : DecalOut_MRT0 ;
}
2022-11-10 05:06:00 -05:00
if ( EnvironmentHasMatchingKeyValue ( Definitions , TEXT ( " DECAL_OUT_MRT1 " ) , TEXT ( " 1 " ) ) )
2022-05-03 09:54:19 -04:00
{
Flags | = EDecalBlendFlags : : DecalOut_MRT1 ;
}
2022-11-10 05:06:00 -05:00
if ( EnvironmentHasMatchingKeyValue ( Definitions , TEXT ( " DECAL_OUT_MRT2 " ) , TEXT ( " 1 " ) ) )
2022-05-03 09:54:19 -04:00
{
Flags | = EDecalBlendFlags : : DecalOut_MRT2 ;
}
2022-11-10 05:06:00 -05:00
if ( EnvironmentHasMatchingKeyValue ( Definitions , TEXT ( " DECAL_OUT_MRT3 " ) , TEXT ( " 1 " ) ) )
2022-05-03 09:54:19 -04:00
{
Flags | = EDecalBlendFlags : : DecalOut_MRT3 ;
}
if ( ! Flags )
{
return 0 ;
}
2022-11-10 05:06:00 -05:00
if ( EnvironmentHasMatchingKeyValue ( Definitions , TEXT ( " MATERIALBLENDING_ALPHACOMPOSITE " ) , TEXT ( " 1 " ) ) )
2022-05-03 09:54:19 -04:00
{
Flags | = EDecalBlendFlags : : AlphaComposite ;
}
2022-11-10 05:06:00 -05:00
else if ( EnvironmentHasMatchingKeyValue ( Definitions , TEXT ( " MATERIALBLENDING_MODULATE " ) , TEXT ( " 1 " ) ) )
2022-05-03 09:54:19 -04:00
{
Flags | = EDecalBlendFlags : : Modulate ;
}
2022-11-10 05:06:00 -05:00
else if ( EnvironmentHasMatchingKeyValue ( Definitions , TEXT ( " MATERIALBLENDING_TRANSLUCENT " ) , TEXT ( " 1 " ) ) )
2022-05-03 09:54:19 -04:00
{
Flags | = EDecalBlendFlags : : Translucent ;
}
return Flags ;
}
enum class EDecalBlendFunction
{
SrcAlpha_One ,
SrcAlpha_InvSrcAlpha ,
DstColor_InvSrcAlpha ,
One_InvSrcAlpha ,
None
} ;
// Emissive, Normal, Metallic\Specular\Roughness, BaseColor
static const EDecalBlendFunction TranslucentBlendFunctions [ ] = { EDecalBlendFunction : : SrcAlpha_One , EDecalBlendFunction : : SrcAlpha_InvSrcAlpha , EDecalBlendFunction : : SrcAlpha_InvSrcAlpha , EDecalBlendFunction : : SrcAlpha_InvSrcAlpha } ;
static const EDecalBlendFunction AlphaCompositeBlendFunctions [ ] = { EDecalBlendFunction : : SrcAlpha_One , EDecalBlendFunction : : None , EDecalBlendFunction : : One_InvSrcAlpha , EDecalBlendFunction : : One_InvSrcAlpha } ;
static const EDecalBlendFunction ModulateBlendFunctions [ ] = { EDecalBlendFunction : : SrcAlpha_One , EDecalBlendFunction : : SrcAlpha_InvSrcAlpha , EDecalBlendFunction : : SrcAlpha_InvSrcAlpha , EDecalBlendFunction : : DstColor_InvSrcAlpha } ;
void GetDecalBlendFunctionString ( const EDecalBlendFunction BlendFunction , const std : : string & AttachmentString , const std : : string & TempOutputName , std : : string & OutputString )
{
switch ( BlendFunction )
{
case EDecalBlendFunction : : SrcAlpha_One :
{
OutputString = AttachmentString + " .rgb = " + TempOutputName + " .a * " + TempOutputName + " .rgb + " + AttachmentString + " .rgb " ;
break ;
}
case EDecalBlendFunction : : SrcAlpha_InvSrcAlpha :
{
OutputString = AttachmentString + " .rgb = " + TempOutputName + " .a * " + TempOutputName + " .rgb + (1.0 - " + TempOutputName + " .a) * " + AttachmentString + " .rgb " ;
break ;
}
case EDecalBlendFunction : : DstColor_InvSrcAlpha :
{
OutputString = AttachmentString + " .rgb = " + TempOutputName + " .rgb * " + AttachmentString + " .rgb + (1.0 - " + TempOutputName + " .a) * " + AttachmentString + " .rgb " ;
break ;
}
case EDecalBlendFunction : : One_InvSrcAlpha :
{
OutputString = AttachmentString + " .rgb = " + TempOutputName + " .rgb + (1.0 - " + TempOutputName + " .a) * " + AttachmentString + " .rgb " ;
break ;
}
case EDecalBlendFunction : : None :
{
OutputString = " " ;
break ;
}
}
}
void ModifyDecalBlending ( std : : string & SourceString , const uint32_t BlendFlags )
{
for ( uint32_t i = 0 ; i < 4 ; + + i )
{
std : : string OutIndex = std : : to_string ( i ) ;
std : : string AttachmentString = " GENERATED_SubpassFetchAttachment " + OutIndex ;
std : : string AttachmentAssignmentString = AttachmentString + " = " ;
size_t AssignmentPos = SourceString . find ( AttachmentAssignmentString ) ;
if ( AssignmentPos ! = std : : string : : npos )
{
size_t AssignmentEndPos = AssignmentPos + AttachmentAssignmentString . size ( ) ;
size_t StringEndPos = SourceString . find ( " ; " , AssignmentEndPos ) ;
std : : string TempOutputName = " TempMulOut " + OutIndex ;
std : : string TempOut = " highp vec4 " + TempOutputName + " = " + SourceString . substr ( AssignmentEndPos , StringEndPos - AssignmentEndPos ) + " ; \n " ;
SourceString . erase ( AssignmentPos , StringEndPos - AssignmentPos ) ;
if ( 1 < < i & BlendFlags )
{
std : : string BlendFnString ;
if ( BlendFlags & EDecalBlendFlags : : Translucent )
{
GetDecalBlendFunctionString ( TranslucentBlendFunctions [ i ] , AttachmentString , TempOutputName , BlendFnString ) ;
}
if ( BlendFlags & EDecalBlendFlags : : AlphaComposite )
{
GetDecalBlendFunctionString ( AlphaCompositeBlendFunctions [ i ] , AttachmentString , TempOutputName , BlendFnString ) ;
}
if ( BlendFlags & EDecalBlendFlags : : Modulate )
{
GetDecalBlendFunctionString ( ModulateBlendFunctions [ i ] , AttachmentString , TempOutputName , BlendFnString ) ;
}
TempOut + = BlendFnString ;
SourceString . insert ( AssignmentPos , TempOut ) ;
}
}
}
}
bool GenerateDeferredMobileShaders ( std : : string & GlslSource , GLSLCompileParameters & GLSLCompileParams , const std : : string & HlslString , ReflectionData & ReflectData ,
bool bWriteToCCHeader , bool bIsDeferred , bool bEmulatedUBs , uint32_t DecalBlendFlags )
2022-02-09 18:32:08 -05:00
{
bool bHasGbufferTextures [ 4 ] ;
bHasGbufferTextures [ 0 ] = HlslString . find ( " GENERATED_SubpassFetchAttachment0 " ) ! = std : : string : : npos ;
bHasGbufferTextures [ 1 ] = HlslString . find ( " GENERATED_SubpassFetchAttachment1 " ) ! = std : : string : : npos ;
bHasGbufferTextures [ 2 ] = HlslString . find ( " GENERATED_SubpassFetchAttachment2 " ) ! = std : : string : : npos ;
bHasGbufferTextures [ 3 ] = HlslString . find ( " GENERATED_SubpassFetchAttachment3 " ) ! = std : : string : : npos ;
bool bHasGBufferOutputs [ 4 ] ;
bHasGBufferOutputs [ 0 ] = HlslString . find ( " OutProxy " ) ! = std : : string : : npos ;
bHasGBufferOutputs [ 1 ] = HlslString . find ( " OutGBufferA " ) ! = std : : string : : npos ;
bHasGBufferOutputs [ 2 ] = HlslString . find ( " OutGBufferB " ) ! = std : : string : : npos ;
bHasGBufferOutputs [ 3 ] = HlslString . find ( " OutGBufferC " ) ! = std : : string : : npos ;
bool bHasInputs = false ;
bool bHasOutputs = false ;
for ( uint32_t i = 0 ; i < 4 ; + + i )
{
bHasInputs | = bHasGbufferTextures [ i ] ;
bHasOutputs | = bHasGBufferOutputs [ i ] ;
}
bool bHasInOut = ( bHasInputs & & bHasOutputs ) | | HlslString . find ( " OutTarget0 " ) ! = std : : string : : npos ;
if ( bHasInputs | | bHasOutputs )
{
std : : string OutString ;
std : : string ESVersionString = " #version 320 es " ;
OutString + = ESVersionString + " \n " ;
OutString + = " #ifdef UE_MRT_FRAMEBUFFER_FETCH \n " ;
FShaderCompilerDefinitions CompileFlagsCopy = GLSLCompileParams . TargetDesc - > CompileFlags ;
// Add defines for FBF in spirv-glsl
for ( uint32_t i = 1 ; i < 4 ; + + i )
{
if ( bHasGbufferTextures [ i ] )
{
FString DefineKey = FString : : Printf ( TEXT ( " remap_ext_framebuffer_fetch%d " ) , i ) ;
FString DefineValue = FString : : Printf ( TEXT ( " %d %d " ) , i + 1 , i ) ;
GLSLCompileParams . TargetDesc - > CompileFlags . SetDefine ( * DefineKey , * DefineValue ) ;
}
}
std : : string FBFSourceString ;
if ( ! GenerateGlslShader ( FBFSourceString , GLSLCompileParams , ReflectData , true , true , bEmulatedUBs ) )
{
return false ;
}
size_t VersionStringPos = FBFSourceString . find ( ESVersionString ) ;
if ( VersionStringPos ! = std : : string : : npos )
{
FBFSourceString . replace ( VersionStringPos , ESVersionString . length ( ) , " " ) ;
}
GLSLCompileParams . TargetDesc - > CompileFlags = CompileFlagsCopy ;
OutString + = FBFSourceString ;
// Generate PLS shader
OutString + = " #else \n " ;
// Using rgb10_a2ui because r11_g11_b10 has issues with swizzle from 4 to 3 components in DXC
static const FString GBufferOutputNames [ ] =
{
TEXT ( " rgb10_a2 out.var.SV_Target0 " ) ,
TEXT ( " rgba8 out.var.SV_Target1 " ) ,
TEXT ( " rgba8 out.var.SV_Target2 " ) ,
TEXT ( " rgba8 out.var.SV_Target3 " ) ,
} ;
static const FString GBufferInputNames [ ] =
{
TEXT ( " rgb10_a2 GENERATED_SubpassFetchAttachment0 " ) ,
TEXT ( " rgba8 GENERATED_SubpassFetchAttachment1 " ) ,
TEXT ( " rgba8 GENERATED_SubpassFetchAttachment2 " ) ,
TEXT ( " rgba8 GENERATED_SubpassFetchAttachment3 " ) ,
} ;
static const FString GBufferInOutNames [ ] =
{
TEXT ( " rgb10_a2 GENERATED_SubpassFetchAttachment0 out.var.SV_Target0 " ) ,
TEXT ( " rgba8 GENERATED_SubpassFetchAttachment1 out.var.SV_Target1 " ) ,
TEXT ( " rgba8 GENERATED_SubpassFetchAttachment2 out.var.SV_Target2 " ) ,
TEXT ( " rgba8 GENERATED_SubpassFetchAttachment3 out.var.SV_Target3 " ) ,
} ;
// Add defines for PLS in spirv-glsl
{
FString DefineKey = " " ;
FString DefineValue = " " ;
for ( uint32_t i = 0 ; i < 4 ; + + i )
{
if ( bHasInOut )
{
DefineKey = FString : : Printf ( TEXT ( " pls_io%d " ) , i ) ;
DefineValue = GBufferInOutNames [ i ] ;
}
else if ( bHasInputs )
{
DefineKey = FString : : Printf ( TEXT ( " pls_in%d " ) , i ) ;
DefineValue = GBufferInputNames [ i ] ;
}
else
{
DefineKey = FString : : Printf ( TEXT ( " pls_out%d " ) , i ) ;
DefineValue = GBufferOutputNames [ i ] ;
}
GLSLCompileParams . TargetDesc - > CompileFlags . SetDefine ( * DefineKey , * DefineValue ) ;
}
}
std : : string PLSSourceString ;
if ( ! GenerateGlslShader ( PLSSourceString , GLSLCompileParams , ReflectData , false , true , bEmulatedUBs ) )
{
return false ;
}
// Replace assignment of output to buffer 0 to additive if the output proxy additive is used
2022-05-03 09:54:19 -04:00
if ( HlslString . find ( " OutProxyAdditive " ) ! = std : : string : : npos )
2022-02-09 18:32:08 -05:00
{
std : : string OutProxyString = " GENERATED_SubpassFetchAttachment0 = " ;
std : : string OutProxyModifiedString = " GENERATED_SubpassFetchAttachment0 += " ;
size_t OutProxyStringPos = PLSSourceString . find ( OutProxyString ) ;
while ( OutProxyStringPos ! = std : : string : : npos )
{
PLSSourceString . replace ( OutProxyStringPos , OutProxyString . size ( ) , OutProxyModifiedString ) ;
OutProxyStringPos = PLSSourceString . find ( OutProxyString ) ;
}
}
2022-05-03 09:54:19 -04:00
if ( DecalBlendFlags )
{
ModifyDecalBlending ( PLSSourceString , DecalBlendFlags ) ;
}
2022-02-09 18:32:08 -05:00
// Strip version string
VersionStringPos = PLSSourceString . find ( ESVersionString ) ;
if ( VersionStringPos ! = std : : string : : npos )
{
PLSSourceString . replace ( VersionStringPos , ESVersionString . length ( ) , " " , 0 ) ;
}
OutString + = PLSSourceString ;
OutString + = " #endif \n " ;
GlslSource = OutString ;
}
else
{
if ( ! GenerateGlslShader ( GlslSource , GLSLCompileParams , ReflectData , true , false , bEmulatedUBs ) )
{
return false ;
}
}
return true ;
}
2020-10-09 22:42:26 -04:00
static bool CompileToGlslWithShaderConductor (
const FShaderCompilerInput & Input ,
FShaderCompilerOutput & Output ,
const FString & WorkingDirectory ,
GLSLVersion Version ,
2021-09-02 16:41:03 -04:00
const EShaderFrequency Frequency ,
2020-10-09 22:42:26 -04:00
uint32 CCFlags ,
const FString & PreprocessedShader ,
char * & OutGlslShaderSource )
{
CrossCompiler : : FShaderConductorContext CompilerContext ;
const bool bDumpDebugInfo = ( Input . DumpDebugInfoPath ! = TEXT ( " " ) & & IFileManager : : Get ( ) . DirectoryExists ( * Input . DumpDebugInfoPath ) ) ;
const bool bRewriteHlslSource = true ;
// Initialize compilation options for ShaderConductor
CrossCompiler : : FShaderConductorOptions Options ;
2021-11-23 14:28:47 -05:00
Options . bDisableScalarBlockLayout = true ;
2021-12-09 15:02:07 -05:00
Options . bRemapAttributeLocations = true ;
2022-01-12 05:06:34 -05:00
Options . bPreserveStorageInput = true ;
2021-11-03 09:25:57 -04:00
2022-03-09 09:47:28 -05:00
// Enable HLSL 2021 if specified
if ( Input . Environment . CompilerFlags . Contains ( CFLAG_HLSL2021 ) )
{
Options . HlslVersion = 2021 ;
}
2020-10-09 22:42:26 -04:00
// Convert input strings from FString to ANSI strings
2019-09-14 09:45:25 -04:00
std : : string SourceData ( TCHAR_TO_UTF8 ( * PreprocessedShader ) ) ;
std : : string FileName ( TCHAR_TO_UTF8 ( * Input . VirtualSourceFilePath ) ) ;
std : : string EntryPointName ( TCHAR_TO_UTF8 ( * Input . EntryPointName ) ) ;
2021-08-11 07:11:25 -04:00
bool bEmulatedUBs = Input . Environment . CompilerFlags . Contains ( CFLAG_UseEmulatedUB ) ;
2019-09-14 09:45:25 -04:00
2020-10-09 22:42:26 -04:00
// HLSL framebuffer declarations. Used to modify HLSL input source.
const ANSICHAR * HlslFrameBufferDeclarations =
" float4 gl_FragColor; \n "
" float4 gl_LastFragColorARM; \n "
" float gl_LastFragDepthARM; \n "
" bool ARM_shader_framebuffer_fetch; \n "
" bool ARM_shader_framebuffer_fetch_depth_stencil; \n "
" float4 FramebufferFetchES2() \n "
" { \n "
" if (!ARM_shader_framebuffer_fetch) \n "
" { \n "
" return gl_FragColor; \n "
" } \n "
" else \n "
" { \n "
" return gl_LastFragColorARM; \n "
" } \n "
" } \n "
" float DepthbufferFetchES2() \n "
" { \n "
2021-08-11 07:11:25 -04:00
" return (ARM_shader_framebuffer_fetch_depth_stencil == 0 ? 0.0 : gl_LastFragDepthARM); \n "
2020-10-09 22:42:26 -04:00
" } \n "
;
2019-09-14 09:45:25 -04:00
2022-02-09 18:32:08 -05:00
if ( SourceData . find ( " DepthbufferFetchES2 " ) ! = std : : string : : npos | |
SourceData . find ( " FramebufferFetchES2 " ) ! = std : : string : : npos )
{
SourceData = HlslFrameBufferDeclarations + SourceData ;
}
2019-09-14 09:45:25 -04:00
2020-10-09 22:42:26 -04:00
// Inject additional macro definitions to circumvent missing features: external textures
FShaderCompilerDefinitions AdditionalDefines ;
AdditionalDefines . SetDefine ( TEXT ( " TextureExternal " ) , TEXT ( " Texture2D " ) ) ;
2019-09-14 09:45:25 -04:00
2022-10-28 11:45:49 -04:00
UE : : ShaderCompilerCommon : : FDebugShaderDataOptions DebugDataOptions ;
DebugDataOptions . HlslCCFlags = CCFlags ;
UE : : ShaderCompilerCommon : : DumpDebugShaderData ( Input , PreprocessedShader , DebugDataOptions ) ;
2019-09-14 09:45:25 -04:00
2022-11-10 05:06:00 -05:00
uint32_t BlendFlags = GetDecalBlendFlags ( Input ) ;
2022-05-03 09:54:19 -04:00
2020-10-09 22:42:26 -04:00
// Load shader source into compiler context
CompilerContext . LoadSource ( SourceData . c_str ( ) , FileName . c_str ( ) , EntryPointName . c_str ( ) , Frequency , & AdditionalDefines ) ;
2019-09-14 09:45:25 -04:00
2020-10-09 22:42:26 -04:00
bool bCompilationFailed = false ;
if ( bRewriteHlslSource )
2019-09-14 09:45:25 -04:00
{
2020-10-09 22:42:26 -04:00
// Rewrite HLSL source code to remove unused global resources and variables
Options . bRemoveUnusedGlobals = true ;
if ( CompilerContext . RewriteHlsl ( Options ) )
2020-09-24 00:43:27 -04:00
{
2020-10-09 22:42:26 -04:00
// Adopt new rewritten shader source
SourceData = CompilerContext . GetSourceString ( ) ;
if ( bDumpDebugInfo )
2020-09-24 00:43:27 -04:00
{
2020-10-09 22:42:26 -04:00
DumpDebugShaderText ( Input , ANSI_TO_TCHAR ( SourceData . c_str ( ) ) , TEXT ( " rewritten.hlsl " ) ) ;
2020-09-24 00:43:27 -04:00
}
}
2020-10-09 22:42:26 -04:00
else
{
CompilerContext . FlushErrors ( Output . Errors ) ;
bCompilationFailed = true ;
}
Options . bRemoveUnusedGlobals = false ;
}
// Compile HLSL source to SPIR-V binary
TArray < uint32 > SpirvData ;
2021-09-08 13:00:48 -04:00
2020-10-09 22:42:26 -04:00
if ( ! bCompilationFailed & & ! CompilerContext . CompileHlslToSpirv ( Options , SpirvData ) )
{
// Flush compile errors
CompilerContext . FlushErrors ( Output . Errors ) ;
bCompilationFailed = true ;
2019-09-14 09:45:25 -04:00
}
2020-09-24 00:43:27 -04:00
2022-09-12 18:18:54 -04:00
// Reduce arrays with const accessors to structs, which will then be packed to an array by GL cross compile
if ( ! bCompilationFailed & & ! Options . bDisableOptimizations & & ( Version = = GLSL_ES3_1_ANDROID | | Version = = GLSL_150_ES3_1 ) )
{
const char * OptArgs [ ] = { " --reduce-const-array-to-struct " } ;
if ( ! CompilerContext . OptimizeSpirv ( SpirvData , OptArgs , UE_ARRAY_COUNT ( OptArgs ) ) )
{
UE_LOG ( LogOpenGLShaderCompiler , Error , TEXT ( " Failed to apply reduce-const-array-to-struct for Android " ) ) ;
return false ;
}
}
2020-09-24 00:43:27 -04:00
if ( ! bCompilationFailed )
2019-09-14 09:45:25 -04:00
{
2022-02-09 18:32:08 -05:00
ReflectionData ReflectData ;
CrossCompiler : : FHlslccHeaderWriter CCHeaderWriter ;
2019-09-14 09:45:25 -04:00
// Now perform reflection on the SPIRV and tweak any decorations that we need to.
// This used to be done via JSON, but that was slow and alloc happy so use SPIRV-Reflect instead.
2020-10-09 22:42:26 -04:00
spv_reflect : : ShaderModule Reflection ( SpirvData . Num ( ) * sizeof ( uint32 ) , SpirvData . GetData ( ) ) ;
2019-09-14 09:45:25 -04:00
check ( Reflection . GetResult ( ) = = SPV_REFLECT_RESULT_SUCCESS ) ;
2021-10-12 10:42:28 -04:00
const ANSICHAR * SPIRV_DummySamplerName = CrossCompiler : : FShaderConductorContext : : GetIdentifierTable ( ) . DummySampler ;
2021-04-08 10:09:56 -04:00
2022-03-02 15:20:27 -05:00
ParseReflectionData ( Input , CCHeaderWriter , ReflectData , SpirvData , Reflection , SPIRV_DummySamplerName , Frequency , bEmulatedUBs ) ;
2022-02-09 18:32:08 -05:00
const ANSICHAR * FrequencyPrefix = GetFrequencyPrefix ( Frequency ) ;
// Step 2 : End of reflection
//
2020-10-09 22:42:26 -04:00
// Overwrite updated SPIRV code
SpirvData = TArray < uint32 > ( Reflection . GetCode ( ) , Reflection . GetCodeSize ( ) / 4 ) ;
2019-09-14 09:45:25 -04:00
if ( bDumpDebugInfo )
{
2020-10-09 22:42:26 -04:00
// SPIR-V file (Binary)
DumpDebugShaderBinary ( Input , SpirvData . GetData ( ) , SpirvData . Num ( ) * sizeof ( uint32 ) , TEXT ( " spv " ) ) ;
2019-09-14 09:45:25 -04:00
}
2020-10-09 22:42:26 -04:00
CrossCompiler : : FShaderConductorTarget TargetDesc ;
2019-09-14 09:45:25 -04:00
switch ( Version )
{
case GLSL_SWITCH_FORWARD :
2020-10-09 22:42:26 -04:00
TargetDesc . Language = CrossCompiler : : EShaderConductorLanguage : : Essl ;
TargetDesc . Version = 320 ;
2019-09-14 09:45:25 -04:00
break ;
case GLSL_SWITCH :
2020-10-09 22:42:26 -04:00
TargetDesc . Language = CrossCompiler : : EShaderConductorLanguage : : Glsl ;
TargetDesc . Version = 430 ;
2019-09-14 09:45:25 -04:00
break ;
2022-03-02 15:20:27 -05:00
case GLSL_150_ES3_1 :
2019-09-14 09:45:25 -04:00
case GLSL_ES3_1_ANDROID :
default :
2021-08-11 07:11:25 -04:00
TargetDesc . CompileFlags . SetDefine ( TEXT ( " force_flattened_io_blocks " ) , 1 ) ;
TargetDesc . CompileFlags . SetDefine ( TEXT ( " emit_uniform_buffer_as_plain_uniforms " ) , 1 ) ;
2022-04-12 08:41:13 -04:00
TargetDesc . CompileFlags . SetDefine ( TEXT ( " pad_ubo_blocks " ) , 1 ) ;
2022-03-21 20:13:01 -04:00
// TODO: Currently disabled due to bug when assigning an array to temporary variable
2023-01-06 11:04:42 -05:00
//TargetDesc.CompileFlags.SetDefine(TEXT("force_temporary"), 1);
2021-10-29 10:20:43 -04:00
// If we have mobile multiview define set then set the view count and enable extension
const FString * MultiViewDefine = Input . Environment . GetDefinitions ( ) . Find ( TEXT ( " MOBILE_MULTI_VIEW " ) ) ;
if ( Frequency = = SF_Vertex & & MultiViewDefine & & * MultiViewDefine = = " 1 " )
2021-10-18 14:48:30 -04:00
{
TargetDesc . CompileFlags . SetDefine ( TEXT ( " ovr_multiview_view_count " ) , 2 ) ;
}
2021-10-29 10:20:43 -04:00
2022-03-02 15:20:27 -05:00
if ( Version = = GLSL_150_ES3_1 )
{
TargetDesc . CompileFlags . SetDefine ( TEXT ( " force_glsl_clipspace " ) , 1 ) ;
}
2020-10-09 22:42:26 -04:00
TargetDesc . Language = CrossCompiler : : EShaderConductorLanguage : : Essl ;
2021-10-01 10:31:37 -04:00
TargetDesc . Version = 320 ;
2019-09-14 09:45:25 -04:00
break ;
}
TSet < FString > ExternalTextures ;
int32 Pos = 0 ;
2019-09-20 15:41:33 -04:00
# if !PLATFORM_MAC
2019-09-14 09:45:25 -04:00
TCHAR TextureExternalName [ 256 ] ;
2019-09-20 15:41:33 -04:00
# else
ANSICHAR TextureExternalName [ 256 ] ;
# endif
2019-09-14 09:45:25 -04:00
do
{
Pos = PreprocessedShader . Find ( TEXT ( " TextureExternal " ) , ESearchCase : : CaseSensitive , ESearchDir : : FromStart , Pos + 15 ) ;
if ( Pos ! = INDEX_NONE )
{
2020-10-09 22:42:26 -04:00
# if PLATFORM_WINDOWS
2019-09-14 09:45:25 -04:00
if ( swscanf_s ( & PreprocessedShader [ Pos ] , TEXT ( " TextureExternal %ls " ) , TextureExternalName , 256 ) = = 1 )
2020-10-09 22:42:26 -04:00
# elif PLATFORM_MAC
if ( sscanf ( TCHAR_TO_ANSI ( & PreprocessedShader [ Pos ] ) , " TextureExternal %s " , TextureExternalName ) = = 1 )
# else // PLATFORM_LINUX
if ( swscanf ( TCHAR_TO_WCHAR ( & PreprocessedShader [ Pos ] ) , L " TextureExternal %ls " , TextureExternalName ) = = 1 )
2019-09-14 09:45:25 -04:00
# endif
{
FString Name = TextureExternalName ;
if ( Name . RemoveFromEnd ( TEXT ( " ; " ) ) )
{
2023-01-06 11:04:42 -05:00
ExternalTextures . Add ( Name + TEXT ( " Sampler " ) ) ;
2019-09-14 09:45:25 -04:00
}
}
}
2020-10-09 22:42:26 -04:00
}
while ( Pos ! = INDEX_NONE ) ;
2019-09-14 09:45:25 -04:00
2020-10-09 22:42:26 -04:00
// Define type renaming callback after all external texture types have been gathered
TargetDesc . VariableTypeRenameCallback = [ & ExternalTextures ] ( const FAnsiStringView & VariableName , const FAnsiStringView & TypeName , FString & OutRenamedTypeName ) - > bool
2019-09-14 09:45:25 -04:00
{
2020-10-09 22:42:26 -04:00
for ( const FString & ExternalTex : ExternalTextures )
2019-09-14 09:45:25 -04:00
{
2023-01-06 11:04:42 -05:00
if ( FCStringWide : : Strstr ( ANSI_TO_TCHAR ( VariableName . GetData ( ) ) , * ExternalTex ) )
2019-09-14 09:45:25 -04:00
{
2020-10-09 22:42:26 -04:00
OutRenamedTypeName = TEXT ( " samplerExternalOES " ) ;
return true ;
2019-09-14 09:45:25 -04:00
}
}
2020-10-09 22:42:26 -04:00
return false ;
} ;
2019-09-14 09:45:25 -04:00
2022-02-09 18:32:08 -05:00
GLSLCompileParameters GLSLCompileParams ;
2019-09-14 09:45:25 -04:00
2022-02-09 18:32:08 -05:00
GLSLCompileParams . CompilerContext = & CompilerContext ;
GLSLCompileParams . CCHeaderWriter = & CCHeaderWriter ;
GLSLCompileParams . TargetDesc = & TargetDesc ;
GLSLCompileParams . Options = & Options ;
GLSLCompileParams . Output = & Output ;
GLSLCompileParams . SpirvData = & SpirvData ;
GLSLCompileParams . Frequency = Frequency ;
GLSLCompileParams . SPIRV_DummySamplerName = SPIRV_DummySamplerName ;
std : : string GlslSource ;
// Handle PLS and FBF in OpenGL
2022-11-10 05:06:00 -05:00
if ( EnvironmentHasMatchingKeyValue ( Input . Environment . GetDefinitions ( ) , TEXT ( " SHADING_PATH_MOBILE " ) , TEXT ( " 1 " ) ) & &
EnvironmentHasMatchingKeyValue ( Input . Environment . GetDefinitions ( ) , TEXT ( " MOBILE_DEFERRED_SHADING " ) , TEXT ( " 1 " ) ) & &
2022-02-09 18:32:08 -05:00
Version = = GLSL_ES3_1_ANDROID )
2019-09-14 09:45:25 -04:00
{
2022-05-03 09:54:19 -04:00
bCompilationFailed = ! GenerateDeferredMobileShaders ( GlslSource , GLSLCompileParams , SourceData , ReflectData , true , false , bEmulatedUBs , BlendFlags ) ;
2019-09-14 09:45:25 -04:00
}
2020-10-09 22:42:26 -04:00
else
2019-09-14 09:45:25 -04:00
{
2022-02-09 18:32:08 -05:00
bCompilationFailed = ! GenerateGlslShader ( GlslSource , GLSLCompileParams , ReflectData , true , false , bEmulatedUBs ) ;
}
2019-09-14 09:45:25 -04:00
2022-02-09 18:32:08 -05:00
// Generate meta data for CCHeader
CCHeaderWriter . WriteSourceInfo ( * Input . GetSourceFilename ( ) , * Input . EntryPointName , * Input . DebugGroupName ) ;
CCHeaderWriter . WriteCompilerInfo ( ) ;
2019-09-14 09:45:25 -04:00
2022-02-09 18:32:08 -05:00
if ( GlslSource . length ( ) > 0 )
{
const FString MetaData = CCHeaderWriter . ToString ( ) ;
2019-09-14 09:45:25 -04:00
2022-02-09 18:32:08 -05:00
// Merge meta data and GLSL source to output string
const int32 GlslShaderSourceLen = MetaData . Len ( ) + static_cast < int32 > ( GlslSource . size ( ) ) + 1 ;
OutGlslShaderSource = ( char * ) malloc ( GlslShaderSourceLen ) ;
FCStringAnsi : : Snprintf ( OutGlslShaderSource , GlslShaderSourceLen , " %s%s " , TCHAR_TO_ANSI ( * MetaData ) , GlslSource . c_str ( ) ) ;
2019-09-14 09:45:25 -04:00
}
}
2020-10-09 22:42:26 -04:00
if ( bDumpDebugInfo & & OutGlslShaderSource ! = nullptr )
{
2021-09-02 16:41:03 -04:00
const TCHAR * ShaderFileExt = CrossCompiler : : FShaderConductorContext : : GetShaderFileExt ( CrossCompiler : : EShaderConductorLanguage : : Essl , Frequency ) ;
DumpDebugShaderText ( Input , OutGlslShaderSource , FCStringAnsi : : Strlen ( OutGlslShaderSource ) , ShaderFileExt ) ;
2020-10-09 22:42:26 -04:00
}
return ! bCompilationFailed ;
2019-09-14 09:45:25 -04:00
}
2020-10-09 22:42:26 -04:00
# endif // DXC_SUPPORTED
2019-09-14 09:45:25 -04:00
2021-02-03 14:57:28 -04:00
static inline FString GetExtension ( EHlslShaderFrequency Frequency , bool bAddDot = true )
{
const TCHAR * Name = nullptr ;
switch ( Frequency )
{
default :
check ( 0 ) ;
// fallthrough...
case HSF_PixelShader : Name = TEXT ( " .frag " ) ; break ;
case HSF_VertexShader : Name = TEXT ( " .vert " ) ; break ;
case HSF_ComputeShader : Name = TEXT ( " .comp " ) ; break ;
case HSF_GeometryShader : Name = TEXT ( " .geom " ) ; break ;
case HSF_HullShader : Name = TEXT ( " .tesc " ) ; break ;
case HSF_DomainShader : Name = TEXT ( " .tese " ) ; break ;
}
if ( ! bAddDot )
{
+ + Name ;
}
return FString ( Name ) ;
}
2016-09-30 21:21:09 -04:00
/**
* Compile a shader for OpenGL on Windows.
* @param Input - The input shader code and environment.
* @param Output - Contains shader compilation results upon return.
*/
2020-10-09 22:42:26 -04:00
void FOpenGLFrontend : : CompileShader ( const FShaderCompilerInput & Input , FShaderCompilerOutput & Output , const FString & WorkingDirectory , GLSLVersion Version )
2016-09-30 21:21:09 -04:00
{
FString PreprocessedShader ;
FShaderCompilerDefinitions AdditionalDefines ;
EHlslCompileTarget HlslCompilerTarget = HCT_InvalidTarget ;
ECompilerFlags PlatformFlowControl = CFLAG_AvoidFlowControl ;
// set up compiler env based on version
SetupPerVersionCompilationEnvironment ( Version , AdditionalDefines , HlslCompilerTarget ) ;
2020-10-09 22:42:26 -04:00
# if DXC_SUPPORTED
const bool bUseSC = Input . Environment . CompilerFlags . Contains ( CFLAG_ForceDXC ) ;
# else
const bool bUseSC = false ;
# endif
2019-09-14 09:45:25 -04:00
AdditionalDefines . SetDefine ( TEXT ( " COMPILER_HLSLCC " ) , bUseSC ? 2 : 1 ) ;
2017-08-21 15:05:19 -04:00
2014-03-14 14:13:41 -04:00
const bool bDumpDebugInfo = ( Input . DumpDebugInfoPath ! = TEXT ( " " ) & & IFileManager : : Get ( ) . DirectoryExists ( * Input . DumpDebugInfoPath ) ) ;
2020-10-09 22:42:26 -04:00
if ( Input . Environment . CompilerFlags . Contains ( CFLAG_AvoidFlowControl ) | | PlatformFlowControl = = CFLAG_AvoidFlowControl )
2015-08-20 10:15:09 -04:00
{
AdditionalDefines . SetDefine ( TEXT ( " COMPILER_SUPPORTS_ATTRIBUTES " ) , ( uint32 ) 1 ) ;
}
else
{
AdditionalDefines . SetDefine ( TEXT ( " COMPILER_SUPPORTS_ATTRIBUTES " ) , ( uint32 ) 0 ) ;
}
2016-03-16 21:16:51 -04:00
2021-11-03 11:57:39 -04:00
if ( Input . Environment . FullPrecisionInPS )
2016-06-13 12:20:22 -04:00
{
AdditionalDefines . SetDefine ( TEXT ( " FORCE_FLOATS " ) , ( uint32 ) 1 ) ;
}
2017-08-24 15:38:57 -04:00
if ( Input . bSkipPreprocessedCache )
2016-03-16 21:16:51 -04:00
{
2017-08-24 15:38:57 -04:00
if ( ! FFileHelper : : LoadFileToString ( PreprocessedShader , * Input . VirtualSourceFilePath ) )
2016-03-16 21:16:51 -04:00
{
2017-08-24 15:38:57 -04:00
return ;
2016-03-16 21:16:51 -04:00
}
2017-08-24 15:38:57 -04:00
// Remove const as we are on debug-only mode
CrossCompiler : : CreateEnvironmentFromResourceTable ( PreprocessedShader , ( FShaderCompilerEnvironment & ) Input . Environment ) ;
}
else
{
if ( ! PreprocessShader ( PreprocessedShader , Output , Input , AdditionalDefines ) )
2016-03-16 21:16:51 -04:00
{
2017-08-24 15:38:57 -04:00
// The preprocessing stage will add any relevant errors.
return ;
2016-03-16 21:16:51 -04:00
}
2017-08-24 15:38:57 -04:00
}
char * GlslShaderSource = NULL ;
char * ErrorLog = NULL ;
const bool bIsSM5 = IsSM5 ( Version ) ;
const EHlslShaderFrequency FrequencyTable [ ] =
{
HSF_VertexShader ,
2021-03-18 18:42:49 -04:00
HSF_InvalidFrequency ,
HSF_InvalidFrequency ,
2017-08-24 15:38:57 -04:00
HSF_PixelShader ,
2020-02-12 13:27:19 -05:00
HSF_GeometryShader ,
2021-11-18 14:37:34 -05:00
HSF_ComputeShader
2016-03-16 21:16:51 -04:00
} ;
2021-03-18 18:42:49 -04:00
static_assert ( SF_NumStandardFrequencies = = UE_ARRAY_COUNT ( FrequencyTable ) , " NumFrequencies changed. Please update tables. " ) ;
2016-03-16 21:16:51 -04:00
2021-09-02 16:41:03 -04:00
const EShaderFrequency Frequency = ( EShaderFrequency ) Input . Target . Frequency ;
const EHlslShaderFrequency HlslFrequency = FrequencyTable [ Frequency ] ;
if ( HlslFrequency = = HSF_InvalidFrequency )
2014-03-14 14:13:41 -04:00
{
2017-08-24 15:38:57 -04:00
Output . bSucceeded = false ;
FShaderCompilerError * NewError = new ( Output . Errors ) FShaderCompilerError ( ) ;
NewError - > StrippedErrorMessage = FString : : Printf (
TEXT ( " %s shaders not supported for use in OpenGL. " ) ,
2021-09-02 16:41:03 -04:00
CrossCompiler : : GetFrequencyName ( Frequency )
2017-08-24 15:38:57 -04:00
) ;
return ;
}
2014-03-14 14:13:41 -04:00
2020-01-24 18:07:01 -05:00
FShaderParameterParser ShaderParameterParser ;
2022-10-18 15:25:05 -04:00
if ( ! ShaderParameterParser . ParseAndModify ( Input , Output , PreprocessedShader ) )
2020-01-24 18:07:01 -05:00
{
// The FShaderParameterParser will add any relevant errors.
return ;
}
2017-08-24 15:38:57 -04:00
// This requires removing the HLSLCC_NoPreprocess flag later on!
2018-05-01 10:36:33 -04:00
RemoveUniformBuffersFromSource ( Input . Environment , PreprocessedShader ) ;
2014-09-18 17:49:40 -04:00
2022-04-06 17:19:38 -04:00
// Process TEXT macro.
TransformStringIntoCharacterArray ( PreprocessedShader ) ;
2022-12-07 15:13:42 -05:00
// Run the experimental shader minifier
# if UE_OPENGL_SHADER_COMPILER_ALLOW_DEAD_CODE_REMOVAL
if ( Input . Environment . CompilerFlags . Contains ( CFLAG_RemoveDeadCode ) )
{
UE : : ShaderCompilerCommon : : RemoveDeadCode ( PreprocessedShader , Input . EntryPointName , Output . Errors ) ;
}
# endif // UE_OPENGL_SHADER_COMPILER_ALLOW_DEAD_CODE_REMOVAL
2021-11-03 11:57:39 -04:00
uint32 CCFlags = CalculateCrossCompilerFlags ( Version , Input . Environment . FullPrecisionInPS , Input . Environment . CompilerFlags ) ;
2019-02-27 14:27:10 -05:00
// Required as we added the RemoveUniformBuffersFromSource() function (the cross-compiler won't be able to interpret comments w/o a preprocessor)
CCFlags & = ~ HLSLCC_NoPreprocess ;
2020-10-09 22:42:26 -04:00
bool bCompilationSucceeded = false ;
# if DXC_SUPPORTED
2019-09-14 09:45:25 -04:00
if ( bUseSC )
2017-08-24 15:38:57 -04:00
{
2020-10-09 22:42:26 -04:00
bCompilationSucceeded = CompileToGlslWithShaderConductor ( Input , Output , WorkingDirectory , Version , Frequency , CCFlags , PreprocessedShader , GlslShaderSource ) ;
2019-09-14 09:45:25 -04:00
}
else
2020-10-09 22:42:26 -04:00
# endif // DXC_SUPPORTED
2019-09-14 09:45:25 -04:00
{
2022-10-28 11:45:49 -04:00
UE : : ShaderCompilerCommon : : FDebugShaderDataOptions DebugDataOptions ;
DebugDataOptions . HlslCCFlags = CCFlags ;
UE : : ShaderCompilerCommon : : DumpDebugShaderData ( Input , PreprocessedShader , DebugDataOptions ) ;
2022-09-12 18:18:54 -04:00
CCFlags | = HLSLCC_NoValidation ;
2019-09-14 09:45:25 -04:00
FGlslCodeBackend * BackEnd = CreateBackend ( Version , CCFlags , HlslCompilerTarget ) ;
2020-03-13 11:36:26 -04:00
bool bDefaultPrecisionIsHalf = ( CCFlags & HLSLCC_UseFullPrecisionInPS ) = = 0 ;
FGlslLanguageSpec * LanguageSpec = CreateLanguageSpec ( Version , bDefaultPrecisionIsHalf ) ;
2019-09-14 09:45:25 -04:00
2021-09-02 16:41:03 -04:00
FHlslCrossCompilerContext CrossCompilerContext ( CCFlags , HlslFrequency , HlslCompilerTarget ) ;
2019-09-14 09:45:25 -04:00
if ( CrossCompilerContext . Init ( TCHAR_TO_ANSI ( * Input . VirtualSourceFilePath ) , LanguageSpec ) )
2017-08-24 15:38:57 -04:00
{
2020-10-09 22:42:26 -04:00
bCompilationSucceeded = CrossCompilerContext . Run (
2019-09-14 09:45:25 -04:00
TCHAR_TO_ANSI ( * PreprocessedShader ) ,
TCHAR_TO_ANSI ( * Input . EntryPointName ) ,
BackEnd ,
& GlslShaderSource ,
& ErrorLog
2020-10-09 22:42:26 -04:00
) ;
2017-08-24 15:38:57 -04:00
}
2019-09-14 09:45:25 -04:00
delete BackEnd ;
delete LanguageSpec ;
2020-12-03 02:29:32 -04:00
if ( bDumpDebugInfo & & bCompilationSucceeded & & GlslShaderSource ! = nullptr )
{
2021-09-02 16:41:03 -04:00
const TCHAR * ShaderFileExt = CrossCompiler : : FShaderConductorContext : : GetShaderFileExt ( CrossCompiler : : EShaderConductorLanguage : : Essl , Frequency ) ;
DumpDebugShaderText ( Input , GlslShaderSource , FCStringAnsi : : Strlen ( GlslShaderSource ) , ShaderFileExt ) ;
2020-12-03 02:29:32 -04:00
}
2017-08-24 15:38:57 -04:00
}
2014-03-14 14:13:41 -04:00
2020-10-09 22:42:26 -04:00
static const bool bDirectCompile = FParse : : Param ( FCommandLine : : Get ( ) , TEXT ( " directcompile " ) ) ;
if ( bCompilationSucceeded )
2017-08-24 15:38:57 -04:00
{
2020-01-24 18:07:01 -05:00
if ( bDirectCompile )
{
FPlatformMisc : : LowLevelOutputDebugStringf ( TEXT ( " %s \n " ) , ANSI_TO_TCHAR ( GlslShaderSource ) ) ;
}
2014-04-23 18:54:23 -04:00
# if VALIDATE_GLSL_WITH_DRIVER
2021-09-02 16:41:03 -04:00
PrecompileShader ( Output , Input , GlslShaderSource , Version , HlslFrequency ) ;
2014-04-23 18:54:23 -04:00
# else // VALIDATE_GLSL_WITH_DRIVER
2021-01-13 09:15:02 -04:00
int32 SourceLen = FCStringAnsi : : Strlen ( GlslShaderSource ) ; //-V595
2017-08-24 15:38:57 -04:00
Output . Target = Input . Target ;
BuildShaderOutput ( Output , Input , GlslShaderSource , SourceLen , Version ) ;
2014-04-23 18:54:23 -04:00
# endif // VALIDATE_GLSL_WITH_DRIVER
2021-02-03 14:57:28 -04:00
2021-10-25 20:05:28 -04:00
if ( bDumpDebugInfo & & GlslShaderSource ! = nullptr )
2021-02-03 14:57:28 -04:00
{
2021-09-02 16:41:03 -04:00
const TCHAR * ShaderFileExt = CrossCompiler : : FShaderConductorContext : : GetShaderFileExt ( CrossCompiler : : EShaderConductorLanguage : : Essl , Frequency ) ;
FString DumpedGlslFile = FString : : Printf ( TEXT ( " %s/Output.%s " ) , * Input . DumpDebugInfoPath , ShaderFileExt ) ;
2021-02-03 14:57:28 -04:00
if ( TUniquePtr < FArchive > FileWriter = TUniquePtr < FArchive > ( IFileManager : : Get ( ) . CreateFileWriter ( * DumpedGlslFile ) ) )
{
FileWriter - > Serialize ( GlslShaderSource , FCStringAnsi : : Strlen ( GlslShaderSource ) ) ;
FileWriter - > Close ( ) ;
}
}
2017-08-24 15:38:57 -04:00
}
2020-10-09 22:42:26 -04:00
else if ( ! bUseSC )
2017-08-24 15:38:57 -04:00
{
2020-10-09 22:42:26 -04:00
const bool bUseAbsolutePaths = bDirectCompile ;
FString Tmp = ANSI_TO_TCHAR ( ErrorLog ) ;
TArray < FString > ErrorLines ;
Tmp . ParseIntoArray ( ErrorLines , TEXT ( " \n " ) , true ) ;
for ( int32 LineIndex = 0 ; LineIndex < ErrorLines . Num ( ) ; + + LineIndex )
2014-09-29 18:57:21 -04:00
{
2020-10-09 22:42:26 -04:00
const FString & Line = ErrorLines [ LineIndex ] ;
CrossCompiler : : ParseHlslccError ( Output . Errors , Line , bUseAbsolutePaths ) ;
2014-03-14 14:13:41 -04:00
}
}
2017-08-24 15:38:57 -04:00
if ( GlslShaderSource )
{
free ( GlslShaderSource ) ;
}
if ( ErrorLog )
{
free ( ErrorLog ) ;
}
2020-01-24 18:07:01 -05:00
// Do not validate as global halfN != UB's halfN
//ShaderParameterParser.ValidateShaderParameterTypes(Input, Output);
2014-03-14 14:13:41 -04:00
}
2018-06-26 08:42:47 -04:00
enum class EPlatformType
{
Android ,
IOS ,
Web ,
Desktop
} ;
struct FDeviceCapabilities
{
EPlatformType TargetPlatform = EPlatformType : : Android ;
} ;
void FOpenGLFrontend : : FillDeviceCapsOfflineCompilation ( struct FDeviceCapabilities & Capabilities , const GLSLVersion ShaderVersion ) const
{
FMemory : : Memzero ( Capabilities ) ;
2020-02-12 13:27:19 -05:00
if ( ShaderVersion = = GLSL_ES3_1_ANDROID )
2018-06-26 08:42:47 -04:00
{
Capabilities . TargetPlatform = EPlatformType : : Android ;
}
else
{
Capabilities . TargetPlatform = EPlatformType : : Desktop ;
}
}
static bool MoveHashLines ( FString & Destination , FString & Source )
{
int32 Index = 0 ;
int32 LineStart = 0 ;
bool bFound = false ;
while ( Index ! = INDEX_NONE & & ! bFound )
{
LineStart = Index ;
Index = Source . Find ( TEXT ( " \n " ) , ESearchCase : : IgnoreCase , ESearchDir : : FromStart , Index ) ;
for ( int32 i = LineStart ; i < Index ; + + i )
{
const auto CharValue = Source [ i ] ;
if ( CharValue = = ' # ' )
{
break ;
}
else if ( ! FChar : : IsWhitespace ( CharValue ) )
{
bFound = true ;
break ;
}
}
+ + Index ;
}
if ( bFound )
{
Destination . Append ( Source . Left ( LineStart ) ) ;
Source . RemoveAt ( 0 , LineStart ) ;
}
return bFound ;
}
TSharedPtr < ANSICHAR > FOpenGLFrontend : : PrepareCodeForOfflineCompilation ( const GLSLVersion ShaderVersion , EShaderFrequency Frequency , const ANSICHAR * InShaderSource ) const
{
FString OriginalShaderSource ( ANSI_TO_TCHAR ( InShaderSource ) ) ;
FString StrOutSource ;
FDeviceCapabilities Capabilities ;
FillDeviceCapsOfflineCompilation ( Capabilities , ShaderVersion ) ;
// Whether we need to emit mobile multi-view code or not.
const bool bEmitMobileMultiView = OriginalShaderSource . Find ( TEXT ( " gl_ViewID_OVR " ) ) ! = INDEX_NONE ;
// Whether we need to emit texture external code or not.
const bool bEmitTextureExternal = OriginalShaderSource . Find ( TEXT ( " samplerExternalOES " ) ) ! = INDEX_NONE ;
bool bNeedsExtDrawInstancedDefine = false ;
if ( Capabilities . TargetPlatform = = EPlatformType : : Android | | Capabilities . TargetPlatform = = EPlatformType : : Web )
{
2021-10-01 10:31:37 -04:00
const TCHAR * ES320Version = TEXT ( " #version 320 es " ) ;
StrOutSource . Append ( ES320Version ) ;
2020-09-24 00:43:27 -04:00
StrOutSource . Append ( TEXT ( " \n " ) ) ;
2021-10-01 10:31:37 -04:00
OriginalShaderSource . RemoveFromStart ( ES320Version ) ;
2018-06-26 08:42:47 -04:00
}
const GLenum TypeEnum = GLFrequencyTable [ Frequency ] ;
// The incoming glsl may have preprocessor code that is dependent on defines introduced via the engine.
2021-10-01 10:31:37 -04:00
// This is the place to insert such engine preprocessor defines, immediately after the glsl version declarati
2018-06-26 08:42:47 -04:00
if ( bEmitMobileMultiView )
{
MoveHashLines ( StrOutSource , OriginalShaderSource ) ;
StrOutSource . Append ( TEXT ( " \n \n " ) ) ;
StrOutSource . Append ( TEXT ( " #extension GL_OVR_multiview2 : enable \n " ) ) ;
StrOutSource . Append ( TEXT ( " \n \n " ) ) ;
}
if ( bEmitTextureExternal )
{
MoveHashLines ( StrOutSource , OriginalShaderSource ) ;
StrOutSource . Append ( TEXT ( " #define samplerExternalOES sampler2D \n " ) ) ;
}
2020-09-24 00:43:27 -04:00
// Move version tag & extensions before beginning all other operations
MoveHashLines ( StrOutSource , OriginalShaderSource ) ;
2018-06-26 08:42:47 -04:00
2020-09-24 00:43:27 -04:00
// OpenGL SM5 shader platforms require location declarations for the layout, but don't necessarily use SSOs
if ( Capabilities . TargetPlatform = = EPlatformType : : Desktop )
{
StrOutSource . Append ( TEXT ( " #define INTERFACE_BLOCK(Pos, Interp, Modifiers, Semantic, PreType, PostType) layout(location=Pos) Interp Modifiers struct { PreType PostType; } \n " ) ) ;
}
else
{
StrOutSource . Append ( TEXT ( " #define INTERFACE_BLOCK(Pos, Interp, Modifiers, Semantic, PreType, PostType) layout(location=Pos) Modifiers Semantic { PreType PostType; } \n " ) ) ;
2018-06-26 08:42:47 -04:00
}
2020-09-24 00:43:27 -04:00
if ( Capabilities . TargetPlatform = = EPlatformType : : Desktop )
2018-06-26 08:42:47 -04:00
{
2020-09-24 00:43:27 -04:00
// If we're running <= featurelevel es3.1 shaders then enable this extension which adds support for uintBitsToFloat etc.
if ( StrOutSource . Contains ( TEXT ( " #version 150 " ) ) )
2018-06-26 08:42:47 -04:00
{
2020-09-24 00:43:27 -04:00
StrOutSource . Append ( TEXT ( " \n \n " ) ) ;
StrOutSource . Append ( TEXT ( " #extension GL_ARB_gpu_shader5 : enable \n " ) ) ;
StrOutSource . Append ( TEXT ( " \n \n " ) ) ;
2018-06-26 08:42:47 -04:00
}
}
StrOutSource . Append ( TEXT ( " #define HLSLCC_DX11ClipSpace 1 \n " ) ) ;
// Append the possibly edited shader to the one we will compile.
// This is to make it easier to debug as we can see the whole
// shader source.
StrOutSource . Append ( TEXT ( " \n \n " ) ) ;
StrOutSource . Append ( OriginalShaderSource ) ;
const int32 SourceLen = StrOutSource . Len ( ) ;
TSharedPtr < ANSICHAR > RetShaderSource = MakeShareable ( new ANSICHAR [ SourceLen + 1 ] ) ;
FCStringAnsi : : Strcpy ( RetShaderSource . Get ( ) , SourceLen + 1 , TCHAR_TO_ANSI ( * StrOutSource ) ) ;
return RetShaderSource ;
}
bool FOpenGLFrontend : : PlatformSupportsOfflineCompilation ( const GLSLVersion ShaderVersion ) const
{
switch ( ShaderVersion )
{
// desktop
case GLSL_150_ES3_1 :
// switch
case GLSL_SWITCH :
case GLSL_SWITCH_FORWARD :
return false ;
break ;
case GLSL_ES3_1_ANDROID :
return true ;
break ;
}
return false ;
}
void FOpenGLFrontend : : CompileOffline ( const FShaderCompilerInput & Input , FShaderCompilerOutput & Output , const GLSLVersion ShaderVersion , const ANSICHAR * InShaderSource )
{
const bool bSupportsOfflineCompilation = PlatformSupportsOfflineCompilation ( ShaderVersion ) ;
if ( ! bSupportsOfflineCompilation )
2019-02-27 14:27:10 -05:00
{
return ;
}
2018-06-26 08:42:47 -04:00
TSharedPtr < ANSICHAR > ShaderSource = PrepareCodeForOfflineCompilation ( ShaderVersion , ( EShaderFrequency ) Input . Target . Frequency , InShaderSource ) ;
PlatformCompileOffline ( Input , Output , ShaderSource . Get ( ) , ShaderVersion ) ;
}
void FOpenGLFrontend : : PlatformCompileOffline ( const FShaderCompilerInput & Input , FShaderCompilerOutput & ShaderOutput , const ANSICHAR * ShaderSource , const GLSLVersion ShaderVersion )
{
2020-02-12 13:27:19 -05:00
if ( ShaderVersion = = GLSL_ES3_1_ANDROID )
2019-02-27 14:27:10 -05:00
{
2018-06-26 08:42:47 -04:00
CompileOfflineMali ( Input , ShaderOutput , ShaderSource , FPlatformString : : Strlen ( ShaderSource ) , false ) ;
2019-02-27 14:27:10 -05:00
}
2018-06-26 08:42:47 -04:00
}