2012-04-03 20:30:07 -07:00
# include <string>
# include <vector>
# include <time.h>
# include "../src/glsl/glsl_optimizer.h"
2014-02-10 23:06:13 -08:00
# define GL_GLEXT_PROTOTYPES 1
2012-04-03 20:30:07 -07:00
# if __linux__
# define GOT_GFX 0
# else
# define GOT_GFX 1
# endif
# if GOT_GFX
2014-02-10 23:06:13 -08:00
// ---- Windows GL bits
2012-04-03 20:30:07 -07:00
# ifdef _MSC_VER
2012-10-07 20:41:18 -07:00
# define GOT_MORE_THAN_GLSL_120 1
2012-04-03 20:30:07 -07:00
# include <windows.h>
# include <gl/GL.h>
extern " C " {
typedef char GLcharARB ; /* native character */
typedef unsigned int GLhandleARB ; /* shader object handle */
# define GL_VERTEX_SHADER_ARB 0x8B31
# define GL_FRAGMENT_SHADER_ARB 0x8B30
# define GL_OBJECT_COMPILE_STATUS_ARB 0x8B81
typedef void ( WINAPI * PFNGLDELETEOBJECTARBPROC ) ( GLhandleARB obj ) ;
typedef GLhandleARB ( WINAPI * PFNGLCREATESHADEROBJECTARBPROC ) ( GLenum shaderType ) ;
typedef void ( WINAPI * PFNGLSHADERSOURCEARBPROC ) ( GLhandleARB shaderObj , GLsizei count , const GLcharARB * * string , const GLint * length ) ;
typedef void ( WINAPI * PFNGLCOMPILESHADERARBPROC ) ( GLhandleARB shaderObj ) ;
typedef void ( WINAPI * PFNGLGETINFOLOGARBPROC ) ( GLhandleARB obj , GLsizei maxLength , GLsizei * length , GLcharARB * infoLog ) ;
typedef void ( WINAPI * PFNGLGETOBJECTPARAMETERIVARBPROC ) ( GLhandleARB obj , GLenum pname , GLint * params ) ;
static PFNGLDELETEOBJECTARBPROC glDeleteObjectARB ;
static PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB ;
static PFNGLSHADERSOURCEARBPROC glShaderSourceARB ;
static PFNGLCOMPILESHADERARBPROC glCompileShaderARB ;
static PFNGLGETINFOLOGARBPROC glGetInfoLogARB ;
static PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB ;
}
2014-02-10 23:06:13 -08:00
# endif // #ifdef _MSC_VER
// ---- Apple GL bits
# ifdef __APPLE__
2012-10-07 20:41:18 -07:00
# define GOT_MORE_THAN_GLSL_120 0
2012-04-03 20:30:07 -07:00
# include <OpenGL/OpenGL.h>
2014-02-10 23:06:13 -08:00
# include <OpenGL/gl.h>
# include <OpenGL/CGLTypes.h>
2012-04-03 20:30:07 -07:00
# include <dirent.h>
2014-02-10 23:06:13 -08:00
static CGLContextObj s_GLContext ;
static CGLContextObj s_GLContext3 ;
static bool s_GL3Active = false ;
# endif // ifdef __APPLE__
# else // #if GOT_GFX
2012-04-03 20:30:07 -07:00
2012-10-07 20:41:18 -07:00
# define GOT_MORE_THAN_GLSL_120 0
2012-04-03 20:30:07 -07:00
# include <cstdio>
# include <cstring>
# include "dirent.h"
# include "GL/gl.h"
# include "GL/glext.h"
2014-02-10 23:06:13 -08:00
# endif // ! #if GOT_GFX
2012-04-03 20:30:07 -07:00
2012-10-07 20:41:18 -07:00
# ifndef _MSC_VER
# include <unistd.h>
# endif
2012-04-03 20:30:07 -07:00
static bool InitializeOpenGL ( )
{
bool hasGLSL = false ;
# if GOT_GFX
# ifdef _MSC_VER
// setup minimal required GL
HWND wnd = CreateWindowA (
" STATIC " ,
" GL " ,
WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN ,
0 , 0 , 16 , 16 ,
NULL , NULL ,
GetModuleHandle ( NULL ) , NULL ) ;
HDC dc = GetDC ( wnd ) ;
PIXELFORMATDESCRIPTOR pfd = {
sizeof ( PIXELFORMATDESCRIPTOR ) , 1 ,
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL ,
PFD_TYPE_RGBA , 32 ,
0 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 ,
16 , 0 ,
0 , PFD_MAIN_PLANE , 0 , 0 , 0 , 0
} ;
int fmt = ChoosePixelFormat ( dc , & pfd ) ;
SetPixelFormat ( dc , fmt , & pfd ) ;
HGLRC rc = wglCreateContext ( dc ) ;
wglMakeCurrent ( dc , rc ) ;
2014-02-10 23:06:13 -08:00
# elif defined(__APPLE__)
CGLPixelFormatAttribute attributes [ ] = {
kCGLPFAAccelerated , // no software rendering
( CGLPixelFormatAttribute ) 0
} ;
CGLPixelFormatAttribute attributes3 [ ] = {
kCGLPFAAccelerated , // no software rendering
kCGLPFAOpenGLProfile , // core profile with the version stated below
( CGLPixelFormatAttribute ) kCGLOGLPVersion_3_2_Core ,
( CGLPixelFormatAttribute ) 0
} ;
GLint num ;
CGLPixelFormatObj pix ;
// create legacy context
CGLChoosePixelFormat ( attributes , & pix , & num ) ;
if ( pix = = NULL )
return false ;
CGLCreateContext ( pix , NULL , & s_GLContext ) ;
if ( s_GLContext = = NULL )
return false ;
CGLDestroyPixelFormat ( pix ) ;
CGLSetCurrentContext ( s_GLContext ) ;
// create core 3.2 context
CGLChoosePixelFormat ( attributes3 , & pix , & num ) ;
if ( pix = = NULL )
return false ;
CGLCreateContext ( pix , NULL , & s_GLContext3 ) ;
if ( s_GLContext3 = = NULL )
return false ;
CGLDestroyPixelFormat ( pix ) ;
2012-04-03 20:30:07 -07:00
# endif
// check if we have GLSL
const char * extensions = ( const char * ) glGetString ( GL_EXTENSIONS ) ;
2014-02-10 23:06:13 -08:00
hasGLSL = extensions ! = NULL & & strstr ( extensions , " GL_ARB_shader_objects " ) & & strstr ( extensions , " GL_ARB_vertex_shader " ) & & strstr ( extensions , " GL_ARB_fragment_shader " ) ;
# if defined(__APPLE__)
// using core profile; always has GLSL
hasGLSL = true ;
# endif
2012-04-03 20:30:07 -07:00
# ifdef _MSC_VER
if ( hasGLSL )
{
glDeleteObjectARB = ( PFNGLDELETEOBJECTARBPROC ) wglGetProcAddress ( " glDeleteObjectARB " ) ;
glCreateShaderObjectARB = ( PFNGLCREATESHADEROBJECTARBPROC ) wglGetProcAddress ( " glCreateShaderObjectARB " ) ;
glShaderSourceARB = ( PFNGLSHADERSOURCEARBPROC ) wglGetProcAddress ( " glShaderSourceARB " ) ;
glCompileShaderARB = ( PFNGLCOMPILESHADERARBPROC ) wglGetProcAddress ( " glCompileShaderARB " ) ;
glGetInfoLogARB = ( PFNGLGETINFOLOGARBPROC ) wglGetProcAddress ( " glGetInfoLogARB " ) ;
glGetObjectParameterivARB = ( PFNGLGETOBJECTPARAMETERIVARBPROC ) wglGetProcAddress ( " glGetObjectParameterivARB " ) ;
}
# endif
# endif
return hasGLSL ;
}
2014-02-10 23:06:13 -08:00
static void CleanupGL ( )
{
# if GOT_GFX
# ifdef __APPLE__
CGLSetCurrentContext ( NULL ) ;
if ( s_GLContext )
CGLDestroyContext ( s_GLContext ) ;
if ( s_GLContext3 )
CGLDestroyContext ( s_GLContext3 ) ;
# endif // #ifdef __APPLE__
# endif // #if GOT_GFX
}
2014-10-11 12:32:43 -07:00
static bool InitializeMetal ( )
{
bool hasMetal = false ;
# if defined(__APPLE__)
hasMetal = true ; //@TODO: detect metal compiler presence
# endif
return hasMetal ;
}
2012-04-03 20:30:07 -07:00
static void replace_string ( std : : string & target , const std : : string & search , const std : : string & replace , size_t startPos )
{
if ( search . empty ( ) )
return ;
std : : string : : size_type p = startPos ;
while ( ( p = target . find ( search , p ) ) ! = std : : string : : npos )
{
target . replace ( p , search . size ( ) , replace ) ;
p + = replace . size ( ) ;
}
}
2012-10-07 20:41:18 -07:00
static bool CheckGLSL ( bool vertex , bool gles , const std : : string & testName , const char * prefix , const std : : string & source )
2012-04-03 20:30:07 -07:00
{
2012-10-07 20:41:18 -07:00
# if !GOT_GFX
return true ; // just assume it's ok
# endif
# if !GOT_MORE_THAN_GLSL_120
if ( source . find ( " #version 140 " ) ! = std : : string : : npos )
return true ;
# endif
2014-10-11 12:32:43 -07:00
const bool need3 =
( source . find ( " #version 150 " ) ! = std : : string : : npos ) | |
( source . find ( " #version 300 " ) ! = std : : string : : npos ) ;
2012-10-07 20:41:18 -07:00
2014-02-10 23:06:13 -08:00
# ifdef __APPLE__
// Mac core context does not accept any older shader versions, so need to switch to
// either legacy context or core one.
if ( need3 )
{
if ( ! s_GL3Active )
CGLSetCurrentContext ( s_GLContext3 ) ;
s_GL3Active = true ;
}
else
{
if ( s_GL3Active )
CGLSetCurrentContext ( s_GLContext ) ;
s_GL3Active = false ;
}
# endif // ifdef __APPLE__
2012-04-03 20:30:07 -07:00
std : : string src ;
if ( gles )
{
src + = " #define lowp \n " ;
src + = " #define mediump \n " ;
src + = " #define highp \n " ;
src + = " #define texture2DLodEXT texture2DLod \n " ;
2012-10-07 20:41:18 -07:00
src + = " #define texture2DProjLodEXT texture2DProjLod \n " ;
2014-02-10 23:06:13 -08:00
src + = " #define texture2DGradEXT texture2DGradARB \n " ;
src + = " #define textureCubeGradEXT textureCubeGradARB \n " ;
2013-03-17 11:29:03 -07:00
src + = " #define gl_FragDepthEXT gl_FragDepth \n " ;
2014-10-11 12:32:43 -07:00
if ( ! need3 )
{
src + = " #define gl_LastFragData _glesLastFragData \n " ;
src + = " varying lowp vec4 _glesLastFragData[4]; \n " ;
}
2015-04-02 23:30:48 -07:00
if ( ! need3 )
{
src + = " float shadow2DEXT (sampler2DShadow s, vec3 p) { return shadow2D(s,p).r; } \n " ;
src + = " float shadow2DProjEXT (sampler2DShadow s, vec4 p) { return shadow2DProj(s,p).r; } \n " ;
}
2012-04-03 20:30:07 -07:00
}
src + = source ;
if ( gles )
{
replace_string ( src , " GL_EXT_shader_texture_lod " , " GL_ARB_shader_texture_lod " , 0 ) ;
replace_string ( src , " #extension GL_OES_standard_derivatives : require " , " " , 0 ) ;
2012-10-07 20:41:18 -07:00
replace_string ( src , " #extension GL_EXT_shadow_samplers : require " , " " , 0 ) ;
2013-03-17 11:29:03 -07:00
replace_string ( src , " #extension GL_EXT_frag_depth : require " , " " , 0 ) ;
2014-02-10 23:06:13 -08:00
replace_string ( src , " #extension GL_OES_standard_derivatives : enable " , " " , 0 ) ;
replace_string ( src , " #extension GL_EXT_shadow_samplers : enable " , " " , 0 ) ;
replace_string ( src , " #extension GL_EXT_frag_depth : enable " , " " , 0 ) ;
2014-10-11 12:32:43 -07:00
replace_string ( src , " #extension GL_EXT_draw_buffers : enable " , " " , 0 ) ;
replace_string ( src , " #extension GL_EXT_draw_buffers : require " , " " , 0 ) ;
2013-03-17 11:29:03 -07:00
replace_string ( src , " precision " , " // precision " , 0 ) ;
2014-10-11 12:32:43 -07:00
replace_string ( src , " #version 300 es " , " " , 0 ) ;
}
2015-04-02 23:30:48 -07:00
// can't check FB fetch on PC
if ( src . find ( " #extension GL_EXT_shader_framebuffer_fetch " ) ! = std : : string : : npos )
return true ;
2014-10-11 12:32:43 -07:00
if ( gles & & need3 )
{
src = " #version 330 \n " + src ;
2012-04-03 20:30:07 -07:00
}
const char * sourcePtr = src . c_str ( ) ;
2015-04-02 23:30:48 -07:00
GLuint shader = glCreateShader ( vertex ? GL_VERTEX_SHADER : GL_FRAGMENT_SHADER ) ;
glShaderSource ( shader , 1 , & sourcePtr , NULL ) ;
glCompileShader ( shader ) ;
2012-04-03 20:30:07 -07:00
GLint status ;
2015-04-02 23:30:48 -07:00
glGetShaderiv ( shader , GL_COMPILE_STATUS , & status ) ;
2012-04-03 20:30:07 -07:00
bool res = true ;
2015-04-02 23:30:48 -07:00
if ( status ! = GL_TRUE )
2012-04-03 20:30:07 -07:00
{
2014-10-11 12:32:43 -07:00
char log [ 20000 ] ;
log [ 0 ] = 0 ;
2012-04-03 20:30:07 -07:00
GLsizei logLength ;
2015-04-02 23:30:48 -07:00
glGetShaderInfoLog ( shader , sizeof ( log ) , & logLength , log ) ;
2012-10-07 20:41:18 -07:00
printf ( " \n %s: real glsl compiler error on %s: \n %s \n " , testName . c_str ( ) , prefix , log ) ;
2012-04-03 20:30:07 -07:00
res = false ;
}
2015-04-02 23:30:48 -07:00
glDeleteShader ( shader ) ;
2012-04-03 20:30:07 -07:00
return res ;
}
2014-10-11 12:32:43 -07:00
static bool CheckMetal ( bool vertex , bool gles , const std : : string & testName , const char * prefix , const std : : string & source )
{
# if !GOT_GFX
return true ; // just assume it's ok
# endif
FILE * f = fopen ( " metalTemp.metal " , " wb " ) ;
fwrite ( source . c_str ( ) , source . size ( ) , 1 , f ) ;
fclose ( f ) ;
2015-04-02 23:30:48 -07:00
# if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
2014-10-11 12:32:43 -07:00
int res = system ( " /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/usr/bin/metal metalTemp.metal -o metalTemp.o -std=ios-metal1.0 -Wno-parentheses-equality " ) ;
if ( res ! = 0 )
{
printf ( " \n %s: Metal compiler failed \n " , testName . c_str ( ) ) ;
return false ;
}
2015-04-02 23:30:48 -07:00
# endif //
2014-10-11 12:32:43 -07:00
return true ;
}
2012-04-03 20:30:07 -07:00
static bool ReadStringFromFile ( const char * pathName , std : : string & output )
{
FILE * file = fopen ( pathName , " rb " ) ;
if ( file = = NULL )
return false ;
fseek ( file , 0 , SEEK_END ) ;
int length = ftell ( file ) ;
fseek ( file , 0 , SEEK_SET ) ;
if ( length < 0 )
{
fclose ( file ) ;
return false ;
}
output . resize ( length ) ;
int readLength = fread ( & * output . begin ( ) , 1 , length , file ) ;
fclose ( file ) ;
if ( readLength ! = length )
{
output . clear ( ) ;
return false ;
}
2014-02-10 23:06:13 -08:00
replace_string ( output , " \r \n " , " \n " , 0 ) ;
2012-04-03 20:30:07 -07:00
return true ;
}
bool EndsWith ( const std : : string & str , const std : : string & sub )
{
return ( str . size ( ) > = sub . size ( ) ) & & ( strncmp ( str . c_str ( ) + str . size ( ) - sub . size ( ) , sub . c_str ( ) , sub . size ( ) ) = = 0 ) ;
}
typedef std : : vector < std : : string > StringVector ;
static StringVector GetFiles ( const std : : string & folder , const std : : string & endsWith )
{
StringVector res ;
# ifdef _MSC_VER
WIN32_FIND_DATAA FindFileData ;
HANDLE hFind = FindFirstFileA ( ( folder + " /* " + endsWith ) . c_str ( ) , & FindFileData ) ;
if ( hFind = = INVALID_HANDLE_VALUE )
return res ;
do {
res . push_back ( FindFileData . cFileName ) ;
} while ( FindNextFileA ( hFind , & FindFileData ) ) ;
FindClose ( hFind ) ;
# else
DIR * dirp ;
struct dirent * dp ;
if ( ( dirp = opendir ( folder . c_str ( ) ) ) = = NULL )
return res ;
while ( ( dp = readdir ( dirp ) ) )
{
std : : string fname = dp - > d_name ;
if ( fname = = " . " | | fname = = " .. " )
continue ;
if ( ! EndsWith ( fname , endsWith ) )
continue ;
res . push_back ( fname ) ;
}
closedir ( dirp ) ;
# endif
return res ;
}
static void DeleteFile ( const std : : string & path )
{
# ifdef _MSC_VER
DeleteFileA ( path . c_str ( ) ) ;
# else
unlink ( path . c_str ( ) ) ;
# endif
}
static void MassageVertexForGLES ( std : : string & s )
{
2014-10-11 12:32:43 -07:00
if ( s . find ( " _glesVertex " ) ! = std : : string : : npos )
return ;
2012-04-03 20:30:07 -07:00
std : : string pre ;
2014-10-11 12:32:43 -07:00
std : : string version = " #version 300 es \n " ;
size_t insertPoint = s . find ( version ) ;
if ( insertPoint ! = std : : string : : npos )
{
insertPoint + = version . size ( ) ;
pre + = " #define gl_Vertex _glesVertex \n in highp vec4 _glesVertex; \n " ;
pre + = " #define gl_Normal _glesNormal \n in mediump vec3 _glesNormal; \n " ;
pre + = " #define gl_MultiTexCoord0 _glesMultiTexCoord0 \n in highp vec4 _glesMultiTexCoord0; \n " ;
pre + = " #define gl_MultiTexCoord1 _glesMultiTexCoord1 \n in highp vec4 _glesMultiTexCoord1; \n " ;
pre + = " #define gl_Color _glesColor \n in lowp vec4 _glesColor; \n " ;
}
else
{
insertPoint = 0 ;
pre + = " #define gl_Vertex _glesVertex \n attribute highp vec4 _glesVertex; \n " ;
pre + = " #define gl_Normal _glesNormal \n attribute mediump vec3 _glesNormal; \n " ;
pre + = " #define gl_MultiTexCoord0 _glesMultiTexCoord0 \n attribute highp vec4 _glesMultiTexCoord0; \n " ;
pre + = " #define gl_MultiTexCoord1 _glesMultiTexCoord1 \n attribute highp vec4 _glesMultiTexCoord1; \n " ;
pre + = " #define gl_Color _glesColor \n attribute lowp vec4 _glesColor; \n " ;
}
s . insert ( insertPoint , pre ) ;
2012-04-03 20:30:07 -07:00
}
static void MassageFragmentForGLES ( std : : string & s )
{
std : : string pre ;
s = pre + s ;
}
2014-10-11 12:32:43 -07:00
static const char * kGlslTypeNames [ kGlslTypeCount ] = {
" float " ,
" int " ,
" bool " ,
" 2d " ,
" 3d " ,
" cube " ,
" other " ,
} ;
static const char * kGlslPrecNames [ kGlslPrecCount ] = {
" high " ,
" medium " ,
" low " ,
} ;
2012-04-03 20:30:07 -07:00
static bool TestFile ( glslopt_ctx * ctx , bool vertex ,
2012-10-07 20:41:18 -07:00
const std : : string & testName ,
2012-04-03 20:30:07 -07:00
const std : : string & inputPath ,
const std : : string & outputPath ,
bool gles ,
2014-10-11 12:32:43 -07:00
bool doCheckGLSL ,
bool doCheckMetal )
2012-04-03 20:30:07 -07:00
{
std : : string input ;
if ( ! ReadStringFromFile ( inputPath . c_str ( ) , input ) )
{
2012-10-07 20:41:18 -07:00
printf ( " \n %s: failed to read input file \n " , testName . c_str ( ) ) ;
2012-04-03 20:30:07 -07:00
return false ;
}
if ( doCheckGLSL )
{
2012-10-07 20:41:18 -07:00
if ( ! CheckGLSL ( vertex , gles , testName , " input " , input . c_str ( ) ) )
2012-04-03 20:30:07 -07:00
return false ;
}
if ( gles )
{
if ( vertex )
MassageVertexForGLES ( input ) ;
else
MassageFragmentForGLES ( input ) ;
}
bool res = true ;
glslopt_shader_type type = vertex ? kGlslOptShaderVertex : kGlslOptShaderFragment ;
glslopt_shader * shader = glslopt_optimize ( ctx , type , input . c_str ( ) , 0 ) ;
bool optimizeOk = glslopt_get_status ( shader ) ;
if ( optimizeOk )
{
std : : string textHir = glslopt_get_raw_output ( shader ) ;
std : : string textOpt = glslopt_get_output ( shader ) ;
2014-02-10 23:06:13 -08:00
2014-10-11 12:32:43 -07:00
// append stats
char buffer [ 1000 ] ;
2014-02-10 23:06:13 -08:00
int statsAlu , statsTex , statsFlow ;
glslopt_shader_get_stats ( shader , & statsAlu , & statsTex , & statsFlow ) ;
2014-10-11 12:32:43 -07:00
sprintf ( buffer , " \n // stats: %i alu %i tex %i flow \n " , statsAlu , statsTex , statsFlow ) ;
2014-02-10 23:06:13 -08:00
textOpt + = buffer ;
2014-10-11 12:32:43 -07:00
// append inputs
const int inputCount = glslopt_shader_get_input_count ( shader ) ;
if ( inputCount > 0 )
{
sprintf ( buffer , " // inputs: %i \n " , inputCount ) ;
textOpt + = buffer ;
}
for ( int i = 0 ; i < inputCount ; + + i )
{
const char * parName ;
glslopt_basic_type parType ;
glslopt_precision parPrec ;
int parVecSize , parMatSize , parArrSize , location ;
glslopt_shader_get_input_desc ( shader , i , & parName , & parType , & parPrec , & parVecSize , & parMatSize , & parArrSize , & location ) ;
if ( location > = 0 )
sprintf ( buffer , " // #%i: %s (%s %s) %ix%i [%i] loc %i \n " , i , parName , kGlslPrecNames [ parPrec ] , kGlslTypeNames [ parType ] , parVecSize , parMatSize , parArrSize , location ) ;
else
sprintf ( buffer , " // #%i: %s (%s %s) %ix%i [%i] \n " , i , parName , kGlslPrecNames [ parPrec ] , kGlslTypeNames [ parType ] , parVecSize , parMatSize , parArrSize ) ;
textOpt + = buffer ;
}
// append uniforms
const int uniformCount = glslopt_shader_get_uniform_count ( shader ) ;
const int uniformSize = glslopt_shader_get_uniform_total_size ( shader ) ;
if ( uniformCount > 0 )
{
sprintf ( buffer , " // uniforms: %i (total size: %i) \n " , uniformCount , uniformSize ) ;
textOpt + = buffer ;
}
for ( int i = 0 ; i < uniformCount ; + + i )
{
const char * parName ;
glslopt_basic_type parType ;
glslopt_precision parPrec ;
int parVecSize , parMatSize , parArrSize , location ;
glslopt_shader_get_uniform_desc ( shader , i , & parName , & parType , & parPrec , & parVecSize , & parMatSize , & parArrSize , & location ) ;
if ( location > = 0 )
sprintf ( buffer , " // #%i: %s (%s %s) %ix%i [%i] loc %i \n " , i , parName , kGlslPrecNames [ parPrec ] , kGlslTypeNames [ parType ] , parVecSize , parMatSize , parArrSize , location ) ;
else
sprintf ( buffer , " // #%i: %s (%s %s) %ix%i [%i] \n " , i , parName , kGlslPrecNames [ parPrec ] , kGlslTypeNames [ parType ] , parVecSize , parMatSize , parArrSize ) ;
textOpt + = buffer ;
}
// append textures
const int textureCount = glslopt_shader_get_texture_count ( shader ) ;
if ( textureCount > 0 )
{
sprintf ( buffer , " // textures: %i \n " , textureCount ) ;
textOpt + = buffer ;
}
for ( int i = 0 ; i < textureCount ; + + i )
{
const char * parName ;
glslopt_basic_type parType ;
glslopt_precision parPrec ;
int parVecSize , parMatSize , parArrSize , location ;
glslopt_shader_get_texture_desc ( shader , i , & parName , & parType , & parPrec , & parVecSize , & parMatSize , & parArrSize , & location ) ;
if ( location > = 0 )
sprintf ( buffer , " // #%i: %s (%s %s) %ix%i [%i] loc %i \n " , i , parName , kGlslPrecNames [ parPrec ] , kGlslTypeNames [ parType ] , parVecSize , parMatSize , parArrSize , location ) ;
else
sprintf ( buffer , " // #%i: %s (%s %s) %ix%i [%i] \n " , i , parName , kGlslPrecNames [ parPrec ] , kGlslTypeNames [ parType ] , parVecSize , parMatSize , parArrSize ) ;
textOpt + = buffer ;
}
2014-02-10 23:06:13 -08:00
2012-04-03 20:30:07 -07:00
std : : string outputOpt ;
ReadStringFromFile ( outputPath . c_str ( ) , outputOpt ) ;
2014-10-11 12:32:43 -07:00
if ( res & & doCheckMetal & & ! CheckMetal ( vertex , gles , testName , " metal " , textOpt . c_str ( ) ) )
2012-04-03 20:30:07 -07:00
res = false ;
2014-10-11 12:32:43 -07:00
2012-04-03 20:30:07 -07:00
if ( textOpt ! = outputOpt )
{
// write output
FILE * f = fopen ( outputPath . c_str ( ) , " wb " ) ;
if ( ! f )
{
2012-10-07 20:41:18 -07:00
printf ( " \n %s: can't write to optimized file! \n " , testName . c_str ( ) ) ;
2012-04-03 20:30:07 -07:00
}
else
{
fwrite ( textOpt . c_str ( ) , 1 , textOpt . size ( ) , f ) ;
fclose ( f ) ;
}
2012-10-07 20:41:18 -07:00
printf ( " \n %s: does not match optimized output \n " , testName . c_str ( ) ) ;
2012-04-03 20:30:07 -07:00
res = false ;
}
2012-10-07 20:41:18 -07:00
if ( res & & doCheckGLSL & & ! CheckGLSL ( vertex , gles , testName , " raw " , textHir . c_str ( ) ) )
2012-04-03 20:30:07 -07:00
res = false ;
2012-10-07 20:41:18 -07:00
if ( res & & doCheckGLSL & & ! CheckGLSL ( vertex , gles , testName , " optimized " , textOpt . c_str ( ) ) )
2012-04-03 20:30:07 -07:00
res = false ;
}
else
{
2012-10-07 20:41:18 -07:00
printf ( " \n %s: optimize error: %s \n " , testName . c_str ( ) , glslopt_get_log ( shader ) ) ;
2012-04-03 20:30:07 -07:00
res = false ;
}
glslopt_shader_delete ( shader ) ;
return res ;
}
int main ( int argc , const char * * argv )
{
if ( argc < 2 )
{
printf ( " USAGE: glsloptimizer testfolder \n " ) ;
return 1 ;
}
bool hasOpenGL = InitializeOpenGL ( ) ;
2014-10-11 12:32:43 -07:00
bool hasMetal = InitializeMetal ( ) ;
2014-02-10 23:06:13 -08:00
glslopt_ctx * ctx [ 3 ] = {
glslopt_initialize ( kGlslTargetOpenGLES20 ) ,
glslopt_initialize ( kGlslTargetOpenGLES30 ) ,
glslopt_initialize ( kGlslTargetOpenGL ) ,
2012-04-03 20:30:07 -07:00
} ;
2014-10-11 12:32:43 -07:00
glslopt_ctx * ctxMetal = glslopt_initialize ( kGlslTargetMetal ) ;
2012-04-03 20:30:07 -07:00
std : : string baseFolder = argv [ 1 ] ;
clock_t time0 = clock ( ) ;
2014-02-10 23:06:13 -08:00
// 2.39s
// ralloc fix 256 initial: 1.35s
2012-04-03 20:30:07 -07:00
static const char * kTypeName [ 2 ] = { " vertex " , " fragment " } ;
size_t tests = 0 ;
size_t errors = 0 ;
for ( int type = 0 ; type < 2 ; + + type )
{
std : : string testFolder = baseFolder + " / " + kTypeName [ type ] ;
2014-02-10 23:06:13 -08:00
static const char * kAPIName [ 3 ] = { " OpenGL ES 2.0 " , " OpenGL ES 3.0 " , " OpenGL " } ;
static const char * kApiIn [ 3 ] = { " -inES.txt " , " -inES3.txt " , " -in.txt " } ;
static const char * kApiOut [ 3 ] = { " -outES.txt " , " -outES3.txt " , " -out.txt " } ;
2014-10-11 12:32:43 -07:00
static const char * kApiOutMetal [ 3 ] = { " -outESMetal.txt " , " -outES3Metal.txt " , " -outMetal.txt " } ;
2014-02-10 23:06:13 -08:00
for ( int api = 0 ; api < 3 ; + + api )
2012-04-03 20:30:07 -07:00
{
2012-10-07 20:41:18 -07:00
printf ( " \n ** running %s tests for %s... \n " , kTypeName [ type ] , kAPIName [ api ] ) ;
2012-04-03 20:30:07 -07:00
StringVector inputFiles = GetFiles ( testFolder , kApiIn [ api ] ) ;
size_t n = inputFiles . size ( ) ;
for ( size_t i = 0 ; i < n ; + + i )
{
std : : string inname = inputFiles [ i ] ;
2012-10-07 20:41:18 -07:00
//if (inname != "ast-in.txt")
// continue;
2012-04-03 20:30:07 -07:00
std : : string outname = inname . substr ( 0 , inname . size ( ) - strlen ( kApiIn [ api ] ) ) + kApiOut [ api ] ;
2014-10-11 12:32:43 -07:00
std : : string outnameMetal = inname . substr ( 0 , inname . size ( ) - strlen ( kApiIn [ api ] ) ) + kApiOutMetal [ api ] ;
const bool useMetal = ( api = = 1 ) ;
bool ok = TestFile ( ctx [ api ] , type = = 0 , inname , testFolder + " / " + inname , testFolder + " / " + outname , api < = 1 , hasOpenGL , false ) ;
2012-04-03 20:30:07 -07:00
if ( ! ok )
{
+ + errors ;
}
2014-10-11 12:32:43 -07:00
if ( useMetal )
{
ok = TestFile ( ctxMetal , type = = 0 , inname , testFolder + " / " + inname , testFolder + " / " + outnameMetal , api = = 0 , false , hasMetal ) ;
if ( ! ok )
{
+ + errors ;
}
}
2012-04-03 20:30:07 -07:00
+ + tests ;
}
}
}
clock_t time1 = clock ( ) ;
float timeDelta = float ( time1 - time0 ) / CLOCKS_PER_SEC ;
if ( errors ! = 0 )
2013-04-08 22:40:18 -07:00
printf ( " \n **** %i tests (%.2fsec), %i !!!FAILED!!! \n " , ( int ) tests , timeDelta , ( int ) errors ) ;
2012-04-03 20:30:07 -07:00
else
2013-04-08 22:40:18 -07:00
printf ( " \n **** %i tests (%.2fsec) succeeded \n " , ( int ) tests , timeDelta ) ;
2012-10-07 20:41:18 -07:00
// 3.25s
// with builtin call linking, 3.84s
2012-04-03 20:30:07 -07:00
for ( int i = 0 ; i < 2 ; + + i )
glslopt_cleanup ( ctx [ i ] ) ;
2014-10-11 12:32:43 -07:00
glslopt_cleanup ( ctxMetal ) ;
2014-02-10 23:06:13 -08:00
CleanupGL ( ) ;
2012-04-03 20:30:07 -07:00
return errors ? 1 : 0 ;
}