2014-12-07 19:09:38 -05:00
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2014-12-15 12:21:10 -05:00
//
2014-07-02 11:08:24 -04:00
2014-03-14 14:13:41 -04:00
# include "ShaderFormatOpenGL.h"
# include "Core.h"
# if PLATFORM_WINDOWS
# include "AllowWindowsPlatformTypes.h"
# include "Windows/PreWindowsApi.h"
# include <objbase.h>
# include <assert.h>
# include <stdio.h>
# include "Windows/PostWindowsApi.h"
# include "Windows/MinWindows.h"
# include "HideWindowsPlatformTypes.h"
# endif
2014-06-05 16:38:54 -04:00
# include "ShaderPreprocessor.h"
# include "ShaderCompilerCommon.h"
2014-03-14 14:13:41 -04:00
# include "hlslcc.h"
2014-09-25 18:03:18 -04:00
# include "GlslBackend.h"
2014-03-14 14:13:41 -04:00
# if PLATFORM_WINDOWS
# include "AllowWindowsPlatformTypes.h"
# include <GL/glcorearb.h>
# include <GL/glext.h>
# include <GL/wglext.h>
# include "HideWindowsPlatformTypes.h"
2014-06-05 17:11:45 -04:00
# elif PLATFORM_LINUX
2014-08-04 18:28:10 -04:00
# define GL_GLEXT_PROTOTYPES 1
2014-07-17 13:49:42 -04:00
# include <GL/glcorearb.h>
2014-06-05 17:11:45 -04:00
# include <GL/glext.h>
2014-08-04 18:28:10 -04:00
# include "SDL.h"
GLAPI GLuint APIENTRY glCreateShader ( GLenum type ) ;
GLAPI void APIENTRY glShaderSource ( GLuint shader , GLsizei count , const GLchar * const * string , const GLint * length ) ;
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
# endif
# 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"
DEFINE_LOG_CATEGORY_STATIC ( LogOpenGLShaderCompiler , Log , All ) ;
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
2014-09-18 17:49:40 -04:00
2014-03-14 14:13:41 -04:00
static FORCEINLINE bool IsES2Platform ( GLSLVersion Version )
{
2015-03-11 13:45:34 -04:00
return ( Version = = GLSL_ES2 | | Version = = GLSL_150_ES2 | | Version = = GLSL_ES2_WEBGL | | Version = = GLSL_ES2_IOS | | Version = = GLSL_150_ES2_NOUB ) ;
2014-03-14 14:13:41 -04:00
}
static FORCEINLINE bool IsPCES2Platform ( GLSLVersion Version )
{
2015-04-13 18:00:32 -04:00
return ( Version = = GLSL_150_ES2 | | Version = = GLSL_150_ES2_NOUB | | Version = = GLSL_150_ES3_1 ) ;
2014-03-14 14:13:41 -04:00
}
2015-02-06 11:35:30 -05:00
// This function should match OpenGLShaderPlatformSeparable
static FORCEINLINE bool SupportsSeparateShaderObjects ( GLSLVersion Version )
{
// Only desktop shader platforms can use separable shaders for now,
// the generated code relies on macros supplied at runtime to determine whether
// shaders may be separable and/or linked.
2015-04-13 18:00:32 -04:00
return Version = = GLSL_150 | | Version = = GLSL_150_MAC | | Version = = GLSL_150_ES2 | | Version = = GLSL_150_ES2_NOUB | | Version = = GLSL_150_ES3_1 | | Version = = GLSL_430 ;
2015-02-06 11:35:30 -05:00
}
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
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 ,
SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOW_HIDDEN ) ;
}
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 ( ) ) ) ;
}
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
GL_TESS_CONTROL_SHADER , // SF_Hull
GL_TESS_EVALUATION_SHADER , // SF_Domain
GL_FRAGMENT_SHADER , // SF_Pixel
GL_GEOMETRY_SHADER , // SF_Geometry
GL_COMPUTE_SHADER , // SF_Compute
} ;
2015-07-02 11:52:03 -04:00
static_assert ( ARRAY_COUNT ( GLFrequencyTable ) = = SF_NumFrequencies , " Frequency table size mismatch. " ) ;
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.
while ( * p & & * p < TEXT ( ' 0 ' ) & & * p > TEXT ( ' 9 ' ) ) { p + + ; }
while ( * p & & * p > = TEXT ( ' 0 ' ) & & * p < = TEXT ( ' 9 ' ) )
{
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 ;
while ( * Str & & * Str > = ' 0 ' & & * Str < = ' 9 ' )
{
Num = Num * 10 + * Str + + - ' 0 ' ;
}
return Num ;
}
/**
* 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 .
*/
static void BuildShaderOutput (
FShaderCompilerOutput & ShaderOutput ,
2014-06-05 16:38:54 -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 " ) ) ;
}
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_Hull :
Header . FrequencyMarker = 0x4853 ;
break ;
case SF_Domain :
Header . FrequencyMarker = 0x4453 ;
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 " ) ;
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 ( ) ) ;
Header . Bindings . InOutMask | = ( 1 < < AttributeIndex ) ;
}
// 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-02-25 10:25:20 -05:00
// Generate vertex attribute remapping table.
// This is used on devices where GL_MAX_VERTEX_ATTRIBS < 16
if ( Frequency = = SF_Vertex )
{
uint32 AttributeMask = Header . Bindings . InOutMask ;
int32 NextAttributeSlot = 0 ;
Header . Bindings . VertexRemappedMask = 0 ;
2015-07-02 11:52:03 -04:00
for ( int32 AttributeIndex = 0 ; AttributeIndex < 16 ; AttributeIndex + + , AttributeMask > > = 1 )
2015-02-25 10:25:20 -05:00
{
if ( AttributeMask & 0x1 )
{
Header . Bindings . VertexRemappedMask | = ( 1 < < NextAttributeSlot ) ;
Header . Bindings . VertexAttributeRemap [ AttributeIndex ] = NextAttributeSlot + + ;
}
else
{
Header . Bindings . VertexAttributeRemap [ AttributeIndex ] = - 1 ;
}
}
}
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
{
2015-07-02 11:52:03 -04:00
// Only targets for pixel shaders must be tracked.
if ( Frequency = = SF_Pixel & & Output . Name . StartsWith ( TargetPrefix ) )
2015-02-06 11:35:30 -05:00
{
2015-07-02 11:52:03 -04:00
uint8 TargetIndex = ParseNumber ( * Output . Name + TargetPrefix . Len ( ) ) ;
Header . Bindings . InOutMask | = ( 1 < < TargetIndex ) ;
}
// Only depth writes for pixel shaders must be tracked.
else if ( Frequency = = SF_Pixel & & Output . Name . Equals ( GL_FragDepth ) )
{
Header . Bindings . InOutMask | = 0x8000 ;
}
// 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 ) ;
2015-02-06 11:35:30 -05:00
}
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 ;
check ( UBIndex = = Header . Bindings . NumUniformBuffers ) ;
UsedUniformBufferSlots [ UBIndex ] = true ;
ParameterMap . AddParameterAllocation ( * UniformBlock . Name , Header . Bindings . NumUniformBuffers + + , 0 , 0 ) ;
2014-03-14 14:13:41 -04:00
}
const uint16 BytesPerComponent = 4 ;
// 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
{
2015-07-02 11:52:03 -04:00
ParameterMap . AddParameterAllocation (
* PackedGlobal . Name ,
PackedGlobal . PackedType ,
PackedGlobal . Offset * BytesPerComponent ,
PackedGlobal . Count * BytesPerComponent
) ;
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
{
2015-07-02 11:52:03 -04:00
check ( PackedUB . Attribute . Index = = Header . Bindings . NumUniformBuffers ) ;
UsedUniformBufferSlots [ PackedUB . Attribute . Index ] = true ;
ParameterMap . AddParameterAllocation ( * PackedUB . Attribute . Name , Header . Bindings . NumUniformBuffers + + , 0 , 0 ) ;
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 ) ;
}
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
{
2015-07-02 11:52:03 -04:00
ParameterMap . AddParameterAllocation (
* Sampler . Name ,
0 ,
Sampler . Offset ,
Sampler . Count
) ;
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
{
ParameterMap . AddParameterAllocation (
2015-07-02 11:52:03 -04:00
* SamplerState ,
2014-03-14 14:13:41 -04:00
0 ,
2015-07-02 11:52:03 -04:00
Sampler . Offset ,
Sampler . Count
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
{
2015-07-02 11:52:03 -04:00
ParameterMap . AddParameterAllocation (
* UAV . Name ,
0 ,
UAV . Offset ,
UAV . Count
) ;
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
2014-06-05 16:38:54 -04:00
// Build the SRT for this shader.
{
// Build the generic SRT for this shader.
FShaderResourceTable GenericSRT ;
BuildResourceTableMapping ( ShaderInput . Environment . ResourceTableMap , ShaderInput . Environment . ResourceTableLayoutHashes , UsedUniformBufferSlots , ShaderOutput . ParameterMap , GenericSRT ) ;
// 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 ) ;
}
2014-03-14 14:13:41 -04:00
const int32 MaxSamplers = GetFeatureLevelMaxTextureSamplers ( GetMaxSupportedFeatureLevel ( ( EShaderPlatform ) ShaderOutput . Target . Platform ) ) ;
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 ) ;
}
else
{
// Write out the header and shader source code.
FMemoryWriter Ar ( ShaderOutput . Code , true ) ;
Ar < < Header ;
2015-07-02 11:52:03 -04:00
Ar . Serialize ( ( void * ) USFSource , SourceLen + 1 - ( USFSource - InShaderSource ) ) ;
2014-03-14 14:13:41 -04:00
ShaderOutput . NumInstructions = 0 ;
ShaderOutput . NumTextureSamplers = Header . Bindings . NumSamplers ;
ShaderOutput . bSucceeded = true ;
}
}
static void OpenGLVersionFromGLSLVersion ( GLSLVersion InVersion , int & OutMajorVersion , int & OutMinorVersion )
{
switch ( InVersion )
{
case GLSL_150 :
2014-04-02 18:09:23 -04:00
case GLSL_150_MAC :
2014-03-14 14:13:41 -04:00
OutMajorVersion = 3 ;
OutMinorVersion = 2 ;
break ;
2014-09-18 17:49:40 -04:00
case GLSL_310_ES_EXT :
2014-03-14 14:13:41 -04:00
case GLSL_430 :
OutMajorVersion = 4 ;
OutMinorVersion = 3 ;
break ;
case GLSL_150_ES2 :
2015-03-11 13:45:34 -04:00
case GLSL_150_ES2_NOUB :
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 ;
case GLSL_ES2_IOS :
case GLSL_ES2_WEBGL :
case GLSL_ES2 :
OutMajorVersion = 0 ;
OutMinorVersion = 0 ;
break ;
default :
// Invalid enum
check ( 0 ) ;
OutMajorVersion = 0 ;
OutMinorVersion = 0 ;
break ;
}
}
static const TCHAR * GetGLSLES2CompilerExecutable ( bool bNDACompiler )
{
// Unfortunately no env var is set to handle install path
return ( bNDACompiler
? TEXT ( " C: \\ Imagination \\ PowerVR \\ GraphicsSDK \\ Compilers \\ OGLES \\ Windows_x86_32 \\ glslcompiler_sgx543_nda.exe " )
: TEXT ( " C: \\ Imagination \\ PowerVR \\ GraphicsSDK \\ Compilers \\ OGLES \\ Windows_x86_32 \\ glslcompiler_sgx543.exe " ) ) ;
}
static FString CreateGLSLES2CompilerArguments ( const FString & ShaderFile , const FString & OutputFile , EHlslShaderFrequency Frequency , bool bNDACompiler )
{
const TCHAR * FrequencySwitch = TEXT ( " " ) ;
switch ( Frequency )
{
2014-04-02 18:09:23 -04:00
case HSF_PixelShader :
2014-03-14 14:13:41 -04:00
FrequencySwitch = TEXT ( " -f " ) ;
break ;
2014-04-02 18:09:23 -04:00
case HSF_VertexShader :
2014-03-14 14:13:41 -04:00
FrequencySwitch = TEXT ( " -v " ) ;
break ;
default :
return TEXT ( " " ) ;
}
FString Arguments = FString : : Printf ( TEXT ( " %s %s %s -profile -perfsim " ) , * FPaths : : GetCleanFilename ( ShaderFile ) , * FPaths : : GetCleanFilename ( OutputFile ) , FrequencySwitch ) ;
if ( bNDACompiler )
{
Arguments + = " -disasm " ;
}
return Arguments ;
}
static FString CreateCommandLineGLSLES2 ( const FString & ShaderFile , const FString & OutputFile , GLSLVersion Version , EHlslShaderFrequency Frequency , bool bNDACompiler )
{
if ( Version ! = GLSL_ES2 & & Version ! = GLSL_ES2_WEBGL & & Version ! = GLSL_ES2_IOS )
{
return TEXT ( " " ) ;
}
FString CmdLine = FString ( GetGLSLES2CompilerExecutable ( bNDACompiler ) ) + TEXT ( " " ) + CreateGLSLES2CompilerArguments ( ShaderFile , OutputFile , Frequency , bNDACompiler ) ;
CmdLine + = FString ( LINE_TERMINATOR ) + TEXT ( " pause " ) ;
return CmdLine ;
}
/** Precompile a glsl shader for ES2. */
static void PrecompileGLSLES2 ( FShaderCompilerOutput & ShaderOutput , const FShaderCompilerInput & ShaderInput , const ANSICHAR * ShaderSource , EHlslShaderFrequency Frequency )
{
const TCHAR * CompilerExecutableName = GetGLSLES2CompilerExecutable ( false ) ;
const int32 SourceLen = FCStringAnsi : : Strlen ( ShaderSource ) ;
const bool bCompilerExecutableExists = FPaths : : FileExists ( CompilerExecutableName ) ;
// Using the debug info path to write out the files to disk for the PVR shader compiler
if ( ShaderInput . DumpDebugInfoPath ! = TEXT ( " " ) & & bCompilerExecutableExists )
{
const FString GLSLSourceFile = ( ShaderInput . DumpDebugInfoPath / TEXT ( " GLSLSource.txt " ) ) ;
bool bSavedSuccessfully = false ;
{
FArchive * Ar = IFileManager : : Get ( ) . CreateFileWriter ( * GLSLSourceFile , FILEWRITE_EvenIfReadOnly ) ;
// Save the ansi file to disk so it can be used as input to the PVR shader compiler
if ( Ar )
{
bSavedSuccessfully = true ;
// @todo: Patch the code so that textureCubeLodEXT gets converted to textureCubeLod to workaround PowerVR issues
const ANSICHAR * VersionString = FCStringAnsi : : Strfind ( ShaderSource , " #version 100 " ) ;
check ( VersionString ) ;
VersionString + = 12 ; // strlen("# version 100");
Ar - > Serialize ( ( void * ) ShaderSource , ( VersionString - ShaderSource ) * sizeof ( ANSICHAR ) ) ;
const char * PVRWorkaround = " \n #ifndef textureCubeLodEXT \n #define textureCubeLodEXT textureCubeLod \n #endif \n " ;
Ar - > Serialize ( ( void * ) PVRWorkaround , FCStringAnsi : : Strlen ( PVRWorkaround ) ) ;
Ar - > Serialize ( ( void * ) VersionString , ( SourceLen - ( VersionString - ShaderSource ) ) * sizeof ( ANSICHAR ) ) ;
delete Ar ;
}
}
if ( bSavedSuccessfully & & ENABLE_IMAGINATION_COMPILER )
{
const FString Arguments = CreateGLSLES2CompilerArguments ( GLSLSourceFile , TEXT ( " ASM.txt " ) , Frequency , false ) ;
FString StdOut ;
FString StdErr ;
int32 ReturnCode = 0 ;
// Run the PowerVR shader compiler and wait for completion
FPlatformProcess : : ExecProcess ( GetGLSLES2CompilerExecutable ( false ) , * Arguments , & ReturnCode , & StdOut , & StdErr ) ;
if ( ReturnCode > = 0 )
{
ShaderOutput . bSucceeded = true ;
ShaderOutput . Target = ShaderInput . Target ;
2014-06-05 16:38:54 -04:00
BuildShaderOutput ( ShaderOutput , ShaderInput , ShaderSource , SourceLen , GLSL_ES2 ) ;
2014-03-14 14:13:41 -04:00
// Parse the cycle count
const int32 CycleCountStringLength = FPlatformString : : Strlen ( TEXT ( " Cycle count: " ) ) ;
const int32 CycleCountIndex = StdOut . Find ( TEXT ( " Cycle count: " ) ) ;
if ( CycleCountIndex ! = INDEX_NONE & & CycleCountIndex + CycleCountStringLength < StdOut . Len ( ) )
{
const int32 CycleCountEndIndex = StdOut . Find ( TEXT ( " \n " ) , ESearchCase : : IgnoreCase , ESearchDir : : FromStart , CycleCountIndex + CycleCountStringLength ) ;
if ( CycleCountEndIndex ! = INDEX_NONE )
{
const FString InstructionSubstring = StdOut . Mid ( CycleCountIndex + CycleCountStringLength , CycleCountEndIndex - ( CycleCountIndex + CycleCountStringLength ) ) ;
ShaderOutput . NumInstructions = FCString : : Atoi ( * InstructionSubstring ) ;
}
}
}
else
{
ShaderOutput . bSucceeded = false ;
FShaderCompilerError * NewError = new ( ShaderOutput . Errors ) FShaderCompilerError ( ) ;
// Print the name of the generated glsl file so we can open it with a double click in the VS.Net output window
NewError - > StrippedErrorMessage = FString : : Printf ( TEXT ( " %s \n PVR SDK glsl compiler for SGX543: %s " ) , * GLSLSourceFile , * StdOut ) ;
}
}
else
{
ShaderOutput . bSucceeded = true ;
ShaderOutput . Target = ShaderInput . Target ;
2014-06-05 16:38:54 -04:00
BuildShaderOutput ( ShaderOutput , ShaderInput , ShaderSource , SourceLen , GLSL_ES2 ) ;
2014-03-14 14:13:41 -04:00
}
}
else
{
ShaderOutput . bSucceeded = true ;
ShaderOutput . Target = ShaderInput . Target ;
2014-06-05 16:38:54 -04:00
BuildShaderOutput ( ShaderOutput , ShaderInput , ShaderSource , SourceLen , GLSL_ES2 ) ;
2014-03-14 14:13:41 -04:00
}
}
/**
* Precompile a GLSL shader .
* @ param ShaderOutput - The precompiled shader .
* @ param ShaderInput - The shader input .
* @ param InPreprocessedShader - The preprocessed source code .
*/
static void PrecompileShader ( FShaderCompilerOutput & ShaderOutput , const FShaderCompilerInput & ShaderInput , const ANSICHAR * ShaderSource , GLSLVersion Version , EHlslShaderFrequency Frequency )
{
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 ;
}
if ( Version = = GLSL_ES2 | | Version = = GLSL_ES2_WEBGL | | Version = = GLSL_ES2_IOS )
{
PrecompileGLSLES2 ( ShaderOutput , ShaderInput , ShaderSource , Frequency ) ;
}
else
{
// Create the shader with the preprocessed source code.
void * ContextPtr ;
void * PrevContextPtr ;
int MajorVersion = 0 ;
int MinorVersion = 0 ;
OpenGLVersionFromGLSLVersion ( Version , MajorVersion , MinorVersion ) ;
PlatformInitOpenGL ( ContextPtr , PrevContextPtr , MajorVersion , MinorVersion ) ;
GLint SourceLen = FCStringAnsi : : Strlen ( ShaderSource ) ;
GLuint Shader = glCreateShader ( GLFrequency ) ;
{
const GLchar * SourcePtr = ShaderSource ;
glShaderSource ( Shader , 1 , & SourcePtr , & SourceLen ) ;
}
// Compile and get results.
glCompileShader ( Shader ) ;
{
GLint CompileStatus ;
glGetShaderiv ( Shader , GL_COMPILE_STATUS , & CompileStatus ) ;
if ( CompileStatus = = GL_TRUE )
{
ShaderOutput . Target = ShaderInput . Target ;
BuildShaderOutput (
ShaderOutput ,
2014-06-05 16:38:54 -04:00
ShaderInput ,
2014-03-14 14:13:41 -04:00
ShaderSource ,
( int32 ) SourceLen ,
Version
) ;
}
else
{
GLint LogLength ;
glGetShaderiv ( Shader , GL_INFO_LOG_LENGTH , & LogLength ) ;
if ( LogLength > 1 )
{
TArray < ANSICHAR > RawCompileLog ;
FString CompileLog ;
TArray < FString > LogLines ;
RawCompileLog . Empty ( LogLength ) ;
RawCompileLog . AddZeroed ( LogLength ) ;
2014-09-29 04:23:44 -04:00
glGetShaderInfoLog ( Shader , LogLength , /*OutLength=*/ NULL , RawCompileLog . GetData ( ) ) ;
CompileLog = ANSI_TO_TCHAR ( RawCompileLog . GetData ( ) ) ;
2015-03-02 15:51:37 -05:00
CompileLog . ParseIntoArray ( LogLines , TEXT ( " \n " ) , true ) ;
2014-03-14 14:13:41 -04:00
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 ) ,
2014-09-29 04:23:44 -04:00
ANSI_TO_TCHAR ( RawCompileLog . GetData ( ) )
2014-03-14 14:13:41 -04:00
) ;
}
}
else
{
FShaderCompilerError * NewError = new ( ShaderOutput . Errors ) FShaderCompilerError ( ) ;
NewError - > StrippedErrorMessage = TEXT ( " Shader compile failed without errors. " ) ;
}
ShaderOutput . bSucceeded = false ;
}
}
glDeleteShader ( Shader ) ;
PlatformReleaseOpenGL ( ContextPtr , PrevContextPtr ) ;
}
}
/*------------------------------------------------------------------------------
External interface .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2014-06-30 18:32:57 -04:00
static FString CreateCrossCompilerBatchFile ( const FString & ShaderFile , const FString & OutputFile , const FString & EntryPoint , EHlslShaderFrequency Frequency , GLSLVersion Version , uint32 CCFlags )
2014-03-14 14:13:41 -04:00
{
const TCHAR * VersionSwitch = TEXT ( " " ) ;
switch ( Version )
{
case GLSL_150 :
2015-03-11 13:45:34 -04:00
case GLSL_150_ES2 :
2015-04-13 18:00:32 -04:00
case GLSL_150_ES3_1 :
2015-07-30 13:31:13 -04:00
case GLSL_150_ES2_NOUB :
VersionSwitch = TEXT ( " -gl3 " ) ;
2014-03-14 14:13:41 -04:00
break ;
2014-04-02 18:09:23 -04:00
case GLSL_150_MAC :
2015-07-30 13:31:13 -04:00
VersionSwitch = TEXT ( " -gl3 -mac " ) ;
2014-03-14 14:13:41 -04:00
break ;
2014-09-18 17:49:40 -04:00
case GLSL_310_ES_EXT :
VersionSwitch = TEXT ( " -es31ext " ) ;
break ;
2014-03-14 14:13:41 -04:00
case GLSL_430 :
2015-07-30 13:31:13 -04:00
VersionSwitch = TEXT ( " -gl4 " ) ;
2014-03-14 14:13:41 -04:00
break ;
case GLSL_ES2 :
case GLSL_ES2_WEBGL :
case GLSL_ES2_IOS :
2014-05-07 16:46:21 -04:00
VersionSwitch = TEXT ( " -es2 " ) ;
2014-03-14 14:13:41 -04:00
break ;
default :
return TEXT ( " " ) ;
}
2015-07-30 13:31:13 -04:00
return CrossCompiler : : CreateBatchFileContents ( ShaderFile , OutputFile , Frequency , EntryPoint , VersionSwitch , CCFlags , TEXT ( " " ) ) ;
2014-03-14 14:13:41 -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 .
*/
2014-04-23 18:54:23 -04:00
void CompileShader_Windows_OGL ( const FShaderCompilerInput & Input , FShaderCompilerOutput & Output , const FString & WorkingDirectory , GLSLVersion Version )
2014-03-14 14:13:41 -04:00
{
FString PreprocessedShader ;
FShaderCompilerDefinitions AdditionalDefines ;
2014-04-02 18:09:23 -04:00
EHlslCompileTarget HlslCompilerTarget = HCT_InvalidTarget ;
2015-08-20 10:15:09 -04:00
ECompilerFlags PlatformFlowControl = CFLAG_AvoidFlowControl ;
2015-08-17 16:09:30 -04:00
AdditionalDefines . SetDefine ( TEXT ( " COMPILER_HLSLCC " ) , 1 ) ;
2014-03-14 14:13:41 -04:00
switch ( Version )
{
2014-09-18 17:49:40 -04:00
case GLSL_310_ES_EXT :
AdditionalDefines . SetDefine ( TEXT ( " COMPILER_GLSL " ) , 1 ) ;
AdditionalDefines . SetDefine ( TEXT ( " ES31_AEP_PROFILE " ) , 1 ) ;
AdditionalDefines . SetDefine ( TEXT ( " GL4_PROFILE " ) , 1 ) ;
HlslCompilerTarget = HCT_FeatureLevelES3_1Ext ;
break ;
2014-03-14 14:13:41 -04:00
case GLSL_430 :
AdditionalDefines . SetDefine ( TEXT ( " COMPILER_GLSL " ) , 1 ) ;
AdditionalDefines . SetDefine ( TEXT ( " GL4_PROFILE " ) , 1 ) ;
2014-04-02 18:09:23 -04:00
HlslCompilerTarget = HCT_FeatureLevelSM5 ;
2014-03-14 14:13:41 -04:00
break ;
case GLSL_150 :
AdditionalDefines . SetDefine ( TEXT ( " COMPILER_GLSL " ) , 1 ) ;
AdditionalDefines . SetDefine ( TEXT ( " GL3_PROFILE " ) , 1 ) ;
2014-04-02 18:09:23 -04:00
HlslCompilerTarget = HCT_FeatureLevelSM4 ;
break ;
case GLSL_150_MAC :
AdditionalDefines . SetDefine ( TEXT ( " MAC " ) , 1 ) ;
AdditionalDefines . SetDefine ( TEXT ( " COMPILER_GLSL " ) , 1 ) ;
AdditionalDefines . SetDefine ( TEXT ( " GL3_PROFILE " ) , 1 ) ;
HlslCompilerTarget = HCT_FeatureLevelSM4 ;
2015-08-20 10:15:09 -04:00
// On OS X it is always better to leave the flow control statements in the GLSL & let the GLSL->GPU compilers
// optimise it appropriately for each GPU. This gives a performance gain on AMD & Intel and is neutral on Nvidia.
PlatformFlowControl = CFLAG_PreferFlowControl ;
2014-03-14 14:13:41 -04:00
break ;
case GLSL_ES2_WEBGL :
AdditionalDefines . SetDefine ( TEXT ( " WEBGL " ) , 1 ) ;
AdditionalDefines . SetDefine ( TEXT ( " COMPILER_GLSL_ES2 " ) , 1 ) ;
AdditionalDefines . SetDefine ( TEXT ( " ES2_PROFILE " ) , 1 ) ;
2014-04-02 18:09:23 -04:00
HlslCompilerTarget = HCT_FeatureLevelES2 ;
2014-03-14 14:13:41 -04:00
AdditionalDefines . SetDefine ( TEXT ( " row_major " ) , TEXT ( " " ) ) ;
break ;
case GLSL_ES2_IOS :
AdditionalDefines . SetDefine ( TEXT ( " IOS " ) , 1 ) ;
AdditionalDefines . SetDefine ( TEXT ( " COMPILER_GLSL_ES2 " ) , 1 ) ;
AdditionalDefines . SetDefine ( TEXT ( " ES2_PROFILE " ) , 1 ) ;
2014-04-02 18:09:23 -04:00
HlslCompilerTarget = HCT_FeatureLevelES2 ;
2014-03-14 14:13:41 -04:00
AdditionalDefines . SetDefine ( TEXT ( " row_major " ) , TEXT ( " " ) ) ;
break ;
case GLSL_ES2 :
AdditionalDefines . SetDefine ( TEXT ( " COMPILER_GLSL_ES2 " ) , 1 ) ;
AdditionalDefines . SetDefine ( TEXT ( " ES2_PROFILE " ) , 1 ) ;
2014-04-02 18:09:23 -04:00
HlslCompilerTarget = HCT_FeatureLevelES2 ;
2014-03-14 14:13:41 -04:00
AdditionalDefines . SetDefine ( TEXT ( " row_major " ) , TEXT ( " " ) ) ;
break ;
case GLSL_150_ES2 :
2015-03-11 13:45:34 -04:00
case GLSL_150_ES2_NOUB :
2014-03-14 14:13:41 -04:00
AdditionalDefines . SetDefine ( TEXT ( " COMPILER_GLSL " ) , 1 ) ;
AdditionalDefines . SetDefine ( TEXT ( " ES2_PROFILE " ) , 1 ) ;
2014-04-02 18:09:23 -04:00
HlslCompilerTarget = HCT_FeatureLevelSM4 ;
2014-03-14 14:13:41 -04:00
AdditionalDefines . SetDefine ( TEXT ( " row_major " ) , TEXT ( " " ) ) ;
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 ) ;
HlslCompilerTarget = HCT_FeatureLevelSM4 ;
AdditionalDefines . SetDefine ( TEXT ( " row_major " ) , TEXT ( " " ) ) ;
break ;
2014-03-14 14:13:41 -04:00
default :
check ( 0 ) ;
}
const bool bDumpDebugInfo = ( Input . DumpDebugInfoPath ! = TEXT ( " " ) & & IFileManager : : Get ( ) . DirectoryExists ( * Input . DumpDebugInfoPath ) ) ;
2015-08-24 06:10:23 -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 ) ;
}
2014-03-14 14:13:41 -04:00
if ( PreprocessShader ( PreprocessedShader , Output , Input , AdditionalDefines ) )
{
2014-09-29 18:57:21 -04:00
char * GlslShaderSource = NULL ;
2014-03-14 14:13:41 -04:00
char * ErrorLog = NULL ;
2014-09-18 17:49:40 -04:00
const bool bIsSM5 = Version = = GLSL_430 | | Version = = GLSL_310_ES_EXT ;
2014-03-14 14:13:41 -04:00
const EHlslShaderFrequency FrequencyTable [ ] =
{
2014-04-02 18:09:23 -04:00
HSF_VertexShader ,
2014-09-18 17:49:40 -04:00
bIsSM5 ? HSF_HullShader : HSF_InvalidFrequency ,
bIsSM5 ? HSF_DomainShader : HSF_InvalidFrequency ,
2014-04-02 18:09:23 -04:00
HSF_PixelShader ,
IsES2Platform ( Version ) ? HSF_InvalidFrequency : HSF_GeometryShader ,
2014-09-18 17:49:40 -04:00
bIsSM5 ? HSF_ComputeShader : HSF_InvalidFrequency
2014-03-14 14:13:41 -04:00
} ;
const EHlslShaderFrequency Frequency = FrequencyTable [ Input . Target . Frequency ] ;
2014-04-02 18:09:23 -04:00
if ( Frequency = = HSF_InvalidFrequency )
2014-03-14 14:13:41 -04:00
{
Output . bSucceeded = false ;
FShaderCompilerError * NewError = new ( Output . Errors ) FShaderCompilerError ( ) ;
NewError - > StrippedErrorMessage = FString : : Printf (
TEXT ( " %s shaders not supported for use in OpenGL. " ) ,
2015-07-02 11:52:03 -04:00
CrossCompiler : : GetFrequencyName ( ( EShaderFrequency ) Input . Target . Frequency )
2014-03-14 14:13:41 -04:00
) ;
return ;
}
2014-08-04 10:49:28 -04:00
// This requires removing the HLSLCC_NoPreprocess flag later on!
2014-06-05 16:38:54 -04:00
if ( ! RemoveUniformBuffersFromSource ( PreprocessedShader ) )
{
2014-08-04 10:49:28 -04:00
return ;
2014-06-05 16:38:54 -04:00
}
2014-03-14 14:13:41 -04:00
// Write out the preprocessed file and a batch file to compile it if requested (DumpDebugInfoPath is valid)
if ( bDumpDebugInfo )
{
FArchive * FileWriter = IFileManager : : Get ( ) . CreateFileWriter ( * ( Input . DumpDebugInfoPath / Input . SourceFilename + TEXT ( " .usf " ) ) ) ;
if ( FileWriter )
{
auto AnsiSourceFile = StringCast < ANSICHAR > ( * PreprocessedShader ) ;
FileWriter - > Serialize ( ( ANSICHAR * ) AnsiSourceFile . Get ( ) , AnsiSourceFile . Length ( ) ) ;
FileWriter - > Close ( ) ;
delete FileWriter ;
}
}
uint32 CCFlags = HLSLCC_NoPreprocess | HLSLCC_PackUniforms | HLSLCC_DX11ClipSpace ;
2014-08-20 08:27:17 -04:00
if ( IsES2Platform ( Version ) & & ! IsPCES2Platform ( Version ) )
2014-03-14 14:13:41 -04:00
{
CCFlags | = HLSLCC_FlattenUniformBuffers | HLSLCC_FlattenUniformBufferStructures ;
// Currently only enabled for ES2, as there are still features to implement for SM4+ (atomics, global store, UAVs, etc)
2014-08-20 08:27:17 -04:00
CCFlags | = HLSLCC_ApplyCommonSubexpressionElimination ;
2014-03-14 14:13:41 -04:00
}
2015-02-06 11:35:30 -05:00
2015-03-11 13:45:34 -04:00
if ( Version = = GLSL_150_ES2_NOUB )
{
CCFlags | = HLSLCC_FlattenUniformBuffers | HLSLCC_FlattenUniformBufferStructures ;
}
if ( SupportsSeparateShaderObjects ( Version ) )
2015-02-06 11:35:30 -05:00
{
CCFlags | = HLSLCC_SeparateShaderObjects ;
}
2014-03-14 14:13:41 -04:00
if ( bDumpDebugInfo )
{
const FString GLSLFile = ( Input . DumpDebugInfoPath / TEXT ( " Output.glsl " ) ) ;
const FString USFFile = ( Input . DumpDebugInfoPath / Input . SourceFilename ) + TEXT ( " .usf " ) ;
2014-06-30 18:32:57 -04:00
const FString CCBatchFileContents = CreateCrossCompilerBatchFile ( USFFile , GLSLFile , * Input . EntryPointName , Frequency , Version , CCFlags ) ;
2014-03-14 14:13:41 -04:00
if ( ! CCBatchFileContents . IsEmpty ( ) )
{
2015-08-03 16:07:57 -04:00
const TCHAR * ScriptName = PLATFORM_WINDOWS ? TEXT ( " CrossCompile.bat " ) : TEXT ( " CrossCompile.sh " ) ;
FFileHelper : : SaveStringToFile ( CCBatchFileContents , * ( Input . DumpDebugInfoPath / ScriptName ) ) ;
2014-03-14 14:13:41 -04:00
}
}
2014-08-04 10:49:28 -04: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 ;
2014-09-29 18:57:21 -04:00
2015-06-18 14:24:11 -04:00
FGlslCodeBackend GlslBackEnd ( CCFlags , HlslCompilerTarget ) ;
2014-06-05 16:38:54 -04:00
FGlslLanguageSpec GlslLanguageSpec ( IsES2Platform ( Version ) & & ! IsPCES2Platform ( Version ) ) ;
2015-03-06 13:09:36 -05:00
int32 Result = 0 ;
FHlslCrossCompilerContext CrossCompilerContext ( CCFlags , Frequency , HlslCompilerTarget ) ;
if ( CrossCompilerContext . Init ( TCHAR_TO_ANSI ( * Input . SourceFilename ) , & GlslLanguageSpec ) )
{
Result = CrossCompilerContext . Run (
TCHAR_TO_ANSI ( * PreprocessedShader ) ,
TCHAR_TO_ANSI ( * Input . EntryPointName ) ,
& GlslBackEnd ,
& GlslShaderSource ,
& ErrorLog
) ? 1 : 0 ;
}
2014-03-14 14:13:41 -04:00
if ( Result ! = 0 )
{
2014-09-29 18:57:21 -04:00
int32 GlslSourceLen = GlslShaderSource ? FCStringAnsi : : Strlen ( GlslShaderSource ) : 0 ;
2014-03-14 14:13:41 -04:00
if ( bDumpDebugInfo )
{
const FString GLSLFile = ( Input . DumpDebugInfoPath / TEXT ( " Output.glsl " ) ) ;
const FString GLBatchFileContents = CreateCommandLineGLSLES2 ( GLSLFile , ( Input . DumpDebugInfoPath / TEXT ( " Output.asm " ) ) , Version , Frequency , false ) ;
if ( ! GLBatchFileContents . IsEmpty ( ) )
{
FFileHelper : : SaveStringToFile ( GLBatchFileContents , * ( Input . DumpDebugInfoPath / TEXT ( " GLSLCompile.bat " ) ) ) ;
}
const FString NDABatchFileContents = CreateCommandLineGLSLES2 ( GLSLFile , ( Input . DumpDebugInfoPath / TEXT ( " Output.asm " ) ) , Version , Frequency , true ) ;
if ( ! NDABatchFileContents . IsEmpty ( ) )
{
FFileHelper : : SaveStringToFile ( NDABatchFileContents , * ( Input . DumpDebugInfoPath / TEXT ( " NDAGLSLCompile.bat " ) ) ) ;
}
2014-09-29 18:57:21 -04:00
if ( GlslSourceLen > 0 )
2014-03-14 14:13:41 -04:00
{
2015-08-20 10:15:09 -04:00
uint32 Len = FCStringAnsi : : Strlen ( TCHAR_TO_ANSI ( * Input . SourceFilename ) ) + FCStringAnsi : : Strlen ( TCHAR_TO_ANSI ( * Input . EntryPointName ) ) + FCStringAnsi : : Strlen ( GlslShaderSource ) + 20 ;
char * Dest = ( char * ) malloc ( Len ) ;
FCStringAnsi : : Snprintf ( Dest , Len , " // ! %s.usf:%s \n %s " , ( const char * ) TCHAR_TO_ANSI ( * Input . SourceFilename ) , ( const char * ) TCHAR_TO_ANSI ( * Input . EntryPointName ) , ( const char * ) GlslShaderSource ) ;
free ( GlslShaderSource ) ;
GlslShaderSource = Dest ;
GlslSourceLen = FCStringAnsi : : Strlen ( GlslShaderSource ) ;
2014-09-29 18:57:21 -04:00
FArchive * FileWriter = IFileManager : : Get ( ) . CreateFileWriter ( * ( Input . DumpDebugInfoPath / Input . SourceFilename + TEXT ( " .glsl " ) ) ) ;
if ( FileWriter )
{
FileWriter - > Serialize ( GlslShaderSource , GlslSourceLen + 1 ) ;
FileWriter - > Close ( ) ;
delete FileWriter ;
}
2014-03-14 14:13:41 -04:00
}
}
2014-04-23 18:54:23 -04:00
# if VALIDATE_GLSL_WITH_DRIVER
PrecompileShader ( Output , Input , GlslShaderSource , Version , Frequency ) ;
# else // VALIDATE_GLSL_WITH_DRIVER
2014-09-29 18:57:21 -04:00
int32 SourceLen = FCStringAnsi : : Strlen ( GlslShaderSource ) ;
2014-04-23 18:54:23 -04:00
Output . Target = Input . Target ;
2015-03-11 13:45:34 -04:00
BuildShaderOutput ( Output , Input , GlslShaderSource , SourceLen , Version ) ;
2014-04-23 18:54:23 -04:00
# endif // VALIDATE_GLSL_WITH_DRIVER
2014-03-14 14:13:41 -04:00
}
else
{
2014-06-05 16:38:54 -04:00
if ( bDumpDebugInfo )
{
// Generate the batch file to help track down cross-compiler issues if necessary
const FString GLSLFile = ( Input . DumpDebugInfoPath / TEXT ( " Output.glsl " ) ) ;
const FString GLBatchFileContents = CreateCommandLineGLSLES2 ( GLSLFile , ( Input . DumpDebugInfoPath / TEXT ( " Output.asm " ) ) , Version , Frequency , false ) ;
if ( ! GLBatchFileContents . IsEmpty ( ) )
{
FFileHelper : : SaveStringToFile ( GLBatchFileContents , * ( Input . DumpDebugInfoPath / TEXT ( " GLSLCompile.bat " ) ) ) ;
}
}
2014-03-14 14:13:41 -04:00
FString Tmp = ANSI_TO_TCHAR ( ErrorLog ) ;
TArray < FString > ErrorLines ;
2015-03-02 15:51:37 -05:00
Tmp . ParseIntoArray ( ErrorLines , TEXT ( " \n " ) , true ) ;
2014-03-14 14:13:41 -04:00
for ( int32 LineIndex = 0 ; LineIndex < ErrorLines . Num ( ) ; + + LineIndex )
{
const FString & Line = ErrorLines [ LineIndex ] ;
2015-07-02 11:52:03 -04:00
CrossCompiler : : ParseHlslccError ( Output . Errors , Line ) ;
2014-03-14 14:13:41 -04:00
}
}
2014-09-29 18:57:21 -04:00
if ( GlslShaderSource )
{
free ( GlslShaderSource ) ;
}
2014-03-14 14:13:41 -04:00
if ( ErrorLog )
{
free ( ErrorLog ) ;
}
}
}