glsl_optimizer_tests.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  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 += "#define gl_FragDepthEXT gl_FragDepth\n";
  136. src += "float shadow2DEXT (sampler2DShadow s, vec3 p) { return shadow2D(s,p).r; }\n";
  137. src += "float shadow2DProjEXT (sampler2DShadow s, vec4 p) { return shadow2DProj(s,p).r; }\n";
  138. }
  139. src += source;
  140. if (gles)
  141. {
  142. replace_string (src, "GL_EXT_shader_texture_lod", "GL_ARB_shader_texture_lod", 0);
  143. replace_string (src, "#extension GL_OES_standard_derivatives : require", "", 0);
  144. replace_string (src, "#extension GL_EXT_shadow_samplers : require", "", 0);
  145. replace_string (src, "#extension GL_EXT_frag_depth : require", "", 0);
  146. replace_string (src, "precision ", "// precision ", 0);
  147. }
  148. const char* sourcePtr = src.c_str();
  149. GLhandleARB shader = glCreateShaderObjectARB (vertex ? GL_VERTEX_SHADER_ARB : GL_FRAGMENT_SHADER_ARB);
  150. glShaderSourceARB (shader, 1, &sourcePtr, NULL);
  151. glCompileShaderARB (shader);
  152. GLint status;
  153. glGetObjectParameterivARB (shader, GL_OBJECT_COMPILE_STATUS_ARB, &status);
  154. bool res = true;
  155. if (status == 0)
  156. {
  157. char log[4096];
  158. GLsizei logLength;
  159. glGetInfoLogARB (shader, sizeof(log), &logLength, log);
  160. printf ("\n %s: real glsl compiler error on %s:\n%s\n", testName.c_str(), prefix, log);
  161. res = false;
  162. }
  163. glDeleteObjectARB (shader);
  164. return res;
  165. }
  166. static bool ReadStringFromFile (const char* pathName, std::string& output)
  167. {
  168. FILE* file = fopen( pathName, "rb" );
  169. if (file == NULL)
  170. return false;
  171. fseek(file, 0, SEEK_END);
  172. int length = ftell(file);
  173. fseek(file, 0, SEEK_SET);
  174. if (length < 0)
  175. {
  176. fclose( file );
  177. return false;
  178. }
  179. output.resize(length);
  180. int readLength = fread(&*output.begin(), 1, length, file);
  181. fclose(file);
  182. if (readLength != length)
  183. {
  184. output.clear();
  185. return false;
  186. }
  187. return true;
  188. }
  189. bool EndsWith (const std::string& str, const std::string& sub)
  190. {
  191. return (str.size() >= sub.size()) && (strncmp (str.c_str()+str.size()-sub.size(), sub.c_str(), sub.size())==0);
  192. }
  193. typedef std::vector<std::string> StringVector;
  194. static StringVector GetFiles (const std::string& folder, const std::string& endsWith)
  195. {
  196. StringVector res;
  197. #ifdef _MSC_VER
  198. WIN32_FIND_DATAA FindFileData;
  199. HANDLE hFind = FindFirstFileA ((folder+"/*"+endsWith).c_str(), &FindFileData);
  200. if (hFind == INVALID_HANDLE_VALUE)
  201. return res;
  202. do {
  203. res.push_back (FindFileData.cFileName);
  204. } while (FindNextFileA (hFind, &FindFileData));
  205. FindClose (hFind);
  206. #else
  207. DIR *dirp;
  208. struct dirent *dp;
  209. if ((dirp = opendir(folder.c_str())) == NULL)
  210. return res;
  211. while ( (dp = readdir(dirp)) )
  212. {
  213. std::string fname = dp->d_name;
  214. if (fname == "." || fname == "..")
  215. continue;
  216. if (!EndsWith (fname, endsWith))
  217. continue;
  218. res.push_back (fname);
  219. }
  220. closedir(dirp);
  221. #endif
  222. return res;
  223. }
  224. static void DeleteFile (const std::string& path)
  225. {
  226. #ifdef _MSC_VER
  227. DeleteFileA (path.c_str());
  228. #else
  229. unlink (path.c_str());
  230. #endif
  231. }
  232. static void MassageVertexForGLES (std::string& s)
  233. {
  234. std::string pre;
  235. pre += "#define gl_Vertex _glesVertex\nattribute highp vec4 _glesVertex;\n";
  236. pre += "#define gl_Normal _glesNormal\nattribute mediump vec3 _glesNormal;\n";
  237. pre += "#define gl_MultiTexCoord0 _glesMultiTexCoord0\nattribute highp vec4 _glesMultiTexCoord0;\n";
  238. pre += "#define gl_MultiTexCoord1 _glesMultiTexCoord1\nattribute highp vec4 _glesMultiTexCoord1;\n";
  239. pre += "#define gl_Color _glesColor\nattribute lowp vec4 _glesColor;\n";
  240. s = pre + s;
  241. }
  242. static void MassageFragmentForGLES (std::string& s)
  243. {
  244. std::string pre;
  245. s = pre + s;
  246. }
  247. static bool TestFile (glslopt_ctx* ctx, bool vertex,
  248. const std::string& testName,
  249. const std::string& inputPath,
  250. const std::string& hirPath,
  251. const std::string& outputPath,
  252. bool gles,
  253. bool doCheckGLSL)
  254. {
  255. std::string input;
  256. if (!ReadStringFromFile (inputPath.c_str(), input))
  257. {
  258. printf ("\n %s: failed to read input file\n", testName.c_str());
  259. return false;
  260. }
  261. if (doCheckGLSL)
  262. {
  263. if (!CheckGLSL (vertex, gles, testName, "input", input.c_str()))
  264. return false;
  265. }
  266. if (gles)
  267. {
  268. if (vertex)
  269. MassageVertexForGLES (input);
  270. else
  271. MassageFragmentForGLES (input);
  272. }
  273. bool res = true;
  274. glslopt_shader_type type = vertex ? kGlslOptShaderVertex : kGlslOptShaderFragment;
  275. glslopt_shader* shader = glslopt_optimize (ctx, type, input.c_str(), 0);
  276. bool optimizeOk = glslopt_get_status(shader);
  277. if (optimizeOk)
  278. {
  279. std::string textHir = glslopt_get_raw_output (shader);
  280. std::string textOpt = glslopt_get_output (shader);
  281. std::string outputHir;
  282. ReadStringFromFile (hirPath.c_str(), outputHir);
  283. std::string outputOpt;
  284. ReadStringFromFile (outputPath.c_str(), outputOpt);
  285. if (textHir != outputHir)
  286. {
  287. // write output
  288. FILE* f = fopen (hirPath.c_str(), "wb");
  289. if (!f)
  290. {
  291. printf ("\n %s: can't write to IR file!\n", testName.c_str());
  292. }
  293. else
  294. {
  295. fwrite (textHir.c_str(), 1, textHir.size(), f);
  296. fclose (f);
  297. }
  298. printf ("\n %s: does not match raw output\n", testName.c_str());
  299. res = false;
  300. }
  301. if (textOpt != outputOpt)
  302. {
  303. // write output
  304. FILE* f = fopen (outputPath.c_str(), "wb");
  305. if (!f)
  306. {
  307. printf ("\n %s: can't write to optimized file!\n", testName.c_str());
  308. }
  309. else
  310. {
  311. fwrite (textOpt.c_str(), 1, textOpt.size(), f);
  312. fclose (f);
  313. }
  314. printf ("\n %s: does not match optimized output\n", testName.c_str());
  315. res = false;
  316. }
  317. if (res && doCheckGLSL && !CheckGLSL (vertex, gles, testName, "raw", textHir.c_str()))
  318. res = false;
  319. if (res && doCheckGLSL && !CheckGLSL (vertex, gles, testName, "optimized", textOpt.c_str()))
  320. res = false;
  321. }
  322. else
  323. {
  324. printf ("\n %s: optimize error: %s\n", testName.c_str(), glslopt_get_log(shader));
  325. res = false;
  326. }
  327. glslopt_shader_delete (shader);
  328. return res;
  329. }
  330. int main (int argc, const char** argv)
  331. {
  332. if (argc < 2)
  333. {
  334. printf ("USAGE: glsloptimizer testfolder\n");
  335. return 1;
  336. }
  337. bool hasOpenGL = InitializeOpenGL ();
  338. glslopt_ctx* ctx[2] = {
  339. glslopt_initialize(true),
  340. glslopt_initialize(false),
  341. };
  342. std::string baseFolder = argv[1];
  343. clock_t time0 = clock();
  344. static const char* kTypeName[2] = { "vertex", "fragment" };
  345. size_t tests = 0;
  346. size_t errors = 0;
  347. for (int type = 0; type < 2; ++type)
  348. {
  349. std::string testFolder = baseFolder + "/" + kTypeName[type];
  350. static const char* kAPIName[2] = { "OpenGL ES 2.0", "OpenGL" };
  351. static const char* kApiIn [2] = {"-inES.txt", "-in.txt"};
  352. static const char* kApiIR [2] = {"-irES.txt", "-ir.txt"};
  353. static const char* kApiOut[2] = {"-outES.txt", "-out.txt"};
  354. for (int api = 0; api < 2; ++api)
  355. {
  356. printf ("\n** running %s tests for %s...\n", kTypeName[type], kAPIName[api]);
  357. StringVector inputFiles = GetFiles (testFolder, kApiIn[api]);
  358. size_t n = inputFiles.size();
  359. for (size_t i = 0; i < n; ++i)
  360. {
  361. std::string inname = inputFiles[i];
  362. //if (inname != "ast-in.txt")
  363. // continue;
  364. std::string hirname = inname.substr (0,inname.size()-strlen(kApiIn[api])) + kApiIR[api];
  365. std::string outname = inname.substr (0,inname.size()-strlen(kApiIn[api])) + kApiOut[api];
  366. bool ok = TestFile (ctx[api], type==0, inname, testFolder + "/" + inname, testFolder + "/" + hirname, testFolder + "/" + outname, api==0, hasOpenGL);
  367. if (!ok)
  368. {
  369. ++errors;
  370. }
  371. ++tests;
  372. }
  373. }
  374. }
  375. clock_t time1 = clock();
  376. float timeDelta = float(time1-time0)/CLOCKS_PER_SEC;
  377. if (errors != 0)
  378. printf ("\n**** %i tests (%.2fsec), %i !!!FAILED!!!\n", (int)tests, timeDelta, (int)errors);
  379. else
  380. printf ("\n**** %i tests (%.2fsec) succeeded\n", (int)tests, timeDelta);
  381. // 3.25s
  382. // with builtin call linking, 3.84s
  383. for (int i = 0; i < 2; ++i)
  384. glslopt_cleanup (ctx[i]);
  385. return errors ? 1 : 0;
  386. }