glsl_optimizer_tests.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706
  1. #include <string>
  2. #include <vector>
  3. #include <time.h>
  4. #include "../src/glsl/glsl_optimizer.h"
  5. #define GL_GLEXT_PROTOTYPES 1
  6. #if __linux__
  7. #define GOT_GFX 0
  8. #else
  9. #define GOT_GFX 1
  10. #endif
  11. #if GOT_GFX
  12. // ---- Windows GL bits
  13. #ifdef _MSC_VER
  14. #define GOT_MORE_THAN_GLSL_120 1
  15. #include <windows.h>
  16. #include <gl/GL.h>
  17. extern "C" {
  18. typedef char GLchar; /* native character */
  19. typedef unsigned int GLuint; /* shader object handle */
  20. #define GL_VERTEX_SHADER 0x8B31
  21. #define GL_FRAGMENT_SHADER 0x8B30
  22. #define GL_COMPILE_STATUS 0x8B81
  23. typedef void (WINAPI * PFNGLDELETESHADERPROC) (GLuint shader);
  24. typedef GLuint (WINAPI * PFNGLCREATESHADERPROC) (GLenum type);
  25. typedef void (WINAPI * PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length);
  26. typedef void (WINAPI * PFNGLCOMPILESHADERPROC) (GLuint shader);
  27. typedef void (WINAPI * PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
  28. typedef void (WINAPI * PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params);
  29. static PFNGLDELETESHADERPROC glDeleteShader;
  30. static PFNGLCREATESHADERPROC glCreateShader;
  31. static PFNGLSHADERSOURCEPROC glShaderSource;
  32. static PFNGLCOMPILESHADERPROC glCompileShader;
  33. static PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;
  34. static PFNGLGETSHADERIVPROC glGetShaderiv;
  35. }
  36. #endif // #ifdef _MSC_VER
  37. // ---- Apple GL bits
  38. #ifdef __APPLE__
  39. #define GOT_MORE_THAN_GLSL_120 0
  40. #include <OpenGL/OpenGL.h>
  41. #include <OpenGL/gl.h>
  42. #include <OpenGL/CGLTypes.h>
  43. #include <dirent.h>
  44. #include <stdlib.h>
  45. static CGLContextObj s_GLContext;
  46. static CGLContextObj s_GLContext3;
  47. static bool s_GL3Active = false;
  48. #endif // ifdef __APPLE__
  49. #else // #if GOT_GFX
  50. #define GOT_MORE_THAN_GLSL_120 0
  51. #include <cstdio>
  52. #include <cstring>
  53. #include "dirent.h"
  54. #include "GL/gl.h"
  55. #include "GL/glext.h"
  56. #endif // ! #if GOT_GFX
  57. #ifndef _MSC_VER
  58. #include <unistd.h>
  59. #endif
  60. static bool InitializeOpenGL ()
  61. {
  62. bool hasGLSL = false;
  63. #if GOT_GFX
  64. #ifdef _MSC_VER
  65. // setup minimal required GL
  66. HWND wnd = CreateWindowA(
  67. "STATIC",
  68. "GL",
  69. WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
  70. 0, 0, 16, 16,
  71. NULL, NULL,
  72. GetModuleHandle(NULL), NULL );
  73. HDC dc = GetDC( wnd );
  74. PIXELFORMATDESCRIPTOR pfd = {
  75. sizeof(PIXELFORMATDESCRIPTOR), 1,
  76. PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL,
  77. PFD_TYPE_RGBA, 32,
  78. 0, 0, 0, 0, 0, 0,
  79. 0, 0, 0, 0, 0, 0, 0,
  80. 16, 0,
  81. 0, PFD_MAIN_PLANE, 0, 0, 0, 0
  82. };
  83. int fmt = ChoosePixelFormat( dc, &pfd );
  84. SetPixelFormat( dc, fmt, &pfd );
  85. HGLRC rc = wglCreateContext( dc );
  86. wglMakeCurrent( dc, rc );
  87. #elif defined(__APPLE__)
  88. CGLPixelFormatAttribute attributes[] = {
  89. kCGLPFAAccelerated, // no software rendering
  90. (CGLPixelFormatAttribute) 0
  91. };
  92. CGLPixelFormatAttribute attributes3[] = {
  93. kCGLPFAAccelerated, // no software rendering
  94. kCGLPFAOpenGLProfile, // core profile with the version stated below
  95. (CGLPixelFormatAttribute) kCGLOGLPVersion_3_2_Core,
  96. (CGLPixelFormatAttribute) 0
  97. };
  98. GLint num;
  99. CGLPixelFormatObj pix;
  100. // create legacy context
  101. CGLChoosePixelFormat(attributes, &pix, &num);
  102. if (pix == NULL)
  103. return false;
  104. CGLCreateContext(pix, NULL, &s_GLContext);
  105. if (s_GLContext == NULL)
  106. return false;
  107. CGLDestroyPixelFormat(pix);
  108. CGLSetCurrentContext(s_GLContext);
  109. // create core 3.2 context
  110. CGLChoosePixelFormat(attributes3, &pix, &num);
  111. if (pix == NULL)
  112. return false;
  113. CGLCreateContext(pix, NULL, &s_GLContext3);
  114. if (s_GLContext3 == NULL)
  115. return false;
  116. CGLDestroyPixelFormat(pix);
  117. #endif
  118. // check if we have GLSL
  119. const char* extensions = (const char*)glGetString(GL_EXTENSIONS);
  120. hasGLSL = extensions != NULL && strstr(extensions, "GL_ARB_shader_objects") && strstr(extensions, "GL_ARB_vertex_shader") && strstr(extensions, "GL_ARB_fragment_shader");
  121. #if defined(__APPLE__)
  122. // using core profile; always has GLSL
  123. hasGLSL = true;
  124. #endif
  125. #ifdef _MSC_VER
  126. if (hasGLSL)
  127. {
  128. glDeleteShader = (PFNGLDELETESHADERPROC)wglGetProcAddress("glDeleteShader");
  129. glCreateShader = (PFNGLCREATESHADERPROC)wglGetProcAddress("glCreateShader");
  130. glShaderSource = (PFNGLSHADERSOURCEPROC)wglGetProcAddress("glShaderSource");
  131. glCompileShader = (PFNGLCOMPILESHADERPROC)wglGetProcAddress("glCompileShader");
  132. glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)wglGetProcAddress("glGetShaderInfoLog");
  133. glGetShaderiv = (PFNGLGETSHADERIVPROC)wglGetProcAddress("glGetShaderiv");
  134. }
  135. #endif
  136. #endif
  137. return hasGLSL;
  138. }
  139. static void CleanupGL()
  140. {
  141. #if GOT_GFX
  142. #ifdef __APPLE__
  143. CGLSetCurrentContext(NULL);
  144. if (s_GLContext)
  145. CGLDestroyContext(s_GLContext);
  146. if (s_GLContext3)
  147. CGLDestroyContext(s_GLContext3);
  148. #endif // #ifdef __APPLE__
  149. #endif // #if GOT_GFX
  150. }
  151. static bool InitializeMetal ()
  152. {
  153. bool hasMetal = false;
  154. #if defined(__APPLE__)
  155. hasMetal = true; //@TODO: detect metal compiler presence
  156. #endif
  157. return hasMetal;
  158. }
  159. static void replace_string (std::string& target, const std::string& search, const std::string& replace, size_t startPos)
  160. {
  161. if (search.empty())
  162. return;
  163. std::string::size_type p = startPos;
  164. while ((p = target.find (search, p)) != std::string::npos)
  165. {
  166. target.replace (p, search.size (), replace);
  167. p += replace.size ();
  168. }
  169. }
  170. static bool CheckGLSL (bool vertex, bool gles, const std::string& testName, const char* prefix, const std::string& source)
  171. {
  172. #if !GOT_GFX
  173. return true; // just assume it's ok
  174. #endif
  175. #if !GOT_MORE_THAN_GLSL_120
  176. if (source.find("#version 140") != std::string::npos)
  177. return true;
  178. #endif
  179. const bool need3 =
  180. (source.find("#version 150") != std::string::npos) ||
  181. (source.find("#version 300") != std::string::npos);
  182. # ifdef __APPLE__
  183. // Mac core context does not accept any older shader versions, so need to switch to
  184. // either legacy context or core one.
  185. if (need3)
  186. {
  187. if (!s_GL3Active)
  188. CGLSetCurrentContext(s_GLContext3);
  189. s_GL3Active = true;
  190. }
  191. else
  192. {
  193. if (s_GL3Active)
  194. CGLSetCurrentContext(s_GLContext);
  195. s_GL3Active = false;
  196. }
  197. # endif // ifdef __APPLE__
  198. std::string src;
  199. if (gles)
  200. {
  201. src += "#define lowp\n";
  202. src += "#define mediump\n";
  203. src += "#define highp\n";
  204. src += "#define texture2DLodEXT texture2DLod\n";
  205. src += "#define texture2DProjLodEXT texture2DProjLod\n";
  206. src += "#define texture2DGradEXT texture2DGradARB\n";
  207. src += "#define textureCubeGradEXT textureCubeGradARB\n";
  208. src += "#define gl_FragDepthEXT gl_FragDepth\n";
  209. if (!need3)
  210. {
  211. src += "#define gl_LastFragData _glesLastFragData\n";
  212. src += "varying lowp vec4 _glesLastFragData[4];\n";
  213. }
  214. if (!need3)
  215. {
  216. src += "float shadow2DEXT (sampler2DShadow s, vec3 p) { return shadow2D(s,p).r; }\n";
  217. src += "float shadow2DProjEXT (sampler2DShadow s, vec4 p) { return shadow2DProj(s,p).r; }\n";
  218. }
  219. }
  220. src += source;
  221. if (gles)
  222. {
  223. replace_string (src, "GL_EXT_shader_texture_lod", "GL_ARB_shader_texture_lod", 0);
  224. replace_string (src, "GL_EXT_draw_instanced", "GL_ARB_draw_instanced", 0);
  225. replace_string (src, "gl_InstanceIDEXT", "gl_InstanceIDARB ", 0);
  226. replace_string (src, "#extension GL_OES_standard_derivatives : require", "", 0);
  227. replace_string (src, "#extension GL_EXT_shadow_samplers : require", "", 0);
  228. replace_string (src, "#extension GL_EXT_frag_depth : require", "", 0);
  229. replace_string (src, "#extension GL_OES_standard_derivatives : enable", "", 0);
  230. replace_string (src, "#extension GL_EXT_shadow_samplers : enable", "", 0);
  231. replace_string (src, "#extension GL_EXT_frag_depth : enable", "", 0);
  232. replace_string (src, "#extension GL_EXT_draw_buffers : enable", "", 0);
  233. replace_string (src, "#extension GL_EXT_draw_buffers : require", "", 0);
  234. replace_string (src, "precision ", "// precision ", 0);
  235. replace_string (src, "#version 300 es", "", 0);
  236. }
  237. // can't check FB fetch on PC
  238. if (src.find("#extension GL_EXT_shader_framebuffer_fetch") != std::string::npos)
  239. return true;
  240. if (gles && need3)
  241. {
  242. src = "#version 330\n" + src;
  243. }
  244. const char* sourcePtr = src.c_str();
  245. GLuint shader = glCreateShader (vertex ? GL_VERTEX_SHADER : GL_FRAGMENT_SHADER);
  246. glShaderSource (shader, 1, &sourcePtr, NULL);
  247. glCompileShader (shader);
  248. GLint status;
  249. glGetShaderiv (shader, GL_COMPILE_STATUS, &status);
  250. bool res = true;
  251. if (status != GL_TRUE)
  252. {
  253. char log[20000];
  254. log[0] = 0;
  255. GLsizei logLength;
  256. glGetShaderInfoLog (shader, sizeof(log), &logLength, log);
  257. printf ("\n %s: real glsl compiler error on %s:\n%s\n", testName.c_str(), prefix, log);
  258. res = false;
  259. }
  260. glDeleteShader (shader);
  261. return res;
  262. }
  263. static bool CheckMetal (bool vertex, bool gles, const std::string& testName, const char* prefix, const std::string& source)
  264. {
  265. #if !GOT_GFX || !defined(__APPLE__)
  266. return true; // just assume it's ok
  267. #else
  268. FILE* f = fopen ("metalTemp.metal", "wb");
  269. fwrite (source.c_str(), source.size(), 1, f);
  270. fclose (f);
  271. #if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
  272. 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");
  273. if (res != 0)
  274. {
  275. printf ("\n %s: Metal compiler failed\n", testName.c_str());
  276. return false;
  277. }
  278. #endif //
  279. return true;
  280. #endif
  281. }
  282. static bool ReadStringFromFile (const char* pathName, std::string& output)
  283. {
  284. FILE* file = fopen( pathName, "rb" );
  285. if (file == NULL)
  286. return false;
  287. fseek(file, 0, SEEK_END);
  288. int length = ftell(file);
  289. fseek(file, 0, SEEK_SET);
  290. if (length < 0)
  291. {
  292. fclose( file );
  293. return false;
  294. }
  295. output.resize(length);
  296. int readLength = fread(&*output.begin(), 1, length, file);
  297. fclose(file);
  298. if (readLength != length)
  299. {
  300. output.clear();
  301. return false;
  302. }
  303. replace_string(output, "\r\n", "\n", 0);
  304. return true;
  305. }
  306. bool EndsWith (const std::string& str, const std::string& sub)
  307. {
  308. return (str.size() >= sub.size()) && (strncmp (str.c_str()+str.size()-sub.size(), sub.c_str(), sub.size())==0);
  309. }
  310. typedef std::vector<std::string> StringVector;
  311. static StringVector GetFiles (const std::string& folder, const std::string& endsWith)
  312. {
  313. StringVector res;
  314. #ifdef _MSC_VER
  315. WIN32_FIND_DATAA FindFileData;
  316. HANDLE hFind = FindFirstFileA ((folder+"/*"+endsWith).c_str(), &FindFileData);
  317. if (hFind == INVALID_HANDLE_VALUE)
  318. return res;
  319. do {
  320. res.push_back (FindFileData.cFileName);
  321. } while (FindNextFileA (hFind, &FindFileData));
  322. FindClose (hFind);
  323. #else
  324. DIR *dirp;
  325. struct dirent *dp;
  326. if ((dirp = opendir(folder.c_str())) == NULL)
  327. return res;
  328. while ( (dp = readdir(dirp)) )
  329. {
  330. std::string fname = dp->d_name;
  331. if (fname == "." || fname == "..")
  332. continue;
  333. if (!EndsWith (fname, endsWith))
  334. continue;
  335. res.push_back (fname);
  336. }
  337. closedir(dirp);
  338. #endif
  339. return res;
  340. }
  341. static void DeleteFile (const std::string& path)
  342. {
  343. #ifdef _MSC_VER
  344. DeleteFileA (path.c_str());
  345. #else
  346. unlink (path.c_str());
  347. #endif
  348. }
  349. static void MassageVertexForGLES (std::string& s)
  350. {
  351. if (s.find ("_glesVertex") != std::string::npos)
  352. return;
  353. std::string pre;
  354. std::string version = "#version 300 es\n";
  355. size_t insertPoint = s.find(version);
  356. if (insertPoint != std::string::npos)
  357. {
  358. insertPoint += version.size();
  359. pre += "#define gl_Vertex _glesVertex\nin highp vec4 _glesVertex;\n";
  360. pre += "#define gl_Normal _glesNormal\nin mediump vec3 _glesNormal;\n";
  361. pre += "#define gl_MultiTexCoord0 _glesMultiTexCoord0\nin highp vec4 _glesMultiTexCoord0;\n";
  362. pre += "#define gl_MultiTexCoord1 _glesMultiTexCoord1\nin highp vec4 _glesMultiTexCoord1;\n";
  363. pre += "#define gl_Color _glesColor\nin lowp vec4 _glesColor;\n";
  364. }
  365. else
  366. {
  367. insertPoint = 0;
  368. pre += "#define gl_Vertex _glesVertex\nattribute highp vec4 _glesVertex;\n";
  369. pre += "#define gl_Normal _glesNormal\nattribute mediump vec3 _glesNormal;\n";
  370. pre += "#define gl_MultiTexCoord0 _glesMultiTexCoord0\nattribute highp vec4 _glesMultiTexCoord0;\n";
  371. pre += "#define gl_MultiTexCoord1 _glesMultiTexCoord1\nattribute highp vec4 _glesMultiTexCoord1;\n";
  372. pre += "#define gl_Color _glesColor\nattribute lowp vec4 _glesColor;\n";
  373. }
  374. s.insert (insertPoint, pre);
  375. }
  376. static void MassageFragmentForGLES (std::string& s)
  377. {
  378. std::string pre;
  379. s = pre + s;
  380. }
  381. static const char* kGlslTypeNames[kGlslTypeCount] = {
  382. "float",
  383. "int",
  384. "bool",
  385. "2d",
  386. "3d",
  387. "cube",
  388. "2dshadow",
  389. "2darray",
  390. "other",
  391. };
  392. static const char* kGlslPrecNames[kGlslPrecCount] = {
  393. "high",
  394. "medium",
  395. "low",
  396. };
  397. static bool TestFile (glslopt_ctx* ctx, bool vertex,
  398. const std::string& testName,
  399. const std::string& inputPath,
  400. const std::string& outputPath,
  401. bool gles,
  402. bool doCheckGLSL,
  403. bool doCheckMetal)
  404. {
  405. std::string input;
  406. if (!ReadStringFromFile (inputPath.c_str(), input))
  407. {
  408. printf ("\n %s: failed to read input file\n", testName.c_str());
  409. return false;
  410. }
  411. if (doCheckGLSL)
  412. {
  413. if (!CheckGLSL (vertex, gles, testName, "input", input.c_str()))
  414. return false;
  415. }
  416. if (gles)
  417. {
  418. if (vertex)
  419. MassageVertexForGLES (input);
  420. else
  421. MassageFragmentForGLES (input);
  422. }
  423. bool res = true;
  424. glslopt_shader_type type = vertex ? kGlslOptShaderVertex : kGlslOptShaderFragment;
  425. glslopt_shader* shader = glslopt_optimize (ctx, type, input.c_str(), 0);
  426. bool optimizeOk = glslopt_get_status(shader);
  427. if (optimizeOk)
  428. {
  429. std::string textHir = glslopt_get_raw_output (shader);
  430. std::string textOpt = glslopt_get_output (shader);
  431. // append stats
  432. char buffer[1000];
  433. int statsAlu, statsTex, statsFlow;
  434. glslopt_shader_get_stats (shader, &statsAlu, &statsTex, &statsFlow);
  435. sprintf(buffer, "\n// stats: %i alu %i tex %i flow\n", statsAlu, statsTex, statsFlow);
  436. textOpt += buffer;
  437. // append inputs
  438. const int inputCount = glslopt_shader_get_input_count (shader);
  439. if (inputCount > 0)
  440. {
  441. sprintf(buffer, "// inputs: %i\n", inputCount);
  442. textOpt += buffer;
  443. }
  444. for (int i = 0; i < inputCount; ++i)
  445. {
  446. const char* parName;
  447. glslopt_basic_type parType;
  448. glslopt_precision parPrec;
  449. int parVecSize, parMatSize, parArrSize, location;
  450. glslopt_shader_get_input_desc(shader, i, &parName, &parType, &parPrec, &parVecSize, &parMatSize, &parArrSize, &location);
  451. if (location >= 0)
  452. sprintf(buffer, "// #%i: %s (%s %s) %ix%i [%i] loc %i\n", i, parName, kGlslPrecNames[parPrec], kGlslTypeNames[parType], parVecSize, parMatSize, parArrSize, location);
  453. else
  454. sprintf(buffer, "// #%i: %s (%s %s) %ix%i [%i]\n", i, parName, kGlslPrecNames[parPrec], kGlslTypeNames[parType], parVecSize, parMatSize, parArrSize);
  455. textOpt += buffer;
  456. }
  457. // append uniforms
  458. const int uniformCount = glslopt_shader_get_uniform_count (shader);
  459. const int uniformSize = glslopt_shader_get_uniform_total_size (shader);
  460. if (uniformCount > 0)
  461. {
  462. sprintf(buffer, "// uniforms: %i (total size: %i)\n", uniformCount, uniformSize);
  463. textOpt += buffer;
  464. }
  465. for (int i = 0; i < uniformCount; ++i)
  466. {
  467. const char* parName;
  468. glslopt_basic_type parType;
  469. glslopt_precision parPrec;
  470. int parVecSize, parMatSize, parArrSize, location;
  471. glslopt_shader_get_uniform_desc(shader, i, &parName, &parType, &parPrec, &parVecSize, &parMatSize, &parArrSize, &location);
  472. if (location >= 0)
  473. sprintf(buffer, "// #%i: %s (%s %s) %ix%i [%i] loc %i\n", i, parName, kGlslPrecNames[parPrec], kGlslTypeNames[parType], parVecSize, parMatSize, parArrSize, location);
  474. else
  475. sprintf(buffer, "// #%i: %s (%s %s) %ix%i [%i]\n", i, parName, kGlslPrecNames[parPrec], kGlslTypeNames[parType], parVecSize, parMatSize, parArrSize);
  476. textOpt += buffer;
  477. }
  478. // append textures
  479. const int textureCount = glslopt_shader_get_texture_count (shader);
  480. if (textureCount > 0)
  481. {
  482. sprintf(buffer, "// textures: %i\n", textureCount);
  483. textOpt += buffer;
  484. }
  485. for (int i = 0; i < textureCount; ++i)
  486. {
  487. const char* parName;
  488. glslopt_basic_type parType;
  489. glslopt_precision parPrec;
  490. int parVecSize, parMatSize, parArrSize, location;
  491. glslopt_shader_get_texture_desc(shader, i, &parName, &parType, &parPrec, &parVecSize, &parMatSize, &parArrSize, &location);
  492. if (location >= 0)
  493. sprintf(buffer, "// #%i: %s (%s %s) %ix%i [%i] loc %i\n", i, parName, kGlslPrecNames[parPrec], kGlslTypeNames[parType], parVecSize, parMatSize, parArrSize, location);
  494. else
  495. sprintf(buffer, "// #%i: %s (%s %s) %ix%i [%i]\n", i, parName, kGlslPrecNames[parPrec], kGlslTypeNames[parType], parVecSize, parMatSize, parArrSize);
  496. textOpt += buffer;
  497. }
  498. std::string outputOpt;
  499. ReadStringFromFile (outputPath.c_str(), outputOpt);
  500. if (res && doCheckMetal && !CheckMetal (vertex, gles, testName, "metal", textOpt.c_str()))
  501. res = false;
  502. if (textOpt != outputOpt)
  503. {
  504. // write output
  505. FILE* f = fopen (outputPath.c_str(), "wb");
  506. if (!f)
  507. {
  508. printf ("\n %s: can't write to optimized file!\n", testName.c_str());
  509. }
  510. else
  511. {
  512. fwrite (textOpt.c_str(), 1, textOpt.size(), f);
  513. fclose (f);
  514. }
  515. printf ("\n %s: does not match optimized output\n", testName.c_str());
  516. res = false;
  517. }
  518. if (res && doCheckGLSL && !CheckGLSL (vertex, gles, testName, "raw", textHir.c_str()))
  519. res = false;
  520. if (res && doCheckGLSL && !CheckGLSL (vertex, gles, testName, "optimized", textOpt.c_str()))
  521. res = false;
  522. }
  523. else
  524. {
  525. printf ("\n %s: optimize error: %s\n", testName.c_str(), glslopt_get_log(shader));
  526. res = false;
  527. }
  528. glslopt_shader_delete (shader);
  529. return res;
  530. }
  531. int main (int argc, const char** argv)
  532. {
  533. if (argc < 2)
  534. {
  535. printf ("USAGE: glsloptimizer testfolder\n");
  536. return 1;
  537. }
  538. bool hasOpenGL = InitializeOpenGL ();
  539. bool hasMetal = InitializeMetal ();
  540. glslopt_ctx* ctx[3] = {
  541. glslopt_initialize(kGlslTargetOpenGLES20),
  542. glslopt_initialize(kGlslTargetOpenGLES30),
  543. glslopt_initialize(kGlslTargetOpenGL),
  544. };
  545. glslopt_ctx* ctxMetal = glslopt_initialize(kGlslTargetMetal);
  546. std::string baseFolder = argv[1];
  547. clock_t time0 = clock();
  548. // 2.39s
  549. // ralloc fix 256 initial: 1.35s
  550. static const char* kTypeName[2] = { "vertex", "fragment" };
  551. size_t tests = 0;
  552. size_t errors = 0;
  553. for (int type = 0; type < 2; ++type)
  554. {
  555. std::string testFolder = baseFolder + "/" + kTypeName[type];
  556. static const char* kAPIName[3] = { "OpenGL ES 2.0", "OpenGL ES 3.0", "OpenGL" };
  557. static const char* kApiIn [3] = {"-inES.txt", "-inES3.txt", "-in.txt"};
  558. static const char* kApiOut[3] = {"-outES.txt", "-outES3.txt", "-out.txt"};
  559. static const char* kApiOutMetal[3] = {"-outESMetal.txt", "-outES3Metal.txt", "-outMetal.txt"};
  560. for (int api = 0; api < 3; ++api)
  561. {
  562. printf ("\n** running %s tests for %s...\n", kTypeName[type], kAPIName[api]);
  563. StringVector inputFiles = GetFiles (testFolder, kApiIn[api]);
  564. size_t n = inputFiles.size();
  565. for (size_t i = 0; i < n; ++i)
  566. {
  567. std::string inname = inputFiles[i];
  568. //if (inname != "ast-in.txt")
  569. // continue;
  570. std::string outname = inname.substr (0,inname.size()-strlen(kApiIn[api])) + kApiOut[api];
  571. std::string outnameMetal = inname.substr (0,inname.size()-strlen(kApiIn[api])) + kApiOutMetal[api];
  572. const bool useMetal = (api == 1);
  573. bool ok = TestFile (ctx[api], type==0, inname, testFolder + "/" + inname, testFolder + "/" + outname, api<=1, hasOpenGL, false);
  574. if (!ok)
  575. {
  576. ++errors;
  577. }
  578. if (useMetal)
  579. {
  580. ok = TestFile (ctxMetal, type==0, inname, testFolder + "/" + inname, testFolder + "/" + outnameMetal, api==0, false, hasMetal);
  581. if (!ok)
  582. {
  583. ++errors;
  584. }
  585. }
  586. ++tests;
  587. }
  588. }
  589. }
  590. clock_t time1 = clock();
  591. float timeDelta = float(time1-time0)/CLOCKS_PER_SEC;
  592. if (errors != 0)
  593. printf ("\n**** %i tests (%.2fsec), %i !!!FAILED!!!\n", (int)tests, timeDelta, (int)errors);
  594. else
  595. printf ("\n**** %i tests (%.2fsec) succeeded\n", (int)tests, timeDelta);
  596. // 3.25s
  597. // with builtin call linking, 3.84s
  598. for (int i = 0; i < 2; ++i)
  599. glslopt_cleanup (ctx[i]);
  600. glslopt_cleanup (ctxMetal);
  601. CleanupGL();
  602. return errors ? 1 : 0;
  603. }