1 /*
2  * Copyright 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <jni.h>
18 #include <stdlib.h>
19 #include <time.h>
20 
21 #include "gles3jni.h"
22 
23 const Vertex QUAD[4] = {
24     // Square with diagonal < 2 so that it fits in a [-1 .. 1]^2 square
25     // regardless of rotation.
26     {{-0.7f, -0.7f}, {0x00, 0xFF, 0x00}},
27     {{ 0.7f, -0.7f}, {0x00, 0x00, 0xFF}},
28     {{-0.7f,  0.7f}, {0xFF, 0x00, 0x00}},
29     {{ 0.7f,  0.7f}, {0xFF, 0xFF, 0xFF}},
30 };
31 
checkGlError(const char * funcName)32 bool checkGlError(const char* funcName) {
33     GLint err = glGetError();
34     if (err != GL_NO_ERROR) {
35         ALOGE("GL error after %s(): 0x%08x\n", funcName, err);
36         return true;
37     }
38     return false;
39 }
40 
createShader(GLenum shaderType,const char * src)41 GLuint createShader(GLenum shaderType, const char* src) {
42     GLuint shader = glCreateShader(shaderType);
43     if (!shader) {
44         checkGlError("glCreateShader");
45         return 0;
46     }
47     glShaderSource(shader, 1, &src, NULL);
48 
49     GLint compiled = GL_FALSE;
50     glCompileShader(shader);
51     glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
52     if (!compiled) {
53         GLint infoLogLen = 0;
54         glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLen);
55         if (infoLogLen > 0) {
56             GLchar* infoLog = (GLchar*)malloc(infoLogLen);
57             if (infoLog) {
58                 glGetShaderInfoLog(shader, infoLogLen, NULL, infoLog);
59                 ALOGE("Could not compile %s shader:\n%s\n",
60                         shaderType == GL_VERTEX_SHADER ? "vertex" : "fragment",
61                         infoLog);
62                 free(infoLog);
63             }
64         }
65         glDeleteShader(shader);
66         return 0;
67     }
68 
69     return shader;
70 }
71 
createProgram(const char * vtxSrc,const char * fragSrc)72 GLuint createProgram(const char* vtxSrc, const char* fragSrc) {
73     GLuint vtxShader = 0;
74     GLuint fragShader = 0;
75     GLuint program = 0;
76     GLint linked = GL_FALSE;
77 
78     vtxShader = createShader(GL_VERTEX_SHADER, vtxSrc);
79     if (!vtxShader)
80         goto exit;
81 
82     fragShader = createShader(GL_FRAGMENT_SHADER, fragSrc);
83     if (!fragShader)
84         goto exit;
85 
86     program = glCreateProgram();
87     if (!program) {
88         checkGlError("glCreateProgram");
89         goto exit;
90     }
91     glAttachShader(program, vtxShader);
92     glAttachShader(program, fragShader);
93 
94     glLinkProgram(program);
95     glGetProgramiv(program, GL_LINK_STATUS, &linked);
96     if (!linked) {
97         ALOGE("Could not link program");
98         GLint infoLogLen = 0;
99         glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLen);
100         if (infoLogLen) {
101             GLchar* infoLog = (GLchar*)malloc(infoLogLen);
102             if (infoLog) {
103                 glGetProgramInfoLog(program, infoLogLen, NULL, infoLog);
104                 ALOGE("Could not link program:\n%s\n", infoLog);
105                 free(infoLog);
106             }
107         }
108         glDeleteProgram(program);
109         program = 0;
110     }
111 
112 exit:
113     glDeleteShader(vtxShader);
114     glDeleteShader(fragShader);
115     return program;
116 }
117 
printGlString(const char * name,GLenum s)118 static void printGlString(const char* name, GLenum s) {
119     const char* v = (const char*)glGetString(s);
120     ALOGV("GL %s: %s\n", name, v);
121 }
122 
123 // ----------------------------------------------------------------------------
124 
Renderer()125 Renderer::Renderer()
126 :   mNumInstances(0),
127     mLastFrameNs(0)
128 {
129     memset(mScale, 0, sizeof(mScale));
130     memset(mAngularVelocity, 0, sizeof(mAngularVelocity));
131     memset(mAngles, 0, sizeof(mAngles));
132 }
133 
~Renderer()134 Renderer::~Renderer() {
135 }
136 
resize(int w,int h)137 void Renderer::resize(int w, int h) {
138     float* offsets = mapOffsetBuf();
139     calcSceneParams(w, h, offsets);
140     unmapOffsetBuf();
141 
142     for (unsigned int i = 0; i < mNumInstances; i++) {
143         mAngles[i] = drand48() * TWO_PI;
144         mAngularVelocity[i] = MAX_ROT_SPEED * (2.0*drand48() - 1.0);
145     }
146 
147     mLastFrameNs = 0;
148 
149     glViewport(0, 0, w, h);
150 }
151 
calcSceneParams(unsigned int w,unsigned int h,float * offsets)152 void Renderer::calcSceneParams(unsigned int w, unsigned int h,
153         float* offsets) {
154     // number of cells along the larger screen dimension
155     const float NCELLS_MAJOR = MAX_INSTANCES_PER_SIDE;
156     // cell size in scene space
157     const float CELL_SIZE = 2.0f / NCELLS_MAJOR;
158 
159     // Calculations are done in "landscape", i.e. assuming dim[0] >= dim[1].
160     // Only at the end are values put in the opposite order if h > w.
161     const float dim[2] = {fmaxf(w,h), fminf(w,h)};
162     const float aspect[2] = {dim[0] / dim[1], dim[1] / dim[0]};
163     const float scene2clip[2] = {1.0f, aspect[0]};
164     const int ncells[2] = {
165             NCELLS_MAJOR,
166             (int)floorf(NCELLS_MAJOR * aspect[1])
167     };
168 
169     float centers[2][MAX_INSTANCES_PER_SIDE];
170     for (int d = 0; d < 2; d++) {
171         float offset = -ncells[d] / NCELLS_MAJOR; // -1.0 for d=0
172         for (int i = 0; i < ncells[d]; i++) {
173             centers[d][i] = scene2clip[d] * (CELL_SIZE*(i + 0.5f) + offset);
174         }
175     }
176 
177     int major = w >= h ? 0 : 1;
178     int minor = w >= h ? 1 : 0;
179     // outer product of centers[0] and centers[1]
180     for (int i = 0; i < ncells[0]; i++) {
181         for (int j = 0; j < ncells[1]; j++) {
182             int idx = i*ncells[1] + j;
183             offsets[2*idx + major] = centers[0][i];
184             offsets[2*idx + minor] = centers[1][j];
185         }
186     }
187 
188     mNumInstances = ncells[0] * ncells[1];
189     mScale[major] = 0.5f * CELL_SIZE * scene2clip[0];
190     mScale[minor] = 0.5f * CELL_SIZE * scene2clip[1];
191 }
192 
step()193 void Renderer::step() {
194     timespec now;
195     clock_gettime(CLOCK_MONOTONIC, &now);
196     uint64_t nowNs = now.tv_sec*1000000000ull + now.tv_nsec;
197 
198     if (mLastFrameNs > 0) {
199         float dt = float(nowNs - mLastFrameNs) * 0.000000001f;
200 
201         for (unsigned int i = 0; i < mNumInstances; i++) {
202             mAngles[i] += mAngularVelocity[i] * dt;
203             if (mAngles[i] >= TWO_PI) {
204                 mAngles[i] -= TWO_PI;
205             } else if (mAngles[i] <= -TWO_PI) {
206                 mAngles[i] += TWO_PI;
207             }
208         }
209 
210         float* transforms = mapTransformBuf();
211         for (unsigned int i = 0; i < mNumInstances; i++) {
212             float s = sinf(mAngles[i]);
213             float c = cosf(mAngles[i]);
214             transforms[4*i + 0] =  c * mScale[0];
215             transforms[4*i + 1] =  s * mScale[1];
216             transforms[4*i + 2] = -s * mScale[0];
217             transforms[4*i + 3] =  c * mScale[1];
218         }
219         unmapTransformBuf();
220     }
221 
222     mLastFrameNs = nowNs;
223 }
224 
render()225 void Renderer::render() {
226     step();
227 
228     glClearColor(0.2f, 0.2f, 0.3f, 1.0f);
229     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
230     draw(mNumInstances);
231     checkGlError("Renderer::render");
232 }
233 
234 // ----------------------------------------------------------------------------
235 
236 static Renderer* g_renderer = NULL;
237 
238 extern "C" {
239     JNIEXPORT void JNICALL Java_com_android_gles3jni_GLES3JNILib_init(JNIEnv* env, jobject obj);
240     JNIEXPORT void JNICALL Java_com_android_gles3jni_GLES3JNILib_resize(JNIEnv* env, jobject obj, jint width, jint height);
241     JNIEXPORT void JNICALL Java_com_android_gles3jni_GLES3JNILib_step(JNIEnv* env, jobject obj);
242 };
243 
244 #if !defined(DYNAMIC_ES3)
gl3stubInit()245 static GLboolean gl3stubInit() {
246     return GL_TRUE;
247 }
248 #endif
249 
250 JNIEXPORT void JNICALL
Java_com_android_gles3jni_GLES3JNILib_init(JNIEnv * env,jobject obj)251 Java_com_android_gles3jni_GLES3JNILib_init(JNIEnv* env, jobject obj) {
252     if (g_renderer) {
253         delete g_renderer;
254         g_renderer = NULL;
255     }
256 
257     printGlString("Version", GL_VERSION);
258     printGlString("Vendor", GL_VENDOR);
259     printGlString("Renderer", GL_RENDERER);
260     printGlString("Extensions", GL_EXTENSIONS);
261 
262     const char* versionStr = (const char*)glGetString(GL_VERSION);
263     if (strstr(versionStr, "OpenGL ES 3.") && gl3stubInit()) {
264         g_renderer = createES3Renderer();
265     } else if (strstr(versionStr, "OpenGL ES 2.")) {
266         g_renderer = createES2Renderer();
267     } else {
268         ALOGE("Unsupported OpenGL ES version");
269     }
270 }
271 
272 JNIEXPORT void JNICALL
Java_com_android_gles3jni_GLES3JNILib_resize(JNIEnv * env,jobject obj,jint width,jint height)273 Java_com_android_gles3jni_GLES3JNILib_resize(JNIEnv* env, jobject obj, jint width, jint height) {
274     if (g_renderer) {
275         g_renderer->resize(width, height);
276     }
277 }
278 
279 JNIEXPORT void JNICALL
Java_com_android_gles3jni_GLES3JNILib_step(JNIEnv * env,jobject obj)280 Java_com_android_gles3jni_GLES3JNILib_step(JNIEnv* env, jobject obj) {
281     if (g_renderer) {
282         g_renderer->render();
283     }
284 }
285