• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  ** Copyright 2007, 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 <nativehelper/jni.h>
18 #include <math.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <assert.h>
23 #include <dlfcn.h>
24 
25 #include <GLES/gl.h>
26 
27 #include <core/SkBitmap.h>
28 
29 #include "android_runtime/AndroidRuntime.h"
30 
31 #undef LOG_TAG
32 #define LOG_TAG "OpenGLUtil"
33 #include <utils/Log.h>
34 #include "utils/misc.h"
35 
36 #include "poly.h"
37 
38 namespace android {
39 
40 static jclass gIAEClass;
41 static jclass gUOEClass;
42 
43 static inline
mx4transform(float x,float y,float z,float w,const float * pM,float * pDest)44 void mx4transform(float x, float y, float z, float w, const float* pM, float* pDest) {
45     pDest[0] = pM[0 + 4 * 0] * x + pM[0 + 4 * 1] * y + pM[0 + 4 * 2] * z + pM[0 + 4 * 3] * w;
46     pDest[1] = pM[1 + 4 * 0] * x + pM[1 + 4 * 1] * y + pM[1 + 4 * 2] * z + pM[1 + 4 * 3] * w;
47     pDest[2] = pM[2 + 4 * 0] * x + pM[2 + 4 * 1] * y + pM[2 + 4 * 2] * z + pM[2 + 4 * 3] * w;
48     pDest[3] = pM[3 + 4 * 0] * x + pM[3 + 4 * 1] * y + pM[3 + 4 * 2] * z + pM[3 + 4 * 3] * w;
49 }
50 
51 class MallocHelper {
52 public:
MallocHelper()53     MallocHelper() {
54         mData = 0;
55     }
56 
~MallocHelper()57     ~MallocHelper() {
58         if (mData != 0) {
59             free(mData);
60         }
61     }
62 
alloc(size_t size)63     void* alloc(size_t size) {
64         mData = malloc(size);
65         return mData;
66     }
67 
68 private:
69     void* mData;
70 };
71 
72 #if 0
73 static
74 void
75 print_poly(const char* label, Poly* pPoly) {
76     LOGI("%s: %d verts", label, pPoly->n);
77     for(int i = 0; i < pPoly->n; i++) {
78         Poly_vert* pV = & pPoly->vert[i];
79         LOGI("[%d] %g, %g, %g %g", i, pV->sx, pV->sy, pV->sz, pV->sw);
80     }
81 }
82 #endif
83 
84 static
visibilityTest(float * pWS,float * pPositions,int positionsLength,unsigned short * pIndices,int indexCount)85 int visibilityTest(float* pWS, float* pPositions, int positionsLength,
86         unsigned short* pIndices, int indexCount) {
87     MallocHelper mallocHelper;
88     int result = POLY_CLIP_OUT;
89     float* pTransformed = 0;
90     int transformedIndexCount = 0;
91 
92     if ( indexCount < 3 ) {
93         return POLY_CLIP_OUT;
94     }
95 
96     // Find out how many vertices we need to transform
97     // We transform every vertex between the min and max indices, inclusive.
98     // This is OK for the data sets we expect to use with this function, but
99     // for other loads it might be better to use a more sophisticated vertex
100     // cache of some sort.
101 
102     int minIndex = 65536;
103     int maxIndex = -1;
104     for(int i = 0; i < indexCount; i++) {
105         int index = pIndices[i];
106         if ( index < minIndex ) {
107             minIndex = index;
108         }
109         if ( index > maxIndex ) {
110             maxIndex = index;
111         }
112     }
113 
114     if ( maxIndex * 3 > positionsLength) {
115         return -1;
116     }
117 
118     transformedIndexCount = maxIndex - minIndex + 1;
119     pTransformed = (float*) mallocHelper.alloc(transformedIndexCount * 4 * sizeof(float));
120 
121     if (pTransformed == 0 ) {
122         return -2;
123     }
124 
125     // Transform the vertices
126     {
127         const float* pSrc = pPositions + 3 * minIndex;
128         float* pDst = pTransformed;
129         for (int i = 0; i < transformedIndexCount; i++, pSrc += 3, pDst += 4) {
130             mx4transform(pSrc[0], pSrc[1], pSrc[2], 1.0f, pWS,  pDst);
131         }
132     }
133 
134     // Clip the triangles
135 
136     Poly poly;
137     float* pDest = & poly.vert[0].sx;
138     for (int i = 0; i < indexCount; i += 3) {
139         poly.n = 3;
140         memcpy(pDest    , pTransformed + 4 * (pIndices[i    ] - minIndex), 4 * sizeof(float));
141         memcpy(pDest + 4, pTransformed + 4 * (pIndices[i + 1] - minIndex), 4 * sizeof(float));
142         memcpy(pDest + 8, pTransformed + 4 * (pIndices[i + 2] - minIndex), 4 * sizeof(float));
143         result = poly_clip_to_frustum(&poly);
144         if ( result != POLY_CLIP_OUT) {
145             return result;
146         }
147     }
148 
149     return result;
150 }
151 
152 template<class JArray, class T>
153 class ArrayHelper {
154 public:
ArrayHelper(JNIEnv * env,JArray ref,jint offset,jint minSize)155     ArrayHelper(JNIEnv* env, JArray ref, jint offset, jint minSize) {
156         mEnv = env;
157         mRef = ref;
158         mOffset = offset;
159         mMinSize = minSize;
160         mBase = 0;
161         mReleaseParam = JNI_ABORT;
162     }
163 
~ArrayHelper()164     ~ArrayHelper() {
165         if (mBase) {
166             mEnv->ReleasePrimitiveArrayCritical(mRef, mBase, mReleaseParam);
167         }
168     }
169 
170     // We seperate the bounds check from the initialization because we want to
171     // be able to bounds-check multiple arrays, and we can't throw an exception
172     // after we've called GetPrimitiveArrayCritical.
173 
174     // Return true if the bounds check succeeded
175     // Else instruct the runtime to throw an exception
176 
check()177     bool check() {
178         if ( ! mRef) {
179             mEnv->ThrowNew(gIAEClass, "array == null");
180             return false;
181         }
182         if ( mOffset < 0) {
183             mEnv->ThrowNew(gIAEClass, "offset < 0");
184             return false;
185         }
186         mLength = mEnv->GetArrayLength(mRef) - mOffset;
187         if (mLength < mMinSize ) {
188             mEnv->ThrowNew(gIAEClass, "length - offset < n");
189             return false;
190         }
191         return true;
192     }
193 
194     // Bind the array.
195 
bind()196     void bind() {
197         mBase = (T*) mEnv->GetPrimitiveArrayCritical(mRef, (jboolean *) 0);
198         mData = mBase + mOffset;
199     }
200 
commitChanges()201     void commitChanges() {
202         mReleaseParam = 0;
203     }
204 
205     T* mData;
206     int mLength;
207 
208 private:
209     T* mBase;
210     JNIEnv* mEnv;
211     JArray mRef;
212     jint mOffset;
213     jint mMinSize;
214     int mReleaseParam;
215 };
216 
217 typedef ArrayHelper<jfloatArray, float> FloatArrayHelper;
218 typedef ArrayHelper<jcharArray, unsigned short> UnsignedShortArrayHelper;
219 typedef ArrayHelper<jintArray, int> IntArrayHelper;
220 typedef ArrayHelper<jbyteArray, unsigned char> ByteArrayHelper;
221 
distance2(float x,float y,float z)222 inline float distance2(float x, float y, float z) {
223     return x * x + y * y + z * z;
224 }
225 
distance(float x,float y,float z)226 inline float distance(float x, float y, float z) {
227     return sqrtf(distance2(x, y, z));
228 }
229 
230 static
util_computeBoundingSphere(JNIEnv * env,jclass clazz,jfloatArray positions_ref,jint positionsOffset,jint positionsCount,jfloatArray sphere_ref,jint sphereOffset)231 void util_computeBoundingSphere(JNIEnv *env, jclass clazz,
232         jfloatArray positions_ref, jint positionsOffset, jint positionsCount,
233         jfloatArray sphere_ref, jint sphereOffset) {
234     FloatArrayHelper positions(env, positions_ref, positionsOffset, 0);
235     FloatArrayHelper sphere(env, sphere_ref, sphereOffset, 4);
236 
237     bool checkOK = positions.check() && sphere.check();
238         if (! checkOK) {
239         return;
240     }
241 
242     positions.bind();
243     sphere.bind();
244 
245     if ( positionsCount < 1 ) {
246         env->ThrowNew(gIAEClass, "positionsCount < 1");
247         return;
248     }
249 
250     const float* pSrc = positions.mData;
251 
252     // find bounding box
253     float x0 = *pSrc++;
254     float x1 = x0;
255     float y0 = *pSrc++;
256     float y1 = y0;
257     float z0 = *pSrc++;
258     float z1 = z0;
259 
260     for(int i = 1; i < positionsCount; i++) {
261         {
262             float x = *pSrc++;
263             if (x < x0) {
264                 x0 = x;
265             }
266             else if (x > x1) {
267                 x1 = x;
268             }
269         }
270         {
271             float y = *pSrc++;
272             if (y < y0) {
273                 y0 = y;
274             }
275             else if (y > y1) {
276                 y1 = y;
277             }
278         }
279         {
280             float z = *pSrc++;
281             if (z < z0) {
282                 z0 = z;
283             }
284             else if (z > z1) {
285                 z1 = z;
286             }
287         }
288     }
289 
290     // Because we know our input meshes fit pretty well into bounding boxes,
291     // just take the diagonal of the box as defining our sphere.
292     float* pSphere = sphere.mData;
293     float dx = x1 - x0;
294     float dy = y1 - y0;
295     float dz = z1 - z0;
296     *pSphere++ = x0 + dx * 0.5f;
297     *pSphere++ = y0 + dy * 0.5f;
298     *pSphere++ = z0 + dz * 0.5f;
299     *pSphere++ = distance(dx, dy, dz) * 0.5f;
300 
301     sphere.commitChanges();
302 }
303 
normalizePlane(float * p)304 static void normalizePlane(float* p) {
305     float rdist = 1.0f / distance(p[0], p[1], p[2]);
306     for(int i = 0; i < 4; i++) {
307         p[i] *= rdist;
308     }
309 }
310 
dot3(float x0,float y0,float z0,float x1,float y1,float z1)311 static inline float dot3(float x0, float y0, float z0, float x1, float y1, float z1) {
312     return x0 * x1 + y0 * y1 + z0 * z1;
313 }
314 
signedDistance(const float * pPlane,float x,float y,float z)315 static inline float signedDistance(const float* pPlane, float x, float y, float z) {
316     return dot3(pPlane[0], pPlane[1], pPlane[2], x, y, z) + pPlane[3];
317 }
318 
319 // Return true if the sphere intersects or is inside the frustum
320 
sphereHitsFrustum(const float * pFrustum,const float * pSphere)321 static bool sphereHitsFrustum(const float* pFrustum, const float* pSphere) {
322     float x = pSphere[0];
323     float y = pSphere[1];
324     float z = pSphere[2];
325     float negRadius = -pSphere[3];
326     for (int i = 0; i < 6; i++, pFrustum += 4) {
327         if (signedDistance(pFrustum, x, y, z) <= negRadius) {
328             return false;
329         }
330     }
331     return true;
332 }
333 
computeFrustum(const float * m,float * f)334 static void computeFrustum(const float* m, float* f) {
335     float m3 = m[3];
336     float m7 = m[7];
337     float m11 = m[11];
338     float m15 = m[15];
339     // right
340     f[0] = m3  - m[0];
341     f[1] = m7  - m[4];
342     f[2] = m11 - m[8];
343     f[3] = m15 - m[12];
344     normalizePlane(f);
345     f+= 4;
346 
347     // left
348     f[0] = m3  + m[0];
349     f[1] = m7  + m[4];
350     f[2] = m11 + m[8];
351     f[3] = m15 + m[12];
352     normalizePlane(f);
353     f+= 4;
354 
355     // top
356     f[0] = m3  - m[1];
357     f[1] = m7  - m[5];
358     f[2] = m11 - m[9];
359     f[3] = m15 - m[13];
360     normalizePlane(f);
361     f+= 4;
362 
363     // bottom
364     f[0] = m3  + m[1];
365     f[1] = m7  + m[5];
366     f[2] = m11 + m[9];
367     f[3] = m15 + m[13];
368     normalizePlane(f);
369     f+= 4;
370 
371     // far
372     f[0] = m3  - m[2];
373     f[1] = m7  - m[6];
374     f[2] = m11 - m[10];
375     f[3] = m15 - m[14];
376     normalizePlane(f);
377     f+= 4;
378 
379     // near
380     f[0] = m3  + m[2];
381     f[1] = m7  + m[6];
382     f[2] = m11 + m[10];
383     f[3] = m15 + m[14];
384     normalizePlane(f);
385 }
386 
387 static
util_frustumCullSpheres(JNIEnv * env,jclass clazz,jfloatArray mvp_ref,jint mvpOffset,jfloatArray spheres_ref,jint spheresOffset,jint spheresCount,jintArray results_ref,jint resultsOffset,jint resultsCapacity)388 int util_frustumCullSpheres(JNIEnv *env, jclass clazz,
389         jfloatArray mvp_ref, jint mvpOffset,
390         jfloatArray spheres_ref, jint spheresOffset, jint spheresCount,
391         jintArray results_ref, jint resultsOffset, jint resultsCapacity) {
392     float frustum[6*4];
393     int outputCount;
394     int* pResults;
395     float* pSphere;
396     FloatArrayHelper mvp(env, mvp_ref, mvpOffset, 16);
397     FloatArrayHelper spheres(env, spheres_ref, spheresOffset, spheresCount * 4);
398     IntArrayHelper results(env, results_ref, resultsOffset, resultsCapacity);
399 
400     bool initializedOK = mvp.check() && spheres.check() && results.check();
401         if (! initializedOK) {
402         return -1;
403     }
404 
405     mvp.bind();
406     spheres.bind();
407     results.bind();
408 
409     computeFrustum(mvp.mData, frustum);
410 
411     // Cull the spheres
412 
413     pSphere = spheres.mData;
414     pResults = results.mData;
415     outputCount = 0;
416     for(int i = 0; i < spheresCount; i++, pSphere += 4) {
417         if (sphereHitsFrustum(frustum, pSphere)) {
418             if (outputCount < resultsCapacity) {
419                 *pResults++ = i;
420             }
421             outputCount++;
422         }
423     }
424     results.commitChanges();
425     return outputCount;
426 }
427 
428 /*
429  public native int visibilityTest(float[] ws, int wsOffset,
430  float[] positions, int positionsOffset,
431  char[] indices, int indicesOffset, int indexCount);
432  */
433 
434 static
util_visibilityTest(JNIEnv * env,jclass clazz,jfloatArray ws_ref,jint wsOffset,jfloatArray positions_ref,jint positionsOffset,jcharArray indices_ref,jint indicesOffset,jint indexCount)435 int util_visibilityTest(JNIEnv *env, jclass clazz,
436         jfloatArray ws_ref, jint wsOffset,
437         jfloatArray positions_ref, jint positionsOffset,
438         jcharArray indices_ref, jint indicesOffset, jint indexCount) {
439 
440     FloatArrayHelper ws(env, ws_ref, wsOffset, 16);
441     FloatArrayHelper positions(env, positions_ref, positionsOffset, 0);
442     UnsignedShortArrayHelper indices(env, indices_ref, indicesOffset, 0);
443 
444     bool checkOK = ws.check() && positions.check() && indices.check();
445     if (! checkOK) {
446         // Return value will be ignored, because an exception has been thrown.
447         return -1;
448     }
449 
450     if (indices.mLength < indexCount) {
451         env->ThrowNew(gIAEClass, "length < offset + indexCount");
452         // Return value will be ignored, because an exception has been thrown.
453         return -1;
454     }
455 
456     ws.bind();
457     positions.bind();
458     indices.bind();
459 
460     return visibilityTest(ws.mData,
461             positions.mData, positions.mLength,
462             indices.mData, indexCount);
463 }
464 
465 #define I(_i, _j) ((_j)+ 4*(_i))
466 
467 static
multiplyMM(float * r,const float * lhs,const float * rhs)468 void multiplyMM(float* r, const float* lhs, const float* rhs)
469 {
470     for (int i=0 ; i<4 ; i++) {
471         register const float rhs_i0 = rhs[ I(i,0) ];
472         register float ri0 = lhs[ I(0,0) ] * rhs_i0;
473         register float ri1 = lhs[ I(0,1) ] * rhs_i0;
474         register float ri2 = lhs[ I(0,2) ] * rhs_i0;
475         register float ri3 = lhs[ I(0,3) ] * rhs_i0;
476         for (int j=1 ; j<4 ; j++) {
477             register const float rhs_ij = rhs[ I(i,j) ];
478             ri0 += lhs[ I(j,0) ] * rhs_ij;
479             ri1 += lhs[ I(j,1) ] * rhs_ij;
480             ri2 += lhs[ I(j,2) ] * rhs_ij;
481             ri3 += lhs[ I(j,3) ] * rhs_ij;
482         }
483         r[ I(i,0) ] = ri0;
484         r[ I(i,1) ] = ri1;
485         r[ I(i,2) ] = ri2;
486         r[ I(i,3) ] = ri3;
487     }
488 }
489 
490 static
util_multiplyMM(JNIEnv * env,jclass clazz,jfloatArray result_ref,jint resultOffset,jfloatArray lhs_ref,jint lhsOffset,jfloatArray rhs_ref,jint rhsOffset)491 void util_multiplyMM(JNIEnv *env, jclass clazz,
492     jfloatArray result_ref, jint resultOffset,
493     jfloatArray lhs_ref, jint lhsOffset,
494     jfloatArray rhs_ref, jint rhsOffset) {
495 
496     FloatArrayHelper resultMat(env, result_ref, resultOffset, 16);
497     FloatArrayHelper lhs(env, lhs_ref, lhsOffset, 16);
498     FloatArrayHelper rhs(env, rhs_ref, rhsOffset, 16);
499 
500     bool checkOK = resultMat.check() && lhs.check() && rhs.check();
501 
502     if ( !checkOK ) {
503         return;
504     }
505 
506     resultMat.bind();
507     lhs.bind();
508     rhs.bind();
509 
510     multiplyMM(resultMat.mData, lhs.mData, rhs.mData);
511 
512     resultMat.commitChanges();
513 }
514 
515 static
multiplyMV(float * r,const float * lhs,const float * rhs)516 void multiplyMV(float* r, const float* lhs, const float* rhs)
517 {
518     mx4transform(rhs[0], rhs[1], rhs[2], rhs[3], lhs, r);
519 }
520 
521 static
util_multiplyMV(JNIEnv * env,jclass clazz,jfloatArray result_ref,jint resultOffset,jfloatArray lhs_ref,jint lhsOffset,jfloatArray rhs_ref,jint rhsOffset)522 void util_multiplyMV(JNIEnv *env, jclass clazz,
523     jfloatArray result_ref, jint resultOffset,
524     jfloatArray lhs_ref, jint lhsOffset,
525     jfloatArray rhs_ref, jint rhsOffset) {
526 
527     FloatArrayHelper resultV(env, result_ref, resultOffset, 4);
528     FloatArrayHelper lhs(env, lhs_ref, lhsOffset, 16);
529     FloatArrayHelper rhs(env, rhs_ref, rhsOffset, 4);
530 
531     bool checkOK = resultV.check() && lhs.check() && rhs.check();
532 
533     if ( !checkOK ) {
534         return;
535     }
536 
537     resultV.bind();
538     lhs.bind();
539     rhs.bind();
540 
541     multiplyMV(resultV.mData, lhs.mData, rhs.mData);
542 
543     resultV.commitChanges();
544 }
545 
546 // ---------------------------------------------------------------------------
547 
548 static jfieldID nativeBitmapID = 0;
549 
nativeUtilsClassInit(JNIEnv * env,jclass clazz)550 void nativeUtilsClassInit(JNIEnv *env, jclass clazz)
551 {
552     jclass bitmapClass = env->FindClass("android/graphics/Bitmap");
553     nativeBitmapID = env->GetFieldID(bitmapClass, "mNativeBitmap", "I");
554 }
555 
checkFormat(SkBitmap::Config config,int format,int type)556 static int checkFormat(SkBitmap::Config config, int format, int type)
557 {
558     switch(config) {
559         case SkBitmap::kIndex8_Config:
560             if (format == GL_PALETTE8_RGBA8_OES)
561                 return 0;
562         case SkBitmap::kARGB_8888_Config:
563         case SkBitmap::kA8_Config:
564             if (type == GL_UNSIGNED_BYTE)
565                 return 0;
566         case SkBitmap::kARGB_4444_Config:
567         case SkBitmap::kRGB_565_Config:
568             switch (type) {
569                 case GL_UNSIGNED_SHORT_4_4_4_4:
570                 case GL_UNSIGNED_SHORT_5_6_5:
571                 case GL_UNSIGNED_SHORT_5_5_5_1:
572                     return 0;
573                 case GL_UNSIGNED_BYTE:
574                     if (format == GL_LUMINANCE_ALPHA)
575                         return 0;
576             }
577             break;
578         default:
579             break;
580     }
581     return -1;
582 }
583 
getInternalFormat(SkBitmap::Config config)584 static int getInternalFormat(SkBitmap::Config config)
585 {
586     switch(config) {
587         case SkBitmap::kA8_Config:
588             return GL_ALPHA;
589         case SkBitmap::kARGB_4444_Config:
590             return GL_RGBA;
591         case SkBitmap::kARGB_8888_Config:
592             return GL_RGBA;
593         case SkBitmap::kIndex8_Config:
594             return GL_PALETTE8_RGBA8_OES;
595         case SkBitmap::kRGB_565_Config:
596             return GL_RGB;
597         default:
598             return -1;
599     }
600 }
601 
getType(SkBitmap::Config config)602 static int getType(SkBitmap::Config config)
603 {
604     switch(config) {
605         case SkBitmap::kA8_Config:
606             return GL_UNSIGNED_BYTE;
607         case SkBitmap::kARGB_4444_Config:
608             return GL_UNSIGNED_SHORT_4_4_4_4;
609         case SkBitmap::kARGB_8888_Config:
610             return GL_UNSIGNED_BYTE;
611         case SkBitmap::kIndex8_Config:
612             return -1; // No type for compressed data.
613         case SkBitmap::kRGB_565_Config:
614             return GL_UNSIGNED_SHORT_5_6_5;
615         default:
616             return -1;
617     }
618 }
619 
util_getInternalFormat(JNIEnv * env,jclass clazz,jobject jbitmap)620 static jint util_getInternalFormat(JNIEnv *env, jclass clazz,
621         jobject jbitmap)
622 {
623     SkBitmap const * nativeBitmap =
624             (SkBitmap const *)env->GetIntField(jbitmap, nativeBitmapID);
625     const SkBitmap& bitmap(*nativeBitmap);
626     SkBitmap::Config config = bitmap.getConfig();
627     return getInternalFormat(config);
628 }
629 
util_getType(JNIEnv * env,jclass clazz,jobject jbitmap)630 static jint util_getType(JNIEnv *env, jclass clazz,
631         jobject jbitmap)
632 {
633     SkBitmap const * nativeBitmap =
634             (SkBitmap const *)env->GetIntField(jbitmap, nativeBitmapID);
635     const SkBitmap& bitmap(*nativeBitmap);
636     SkBitmap::Config config = bitmap.getConfig();
637     return getType(config);
638 }
639 
util_texImage2D(JNIEnv * env,jclass clazz,jint target,jint level,jint internalformat,jobject jbitmap,jint type,jint border)640 static jint util_texImage2D(JNIEnv *env, jclass clazz,
641         jint target, jint level, jint internalformat,
642         jobject jbitmap, jint type, jint border)
643 {
644     SkBitmap const * nativeBitmap =
645             (SkBitmap const *)env->GetIntField(jbitmap, nativeBitmapID);
646     const SkBitmap& bitmap(*nativeBitmap);
647     SkBitmap::Config config = bitmap.getConfig();
648     if (internalformat < 0) {
649         internalformat = getInternalFormat(config);
650     }
651     if (type < 0) {
652         type = getType(config);
653     }
654     int err = checkFormat(config, internalformat, type);
655     if (err)
656         return err;
657     bitmap.lockPixels();
658     const int w = bitmap.width();
659     const int h = bitmap.height();
660     const void* p = bitmap.getPixels();
661     if (internalformat == GL_PALETTE8_RGBA8_OES) {
662         if (sizeof(SkPMColor) != sizeof(uint32_t)) {
663             err = -1;
664             goto error;
665         }
666         const size_t size = bitmap.getSize();
667         const size_t palette_size = 256*sizeof(SkPMColor);
668         const size_t imageSize = size + palette_size;
669         void* const data = malloc(imageSize);
670         if (data) {
671             void* const pixels = (char*)data + palette_size;
672             SkColorTable* ctable = bitmap.getColorTable();
673             memcpy(data, ctable->lockColors(), ctable->count() * sizeof(SkPMColor));
674             memcpy(pixels, p, size);
675             ctable->unlockColors(false);
676             glCompressedTexImage2D(target, level, internalformat, w, h, border, imageSize, data);
677             free(data);
678         } else {
679             err = -1;
680         }
681     } else {
682         glTexImage2D(target, level, internalformat, w, h, border, internalformat, type, p);
683     }
684 error:
685     bitmap.unlockPixels();
686     return err;
687 }
688 
util_texSubImage2D(JNIEnv * env,jclass clazz,jint target,jint level,jint xoffset,jint yoffset,jobject jbitmap,jint format,jint type)689 static jint util_texSubImage2D(JNIEnv *env, jclass clazz,
690         jint target, jint level, jint xoffset, jint yoffset,
691         jobject jbitmap, jint format, jint type)
692 {
693     SkBitmap const * nativeBitmap =
694             (SkBitmap const *)env->GetIntField(jbitmap, nativeBitmapID);
695     const SkBitmap& bitmap(*nativeBitmap);
696     SkBitmap::Config config = bitmap.getConfig();
697     if (format < 0) {
698         format = getInternalFormat(config);
699         if (format == GL_PALETTE8_RGBA8_OES)
700             return -1; // glCompressedTexSubImage2D() not supported
701     }
702     int err = checkFormat(config, format, type);
703     if (err)
704         return err;
705     bitmap.lockPixels();
706     const int w = bitmap.width();
707     const int h = bitmap.height();
708     const void* p = bitmap.getPixels();
709     glTexSubImage2D(target, level, xoffset, yoffset, w, h, format, type, p);
710     bitmap.unlockPixels();
711     return 0;
712 }
713 
714 /*
715  * JNI registration
716  */
717 
718 static void
lookupClasses(JNIEnv * env)719 lookupClasses(JNIEnv* env) {
720     gIAEClass = (jclass) env->NewGlobalRef(
721             env->FindClass("java/lang/IllegalArgumentException"));
722     gUOEClass = (jclass) env->NewGlobalRef(
723             env->FindClass("java/lang/UnsupportedOperationException"));
724 }
725 
726 static JNINativeMethod gMatrixMethods[] = {
727     { "multiplyMM", "([FI[FI[FI)V", (void*)util_multiplyMM },
728     { "multiplyMV", "([FI[FI[FI)V", (void*)util_multiplyMV },
729 };
730 
731 static JNINativeMethod gVisiblityMethods[] = {
732     { "computeBoundingSphere", "([FII[FI)V", (void*)util_computeBoundingSphere },
733     { "frustumCullSpheres", "([FI[FII[III)I", (void*)util_frustumCullSpheres },
734     { "visibilityTest", "([FI[FI[CII)I", (void*)util_visibilityTest },
735 };
736 
737 static JNINativeMethod gUtilsMethods[] = {
738     {"nativeClassInit", "()V",                          (void*)nativeUtilsClassInit },
739     { "native_getInternalFormat", "(Landroid/graphics/Bitmap;)I", (void*) util_getInternalFormat },
740     { "native_getType", "(Landroid/graphics/Bitmap;)I", (void*) util_getType },
741     { "native_texImage2D", "(IIILandroid/graphics/Bitmap;II)I", (void*)util_texImage2D },
742     { "native_texSubImage2D", "(IIIILandroid/graphics/Bitmap;II)I", (void*)util_texSubImage2D },
743 };
744 
745 typedef struct _ClassRegistrationInfo {
746     const char* classPath;
747     JNINativeMethod* methods;
748     size_t methodCount;
749 } ClassRegistrationInfo;
750 
751 static ClassRegistrationInfo gClasses[] = {
752         {"android/opengl/Matrix", gMatrixMethods, NELEM(gMatrixMethods)},
753         {"android/opengl/Visibility", gVisiblityMethods, NELEM(gVisiblityMethods)},
754         {"android/opengl/GLUtils", gUtilsMethods, NELEM(gUtilsMethods)},
755 };
756 
register_android_opengl_classes(JNIEnv * env)757 int register_android_opengl_classes(JNIEnv* env)
758 {
759     lookupClasses(env);
760     int result = 0;
761     for (int i = 0; i < NELEM(gClasses); i++) {
762         ClassRegistrationInfo* cri = &gClasses[i];
763         result = AndroidRuntime::registerNativeMethods(env,
764                 cri->classPath, cri->methods, cri->methodCount);
765         if (result < 0) {
766             LOGE("Failed to register %s: %d", cri->classPath, result);
767             break;
768         }
769     }
770     return result;
771 }
772 
773 } // namespace android
774 
775