glsl_optimizer_tests.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. #include <string>
  2. #include <vector>
  3. #include <time.h>
  4. #include "../src/glsl/glsl_optimizer.h"
  5. #if __linux__
  6. #define GOT_GFX 0
  7. #else
  8. #define GOT_GFX 1
  9. #endif
  10. #if GOT_GFX
  11. #ifdef _MSC_VER
  12. #define GOT_MORE_THAN_GLSL_120 1
  13. #include <windows.h>
  14. #include <gl/GL.h>
  15. extern "C" {
  16. typedef char GLcharARB; /* native character */
  17. typedef unsigned int GLhandleARB; /* shader object handle */
  18. #define GL_VERTEX_SHADER_ARB 0x8B31
  19. #define GL_FRAGMENT_SHADER_ARB 0x8B30
  20. #define GL_OBJECT_COMPILE_STATUS_ARB 0x8B81
  21. typedef void (WINAPI * PFNGLDELETEOBJECTARBPROC) (GLhandleARB obj);
  22. typedef GLhandleARB (WINAPI * PFNGLCREATESHADEROBJECTARBPROC) (GLenum shaderType);
  23. typedef void (WINAPI * PFNGLSHADERSOURCEARBPROC) (GLhandleARB shaderObj, GLsizei count, const GLcharARB* *string, const GLint *length);
  24. typedef void (WINAPI * PFNGLCOMPILESHADERARBPROC) (GLhandleARB shaderObj);
  25. typedef void (WINAPI * PFNGLGETINFOLOGARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog);
  26. typedef void (WINAPI * PFNGLGETOBJECTPARAMETERIVARBPROC) (GLhandleARB obj, GLenum pname, GLint *params);
  27. static PFNGLDELETEOBJECTARBPROC glDeleteObjectARB;
  28. static PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB;
  29. static PFNGLSHADERSOURCEARBPROC glShaderSourceARB;
  30. static PFNGLCOMPILESHADERARBPROC glCompileShaderARB;
  31. static PFNGLGETINFOLOGARBPROC glGetInfoLogARB;
  32. static PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB;
  33. }
  34. #else
  35. #define GOT_MORE_THAN_GLSL_120 0
  36. #include <OpenGL/OpenGL.h>
  37. #include <AGL/agl.h>
  38. #include <dirent.h>
  39. #endif
  40. #else // GOT_GFX
  41. #define GOT_MORE_THAN_GLSL_120 0
  42. #include <cstdio>
  43. #include <cstring>
  44. #include "dirent.h"
  45. #include "GL/gl.h"
  46. #include "GL/glext.h"
  47. #endif
  48. #ifndef _MSC_VER
  49. #include <unistd.h>
  50. #endif
  51. static bool InitializeOpenGL ()
  52. {
  53. bool hasGLSL = false;
  54. #if GOT_GFX
  55. #ifdef _MSC_VER
  56. // setup minimal required GL
  57. HWND wnd = CreateWindowA(
  58. "STATIC",
  59. "GL",
  60. WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
  61. 0, 0, 16, 16,
  62. NULL, NULL,
  63. GetModuleHandle(NULL), NULL );
  64. HDC dc = GetDC( wnd );
  65. PIXELFORMATDESCRIPTOR pfd = {
  66. sizeof(PIXELFORMATDESCRIPTOR), 1,
  67. PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL,
  68. PFD_TYPE_RGBA, 32,
  69. 0, 0, 0, 0, 0, 0,
  70. 0, 0, 0, 0, 0, 0, 0,
  71. 16, 0,
  72. 0, PFD_MAIN_PLANE, 0, 0, 0, 0
  73. };
  74. int fmt = ChoosePixelFormat( dc, &pfd );
  75. SetPixelFormat( dc, fmt, &pfd );
  76. HGLRC rc = wglCreateContext( dc );
  77. wglMakeCurrent( dc, rc );
  78. #else
  79. GLint attributes[16];
  80. int i = 0;
  81. attributes[i++]=AGL_RGBA;
  82. attributes[i++]=AGL_PIXEL_SIZE;
  83. attributes[i++]=32;
  84. attributes[i++]=AGL_NO_RECOVERY;
  85. attributes[i++]=AGL_NONE;
  86. AGLPixelFormat pixelFormat = aglChoosePixelFormat(NULL,0,attributes);
  87. AGLContext agl = aglCreateContext(pixelFormat, NULL);
  88. aglSetCurrentContext (agl);
  89. #endif
  90. // check if we have GLSL
  91. const char* extensions = (const char*)glGetString(GL_EXTENSIONS);
  92. hasGLSL = strstr(extensions, "GL_ARB_shader_objects") && strstr(extensions, "GL_ARB_vertex_shader") && strstr(extensions, "GL_ARB_fragment_shader");
  93. #ifdef _MSC_VER
  94. if (hasGLSL)
  95. {
  96. glDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC)wglGetProcAddress("glDeleteObjectARB");
  97. glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC)wglGetProcAddress("glCreateShaderObjectARB");
  98. glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC)wglGetProcAddress("glShaderSourceARB");
  99. glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC)wglGetProcAddress("glCompileShaderARB");
  100. glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC)wglGetProcAddress("glGetInfoLogARB");
  101. glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC)wglGetProcAddress("glGetObjectParameterivARB");
  102. }
  103. #endif
  104. #endif
  105. return hasGLSL;
  106. }
  107. static void replace_string (std::string& target, const std::string& search, const std::string& replace, size_t startPos)
  108. {
  109. if (search.empty())
  110. return;
  111. std::string::size_type p = startPos;
  112. while ((p = target.find (search, p)) != std::string::npos)
  113. {
  114. target.replace (p, search.size (), replace);
  115. p += replace.size ();
  116. }
  117. }
  118. static bool CheckGLSL (bool vertex, bool gles, const std::string& testName, const char* prefix, const std::string& source)
  119. {
  120. #if !GOT_GFX
  121. return true; // just assume it's ok
  122. #endif
  123. #if !GOT_MORE_THAN_GLSL_120
  124. if (source.find("#version 140") != std::string::npos)
  125. return true;
  126. #endif
  127. std::string src;
  128. if (gles)
  129. {
  130. src += "#define lowp\n";
  131. src += "#define mediump\n";
  132. src += "#define highp\n";
  133. src += "#define texture2DLodEXT texture2DLod\n";
  134. src += "#define texture2DProjLodEXT texture2DProjLod\n";
  135. src += "float shadow2DEXT (sampler2DShadow s, vec3 p) { return shadow2D(s,p).r; }\n";
  136. src += "float shadow2DProjEXT (sampler2DShadow s, vec4 p) { return shadow2DProj(s,p).r; }\n";
  137. }
  138. src += source;
  139. if (gles)
  140. {
  141. replace_string (src, "GL_EXT_shader_texture_lod", "GL_ARB_shader_texture_lod", 0);
  142. replace_string (src, "#extension GL_OES_standard_derivatives : require", "", 0);
  143. replace_string (src, "#extension GL_EXT_shadow_samplers : require", "", 0);
  144. }
  145. const char* sourcePtr = src.c_str();
  146. GLhandleARB shader = glCreateShaderObjectARB (vertex ? GL_VERTEX_SHADER_ARB : GL_FRAGMENT_SHADER_ARB);
  147. glShaderSourceARB (shader, 1, &sourcePtr, NULL);
  148. glCompileShaderARB (shader);
  149. GLint status;
  150. glGetObjectParameterivARB (shader, GL_OBJECT_COMPILE_STATUS_ARB, &status);
  151. bool res = true;
  152. if (status == 0)
  153. {
  154. char log[4096];
  155. GLsizei logLength;
  156. glGetInfoLogARB (shader, sizeof(log), &logLength, log);
  157. printf ("\n %s: real glsl compiler error on %s:\n%s\n", testName.c_str(), prefix, log);
  158. res = false;
  159. }
  160. glDeleteObjectARB (shader);
  161. return res;
  162. }
  163. static bool ReadStringFromFile (const char* pathName, std::string& output)
  164. {
  165. FILE* file = fopen( pathName, "rb" );
  166. if (file == NULL)
  167. return false;
  168. fseek(file, 0, SEEK_END);
  169. int length = ftell(file);
  170. fseek(file, 0, SEEK_SET);
  171. if (length < 0)
  172. {
  173. fclose( file );
  174. return false;
  175. }
  176. output.resize(length);
  177. int readLength = fread(&*output.begin(), 1, length, file);
  178. fclose(file);
  179. if (readLength != length)
  180. {
  181. output.clear();
  182. return false;
  183. }
  184. return true;
  185. }
  186. bool EndsWith (const std::string& str, const std::string& sub)
  187. {
  188. return (str.size() >= sub.size()) && (strncmp (str.c_str()+str.size()-sub.size(), sub.c_str(), sub.size())==0);
  189. }
  190. typedef std::vector<std::string> StringVector;
  191. static StringVector GetFiles (const std::string& folder, const std::string& endsWith)
  192. {
  193. StringVector res;
  194. #ifdef _MSC_VER
  195. WIN32_FIND_DATAA FindFileData;
  196. HANDLE hFind = FindFirstFileA ((folder+"/*"+endsWith).c_str(), &FindFileData);
  197. if (hFind == INVALID_HANDLE_VALUE)
  198. return res;
  199. do {
  200. res.push_back (FindFileData.cFileName);
  201. } while (FindNextFileA (hFind, &FindFileData));
  202. FindClose (hFind);
  203. #else
  204. DIR *dirp;
  205. struct dirent *dp;
  206. if ((dirp = opendir(folder.c_str())) == NULL)
  207. return res;
  208. while ( (dp = readdir(dirp)) )
  209. {
  210. std::string fname = dp->d_name;
  211. if (fname == "." || fname == "..")
  212. continue;
  213. if (!EndsWith (fname, endsWith))
  214. continue;
  215. res.push_back (fname);
  216. }
  217. closedir(dirp);
  218. #endif
  219. return res;
  220. }
  221. static void DeleteFile (const std::string& path)
  222. {
  223. #ifdef _MSC_VER
  224. DeleteFileA (path.c_str());
  225. #else
  226. unlink (path.c_str());
  227. #endif
  228. }
  229. static void MassageVertexForGLES (std::string& s)
  230. {
  231. std::string pre;
  232. pre += "#define gl_Vertex _glesVertex\nattribute highp vec4 _glesVertex;\n";
  233. pre += "#define gl_Normal _glesNormal\nattribute mediump vec3 _glesNormal;\n";
  234. pre += "#define gl_MultiTexCoord0 _glesMultiTexCoord0\nattribute highp vec4 _glesMultiTexCoord0;\n";
  235. pre += "#define gl_MultiTexCoord1 _glesMultiTexCoord1\nattribute highp vec4 _glesMultiTexCoord1;\n";
  236. pre += "#define gl_Color _glesColor\nattribute lowp vec4 _glesColor;\n";
  237. s = pre + s;
  238. }
  239. static void MassageFragmentForGLES (std::string& s)
  240. {
  241. std::string pre;
  242. s = pre + s;
  243. }
  244. static bool TestFile (glslopt_ctx* ctx, bool vertex,
  245. const std::string& testName,
  246. const std::string& inputPath,
  247. const std::string& hirPath,
  248. const std::string& outputPath,
  249. bool gles,
  250. bool doCheckGLSL)
  251. {
  252. std::string input;
  253. if (!ReadStringFromFile (inputPath.c_str(), input))
  254. {
  255. printf ("\n %s: failed to read input file\n", testName.c_str());
  256. return false;
  257. }
  258. if (doCheckGLSL)
  259. {
  260. if (!CheckGLSL (vertex, gles, testName, "input", input.c_str()))
  261. return false;
  262. }
  263. if (gles)
  264. {
  265. if (vertex)
  266. MassageVertexForGLES (input);
  267. else
  268. MassageFragmentForGLES (input);
  269. }
  270. bool res = true;
  271. glslopt_shader_type type = vertex ? kGlslOptShaderVertex : kGlslOptShaderFragment;
  272. glslopt_shader* shader = glslopt_optimize (ctx, type, input.c_str(), 0);
  273. bool optimizeOk = glslopt_get_status(shader);
  274. if (optimizeOk)
  275. {
  276. std::string textHir = glslopt_get_raw_output (shader);
  277. std::string textOpt = glslopt_get_output (shader);
  278. std::string outputHir;
  279. ReadStringFromFile (hirPath.c_str(), outputHir);
  280. std::string outputOpt;
  281. ReadStringFromFile (outputPath.c_str(), outputOpt);
  282. if (textHir != outputHir)
  283. {
  284. // write output
  285. FILE* f = fopen (hirPath.c_str(), "wb");
  286. if (!f)
  287. {
  288. printf ("\n %s: can't write to IR file!\n", testName.c_str());
  289. }
  290. else
  291. {
  292. fwrite (textHir.c_str(), 1, textHir.size(), f);
  293. fclose (f);
  294. }
  295. printf ("\n %s: does not match raw output\n", testName.c_str());
  296. res = false;
  297. }
  298. if (textOpt != outputOpt)
  299. {
  300. // write output
  301. FILE* f = fopen (outputPath.c_str(), "wb");
  302. if (!f)
  303. {
  304. printf ("\n %s: can't write to optimized file!\n", testName.c_str());
  305. }
  306. else
  307. {
  308. fwrite (textOpt.c_str(), 1, textOpt.size(), f);
  309. fclose (f);
  310. }
  311. printf ("\n %s: does not match optimized output\n", testName.c_str());
  312. res = false;
  313. }
  314. if (res && doCheckGLSL && !CheckGLSL (vertex, gles, testName, "raw", textHir.c_str()))
  315. res = false;
  316. if (res && doCheckGLSL && !CheckGLSL (vertex, gles, testName, "optimized", textOpt.c_str()))
  317. res = false;
  318. }
  319. else
  320. {
  321. printf ("\n %s: optimize error: %s\n", testName.c_str(), glslopt_get_log(shader));
  322. res = false;
  323. }
  324. glslopt_shader_delete (shader);
  325. return res;
  326. }
  327. int main (int argc, const char** argv)
  328. {
  329. if (argc < 2)
  330. {
  331. printf ("USAGE: glsloptimizer testfolder\n");
  332. return 1;
  333. }
  334. bool hasOpenGL = InitializeOpenGL ();
  335. glslopt_ctx* ctx[2] = {
  336. glslopt_initialize(true),
  337. glslopt_initialize(false),
  338. };
  339. std::string baseFolder = argv[1];
  340. clock_t time0 = clock();
  341. static const char* kTypeName[2] = { "vertex", "fragment" };
  342. size_t tests = 0;
  343. size_t errors = 0;
  344. for (int type = 0; type < 2; ++type)
  345. {
  346. std::string testFolder = baseFolder + "/" + kTypeName[type];
  347. static const char* kAPIName[2] = { "OpenGL ES 2.0", "OpenGL" };
  348. static const char* kApiIn [2] = {"-inES.txt", "-in.txt"};
  349. static const char* kApiIR [2] = {"-irES.txt", "-ir.txt"};
  350. static const char* kApiOut[2] = {"-outES.txt", "-out.txt"};
  351. for (int api = 0; api < 2; ++api)
  352. {
  353. printf ("\n** running %s tests for %s...\n", kTypeName[type], kAPIName[api]);
  354. StringVector inputFiles = GetFiles (testFolder, kApiIn[api]);
  355. size_t n = inputFiles.size();
  356. for (size_t i = 0; i < n; ++i)
  357. {
  358. std::string inname = inputFiles[i];
  359. //if (inname != "ast-in.txt")
  360. // continue;
  361. std::string hirname = inname.substr (0,inname.size()-strlen(kApiIn[api])) + kApiIR[api];
  362. std::string outname = inname.substr (0,inname.size()-strlen(kApiIn[api])) + kApiOut[api];
  363. bool ok = TestFile (ctx[api], type==0, inname, testFolder + "/" + inname, testFolder + "/" + hirname, testFolder + "/" + outname, api==0, hasOpenGL);
  364. if (!ok)
  365. {
  366. ++errors;
  367. }
  368. ++tests;
  369. }
  370. }
  371. }
  372. clock_t time1 = clock();
  373. float timeDelta = float(time1-time0)/CLOCKS_PER_SEC;
  374. if (errors != 0)
  375. printf ("\n**** %i tests (%.2fsec), %i !!!FAILED!!!\n", tests, timeDelta, errors);
  376. else
  377. printf ("\n**** %i tests (%.2fsec) succeeded\n", tests, timeDelta);
  378. // 3.25s
  379. // with builtin call linking, 3.84s
  380. for (int i = 0; i < 2; ++i)
  381. glslopt_cleanup (ctx[i]);
  382. return errors ? 1 : 0;
  383. }