gl_code.cpp revision 92a9ae4a02682a9e195f3e3a68d2c7293c018173
1// OpenGL ES 2.0 code
2
3#include <nativehelper/jni.h>
4#define LOG_TAG "GLPerf gl_code.cpp"
5#include <utils/Log.h>
6
7#include <EGL/egl.h>
8#include <GLES2/gl2.h>
9#include <GLES2/gl2ext.h>
10#include <utils/Timers.h>
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <math.h>
15
16FILE * out;
17
18static void printGLString(const char *name, GLenum s) {
19    const char *v = (const char *) glGetString(s);
20    LOGI("GL %s = %s\n", name, v);
21}
22
23static void checkGlError(const char* op) {
24    for (GLint error = glGetError(); error; error
25            = glGetError()) {
26        LOGI("after %s() glError (0x%x)\n", op, error);
27    }
28}
29
30GLuint loadShader(GLenum shaderType, const char* pSource) {
31    GLuint shader = glCreateShader(shaderType);
32    if (shader) {
33        glShaderSource(shader, 1, &pSource, NULL);
34        glCompileShader(shader);
35        GLint compiled = 0;
36        glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
37        if (!compiled) {
38            GLint infoLen = 0;
39            glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
40            if (infoLen) {
41                char* buf = (char*) malloc(infoLen);
42                if (buf) {
43                    glGetShaderInfoLog(shader, infoLen, NULL, buf);
44                    LOGE("Could not compile shader %d:\n%s\n",
45                            shaderType, buf);
46                    free(buf);
47                }
48                glDeleteShader(shader);
49                shader = 0;
50            }
51        }
52    }
53    return shader;
54}
55
56enum {
57    A_POS,
58    A_COLOR,
59    A_TEX0,
60    A_TEX1
61};
62
63GLuint createProgram(const char* pVertexSource, const char* pFragmentSource) {
64    GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource);
65    if (!vertexShader) {
66        return 0;
67    }
68
69    GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);
70    if (!pixelShader) {
71        return 0;
72    }
73
74    GLuint program = glCreateProgram();
75    if (program) {
76        glAttachShader(program, vertexShader);
77        checkGlError("glAttachShader v");
78        glAttachShader(program, pixelShader);
79        checkGlError("glAttachShader p");
80
81        glBindAttribLocation(program, A_POS, "a_pos");
82        glBindAttribLocation(program, A_COLOR, "a_color");
83        glBindAttribLocation(program, A_TEX0, "a_tex0");
84        glBindAttribLocation(program, A_TEX1, "a_tex1");
85        glLinkProgram(program);
86        GLint linkStatus = GL_FALSE;
87        glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
88        if (linkStatus != GL_TRUE) {
89            GLint bufLength = 0;
90            glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
91            if (bufLength) {
92                char* buf = (char*) malloc(bufLength);
93                if (buf) {
94                    glGetProgramInfoLog(program, bufLength, NULL, buf);
95                    LOGE("Could not link program:\n%s\n", buf);
96                    free(buf);
97                }
98            }
99            glDeleteProgram(program);
100            program = 0;
101        }
102    }
103    checkGlError("createProgram");
104    glUseProgram(program);
105    return program;
106}
107
108uint64_t getTime() {
109    struct timespec t;
110    clock_gettime(CLOCK_MONOTONIC, &t);
111    return t.tv_nsec + ((uint64_t)t.tv_sec * 1000 * 1000 * 1000);
112}
113
114uint64_t gTime;
115void startTimer() {
116    gTime = getTime();
117}
118
119void endTimer(const char *str, int w, int h, double dc, int count) {
120    uint64_t t2 = getTime();
121    double delta = ((double)(t2 - gTime)) / 1000000000;
122    double pixels = dc * (w * h) * count;
123    double mpps = pixels / delta / 1000000;
124    double dc60 = pixels / delta / (w * h) / 60;
125
126    LOGI("%s, %f, %f\n", str, mpps, dc60);
127    if (out) {
128        fprintf(out, "%s, %f, %f\r\n", str, mpps, dc60);
129        fflush(out);
130    }
131}
132
133static const char gVertexShader[] =
134    "attribute vec4 a_pos;\n"
135    "attribute vec4 a_color;\n"
136    "attribute vec2 a_tex0;\n"
137    "attribute vec2 a_tex1;\n"
138    "varying vec4 v_color;\n"
139    "varying vec2 v_tex0;\n"
140    "varying vec2 v_tex1;\n"
141
142    "void main() {\n"
143    "    v_color = a_color;\n"
144    "    v_tex0 = a_tex0;\n"
145    "    v_tex1 = a_tex1;\n"
146    "    gl_Position = a_pos;\n"
147    "}\n";
148
149static const char gShaderPrefix[] =
150    "precision mediump float;\n"
151    "uniform vec4 u_color;\n"
152    "uniform vec4 u_0;\n"
153    "uniform vec4 u_1;\n"
154    "uniform vec4 u_2;\n"
155    "uniform vec4 u_3;\n"
156    "varying vec4 v_color;\n"
157    "varying vec2 v_tex0;\n"
158    "varying vec2 v_tex1;\n"
159    "uniform sampler2D u_tex0;\n"
160    "uniform sampler2D u_tex1;\n"
161    "void main() {\n";
162
163static const char gShaderPostfix[] =
164    "  gl_FragColor = c;\n"
165    "}\n";
166
167
168static char * append(char *d, const char *s) {
169    size_t len = strlen(s);
170    memcpy(d, s, len);
171    return d + len;
172}
173
174static char * genShader(
175    bool useVarColor,
176    int texCount,
177    bool modulateFirstTex,
178    int extraMath)
179{
180    char *str = (char *)calloc(16 * 1024, 1);
181    char *tmp = append(str, gShaderPrefix);
182
183    if (modulateFirstTex || !texCount) {
184        if (useVarColor) {
185            tmp = append(tmp, "  vec4 c = v_color;\n");
186        } else {
187            tmp = append(tmp, "  vec4 c = u_color;\n");
188        }
189    } else {
190        tmp = append(tmp, "  vec4 c = texture2D(u_tex0, v_tex0);\n");
191    }
192
193    if (modulateFirstTex && texCount) {
194        tmp = append(tmp, "  c *= texture2D(u_tex0, v_tex0);\n");
195    }
196    if (texCount > 1) {
197        tmp = append(tmp, "  c *= texture2D(u_tex1, v_tex1);\n");
198    }
199
200    if (extraMath > 0) {
201        tmp = append(tmp, "  c *= u_0;\n");
202    }
203    if (extraMath > 1) {
204        tmp = append(tmp, "  c *= u_1;\n");
205    }
206    if (extraMath > 2) {
207        tmp = append(tmp, "  c *= u_2;\n");
208    }
209    if (extraMath > 3) {
210        tmp = append(tmp, "  c *= u_3;\n");
211    }
212
213
214    tmp = append(tmp, gShaderPostfix);
215    tmp[0] = 0;
216
217    //LOGI("%s", str);
218    return str;
219}
220
221static void setupVA() {
222    static const float vtx[] = {
223        -2.0f,-1.0f,
224         1.0f,-1.0f,
225        -2.0f, 1.0f,
226         1.0f, 1.0f };
227    static const float color[] = {
228        1.0f,0.0f,1.0f,1.0f,
229        0.0f,0.0f,1.0f,1.0f,
230        1.0f,1.0f,0.0f,1.0f,
231        1.0f,1.0f,1.0f,1.0f };
232    static const float tex0[] = {
233        0.0f,0.0f,
234        1.0f,0.0f,
235        1.0f,1.0f,
236        0.0f,1.0f };
237    static const float tex1[] = {
238        1.0f,0.0f,
239        1.0f,1.0f,
240        0.0f,1.0f,
241        0.0f,0.0f };
242
243    glEnableVertexAttribArray(A_POS);
244    glEnableVertexAttribArray(A_COLOR);
245    glEnableVertexAttribArray(A_TEX0);
246    glEnableVertexAttribArray(A_TEX1);
247
248    glVertexAttribPointer(A_POS, 2, GL_FLOAT, false, 8, vtx);
249    glVertexAttribPointer(A_COLOR, 4, GL_FLOAT, false, 16, color);
250    glVertexAttribPointer(A_TEX0, 2, GL_FLOAT, false, 8, tex0);
251    glVertexAttribPointer(A_TEX1, 2, GL_FLOAT, false, 8, tex1);
252}
253
254//////////////////////////
255
256// Width and height of the screen
257
258uint32_t w;
259uint32_t h;
260
261// The stateClock starts at zero and increments by 1 every time we draw a frame. It is used to control which phase of the test we are in.
262
263int stateClock;
264const int doLoopStates = 2;
265const int doSingleTestStates = 2;
266bool done;
267
268// Saves the parameters of the test (so we can print them out when we finish the timing.)
269
270char saveBuf[1024];
271
272static void doLoop(uint32_t w, uint32_t h, const char *str) {
273    int doLoopState = stateClock % doLoopStates;
274    // LOGI("doLoop %d\n", doLoopState);
275    switch(doLoopState) {
276    case 0:
277	    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
278	    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
279    	break;
280    case 1:
281            strcpy(saveBuf, str);
282	    startTimer();
283	    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
284	    for (int ct=0; ct < 100; ct++) {
285		glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
286	    }
287	break;
288    }
289}
290
291static void doSingleTest(uint32_t w, uint32_t h,
292                         bool useVarColor,
293                         int texCount,
294                         bool modulateFirstTex,
295                         int extraMath,
296                         int tex0, int tex1) {
297    int doSingleTestState = (stateClock / doLoopStates) % doSingleTestStates;
298    // LOGI("doSingleTest %d\n", doSingleTestState);
299    switch (doSingleTestState) {
300	case 0: {
301	    char *pgmTxt = genShader(useVarColor, texCount, modulateFirstTex, extraMath);
302	    int pgm = createProgram(gVertexShader, pgmTxt);
303	    if (!pgm) {
304		LOGE("error running test\n");
305		return;
306	    }
307	    int loc = glGetUniformLocation(pgm, "u_tex0");
308	    //LOGI("loc = %i \n", loc);
309	    if (loc >= 0) glUniform1i(loc, 0);
310	    loc = glGetUniformLocation(pgm, "u_tex1");
311	    if (loc >= 0) glUniform1i(loc, 1);
312
313	    loc = glGetUniformLocation(pgm, "u_color");
314	    if (loc >= 0) glUniform4f(loc, 1.f, 0.4f, 0.6f, 0.8f);
315
316	    loc = glGetUniformLocation(pgm, "u_0");
317	    if (loc >= 0) glUniform4f(loc, 1.f, 0.4f, 0.6f, 0.8f);
318
319	    loc = glGetUniformLocation(pgm, "u_1");
320	    if (loc >= 0) glUniform4f(loc, 0.7f, 0.8f, 0.6f, 0.8f);
321
322	    loc = glGetUniformLocation(pgm, "u_2");
323	    if (loc >= 0) glUniform4f(loc, 0.9f, 0.6f, 0.7f, 1.0f);
324
325	    loc = glGetUniformLocation(pgm, "u_3");
326	    if (loc >= 0) glUniform4f(loc, 0.88f, 0.2f, 0.4f, 0.2f);
327
328	    glActiveTexture(GL_TEXTURE0);
329	    glBindTexture(GL_TEXTURE_2D, tex0);
330	    glActiveTexture(GL_TEXTURE1);
331	    glBindTexture(GL_TEXTURE_2D, tex1);
332	    glActiveTexture(GL_TEXTURE0);
333
334
335	    glBlendFunc(GL_ONE, GL_ONE);
336	    glDisable(GL_BLEND);
337            char str2[1024];
338	    sprintf(str2, "%i, %i, %i, %i, %i, 0",
339		    useVarColor, texCount, modulateFirstTex, extraMath, tex0);
340    	    doLoop(w, h, str2);
341	 }
342         break;
343         case 1: {
344            char str2[1024];
345	    glEnable(GL_BLEND);
346	    sprintf(str2, "%i, %i, %i, %i, %i, 1",
347		    useVarColor, texCount, modulateFirstTex, extraMath, tex0);
348	    doLoop(w, h, str2);
349        }
350        break;
351    }
352}
353
354void genTextures() {
355    uint32_t *m = (uint32_t *)malloc(1024*1024*4);
356    for (int y=0; y < 1024; y++){
357        for (int x=0; x < 1024; x++){
358            m[y*1024 + x] = 0xff0000ff | ((x & 0xff) << 8) | (y << 16);
359        }
360    }
361    glBindTexture(GL_TEXTURE_2D, 1);
362    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1024, 1024, 0, GL_RGBA, GL_UNSIGNED_BYTE, m);
363    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
364    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
365    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
366    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
367
368    for (int y=0; y < 16; y++){
369        for (int x=0; x < 16; x++){
370            m[y*16 + x] = 0xff0000ff | (x<<12) | (y<<20);
371        }
372    }
373    glBindTexture(GL_TEXTURE_2D, 2);
374    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, m);
375    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
376    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
377    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
378    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
379
380}
381
382void doTest(uint32_t w, uint32_t h) {
383    int testState = stateClock / (doLoopStates * doSingleTestStates);
384    int texCount;
385    int extraMath;
386    int testSubState;
387    if ( testState < 5 * 2) {
388       texCount = 0; // Only 10 tests for texCout 0
389       extraMath = testState / 2;
390       testSubState = testState % 2;
391    } else {
392       texCount = 1 + (testState - 10) / (5 * 8);
393       extraMath = testState / 8;
394       testSubState = testState % 8;
395    }
396    if (texCount >= 3) {
397       LOGI("done\n");
398       if (out) {
399           fclose(out);
400           out = NULL;
401       }
402       done = true;
403       return;
404    }
405
406
407    // LOGI("doTest %d %d %d\n", texCount, extraMath, testSubState);
408
409    switch(testSubState) {
410	case 0:
411            doSingleTest(w, h, false, texCount, false, extraMath, 1, 1);
412	break;
413	case 1:
414            doSingleTest(w, h, true, texCount, false, extraMath, 1, 1);
415	break;
416	case 2:
417                doSingleTest(w, h, false, texCount, true, extraMath, 1, 1);
418	break;
419	case 3:
420                doSingleTest(w, h, true, texCount, true, extraMath, 1, 1);
421	break;
422
423	case 4:
424                doSingleTest(w, h, false, texCount, false, extraMath, 2, 2);
425	break;
426	case 5:
427                doSingleTest(w, h, true, texCount, false, extraMath, 2, 2);
428	break;
429	case 6:
430                doSingleTest(w, h, false, texCount, true, extraMath, 2, 2);
431	break;
432	case 7:
433                doSingleTest(w, h, true, texCount, true, extraMath, 2, 2);
434	break;
435    }
436}
437
438extern "C" {
439    JNIEXPORT void JNICALL Java_com_android_glperf_GLPerfLib_init(JNIEnv * env, jobject obj,  jint width, jint height);
440    JNIEXPORT void JNICALL Java_com_android_glperf_GLPerfLib_step(JNIEnv * env, jobject obj);
441};
442
443JNIEXPORT void JNICALL Java_com_android_glperf_GLPerfLib_init(JNIEnv * env, jobject obj,  jint width, jint height)
444{
445    if (!done) {
446	    w = width;
447	    h = height;
448	    stateClock = 0;
449	    done = false;
450	    setupVA();
451	    genTextures();
452	    const char* fileName = "/sdcard/glperf.csv";
453            if (out != NULL) {
454                 LOGI("Closing partially written output.n");
455                 fclose(out);
456                 out = NULL;
457            }
458	    LOGI("Writing to: %s\n",fileName);
459	    out = fopen(fileName, "w");
460	    if (out == NULL) {
461		LOGE("Could not open: %s\n", fileName);
462	    }
463
464	    LOGI("\nvarColor, texCount, modulate, extraMath, texSize, blend, Mpps, DC60\n");
465	    if (out) fprintf(out,"varColor, texCount, modulate, extraMath, texSize, blend, Mpps, DC60\r\n");
466    }
467}
468
469JNIEXPORT void JNICALL Java_com_android_glperf_GLPerfLib_step(JNIEnv * env, jobject obj)
470{
471    if (! done) {
472        if (stateClock > 0 && ((stateClock & 1) == 0)) {
473	    endTimer(saveBuf, w, h, 1, 100);
474        }
475        doTest(w, h);
476        stateClock++;
477    } else {
478	    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
479    }
480}
481