gl_code.cpp revision 63bcb5f8e2d2c1d054b09a5ab9f989644cfeb9b1
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) fprintf(out, "%s, %f, %f\r\n", str, mpps, dc60);
128}
129
130static const char gVertexShader[] =
131    "attribute vec4 a_pos;\n"
132    "attribute vec4 a_color;\n"
133    "attribute vec2 a_tex0;\n"
134    "attribute vec2 a_tex1;\n"
135    "varying vec4 v_color;\n"
136    "varying vec2 v_tex0;\n"
137    "varying vec2 v_tex1;\n"
138
139    "void main() {\n"
140    "    v_color = a_color;\n"
141    "    v_tex0 = a_tex0;\n"
142    "    v_tex1 = a_tex1;\n"
143    "    gl_Position = a_pos;\n"
144    "}\n";
145
146static const char gShaderPrefix[] =
147    "precision mediump float;\n"
148    "uniform vec4 u_color;\n"
149    "uniform vec4 u_0;\n"
150    "uniform vec4 u_1;\n"
151    "uniform vec4 u_2;\n"
152    "uniform vec4 u_3;\n"
153    "varying vec4 v_color;\n"
154    "varying vec2 v_tex0;\n"
155    "varying vec2 v_tex1;\n"
156    "uniform sampler2D u_tex0;\n"
157    "uniform sampler2D u_tex1;\n"
158    "void main() {\n";
159
160static const char gShaderPostfix[] =
161    "  gl_FragColor = c;\n"
162    "}\n";
163
164
165static char * append(char *d, const char *s) {
166    size_t len = strlen(s);
167    memcpy(d, s, len);
168    return d + len;
169}
170
171static char * genShader(
172    bool useVarColor,
173    int texCount,
174    bool modulateFirstTex,
175    int extraMath)
176{
177    char *str = (char *)calloc(16 * 1024, 1);
178    char *tmp = append(str, gShaderPrefix);
179
180    if (modulateFirstTex || !texCount) {
181        if (useVarColor) {
182            tmp = append(tmp, "  vec4 c = v_color;\n");
183        } else {
184            tmp = append(tmp, "  vec4 c = u_color;\n");
185        }
186    } else {
187        tmp = append(tmp, "  vec4 c = texture2D(u_tex0, v_tex0);\n");
188    }
189
190    if (modulateFirstTex && texCount) {
191        tmp = append(tmp, "  c *= texture2D(u_tex0, v_tex0);\n");
192    }
193    if (texCount > 1) {
194        tmp = append(tmp, "  c *= texture2D(u_tex1, v_tex1);\n");
195    }
196
197    if (extraMath > 0) {
198        tmp = append(tmp, "  c *= u_0;\n");
199    }
200    if (extraMath > 1) {
201        tmp = append(tmp, "  c *= u_1;\n");
202    }
203    if (extraMath > 2) {
204        tmp = append(tmp, "  c *= u_2;\n");
205    }
206    if (extraMath > 3) {
207        tmp = append(tmp, "  c *= u_3;\n");
208    }
209
210
211    tmp = append(tmp, gShaderPostfix);
212    tmp[0] = 0;
213
214    //LOGI("%s", str);
215    return str;
216}
217
218static void setupVA() {
219    static const float vtx[] = {
220        -2.0f,-1.0f,
221         1.0f,-1.0f,
222        -2.0f, 1.0f,
223         1.0f, 1.0f };
224    static const float color[] = {
225        1.0f,0.0f,1.0f,1.0f,
226        0.0f,0.0f,1.0f,1.0f,
227        1.0f,1.0f,0.0f,1.0f,
228        1.0f,1.0f,1.0f,1.0f };
229    static const float tex0[] = {
230        0.0f,0.0f,
231        1.0f,0.0f,
232        1.0f,1.0f,
233        0.0f,1.0f };
234    static const float tex1[] = {
235        1.0f,0.0f,
236        1.0f,1.0f,
237        0.0f,1.0f,
238        0.0f,0.0f };
239
240    glEnableVertexAttribArray(A_POS);
241    glEnableVertexAttribArray(A_COLOR);
242    glEnableVertexAttribArray(A_TEX0);
243    glEnableVertexAttribArray(A_TEX1);
244
245    glVertexAttribPointer(A_POS, 2, GL_FLOAT, false, 8, vtx);
246    glVertexAttribPointer(A_COLOR, 4, GL_FLOAT, false, 16, color);
247    glVertexAttribPointer(A_TEX0, 2, GL_FLOAT, false, 8, tex0);
248    glVertexAttribPointer(A_TEX1, 2, GL_FLOAT, false, 8, tex1);
249}
250
251//////////////////////////
252
253// Width and height of the screen
254
255uint32_t w;
256uint32_t h;
257
258// 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.
259
260int stateClock;
261const int doLoopStates = 2;
262const int doSingleTestStates = 2;
263bool done;
264
265// Saves the parameters of the test (so we can print them out when we finish the timing.)
266
267char saveBuf[1024];
268
269static void doLoop(uint32_t w, uint32_t h, const char *str) {
270    int doLoopState = stateClock % doLoopStates;
271    // LOGI("doLoop %d\n", doLoopState);
272    switch(doLoopState) {
273    case 0:
274	    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
275	    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
276    	break;
277    case 1:
278            strcpy(saveBuf, str);
279	    startTimer();
280	    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
281	    for (int ct=0; ct < 100; ct++) {
282		glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
283	    }
284	break;
285    }
286}
287
288static void doSingleTest(uint32_t w, uint32_t h,
289                         bool useVarColor,
290                         int texCount,
291                         bool modulateFirstTex,
292                         int extraMath,
293                         int tex0, int tex1) {
294    int doSingleTestState = (stateClock / doLoopStates) % doSingleTestStates;
295    // LOGI("doSingleTest %d\n", doSingleTestState);
296    switch (doSingleTestState) {
297	case 0: {
298	    char *pgmTxt = genShader(useVarColor, texCount, modulateFirstTex, extraMath);
299	    int pgm = createProgram(gVertexShader, pgmTxt);
300	    if (!pgm) {
301		LOGE("error running test\n");
302		return;
303	    }
304	    int loc = glGetUniformLocation(pgm, "u_tex0");
305	    //LOGI("loc = %i \n", loc);
306	    if (loc >= 0) glUniform1i(loc, 0);
307	    loc = glGetUniformLocation(pgm, "u_tex1");
308	    if (loc >= 0) glUniform1i(loc, 1);
309
310	    loc = glGetUniformLocation(pgm, "u_color");
311	    if (loc >= 0) glUniform4f(loc, 1.f, 0.4f, 0.6f, 0.8f);
312
313	    loc = glGetUniformLocation(pgm, "u_0");
314	    if (loc >= 0) glUniform4f(loc, 1.f, 0.4f, 0.6f, 0.8f);
315
316	    loc = glGetUniformLocation(pgm, "u_1");
317	    if (loc >= 0) glUniform4f(loc, 0.7f, 0.8f, 0.6f, 0.8f);
318
319	    loc = glGetUniformLocation(pgm, "u_2");
320	    if (loc >= 0) glUniform4f(loc, 0.9f, 0.6f, 0.7f, 1.0f);
321
322	    loc = glGetUniformLocation(pgm, "u_3");
323	    if (loc >= 0) glUniform4f(loc, 0.88f, 0.2f, 0.4f, 0.2f);
324
325	    glActiveTexture(GL_TEXTURE0);
326	    glBindTexture(GL_TEXTURE_2D, tex0);
327	    glActiveTexture(GL_TEXTURE1);
328	    glBindTexture(GL_TEXTURE_2D, tex1);
329	    glActiveTexture(GL_TEXTURE0);
330
331
332	    glBlendFunc(GL_ONE, GL_ONE);
333	    glDisable(GL_BLEND);
334            char str2[1024];
335	    sprintf(str2, "%i, %i, %i, %i, %i, 0",
336		    useVarColor, texCount, modulateFirstTex, extraMath, tex0);
337    	    doLoop(w, h, str2);
338	 }
339         break;
340         case 1: {
341            char str2[1024];
342	    glEnable(GL_BLEND);
343	    sprintf(str2, "%i, %i, %i, %i, %i, 1",
344		    useVarColor, texCount, modulateFirstTex, extraMath, tex0);
345	    doLoop(w, h, str2);
346        }
347        break;
348    }
349}
350
351void genTextures() {
352    uint32_t *m = (uint32_t *)malloc(1024*1024*4);
353    for (int y=0; y < 1024; y++){
354        for (int x=0; x < 1024; x++){
355            m[y*1024 + x] = 0xff0000ff | ((x & 0xff) << 8) | (y << 16);
356        }
357    }
358    glBindTexture(GL_TEXTURE_2D, 1);
359    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1024, 1024, 0, GL_RGBA, GL_UNSIGNED_BYTE, m);
360    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
361    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
362    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
363    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
364
365    for (int y=0; y < 16; y++){
366        for (int x=0; x < 16; x++){
367            m[y*16 + x] = 0xff0000ff | (x<<12) | (y<<20);
368        }
369    }
370    glBindTexture(GL_TEXTURE_2D, 2);
371    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, m);
372    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
373    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
374    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
375    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
376
377}
378
379void doTest(uint32_t w, uint32_t h) {
380    int testState = stateClock / (doLoopStates * doSingleTestStates);
381    int texCount;
382    int extraMath;
383    int testSubState;
384    if ( testState < 5 * 2) {
385       texCount = 0; // Only 10 tests for texCout 0
386       extraMath = testState / 2;
387       testSubState = testState % 2;
388    } else {
389       texCount = 1 + (testState - 10) / (5 * 8);
390       extraMath = testState / 8;
391       testSubState = testState % 8;
392    }
393    if (texCount >= 3) {
394       LOGI("done\n");
395       if (out) {
396           fclose(out);
397           out = NULL;
398       }
399       done = true;
400       exit(0);
401       return;
402    }
403
404
405    // LOGI("doTest %d %d %d\n", texCount, extraMath, testSubState);
406
407    switch(testSubState) {
408	case 0:
409            doSingleTest(w, h, false, texCount, false, extraMath, 1, 1);
410	break;
411	case 1:
412            doSingleTest(w, h, true, texCount, false, extraMath, 1, 1);
413	break;
414	case 2:
415                doSingleTest(w, h, false, texCount, true, extraMath, 1, 1);
416	break;
417	case 3:
418                doSingleTest(w, h, true, texCount, true, extraMath, 1, 1);
419	break;
420
421	case 4:
422                doSingleTest(w, h, false, texCount, false, extraMath, 2, 2);
423	break;
424	case 5:
425                doSingleTest(w, h, true, texCount, false, extraMath, 2, 2);
426	break;
427	case 6:
428                doSingleTest(w, h, false, texCount, true, extraMath, 2, 2);
429	break;
430	case 7:
431                doSingleTest(w, h, true, texCount, true, extraMath, 2, 2);
432	break;
433    }
434}
435
436extern "C" {
437    JNIEXPORT void JNICALL Java_com_android_glperf_GLPerfLib_init(JNIEnv * env, jobject obj,  jint width, jint height);
438    JNIEXPORT void JNICALL Java_com_android_glperf_GLPerfLib_step(JNIEnv * env, jobject obj);
439};
440
441JNIEXPORT void JNICALL Java_com_android_glperf_GLPerfLib_init(JNIEnv * env, jobject obj,  jint width, jint height)
442{
443    w = width;
444    h = height;
445    stateClock = 0;
446    done = false;
447    setupVA();
448    genTextures();
449    const char* fileName = "/sdcard/glperf.csv";
450    LOGI("Writing to: %s\n",fileName);
451    out = fopen(fileName, "w");
452    if (out == NULL) {
453        LOGE("Could not open: %s\n", fileName);
454    }
455
456    LOGI("\nvarColor, texCount, modulate, extraMath, texSize, blend, Mpps, DC60\n");
457    if (out) fprintf(out,"\nvarColor, texCount, modulate, extraMath, texSize, blend, Mpps, DC60\r\n");
458}
459
460JNIEXPORT void JNICALL Java_com_android_glperf_GLPerfLib_step(JNIEnv * env, jobject obj)
461{
462    if (! done) {
463        if (stateClock > 0 && ((stateClock & 1) == 0)) {
464	    endTimer(saveBuf, w, h, 1, 100);
465        }
466        doTest(w, h);
467        stateClock++;
468    } else {
469	    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
470    }
471}
472