Home | History | Annotate | Download | only in jni
      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 
     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 
     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 
     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 
    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 
    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 
    134 Renderer::~Renderer() {
    135 }
    136 
    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 
    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 
    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 
    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)
    245 static GLboolean gl3stubInit() {
    246     return GL_TRUE;
    247 }
    248 #endif
    249 
    250 JNIEXPORT void JNICALL
    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
    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
    280 Java_com_android_gles3jni_GLES3JNILib_step(JNIEnv* env, jobject obj) {
    281     if (g_renderer) {
    282         g_renderer->render();
    283     }
    284 }
    285