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