17ec3b29aSmrg/** 27ec3b29aSmrg * Test compilation, link, draw time for very large shaders. 37ec3b29aSmrg * Command line arguments: 47ec3b29aSmrg * -v verbose output (print shader code) 57ec3b29aSmrg * -c N generate shaders of complexity N 67ec3b29aSmrg * -n N generate and draw with N shader programs 77ec3b29aSmrg * 87ec3b29aSmrg * Brian Paul 97ec3b29aSmrg * 3 Dec 2015 107ec3b29aSmrg */ 117ec3b29aSmrg 127ec3b29aSmrg 137ec3b29aSmrg#include <assert.h> 147ec3b29aSmrg#include <stdio.h> 157ec3b29aSmrg#include <stdbool.h> 167ec3b29aSmrg#include <stdlib.h> 177ec3b29aSmrg#include <string.h> 187ec3b29aSmrg#include <math.h> 197ec3b29aSmrg#include <GL/glew.h> 207ec3b29aSmrg#include "glut_wrap.h" 217ec3b29aSmrg#include "shaderutil.h" 227ec3b29aSmrg 237ec3b29aSmrg#if defined(_MSC_VER) 247ec3b29aSmrg#define snprintf _snprintf 257ec3b29aSmrg#endif 267ec3b29aSmrg 277ec3b29aSmrg 287ec3b29aSmrg#define MAX_PROGRAMS 10000 297ec3b29aSmrg 307ec3b29aSmrgstatic int Win; 317ec3b29aSmrgstatic int WinWidth = 400, WinHeight = 400; 327ec3b29aSmrgstatic int verbose = 0; 337ec3b29aSmrgstatic int num_shaders = 1; 347ec3b29aSmrgstatic int complexity = 5; 357ec3b29aSmrgstatic int programs[MAX_PROGRAMS]; 367ec3b29aSmrg 377ec3b29aSmrgstatic const float u1_val[4] = {.1, .2, .3, .4}; 387ec3b29aSmrgstatic const float u2_val[4] = {.6, .7, .8, .9}; 397ec3b29aSmrg 407ec3b29aSmrgstatic const char *VS_code = 417ec3b29aSmrg "void main()\n" 427ec3b29aSmrg "{\n" 437ec3b29aSmrg " gl_Position = ftransform();\n" 447ec3b29aSmrg "}\n"; 457ec3b29aSmrg 467ec3b29aSmrgstatic const float coords[3][4] = { 477ec3b29aSmrg {0, 0.1, 0, 1}, 487ec3b29aSmrg {0, 0, 0, 1}, 497ec3b29aSmrg {0, -0.1, 0, 1} 507ec3b29aSmrg}; 517ec3b29aSmrg 527ec3b29aSmrg#define NUM_POINTS (sizeof(coords) / sizeof(coords[0])) 537ec3b29aSmrg 547ec3b29aSmrg 557ec3b29aSmrg 567ec3b29aSmrgstruct dynamic_string { 577ec3b29aSmrg char *buffer; 587ec3b29aSmrg unsigned len; 597ec3b29aSmrg unsigned buffer_size; 607ec3b29aSmrg}; 617ec3b29aSmrg 627ec3b29aSmrg 637ec3b29aSmrgstatic void 647ec3b29aSmrgappend_string(struct dynamic_string *ds, const char *s) 657ec3b29aSmrg{ 667ec3b29aSmrg int l = strlen(s); 677ec3b29aSmrg if (ds->len + l >= ds->buffer_size) { 687ec3b29aSmrg /* grow buffer */ 697ec3b29aSmrg int newsize = ds->buffer_size + l + 4096; 707ec3b29aSmrg char *newbuf = malloc(newsize); 717ec3b29aSmrg assert(newbuf); 727ec3b29aSmrg if (ds->buffer) 737ec3b29aSmrg strcpy(newbuf, ds->buffer); 747ec3b29aSmrg free(ds->buffer); 757ec3b29aSmrg ds->buffer = newbuf; 767ec3b29aSmrg ds->buffer_size = newsize; 777ec3b29aSmrg } 787ec3b29aSmrg strcpy(ds->buffer + ds->len, s); 797ec3b29aSmrg ds->len += l; 807ec3b29aSmrg assert(strlen(ds->buffer) == ds->len); 817ec3b29aSmrg} 827ec3b29aSmrg 837ec3b29aSmrg 847ec3b29aSmrg/** 857ec3b29aSmrg * Index is a term put into the shader code to make each shader a little 867ec3b29aSmrg * different. 877ec3b29aSmrg */ 887ec3b29aSmrgstatic char * 897ec3b29aSmrggen_large_shader(int num_functions, int index) 907ec3b29aSmrg{ 917ec3b29aSmrg int i; 927ec3b29aSmrg struct dynamic_string ds = {0}; 937ec3b29aSmrg char s[100]; 947ec3b29aSmrg 957ec3b29aSmrg append_string(&ds, "#version 120\n"); 967ec3b29aSmrg append_string(&ds, "\nuniform vec4 u1, u2;\n\n"); 977ec3b29aSmrg 987ec3b29aSmrg for (i = 0; i < num_functions; i++) { 997ec3b29aSmrg snprintf(s, sizeof(s), "vec4 func%d(vec4 a, float b)\n", i); 1007ec3b29aSmrg append_string(&ds, s); 1017ec3b29aSmrg append_string(&ds, "{\n"); 1027ec3b29aSmrg if (i == 0) { 1037ec3b29aSmrg append_string(&ds, " return a * b;\n"); 1047ec3b29aSmrg } 1057ec3b29aSmrg else { 1067ec3b29aSmrg snprintf(s, sizeof(s), 1077ec3b29aSmrg " vec4 s = a * func%d(a, float(%d)) + vec4(b);\n", 1087ec3b29aSmrg i-1, index); 1097ec3b29aSmrg append_string(&ds, s); 1107ec3b29aSmrg 1117ec3b29aSmrg snprintf(s, sizeof(s), 1127ec3b29aSmrg " vec4 t = a / func%d(a, 3.0) - vec4(b);\n", i-1); 1137ec3b29aSmrg append_string(&ds, s); 1147ec3b29aSmrg 1157ec3b29aSmrg if (i & 1) { 1167ec3b29aSmrg append_string(&ds, " vec4 u = max(s, t);\n"); 1177ec3b29aSmrg } 1187ec3b29aSmrg else { 1197ec3b29aSmrg /* use a conditional */ 1207ec3b29aSmrg append_string(&ds, " vec4 u = min(s, t);\n"); 1217ec3b29aSmrg append_string(&ds, " if (s.x > t.x) {\n"); 1227ec3b29aSmrg snprintf(s, sizeof(s), " u = vec4(%d);\n", i); 1237ec3b29aSmrg append_string(&ds, s); 1247ec3b29aSmrg append_string(&ds, " }\n"); 1257ec3b29aSmrg } 1267ec3b29aSmrg 1277ec3b29aSmrg append_string(&ds, " return u;\n"); 1287ec3b29aSmrg } 1297ec3b29aSmrg 1307ec3b29aSmrg append_string(&ds, "}\n\n"); 1317ec3b29aSmrg } 1327ec3b29aSmrg 1337ec3b29aSmrg append_string(&ds, "void main()\n"); 1347ec3b29aSmrg append_string(&ds, "{\n"); 1357ec3b29aSmrg snprintf(s, sizeof(s), " gl_FragColor = func%d(u1, u2.x);\n", i-1); 1367ec3b29aSmrg append_string(&ds, s); 1377ec3b29aSmrg append_string(&ds, "}\n"); 1387ec3b29aSmrg 1397ec3b29aSmrg return ds.buffer; 1407ec3b29aSmrg} 1417ec3b29aSmrg 1427ec3b29aSmrg 1437ec3b29aSmrgstatic void 1447ec3b29aSmrgDraw(void) 1457ec3b29aSmrg{ 1467ec3b29aSmrg int t0, t1; 1477ec3b29aSmrg int i; 1487ec3b29aSmrg int fixed_func_time = 0, glsl_time_1 = 0, glsl_time_2 = 0; 1497ec3b29aSmrg 1507ec3b29aSmrg glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 1517ec3b29aSmrg 1527ec3b29aSmrg for (i = 0; i < num_shaders; i++) { 1537ec3b29aSmrg UseProgram(0); 1547ec3b29aSmrg t0 = glutGet(GLUT_ELAPSED_TIME); 1557ec3b29aSmrg glDrawArrays(GL_POINTS, 0, NUM_POINTS); 1567ec3b29aSmrg glFinish(); 1577ec3b29aSmrg t1 = glutGet(GLUT_ELAPSED_TIME); 1587ec3b29aSmrg fixed_func_time += t1 - t0; 1597ec3b29aSmrg 1607ec3b29aSmrg UseProgram(programs[i]); 1617ec3b29aSmrg t0 = glutGet(GLUT_ELAPSED_TIME); 1627ec3b29aSmrg glDrawArrays(GL_POINTS, 0, NUM_POINTS); 1637ec3b29aSmrg glFinish(); 1647ec3b29aSmrg t1 = glutGet(GLUT_ELAPSED_TIME); 1657ec3b29aSmrg glsl_time_1 += t1 - t0; 1667ec3b29aSmrg 1677ec3b29aSmrg t0 = glutGet(GLUT_ELAPSED_TIME); 1687ec3b29aSmrg glDrawArrays(GL_POINTS, 0, NUM_POINTS); 1697ec3b29aSmrg glFinish(); 1707ec3b29aSmrg t1 = glutGet(GLUT_ELAPSED_TIME); 1717ec3b29aSmrg glsl_time_2 += t1 - t0; 1727ec3b29aSmrg } 1737ec3b29aSmrg 1747ec3b29aSmrg printf("Time to draw fixed-function points: %d ms\n", fixed_func_time); 1757ec3b29aSmrg printf("Time to draw 1st GLSL shader points: %d ms\n", glsl_time_1); 1767ec3b29aSmrg printf("Time to draw 2st GLSL shader points: %d ms\n", glsl_time_2); 1777ec3b29aSmrg 1787ec3b29aSmrg glutSwapBuffers(); 1797ec3b29aSmrg} 1807ec3b29aSmrg 1817ec3b29aSmrg 1827ec3b29aSmrgstatic void 1837ec3b29aSmrgReshape(int width, int height) 1847ec3b29aSmrg{ 1857ec3b29aSmrg WinWidth = width; 1867ec3b29aSmrg WinHeight = height; 1877ec3b29aSmrg glViewport(0, 0, width, height); 1887ec3b29aSmrg glMatrixMode(GL_PROJECTION); 1897ec3b29aSmrg glLoadIdentity(); 1907ec3b29aSmrg glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 25.0); 1917ec3b29aSmrg glMatrixMode(GL_MODELVIEW); 1927ec3b29aSmrg glLoadIdentity(); 1937ec3b29aSmrg glTranslatef(0.0, 0.0, -15.0); 1947ec3b29aSmrg} 1957ec3b29aSmrg 1967ec3b29aSmrg 1977ec3b29aSmrgstatic void 1987ec3b29aSmrgKey(unsigned char key, int x, int y) 1997ec3b29aSmrg{ 2007ec3b29aSmrg if (key == 27) { 2017ec3b29aSmrg glutDestroyWindow(Win); 2027ec3b29aSmrg exit(0); 2037ec3b29aSmrg } 2047ec3b29aSmrg glutPostRedisplay(); 2057ec3b29aSmrg} 2067ec3b29aSmrg 2077ec3b29aSmrg 2087ec3b29aSmrgstatic GLuint 2097ec3b29aSmrgcreate_shader_program(const char *fs_code, 2107ec3b29aSmrg int *compile_time, int *link_time) 2117ec3b29aSmrg{ 2127ec3b29aSmrg GLuint fragShader; 2137ec3b29aSmrg GLuint vertShader; 2147ec3b29aSmrg GLuint program; 2157ec3b29aSmrg GLint u1_loc, u2_loc; 2167ec3b29aSmrg GLint t0, t1, t2; 2177ec3b29aSmrg 2187ec3b29aSmrg vertShader = CompileShaderText(GL_VERTEX_SHADER, VS_code); 2197ec3b29aSmrg 2207ec3b29aSmrg t0 = glutGet(GLUT_ELAPSED_TIME); 2217ec3b29aSmrg fragShader = CompileShaderText(GL_FRAGMENT_SHADER, fs_code); 2227ec3b29aSmrg t1 = glutGet(GLUT_ELAPSED_TIME); 2237ec3b29aSmrg program = LinkShaders(vertShader, fragShader); 2247ec3b29aSmrg t2 = glutGet(GLUT_ELAPSED_TIME); 2257ec3b29aSmrg 2267ec3b29aSmrg UseProgram(program); 2277ec3b29aSmrg u1_loc = glGetUniformLocation(program, "u1"); 2287ec3b29aSmrg u2_loc = glGetUniformLocation(program, "u2"); 2297ec3b29aSmrg glUniform4fv(u1_loc, 1, u1_val); 2307ec3b29aSmrg glUniform4fv(u2_loc, 1, u2_val); 2317ec3b29aSmrg UseProgram(0); 2327ec3b29aSmrg 2337ec3b29aSmrg *compile_time = t1 - t0; 2347ec3b29aSmrg *link_time = t2 - t1; 2357ec3b29aSmrg 2367ec3b29aSmrg assert(glGetError() == GL_NO_ERROR); 2377ec3b29aSmrg 2387ec3b29aSmrg return program; 2397ec3b29aSmrg} 2407ec3b29aSmrg 2417ec3b29aSmrg 2427ec3b29aSmrgstatic void 2437ec3b29aSmrgInit(void) 2447ec3b29aSmrg{ 2457ec3b29aSmrg GLuint vbo; 2467ec3b29aSmrg int i, compile_time, link_time, total_compile_time, total_link_time; 2477ec3b29aSmrg 2487ec3b29aSmrg if (!ShadersSupported()) 2497ec3b29aSmrg exit(1); 2507ec3b29aSmrg 2517ec3b29aSmrg printf("Shader complexity: %d\n", complexity); 2527ec3b29aSmrg printf("Num shaders: %d\n", num_shaders); 2537ec3b29aSmrg 2547ec3b29aSmrg total_compile_time = total_link_time = 0; 2557ec3b29aSmrg 2567ec3b29aSmrg /* create the shader programs */ 2577ec3b29aSmrg for (i = 0; i < num_shaders; i++) { 2587ec3b29aSmrg char *fs_code = gen_large_shader(complexity, i); 2597ec3b29aSmrg 2607ec3b29aSmrg if (verbose && i==0) { 2617ec3b29aSmrg printf("Shader[0] code:\n%s\n", fs_code); 2627ec3b29aSmrg } 2637ec3b29aSmrg 2647ec3b29aSmrg programs[i] = create_shader_program(fs_code, &compile_time, &link_time); 2657ec3b29aSmrg total_compile_time += compile_time; 2667ec3b29aSmrg total_link_time += link_time; 2677ec3b29aSmrg 2687ec3b29aSmrg free(fs_code); 2697ec3b29aSmrg } 2707ec3b29aSmrg 2717ec3b29aSmrg printf("Total glCompileShader() time: %d ms\n", total_compile_time); 2727ec3b29aSmrg printf("Total glLinkProgram() time: %d ms\n", total_link_time); 2737ec3b29aSmrg 2747ec3b29aSmrg glGenBuffers(1, &vbo); 2757ec3b29aSmrg glBindBuffer(GL_ARRAY_BUFFER, vbo); 2767ec3b29aSmrg glBufferData(GL_ARRAY_BUFFER, sizeof(coords), coords, GL_STATIC_DRAW); 2777ec3b29aSmrg glVertexPointer(4, GL_FLOAT, 0, NULL); 2787ec3b29aSmrg glEnable(GL_VERTEX_ARRAY); 2797ec3b29aSmrg} 2807ec3b29aSmrg 2817ec3b29aSmrg 2827ec3b29aSmrgint 2837ec3b29aSmrgmain(int argc, char *argv[]) 2847ec3b29aSmrg{ 2857ec3b29aSmrg int i; 2867ec3b29aSmrg 2877ec3b29aSmrg glutInit(&argc, argv); 2887ec3b29aSmrg glutInitWindowSize(WinWidth, WinHeight); 2897ec3b29aSmrg glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); 2907ec3b29aSmrg Win = glutCreateWindow(argv[0]); 2917ec3b29aSmrg glewInit(); 2927ec3b29aSmrg glutReshapeFunc(Reshape); 2937ec3b29aSmrg glutKeyboardFunc(Key); 2947ec3b29aSmrg glutDisplayFunc(Draw); 2957ec3b29aSmrg 2967ec3b29aSmrg for (i = 1; i < argc; i++) { 2977ec3b29aSmrg if (strcmp(argv[i], "-v") == 0) { 2987ec3b29aSmrg verbose = 1; 2997ec3b29aSmrg } 3007ec3b29aSmrg else if (strcmp(argv[i], "-c") == 0) { 3017ec3b29aSmrg i++; 3027ec3b29aSmrg complexity = atoi(argv[i]); 3037ec3b29aSmrg } 3047ec3b29aSmrg else if (strcmp(argv[i], "-n") == 0) { 3057ec3b29aSmrg i++; 3067ec3b29aSmrg num_shaders = atoi(argv[i]); 3077ec3b29aSmrg } 3087ec3b29aSmrg else { 3097ec3b29aSmrg printf("unexpected option: %s\n", argv[i]); 3107ec3b29aSmrg exit(1); 3117ec3b29aSmrg } 3127ec3b29aSmrg } 3137ec3b29aSmrg 3147ec3b29aSmrg Init(); 3157ec3b29aSmrg 3167ec3b29aSmrg glutMainLoop(); 3177ec3b29aSmrg return 0; 3187ec3b29aSmrg} 319