glsl_optimizer_tests.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  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 GLcharARB; /* native character */
  19. typedef unsigned int GLhandleARB; /* shader object handle */
  20. #define GL_VERTEX_SHADER_ARB 0x8B31
  21. #define GL_FRAGMENT_SHADER_ARB 0x8B30
  22. #define GL_OBJECT_COMPILE_STATUS_ARB 0x8B81
  23. typedef void (WINAPI * PFNGLDELETEOBJECTARBPROC) (GLhandleARB obj);
  24. typedef GLhandleARB (WINAPI * PFNGLCREATESHADEROBJECTARBPROC) (GLenum shaderType);
  25. typedef void (WINAPI * PFNGLSHADERSOURCEARBPROC) (GLhandleARB shaderObj, GLsizei count, const GLcharARB* *string, const GLint *length);
  26. typedef void (WINAPI * PFNGLCOMPILESHADERARBPROC) (GLhandleARB shaderObj);
  27. typedef void (WINAPI * PFNGLGETINFOLOGARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog);
  28. typedef void (WINAPI * PFNGLGETOBJECTPARAMETERIVARBPROC) (GLhandleARB obj, GLenum pname, GLint *params);
  29. static PFNGLDELETEOBJECTARBPROC glDeleteObjectARB;
  30. static PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB;
  31. static PFNGLSHADERSOURCEARBPROC glShaderSourceARB;
  32. static PFNGLCOMPILESHADERARBPROC glCompileShaderARB;
  33. static PFNGLGETINFOLOGARBPROC glGetInfoLogARB;
  34. static PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB;
  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. static CGLContextObj s_GLContext;
  45. static CGLContextObj s_GLContext3;
  46. static bool s_GL3Active = false;
  47. #endif // ifdef __APPLE__
  48. #else // #if GOT_GFX
  49. #define GOT_MORE_THAN_GLSL_120 0
  50. #include <cstdio>
  51. #include <cstring>
  52. #include "dirent.h"
  53. #include "GL/gl.h"
  54. #include "GL/glext.h"
  55. #endif // ! #if GOT_GFX
  56. #ifndef _MSC_VER
  57. #include <unistd.h>
  58. #endif
  59. static bool InitializeOpenGL ()
  60. {
  61. bool hasGLSL = false;
  62. #if GOT_GFX
  63. #ifdef _MSC_VER
  64. // setup minimal required GL
  65. HWND wnd = CreateWindowA(
  66. "STATIC",
  67. "GL",
  68. WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
  69. 0, 0, 16, 16,
  70. NULL, NULL,
  71. GetModuleHandle(NULL), NULL );
  72. HDC dc = GetDC( wnd );
  73. PIXELFORMATDESCRIPTOR pfd = {
  74. sizeof(PIXELFORMATDESCRIPTOR), 1,
  75. PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL,
  76. PFD_TYPE_RGBA, 32,
  77. 0, 0, 0, 0, 0, 0,
  78. 0, 0, 0, 0, 0, 0, 0,
  79. 16, 0,
  80. 0, PFD_MAIN_PLANE, 0, 0, 0, 0
  81. };
  82. int fmt = ChoosePixelFormat( dc, &pfd );
  83. SetPixelFormat( dc, fmt, &pfd );
  84. HGLRC rc = wglCreateContext( dc );
  85. wglMakeCurrent( dc, rc );
  86. #elif defined(__APPLE__)
  87. CGLPixelFormatAttribute attributes[] = {
  88. kCGLPFAAccelerated, // no software rendering
  89. (CGLPixelFormatAttribute) 0
  90. };
  91. CGLPixelFormatAttribute attributes3[] = {
  92. kCGLPFAAccelerated, // no software rendering
  93. kCGLPFAOpenGLProfile, // core profile with the version stated below
  94. (CGLPixelFormatAttribute) kCGLOGLPVersion_3_2_Core,
  95. (CGLPixelFormatAttribute) 0
  96. };
  97. GLint num;
  98. CGLPixelFormatObj pix;
  99. // create legacy context
  100. CGLChoosePixelFormat(attributes, &pix, &num);
  101. if (pix == NULL)
  102. return false;
  103. CGLCreateContext(pix, NULL, &s_GLContext);
  104. if (s_GLContext == NULL)
  105. return false;
  106. CGLDestroyPixelFormat(pix);
  107. CGLSetCurrentContext(s_GLContext);
  108. // create core 3.2 context
  109. CGLChoosePixelFormat(attributes3, &pix, &num);
  110. if (pix == NULL)
  111. return false;
  112. CGLCreateContext(pix, NULL, &s_GLContext3);
  113. if (s_GLContext3 == NULL)
  114. return false;
  115. CGLDestroyPixelFormat(pix);
  116. #endif
  117. // check if we have GLSL
  118. const char* extensions = (const char*)glGetString(GL_EXTENSIONS);
  119. hasGLSL = extensions != NULL && strstr(extensions, "GL_ARB_shader_objects") && strstr(extensions, "GL_ARB_vertex_shader") && strstr(extensions, "GL_ARB_fragment_shader");
  120. #if defined(__APPLE__)
  121. // using core profile; always has GLSL
  122. hasGLSL = true;
  123. #endif
  124. #ifdef _MSC_VER
  125. if (hasGLSL)
  126. {
  127. glDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC)wglGetProcAddress("glDeleteObjectARB");
  128. glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC)wglGetProcAddress("glCreateShaderObjectARB");
  129. glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC)wglGetProcAddress("glShaderSourceARB");
  130. glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC)wglGetProcAddress("glCompileShaderARB");
  131. glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC)wglGetProcAddress("glGetInfoLogARB");
  132. glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC)wglGetProcAddress("glGetObjectParameterivARB");
  133. }
  134. #endif
  135. #endif
  136. return hasGLSL;
  137. }
  138. static void CleanupGL()
  139. {
  140. #if GOT_GFX
  141. #ifdef __APPLE__
  142. CGLSetCurrentContext(NULL);
  143. if (s_GLContext)
  144. CGLDestroyContext(s_GLContext);
  145. if (s_GLContext3)
  146. CGLDestroyContext(s_GLContext3);
  147. #endif // #ifdef __APPLE__
  148. #endif // #if GOT_GFX
  149. }
  150. static void replace_string (std::string& target, const std::string& search, const std::string& replace, size_t startPos)
  151. {
  152. if (search.empty())
  153. return;
  154. std::string::size_type p = startPos;
  155. while ((p = target.find (search, p)) != std::string::npos)
  156. {
  157. target.replace (p, search.size (), replace);
  158. p += replace.size ();
  159. }
  160. }
  161. static bool CheckGLSL (bool vertex, bool gles, const std::string& testName, const char* prefix, const std::string& source)
  162. {
  163. #if !GOT_GFX
  164. return true; // just assume it's ok
  165. #endif
  166. #if !GOT_MORE_THAN_GLSL_120
  167. if (source.find("#version 140") != std::string::npos)
  168. return true;
  169. #endif
  170. # ifdef __APPLE__
  171. // Mac core context does not accept any older shader versions, so need to switch to
  172. // either legacy context or core one.
  173. const bool need3 =
  174. (source.find("#version 150") != std::string::npos) ||
  175. (source.find("#version 300") != std::string::npos);
  176. if (need3)
  177. {
  178. if (!s_GL3Active)
  179. CGLSetCurrentContext(s_GLContext3);
  180. s_GL3Active = true;
  181. }
  182. else
  183. {
  184. if (s_GL3Active)
  185. CGLSetCurrentContext(s_GLContext);
  186. s_GL3Active = false;
  187. }
  188. # endif // ifdef __APPLE__
  189. std::string src;
  190. if (gles)
  191. {
  192. src += "#define lowp\n";
  193. src += "#define mediump\n";
  194. src += "#define highp\n";
  195. src += "#define texture2DLodEXT texture2DLod\n";
  196. src += "#define texture2DProjLodEXT texture2DProjLod\n";
  197. src += "#define texture2DGradEXT texture2DGradARB\n";
  198. src += "#define textureCubeGradEXT textureCubeGradARB\n";
  199. src += "#define gl_FragDepthEXT gl_FragDepth\n";
  200. src += "float shadow2DEXT (sampler2DShadow s, vec3 p) { return shadow2D(s,p).r; }\n";
  201. src += "float shadow2DProjEXT (sampler2DShadow s, vec4 p) { return shadow2DProj(s,p).r; }\n";
  202. }
  203. src += source;
  204. if (gles)
  205. {
  206. replace_string (src, "GL_EXT_shader_texture_lod", "GL_ARB_shader_texture_lod", 0);
  207. replace_string (src, "#extension GL_OES_standard_derivatives : require", "", 0);
  208. replace_string (src, "#extension GL_EXT_shadow_samplers : require", "", 0);
  209. replace_string (src, "#extension GL_EXT_frag_depth : require", "", 0);
  210. replace_string (src, "#extension GL_OES_standard_derivatives : enable", "", 0);
  211. replace_string (src, "#extension GL_EXT_shadow_samplers : enable", "", 0);
  212. replace_string (src, "#extension GL_EXT_frag_depth : enable", "", 0);
  213. replace_string (src, "precision ", "// precision ", 0);
  214. replace_string (src, "#version 300 es", "#version 330", 0);
  215. }
  216. const char* sourcePtr = src.c_str();
  217. GLhandleARB shader = glCreateShaderObjectARB (vertex ? GL_VERTEX_SHADER_ARB : GL_FRAGMENT_SHADER_ARB);
  218. glShaderSourceARB (shader, 1, &sourcePtr, NULL);
  219. glCompileShaderARB (shader);
  220. GLint status;
  221. glGetObjectParameterivARB (shader, GL_OBJECT_COMPILE_STATUS_ARB, &status);
  222. bool res = true;
  223. if (status == 0)
  224. {
  225. char log[4096];
  226. GLsizei logLength;
  227. glGetInfoLogARB (shader, sizeof(log), &logLength, log);
  228. printf ("\n %s: real glsl compiler error on %s:\n%s\n", testName.c_str(), prefix, log);
  229. res = false;
  230. }
  231. glDeleteObjectARB (shader);
  232. return res;
  233. }
  234. static bool ReadStringFromFile (const char* pathName, std::string& output)
  235. {
  236. FILE* file = fopen( pathName, "rb" );
  237. if (file == NULL)
  238. return false;
  239. fseek(file, 0, SEEK_END);
  240. int length = ftell(file);
  241. fseek(file, 0, SEEK_SET);
  242. if (length < 0)
  243. {
  244. fclose( file );
  245. return false;
  246. }
  247. output.resize(length);
  248. int readLength = fread(&*output.begin(), 1, length, file);
  249. fclose(file);
  250. if (readLength != length)
  251. {
  252. output.clear();
  253. return false;
  254. }
  255. replace_string(output, "\r\n", "\n", 0);
  256. return true;
  257. }
  258. bool EndsWith (const std::string& str, const std::string& sub)
  259. {
  260. return (str.size() >= sub.size()) && (strncmp (str.c_str()+str.size()-sub.size(), sub.c_str(), sub.size())==0);
  261. }
  262. typedef std::vector<std::string> StringVector;
  263. static StringVector GetFiles (const std::string& folder, const std::string& endsWith)
  264. {
  265. StringVector res;
  266. #ifdef _MSC_VER
  267. WIN32_FIND_DATAA FindFileData;
  268. HANDLE hFind = FindFirstFileA ((folder+"/*"+endsWith).c_str(), &FindFileData);
  269. if (hFind == INVALID_HANDLE_VALUE)
  270. return res;
  271. do {
  272. res.push_back (FindFileData.cFileName);
  273. } while (FindNextFileA (hFind, &FindFileData));
  274. FindClose (hFind);
  275. #else
  276. DIR *dirp;
  277. struct dirent *dp;
  278. if ((dirp = opendir(folder.c_str())) == NULL)
  279. return res;
  280. while ( (dp = readdir(dirp)) )
  281. {
  282. std::string fname = dp->d_name;
  283. if (fname == "." || fname == "..")
  284. continue;
  285. if (!EndsWith (fname, endsWith))
  286. continue;
  287. res.push_back (fname);
  288. }
  289. closedir(dirp);
  290. #endif
  291. return res;
  292. }
  293. static void DeleteFile (const std::string& path)
  294. {
  295. #ifdef _MSC_VER
  296. DeleteFileA (path.c_str());
  297. #else
  298. unlink (path.c_str());
  299. #endif
  300. }
  301. static void MassageVertexForGLES (std::string& s)
  302. {
  303. std::string pre;
  304. pre += "#define gl_Vertex _glesVertex\nattribute highp vec4 _glesVertex;\n";
  305. pre += "#define gl_Normal _glesNormal\nattribute mediump vec3 _glesNormal;\n";
  306. pre += "#define gl_MultiTexCoord0 _glesMultiTexCoord0\nattribute highp vec4 _glesMultiTexCoord0;\n";
  307. pre += "#define gl_MultiTexCoord1 _glesMultiTexCoord1\nattribute highp vec4 _glesMultiTexCoord1;\n";
  308. pre += "#define gl_Color _glesColor\nattribute lowp vec4 _glesColor;\n";
  309. s = pre + s;
  310. }
  311. static void MassageFragmentForGLES (std::string& s)
  312. {
  313. std::string pre;
  314. s = pre + s;
  315. }
  316. static bool TestFile (glslopt_ctx* ctx, bool vertex,
  317. const std::string& testName,
  318. const std::string& inputPath,
  319. const std::string& hirPath,
  320. const std::string& outputPath,
  321. bool gles,
  322. bool doCheckGLSL)
  323. {
  324. std::string input;
  325. if (!ReadStringFromFile (inputPath.c_str(), input))
  326. {
  327. printf ("\n %s: failed to read input file\n", testName.c_str());
  328. return false;
  329. }
  330. if (doCheckGLSL)
  331. {
  332. if (!CheckGLSL (vertex, gles, testName, "input", input.c_str()))
  333. return false;
  334. }
  335. if (gles)
  336. {
  337. if (vertex)
  338. MassageVertexForGLES (input);
  339. else
  340. MassageFragmentForGLES (input);
  341. }
  342. bool res = true;
  343. glslopt_shader_type type = vertex ? kGlslOptShaderVertex : kGlslOptShaderFragment;
  344. glslopt_shader* shader = glslopt_optimize (ctx, type, input.c_str(), 0);
  345. bool optimizeOk = glslopt_get_status(shader);
  346. if (optimizeOk)
  347. {
  348. std::string textHir = glslopt_get_raw_output (shader);
  349. std::string textOpt = glslopt_get_output (shader);
  350. char buffer[200];
  351. int statsAlu, statsTex, statsFlow;
  352. glslopt_shader_get_stats (shader, &statsAlu, &statsTex, &statsFlow);
  353. int inputCount = glslopt_shader_get_input_count (shader);
  354. sprintf(buffer, "\n// inputs: %i, stats: %i alu %i tex %i flow\n", inputCount, statsAlu, statsTex, statsFlow);
  355. textOpt += buffer;
  356. std::string outputHir;
  357. ReadStringFromFile (hirPath.c_str(), outputHir);
  358. std::string outputOpt;
  359. ReadStringFromFile (outputPath.c_str(), outputOpt);
  360. if (textHir != outputHir)
  361. {
  362. // write output
  363. FILE* f = fopen (hirPath.c_str(), "wb");
  364. if (!f)
  365. {
  366. printf ("\n %s: can't write to IR file!\n", testName.c_str());
  367. }
  368. else
  369. {
  370. fwrite (textHir.c_str(), 1, textHir.size(), f);
  371. fclose (f);
  372. }
  373. printf ("\n %s: does not match raw output\n", testName.c_str());
  374. res = false;
  375. }
  376. if (textOpt != outputOpt)
  377. {
  378. // write output
  379. FILE* f = fopen (outputPath.c_str(), "wb");
  380. if (!f)
  381. {
  382. printf ("\n %s: can't write to optimized file!\n", testName.c_str());
  383. }
  384. else
  385. {
  386. fwrite (textOpt.c_str(), 1, textOpt.size(), f);
  387. fclose (f);
  388. }
  389. printf ("\n %s: does not match optimized output\n", testName.c_str());
  390. res = false;
  391. }
  392. if (res && doCheckGLSL && !CheckGLSL (vertex, gles, testName, "raw", textHir.c_str()))
  393. res = false;
  394. if (res && doCheckGLSL && !CheckGLSL (vertex, gles, testName, "optimized", textOpt.c_str()))
  395. res = false;
  396. }
  397. else
  398. {
  399. printf ("\n %s: optimize error: %s\n", testName.c_str(), glslopt_get_log(shader));
  400. res = false;
  401. }
  402. glslopt_shader_delete (shader);
  403. return res;
  404. }
  405. int main (int argc, const char** argv)
  406. {
  407. if (argc < 2)
  408. {
  409. printf ("USAGE: glsloptimizer testfolder\n");
  410. return 1;
  411. }
  412. bool hasOpenGL = InitializeOpenGL ();
  413. glslopt_ctx* ctx[3] = {
  414. glslopt_initialize(kGlslTargetOpenGLES20),
  415. glslopt_initialize(kGlslTargetOpenGLES30),
  416. glslopt_initialize(kGlslTargetOpenGL),
  417. };
  418. std::string baseFolder = argv[1];
  419. clock_t time0 = clock();
  420. // 2.39s
  421. // ralloc fix 256 initial: 1.35s
  422. static const char* kTypeName[2] = { "vertex", "fragment" };
  423. size_t tests = 0;
  424. size_t errors = 0;
  425. for (int type = 0; type < 2; ++type)
  426. {
  427. std::string testFolder = baseFolder + "/" + kTypeName[type];
  428. static const char* kAPIName[3] = { "OpenGL ES 2.0", "OpenGL ES 3.0", "OpenGL" };
  429. static const char* kApiIn [3] = {"-inES.txt", "-inES3.txt", "-in.txt"};
  430. static const char* kApiIR [3] = {"-irES.txt", "-irES3.txt", "-ir.txt"};
  431. static const char* kApiOut[3] = {"-outES.txt", "-outES3.txt", "-out.txt"};
  432. for (int api = 0; api < 3; ++api)
  433. {
  434. printf ("\n** running %s tests for %s...\n", kTypeName[type], kAPIName[api]);
  435. StringVector inputFiles = GetFiles (testFolder, kApiIn[api]);
  436. size_t n = inputFiles.size();
  437. for (size_t i = 0; i < n; ++i)
  438. {
  439. std::string inname = inputFiles[i];
  440. //if (inname != "ast-in.txt")
  441. // continue;
  442. std::string hirname = inname.substr (0,inname.size()-strlen(kApiIn[api])) + kApiIR[api];
  443. std::string outname = inname.substr (0,inname.size()-strlen(kApiIn[api])) + kApiOut[api];
  444. bool ok = TestFile (ctx[api], type==0, inname, testFolder + "/" + inname, testFolder + "/" + hirname, testFolder + "/" + outname, api==0, hasOpenGL);
  445. if (!ok)
  446. {
  447. ++errors;
  448. }
  449. ++tests;
  450. }
  451. }
  452. }
  453. clock_t time1 = clock();
  454. float timeDelta = float(time1-time0)/CLOCKS_PER_SEC;
  455. if (errors != 0)
  456. printf ("\n**** %i tests (%.2fsec), %i !!!FAILED!!!\n", (int)tests, timeDelta, (int)errors);
  457. else
  458. printf ("\n**** %i tests (%.2fsec) succeeded\n", (int)tests, timeDelta);
  459. // 3.25s
  460. // with builtin call linking, 3.84s
  461. for (int i = 0; i < 2; ++i)
  462. glslopt_cleanup (ctx[i]);
  463. CleanupGL();
  464. return errors ? 1 : 0;
  465. }