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