rsScriptC_Lib.cpp revision 49f5ae32fd9d0bec27a1da8b82b511341e3649ed
1/*
2 * Copyright (C) 2009 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 "rsContext.h"
18#include "rsScriptC.h"
19#include "rsMatrix.h"
20
21#include "utils/Timers.h"
22
23#include <time.h>
24
25using namespace android;
26using namespace android::renderscript;
27
28#define GET_TLS()  Context::ScriptTLSStruct * tls = \
29    (Context::ScriptTLSStruct *)pthread_getspecific(Context::gThreadTLSKey); \
30    Context * rsc = tls->mContext; \
31    ScriptC * sc = (ScriptC *) tls->mScript
32
33
34//////////////////////////////////////////////////////////////////////////////
35// Math routines
36//////////////////////////////////////////////////////////////////////////////
37
38#if 0
39static float SC_sinf_fast(float x) {
40    const float A =   1.0f / (2.0f * M_PI);
41    const float B = -16.0f;
42    const float C =   8.0f;
43
44    // scale angle for easy argument reduction
45    x *= A;
46
47    if (fabsf(x) >= 0.5f) {
48        // argument reduction
49        x = x - ceilf(x + 0.5f) + 1.0f;
50    }
51
52    const float y = B * x * fabsf(x) + C * x;
53    return 0.2215f * (y * fabsf(y) - y) + y;
54}
55
56static float SC_cosf_fast(float x) {
57    x += float(M_PI / 2);
58
59    const float A =   1.0f / (2.0f * M_PI);
60    const float B = -16.0f;
61    const float C =   8.0f;
62
63    // scale angle for easy argument reduction
64    x *= A;
65
66    if (fabsf(x) >= 0.5f) {
67        // argument reduction
68        x = x - ceilf(x + 0.5f) + 1.0f;
69    }
70
71    const float y = B * x * fabsf(x) + C * x;
72    return 0.2215f * (y * fabsf(y) - y) + y;
73}
74#endif
75
76static float SC_randf(float max) {
77    float r = (float)rand();
78    r *= max;
79    return r / RAND_MAX;
80}
81
82static float SC_randf2(float min, float max) {
83    float r = (float)rand();
84    r = r * (max - min) + min;
85    return r / RAND_MAX;
86}
87
88static int SC_randi(int max) {
89    return (int)SC_randf(max);
90}
91
92static int SC_randi2(int min, int max) {
93    return (int)SC_randf2(min, max);
94}
95
96static float SC_frac(float v) {
97    int i = (int)floor(v);
98    return fmin(v - i, 0x1.fffffep-1f);
99}
100
101//////////////////////////////////////////////////////////////////////////////
102// Time routines
103//////////////////////////////////////////////////////////////////////////////
104
105static time_t SC_time(time_t *timer) {
106    GET_TLS();
107    return time(timer);
108}
109
110static tm* SC_localtime(tm *local, time_t *timer) {
111    GET_TLS();
112    if (!local) {
113      return NULL;
114    }
115
116    // The native localtime function is not thread-safe, so we
117    // have to apply locking for proper behavior in RenderScript.
118    pthread_mutex_lock(&rsc->gLibMutex);
119    tm *tmp = localtime(timer);
120    memcpy(local, tmp, sizeof(*tmp));
121    pthread_mutex_unlock(&rsc->gLibMutex);
122    return local;
123}
124
125static int64_t SC_uptimeMillis() {
126    return nanoseconds_to_milliseconds(systemTime(SYSTEM_TIME_MONOTONIC));
127}
128
129static int64_t SC_uptimeNanos() {
130    return systemTime(SYSTEM_TIME_MONOTONIC);
131}
132
133static float SC_getDt() {
134    GET_TLS();
135    int64_t l = sc->mEnviroment.mLastDtTime;
136    sc->mEnviroment.mLastDtTime = systemTime(SYSTEM_TIME_MONOTONIC);
137    return ((float)(sc->mEnviroment.mLastDtTime - l)) / 1.0e9;
138}
139
140//////////////////////////////////////////////////////////////////////////////
141//
142//////////////////////////////////////////////////////////////////////////////
143
144static uint32_t SC_allocGetDimX(RsAllocation va) {
145    const Allocation *a = static_cast<const Allocation *>(va);
146    CHECK_OBJ(a);
147    //LOGE("SC_allocGetDimX a=%p  type=%p", a, a->getType());
148    return a->getType()->getDimX();
149}
150
151static uint32_t SC_allocGetDimY(RsAllocation va) {
152    const Allocation *a = static_cast<const Allocation *>(va);
153    CHECK_OBJ(a);
154    return a->getType()->getDimY();
155}
156
157static uint32_t SC_allocGetDimZ(RsAllocation va) {
158    const Allocation *a = static_cast<const Allocation *>(va);
159    CHECK_OBJ(a);
160    return a->getType()->getDimZ();
161}
162
163static uint32_t SC_allocGetDimLOD(RsAllocation va) {
164    const Allocation *a = static_cast<const Allocation *>(va);
165    CHECK_OBJ(a);
166    return a->getType()->getDimLOD();
167}
168
169static uint32_t SC_allocGetDimFaces(RsAllocation va) {
170    const Allocation *a = static_cast<const Allocation *>(va);
171    CHECK_OBJ(a);
172    return a->getType()->getDimFaces();
173}
174
175static const void * SC_getElementAtX(RsAllocation va, uint32_t x) {
176    const Allocation *a = static_cast<const Allocation *>(va);
177    CHECK_OBJ(a);
178    const Type *t = a->getType();
179    CHECK_OBJ(t);
180    const uint8_t *p = (const uint8_t *)a->getPtr();
181    return &p[t->getElementSizeBytes() * x];
182}
183
184static const void * SC_getElementAtXY(RsAllocation va, uint32_t x, uint32_t y) {
185    const Allocation *a = static_cast<const Allocation *>(va);
186    CHECK_OBJ(a);
187    const Type *t = a->getType();
188    CHECK_OBJ(t);
189    const uint8_t *p = (const uint8_t *)a->getPtr();
190    return &p[t->getElementSizeBytes() * (x + y*t->getDimX())];
191}
192
193static const void * SC_getElementAtXYZ(RsAllocation va, uint32_t x, uint32_t y, uint32_t z) {
194    const Allocation *a = static_cast<const Allocation *>(va);
195    CHECK_OBJ(a);
196    const Type *t = a->getType();
197    CHECK_OBJ(t);
198    const uint8_t *p = (const uint8_t *)a->getPtr();
199    return &p[t->getElementSizeBytes() * (x + y*t->getDimX())];
200}
201
202static void SC_setObject(void **vdst, void * vsrc) {
203    //LOGE("SC_setObject  %p,%p  %p", vdst, *vdst, vsrc);
204    if (vsrc) {
205        CHECK_OBJ(vsrc);
206        static_cast<ObjectBase *>(vsrc)->incSysRef();
207    }
208    if (vdst[0]) {
209        CHECK_OBJ(vdst[0]);
210        static_cast<ObjectBase *>(vdst[0])->decSysRef();
211    }
212    *vdst = vsrc;
213    //LOGE("SC_setObject *");
214}
215
216static void SC_clearObject(void **vdst) {
217    //LOGE("SC_clearObject  %p,%p", vdst, *vdst);
218    if (vdst[0]) {
219        CHECK_OBJ(vdst[0]);
220        static_cast<ObjectBase *>(vdst[0])->decSysRef();
221    }
222    *vdst = NULL;
223    //LOGE("SC_clearObject *");
224}
225
226static bool SC_isObject(RsAllocation vsrc) {
227    return vsrc != NULL;
228}
229
230static void SC_debugF(const char *s, float f) {
231    LOGD("%s %f, 0x%08x", s, f, *((int *) (&f)));
232}
233static void SC_debugFv2(const char *s, float f1, float f2) {
234    LOGD("%s {%f, %f}", s, f1, f2);
235}
236static void SC_debugFv3(const char *s, float f1, float f2, float f3) {
237    LOGD("%s {%f, %f, %f}", s, f1, f2, f3);
238}
239static void SC_debugFv4(const char *s, float f1, float f2, float f3, float f4) {
240    LOGD("%s {%f, %f, %f, %f}", s, f1, f2, f3, f4);
241}
242static void SC_debugD(const char *s, double d) {
243    LOGD("%s %f, 0x%08llx", s, d, *((long long *) (&d)));
244}
245static void SC_debugFM4v4(const char *s, const float *f) {
246    LOGD("%s {%f, %f, %f, %f", s, f[0], f[4], f[8], f[12]);
247    LOGD("%s  %f, %f, %f, %f", s, f[1], f[5], f[9], f[13]);
248    LOGD("%s  %f, %f, %f, %f", s, f[2], f[6], f[10], f[14]);
249    LOGD("%s  %f, %f, %f, %f}", s, f[3], f[7], f[11], f[15]);
250}
251static void SC_debugFM3v3(const char *s, const float *f) {
252    LOGD("%s {%f, %f, %f", s, f[0], f[3], f[6]);
253    LOGD("%s  %f, %f, %f", s, f[1], f[4], f[7]);
254    LOGD("%s  %f, %f, %f}",s, f[2], f[5], f[8]);
255}
256static void SC_debugFM2v2(const char *s, const float *f) {
257    LOGD("%s {%f, %f", s, f[0], f[2]);
258    LOGD("%s  %f, %f}",s, f[1], f[3]);
259}
260
261static void SC_debugI32(const char *s, int32_t i) {
262    LOGD("%s %i  0x%x", s, i, i);
263}
264static void SC_debugU32(const char *s, uint32_t i) {
265    LOGD("%s %u  0x%x", s, i, i);
266}
267static void SC_debugLL64(const char *s, long long ll) {
268    LOGD("%s %lld  0x%llx", s, ll, ll);
269}
270static void SC_debugULL64(const char *s, unsigned long long ll) {
271    LOGD("%s %llu  0x%llx", s, ll, ll);
272}
273
274static void SC_debugP(const char *s, const void *p) {
275    LOGD("%s %p", s, p);
276}
277
278static uint32_t SC_toClient2(int cmdID, void *data, int len) {
279    GET_TLS();
280    //LOGE("SC_toClient %i %i %i", cmdID, len);
281    return rsc->sendMessageToClient(data, RS_MESSAGE_TO_CLIENT_USER, cmdID, len, false);
282}
283
284static uint32_t SC_toClient(int cmdID) {
285    GET_TLS();
286    //LOGE("SC_toClient %i", cmdID);
287    return rsc->sendMessageToClient(NULL, RS_MESSAGE_TO_CLIENT_USER, cmdID, 0, false);
288}
289
290static uint32_t SC_toClientBlocking2(int cmdID, void *data, int len) {
291    GET_TLS();
292    //LOGE("SC_toClientBlocking %i %i", cmdID, len);
293    return rsc->sendMessageToClient(data, RS_MESSAGE_TO_CLIENT_USER, cmdID, len, true);
294}
295
296static uint32_t SC_toClientBlocking(int cmdID) {
297    GET_TLS();
298    //LOGE("SC_toClientBlocking %i", cmdID);
299    return rsc->sendMessageToClient(NULL, RS_MESSAGE_TO_CLIENT_USER, cmdID, 0, true);
300}
301
302int SC_divsi3(int a, int b) {
303    return a / b;
304}
305
306int SC_modsi3(int a, int b) {
307    return a % b;
308}
309
310unsigned int SC_udivsi3(unsigned int a, unsigned int b) {
311    return a / b;
312}
313
314unsigned int SC_umodsi3(unsigned int a, unsigned int b) {
315    return a % b;
316}
317
318int SC_getAllocation(const void *ptr) {
319    GET_TLS();
320    const Allocation *alloc = sc->ptrToAllocation(ptr);
321    return (int)alloc;
322}
323
324void SC_allocationMarkDirty(RsAllocation a) {
325    Allocation *alloc = static_cast<Allocation *>(a);
326    alloc->sendDirty();
327}
328
329void SC_ForEach(RsScript vs,
330                RsAllocation vin,
331                RsAllocation vout,
332                const void *usr) {
333    GET_TLS();
334    const Allocation *ain = static_cast<const Allocation *>(vin);
335    Allocation *aout = static_cast<Allocation *>(vout);
336    Script *s = static_cast<Script *>(vs);
337    s->runForEach(rsc, ain, aout, usr);
338}
339
340void SC_ForEach2(RsScript vs,
341                RsAllocation vin,
342                RsAllocation vout,
343                const void *usr,
344                const RsScriptCall *call) {
345    GET_TLS();
346    const Allocation *ain = static_cast<const Allocation *>(vin);
347    Allocation *aout = static_cast<Allocation *>(vout);
348    Script *s = static_cast<Script *>(vs);
349    s->runForEach(rsc, ain, aout, usr, call);
350}
351
352
353//////////////////////////////////////////////////////////////////////////////
354// Heavy math functions
355//////////////////////////////////////////////////////////////////////////////
356
357typedef struct {
358    float m[16];
359} rs_matrix4x4;
360
361typedef struct {
362    float m[9];
363} rs_matrix3x3;
364
365typedef struct {
366    float m[4];
367} rs_matrix2x2;
368
369static inline void
370rsMatrixSet(rs_matrix4x4 *m, uint32_t row, uint32_t col, float v) {
371    m->m[row * 4 + col] = v;
372}
373
374static inline float
375rsMatrixGet(const rs_matrix4x4 *m, uint32_t row, uint32_t col) {
376    return m->m[row * 4 + col];
377}
378
379static inline void
380rsMatrixSet(rs_matrix3x3 *m, uint32_t row, uint32_t col, float v) {
381    m->m[row * 3 + col] = v;
382}
383
384static inline float
385rsMatrixGet(const rs_matrix3x3 *m, uint32_t row, uint32_t col) {
386    return m->m[row * 3 + col];
387}
388
389static inline void
390rsMatrixSet(rs_matrix2x2 *m, uint32_t row, uint32_t col, float v) {
391    m->m[row * 2 + col] = v;
392}
393
394static inline float
395rsMatrixGet(const rs_matrix2x2 *m, uint32_t row, uint32_t col) {
396    return m->m[row * 2 + col];
397}
398
399
400static void SC_MatrixLoadIdentity_4x4(rs_matrix4x4 *m) {
401    m->m[0] = 1.f;
402    m->m[1] = 0.f;
403    m->m[2] = 0.f;
404    m->m[3] = 0.f;
405    m->m[4] = 0.f;
406    m->m[5] = 1.f;
407    m->m[6] = 0.f;
408    m->m[7] = 0.f;
409    m->m[8] = 0.f;
410    m->m[9] = 0.f;
411    m->m[10] = 1.f;
412    m->m[11] = 0.f;
413    m->m[12] = 0.f;
414    m->m[13] = 0.f;
415    m->m[14] = 0.f;
416    m->m[15] = 1.f;
417}
418
419static void SC_MatrixLoadIdentity_3x3(rs_matrix3x3 *m) {
420    m->m[0] = 1.f;
421    m->m[1] = 0.f;
422    m->m[2] = 0.f;
423    m->m[3] = 0.f;
424    m->m[4] = 1.f;
425    m->m[5] = 0.f;
426    m->m[6] = 0.f;
427    m->m[7] = 0.f;
428    m->m[8] = 1.f;
429}
430
431static void SC_MatrixLoadIdentity_2x2(rs_matrix2x2 *m) {
432    m->m[0] = 1.f;
433    m->m[1] = 0.f;
434    m->m[2] = 0.f;
435    m->m[3] = 1.f;
436}
437
438static void SC_MatrixLoad_4x4_f(rs_matrix4x4 *m, const float *v) {
439    m->m[0] = v[0];
440    m->m[1] = v[1];
441    m->m[2] = v[2];
442    m->m[3] = v[3];
443    m->m[4] = v[4];
444    m->m[5] = v[5];
445    m->m[6] = v[6];
446    m->m[7] = v[7];
447    m->m[8] = v[8];
448    m->m[9] = v[9];
449    m->m[10] = v[10];
450    m->m[11] = v[11];
451    m->m[12] = v[12];
452    m->m[13] = v[13];
453    m->m[14] = v[14];
454    m->m[15] = v[15];
455}
456
457static void SC_MatrixLoad_3x3_f(rs_matrix3x3 *m, const float *v) {
458    m->m[0] = v[0];
459    m->m[1] = v[1];
460    m->m[2] = v[2];
461    m->m[3] = v[3];
462    m->m[4] = v[4];
463    m->m[5] = v[5];
464    m->m[6] = v[6];
465    m->m[7] = v[7];
466    m->m[8] = v[8];
467}
468
469static void SC_MatrixLoad_2x2_f(rs_matrix2x2 *m, const float *v) {
470    m->m[0] = v[0];
471    m->m[1] = v[1];
472    m->m[2] = v[2];
473    m->m[3] = v[3];
474}
475
476static void SC_MatrixLoad_4x4_4x4(rs_matrix4x4 *m, const rs_matrix4x4 *v) {
477    m->m[0] = v->m[0];
478    m->m[1] = v->m[1];
479    m->m[2] = v->m[2];
480    m->m[3] = v->m[3];
481    m->m[4] = v->m[4];
482    m->m[5] = v->m[5];
483    m->m[6] = v->m[6];
484    m->m[7] = v->m[7];
485    m->m[8] = v->m[8];
486    m->m[9] = v->m[9];
487    m->m[10] = v->m[10];
488    m->m[11] = v->m[11];
489    m->m[12] = v->m[12];
490    m->m[13] = v->m[13];
491    m->m[14] = v->m[14];
492    m->m[15] = v->m[15];
493}
494
495static void SC_MatrixLoad_4x4_3x3(rs_matrix4x4 *m, const rs_matrix3x3 *v) {
496    m->m[0] = v->m[0];
497    m->m[1] = v->m[1];
498    m->m[2] = v->m[2];
499    m->m[3] = 0.f;
500    m->m[4] = v->m[3];
501    m->m[5] = v->m[4];
502    m->m[6] = v->m[5];
503    m->m[7] = 0.f;
504    m->m[8] = v->m[6];
505    m->m[9] = v->m[7];
506    m->m[10] = v->m[8];
507    m->m[11] = 0.f;
508    m->m[12] = 0.f;
509    m->m[13] = 0.f;
510    m->m[14] = 0.f;
511    m->m[15] = 1.f;
512}
513
514static void SC_MatrixLoad_4x4_2x2(rs_matrix4x4 *m, const rs_matrix2x2 *v) {
515    m->m[0] = v->m[0];
516    m->m[1] = v->m[1];
517    m->m[2] = 0.f;
518    m->m[3] = 0.f;
519    m->m[4] = v->m[2];
520    m->m[5] = v->m[3];
521    m->m[6] = 0.f;
522    m->m[7] = 0.f;
523    m->m[8] = 0.f;
524    m->m[9] = 0.f;
525    m->m[10] = 1.f;
526    m->m[11] = 0.f;
527    m->m[12] = 0.f;
528    m->m[13] = 0.f;
529    m->m[14] = 0.f;
530    m->m[15] = 1.f;
531}
532
533static void SC_MatrixLoad_3x3_3x3(rs_matrix3x3 *m, const rs_matrix3x3 *v) {
534    m->m[0] = v->m[0];
535    m->m[1] = v->m[1];
536    m->m[2] = v->m[2];
537    m->m[3] = v->m[3];
538    m->m[4] = v->m[4];
539    m->m[5] = v->m[5];
540    m->m[6] = v->m[6];
541    m->m[7] = v->m[7];
542    m->m[8] = v->m[8];
543}
544
545static void SC_MatrixLoad_2x2_2x2(rs_matrix2x2 *m, const rs_matrix2x2 *v) {
546    m->m[0] = v->m[0];
547    m->m[1] = v->m[1];
548    m->m[2] = v->m[2];
549    m->m[3] = v->m[3];
550}
551
552static void SC_MatrixLoadRotate(rs_matrix4x4 *m, float rot, float x, float y, float z) {
553    float c, s;
554    m->m[3] = 0;
555    m->m[7] = 0;
556    m->m[11]= 0;
557    m->m[12]= 0;
558    m->m[13]= 0;
559    m->m[14]= 0;
560    m->m[15]= 1;
561    rot *= (float)(M_PI / 180.0f);
562    c = cos(rot);
563    s = sin(rot);
564
565    const float len = x*x + y*y + z*z;
566    if (len != 1) {
567        const float recipLen = 1.f / sqrt(len);
568        x *= recipLen;
569        y *= recipLen;
570        z *= recipLen;
571    }
572    const float nc = 1.0f - c;
573    const float xy = x * y;
574    const float yz = y * z;
575    const float zx = z * x;
576    const float xs = x * s;
577    const float ys = y * s;
578    const float zs = z * s;
579    m->m[ 0] = x*x*nc +  c;
580    m->m[ 4] =  xy*nc - zs;
581    m->m[ 8] =  zx*nc + ys;
582    m->m[ 1] =  xy*nc + zs;
583    m->m[ 5] = y*y*nc +  c;
584    m->m[ 9] =  yz*nc - xs;
585    m->m[ 2] =  zx*nc - ys;
586    m->m[ 6] =  yz*nc + xs;
587    m->m[10] = z*z*nc +  c;
588}
589
590static void SC_MatrixLoadScale(rs_matrix4x4 *m, float x, float y, float z) {
591    SC_MatrixLoadIdentity_4x4(m);
592    m->m[0] = x;
593    m->m[5] = y;
594    m->m[10] = z;
595}
596
597static void SC_MatrixLoadTranslate(rs_matrix4x4 *m, float x, float y, float z) {
598    SC_MatrixLoadIdentity_4x4(m);
599    m->m[12] = x;
600    m->m[13] = y;
601    m->m[14] = z;
602}
603
604static void SC_MatrixLoadMultiply_4x4_4x4_4x4(rs_matrix4x4 *m, const rs_matrix4x4 *lhs, const rs_matrix4x4 *rhs) {
605    for (int i=0 ; i<4 ; i++) {
606        float ri0 = 0;
607        float ri1 = 0;
608        float ri2 = 0;
609        float ri3 = 0;
610        for (int j=0 ; j<4 ; j++) {
611            const float rhs_ij = rsMatrixGet(rhs, i,j);
612            ri0 += rsMatrixGet(lhs, j, 0) * rhs_ij;
613            ri1 += rsMatrixGet(lhs, j, 1) * rhs_ij;
614            ri2 += rsMatrixGet(lhs, j, 2) * rhs_ij;
615            ri3 += rsMatrixGet(lhs, j, 3) * rhs_ij;
616        }
617        rsMatrixSet(m, i, 0, ri0);
618        rsMatrixSet(m, i, 1, ri1);
619        rsMatrixSet(m, i, 2, ri2);
620        rsMatrixSet(m, i, 3, ri3);
621    }
622}
623
624static void SC_MatrixMultiply_4x4_4x4(rs_matrix4x4 *m, const rs_matrix4x4 *rhs) {
625    rs_matrix4x4 mt;
626    SC_MatrixLoadMultiply_4x4_4x4_4x4(&mt, m, rhs);
627    SC_MatrixLoad_4x4_4x4(m, &mt);
628}
629
630static void SC_MatrixLoadMultiply_3x3_3x3_3x3(rs_matrix3x3 *m, const rs_matrix3x3 *lhs, const rs_matrix3x3 *rhs) {
631    for (int i=0 ; i<3 ; i++) {
632        float ri0 = 0;
633        float ri1 = 0;
634        float ri2 = 0;
635        for (int j=0 ; j<3 ; j++) {
636            const float rhs_ij = rsMatrixGet(rhs, i,j);
637            ri0 += rsMatrixGet(lhs, j, 0) * rhs_ij;
638            ri1 += rsMatrixGet(lhs, j, 1) * rhs_ij;
639            ri2 += rsMatrixGet(lhs, j, 2) * rhs_ij;
640        }
641        rsMatrixSet(m, i, 0, ri0);
642        rsMatrixSet(m, i, 1, ri1);
643        rsMatrixSet(m, i, 2, ri2);
644    }
645}
646
647static void SC_MatrixMultiply_3x3_3x3(rs_matrix3x3 *m, const rs_matrix3x3 *rhs) {
648    rs_matrix3x3 mt;
649    SC_MatrixLoadMultiply_3x3_3x3_3x3(&mt, m, rhs);
650    SC_MatrixLoad_3x3_3x3(m, &mt);
651}
652
653static void SC_MatrixLoadMultiply_2x2_2x2_2x2(rs_matrix2x2 *m, const rs_matrix2x2 *lhs, const rs_matrix2x2 *rhs) {
654    for (int i=0 ; i<2 ; i++) {
655        float ri0 = 0;
656        float ri1 = 0;
657        for (int j=0 ; j<2 ; j++) {
658            const float rhs_ij = rsMatrixGet(rhs, i,j);
659            ri0 += rsMatrixGet(lhs, j, 0) * rhs_ij;
660            ri1 += rsMatrixGet(lhs, j, 1) * rhs_ij;
661        }
662        rsMatrixSet(m, i, 0, ri0);
663        rsMatrixSet(m, i, 1, ri1);
664    }
665}
666
667static void SC_MatrixMultiply_2x2_2x2(rs_matrix2x2 *m, const rs_matrix2x2 *rhs) {
668    rs_matrix2x2 mt;
669    SC_MatrixLoadMultiply_2x2_2x2_2x2(&mt, m, rhs);
670    SC_MatrixLoad_2x2_2x2(m, &mt);
671}
672
673static void SC_MatrixRotate(rs_matrix4x4 *m, float rot, float x, float y, float z) {
674    rs_matrix4x4 m1;
675    SC_MatrixLoadRotate(&m1, rot, x, y, z);
676    SC_MatrixMultiply_4x4_4x4(m, &m1);
677}
678
679static void SC_MatrixScale(rs_matrix4x4 *m, float x, float y, float z) {
680    rs_matrix4x4 m1;
681    SC_MatrixLoadScale(&m1, x, y, z);
682    SC_MatrixMultiply_4x4_4x4(m, &m1);
683}
684
685static void SC_MatrixTranslate(rs_matrix4x4 *m, float x, float y, float z) {
686    rs_matrix4x4 m1;
687    SC_MatrixLoadTranslate(&m1, x, y, z);
688    SC_MatrixMultiply_4x4_4x4(m, &m1);
689}
690
691static void SC_MatrixLoadOrtho(rs_matrix4x4 *m, float left, float right, float bottom, float top, float near, float far) {
692    SC_MatrixLoadIdentity_4x4(m);
693    m->m[0] = 2.f / (right - left);
694    m->m[5] = 2.f / (top - bottom);
695    m->m[10]= -2.f / (far - near);
696    m->m[12]= -(right + left) / (right - left);
697    m->m[13]= -(top + bottom) / (top - bottom);
698    m->m[14]= -(far + near) / (far - near);
699}
700
701static void SC_MatrixLoadFrustum(rs_matrix4x4 *m, float left, float right, float bottom, float top, float near, float far) {
702    SC_MatrixLoadIdentity_4x4(m);
703    m->m[0] = 2.f * near / (right - left);
704    m->m[5] = 2.f * near / (top - bottom);
705    m->m[8] = (right + left) / (right - left);
706    m->m[9] = (top + bottom) / (top - bottom);
707    m->m[10]= -(far + near) / (far - near);
708    m->m[11]= -1.f;
709    m->m[14]= -2.f * far * near / (far - near);
710    m->m[15]= 0.f;
711}
712
713static void SC_MatrixLoadPerspective(rs_matrix4x4* m, float fovy, float aspect, float near, float far) {
714    float top = near * tan((float) (fovy * M_PI / 360.0f));
715    float bottom = -top;
716    float left = bottom * aspect;
717    float right = top * aspect;
718    SC_MatrixLoadFrustum(m, left, right, bottom, top, near, far);
719}
720
721
722// Returns true if the matrix was successfully inversed
723static bool SC_MatrixInverse_4x4(rs_matrix4x4 *m) {
724    rs_matrix4x4 result;
725
726    int i, j;
727    for (i = 0; i < 4; ++i) {
728        for (j = 0; j < 4; ++j) {
729            // computeCofactor for int i, int j
730            int c0 = (i+1) % 4;
731            int c1 = (i+2) % 4;
732            int c2 = (i+3) % 4;
733            int r0 = (j+1) % 4;
734            int r1 = (j+2) % 4;
735            int r2 = (j+3) % 4;
736
737            float minor = (m->m[c0 + 4*r0] * (m->m[c1 + 4*r1] * m->m[c2 + 4*r2] - m->m[c1 + 4*r2] * m->m[c2 + 4*r1]))
738                         - (m->m[c0 + 4*r1] * (m->m[c1 + 4*r0] * m->m[c2 + 4*r2] - m->m[c1 + 4*r2] * m->m[c2 + 4*r0]))
739                         + (m->m[c0 + 4*r2] * (m->m[c1 + 4*r0] * m->m[c2 + 4*r1] - m->m[c1 + 4*r1] * m->m[c2 + 4*r0]));
740
741            float cofactor = (i+j) & 1 ? -minor : minor;
742
743            result.m[4*i + j] = cofactor;
744        }
745    }
746
747    // Dot product of 0th column of source and 0th row of result
748    float det = m->m[0]*result.m[0] + m->m[4]*result.m[1] +
749                 m->m[8]*result.m[2] + m->m[12]*result.m[3];
750
751    if (fabs(det) < 1e-6) {
752        return false;
753    }
754
755    det = 1.0f / det;
756    for (i = 0; i < 16; ++i) {
757        m->m[i] = result.m[i] * det;
758    }
759
760    return true;
761}
762
763// Returns true if the matrix was successfully inversed
764static bool SC_MatrixInverseTranspose_4x4(rs_matrix4x4 *m) {
765    rs_matrix4x4 result;
766
767    int i, j;
768    for (i = 0; i < 4; ++i) {
769        for (j = 0; j < 4; ++j) {
770            // computeCofactor for int i, int j
771            int c0 = (i+1) % 4;
772            int c1 = (i+2) % 4;
773            int c2 = (i+3) % 4;
774            int r0 = (j+1) % 4;
775            int r1 = (j+2) % 4;
776            int r2 = (j+3) % 4;
777
778            float minor = (m->m[c0 + 4*r0] * (m->m[c1 + 4*r1] * m->m[c2 + 4*r2] - m->m[c1 + 4*r2] * m->m[c2 + 4*r1]))
779                         - (m->m[c0 + 4*r1] * (m->m[c1 + 4*r0] * m->m[c2 + 4*r2] - m->m[c1 + 4*r2] * m->m[c2 + 4*r0]))
780                         + (m->m[c0 + 4*r2] * (m->m[c1 + 4*r0] * m->m[c2 + 4*r1] - m->m[c1 + 4*r1] * m->m[c2 + 4*r0]));
781
782            float cofactor = (i+j) & 1 ? -minor : minor;
783
784            result.m[4*j + i] = cofactor;
785        }
786    }
787
788    // Dot product of 0th column of source and 0th column of result
789    float det = m->m[0]*result.m[0] + m->m[4]*result.m[4] +
790                 m->m[8]*result.m[8] + m->m[12]*result.m[12];
791
792    if (fabs(det) < 1e-6) {
793        return false;
794    }
795
796    det = 1.0f / det;
797    for (i = 0; i < 16; ++i) {
798        m->m[i] = result.m[i] * det;
799    }
800
801    return true;
802}
803
804static void SC_MatrixTranspose_4x4(rs_matrix4x4 *m) {
805    int i, j;
806    float temp;
807    for (i = 0; i < 3; ++i) {
808        for (j = i + 1; j < 4; ++j) {
809            temp = m->m[i*4 + j];
810            m->m[i*4 + j] = m->m[j*4 + i];
811            m->m[j*4 + i] = temp;
812        }
813    }
814}
815
816static void SC_MatrixTranspose_3x3(rs_matrix3x3 *m) {
817    int i, j;
818    float temp;
819    for (i = 0; i < 2; ++i) {
820        for (j = i + 1; j < 3; ++j) {
821            temp = m->m[i*3 + j];
822            m->m[i*3 + j] = m->m[j*4 + i];
823            m->m[j*3 + i] = temp;
824        }
825    }
826}
827
828static void SC_MatrixTranspose_2x2(rs_matrix2x2 *m) {
829    float temp = m->m[1];
830    m->m[1] = m->m[2];
831    m->m[2] = temp;
832}
833
834
835//////////////////////////////////////////////////////////////////////////////
836// Class implementation
837//////////////////////////////////////////////////////////////////////////////
838
839// llvm name mangling ref
840//  <builtin-type> ::= v  # void
841//                 ::= b  # bool
842//                 ::= c  # char
843//                 ::= a  # signed char
844//                 ::= h  # unsigned char
845//                 ::= s  # short
846//                 ::= t  # unsigned short
847//                 ::= i  # int
848//                 ::= j  # unsigned int
849//                 ::= l  # long
850//                 ::= m  # unsigned long
851//                 ::= x  # long long, __int64
852//                 ::= y  # unsigned long long, __int64
853//                 ::= f  # float
854//                 ::= d  # double
855
856static ScriptCState::SymbolTable_t gSyms[] = {
857    { "__divsi3", (void *)&SC_divsi3, true },
858    { "__modsi3", (void *)&SC_modsi3, true },
859    { "__udivsi3", (void *)&SC_udivsi3, true },
860    { "__umodsi3", (void *)&SC_umodsi3, true },
861    { "memset", (void *)&memset, true },
862    { "memcpy", (void *)&memcpy, true },
863
864    // allocation
865    { "_Z19rsAllocationGetDimX13rs_allocation", (void *)&SC_allocGetDimX, true },
866    { "_Z19rsAllocationGetDimY13rs_allocation", (void *)&SC_allocGetDimY, true },
867    { "_Z19rsAllocationGetDimZ13rs_allocation", (void *)&SC_allocGetDimZ, true },
868    { "_Z21rsAllocationGetDimLOD13rs_allocation", (void *)&SC_allocGetDimLOD, true },
869    { "_Z23rsAllocationGetDimFaces13rs_allocation", (void *)&SC_allocGetDimFaces, true },
870    { "_Z15rsGetAllocationPKv", (void *)&SC_getAllocation, true },
871
872    { "_Z14rsGetElementAt13rs_allocationj", (void *)&SC_getElementAtX, true },
873    { "_Z14rsGetElementAt13rs_allocationjj", (void *)&SC_getElementAtXY, true },
874    { "_Z14rsGetElementAt13rs_allocationjjj", (void *)&SC_getElementAtXYZ, true },
875
876    { "_Z11rsSetObjectP10rs_elementS_", (void *)&SC_setObject, true },
877    { "_Z13rsClearObjectP10rs_element", (void *)&SC_clearObject, true },
878    { "_Z10rsIsObject10rs_element", (void *)&SC_isObject, true },
879
880    { "_Z11rsSetObjectP7rs_typeS_", (void *)&SC_setObject, true },
881    { "_Z13rsClearObjectP7rs_type", (void *)&SC_clearObject, true },
882    { "_Z10rsIsObject7rs_type", (void *)&SC_isObject, true },
883
884    { "_Z11rsSetObjectP13rs_allocationS_", (void *)&SC_setObject, true },
885    { "_Z13rsClearObjectP13rs_allocation", (void *)&SC_clearObject, true },
886    { "_Z10rsIsObject13rs_allocation", (void *)&SC_isObject, true },
887
888    { "_Z11rsSetObjectP10rs_samplerS_", (void *)&SC_setObject, true },
889    { "_Z13rsClearObjectP10rs_sampler", (void *)&SC_clearObject, true },
890    { "_Z10rsIsObject10rs_sampler", (void *)&SC_isObject, true },
891
892    { "_Z11rsSetObjectP9rs_scriptS_", (void *)&SC_setObject, true },
893    { "_Z13rsClearObjectP9rs_script", (void *)&SC_clearObject, true },
894    { "_Z10rsIsObject9rs_script", (void *)&SC_isObject, true },
895
896    { "_Z11rsSetObjectP7rs_meshS_", (void *)&SC_setObject, true },
897    { "_Z13rsClearObjectP7rs_mesh", (void *)&SC_clearObject, true },
898    { "_Z10rsIsObject7rs_mesh", (void *)&SC_isObject, true },
899
900    { "_Z11rsSetObjectP19rs_program_fragmentS_", (void *)&SC_setObject, true },
901    { "_Z13rsClearObjectP19rs_program_fragment", (void *)&SC_clearObject, true },
902    { "_Z10rsIsObject19rs_program_fragment", (void *)&SC_isObject, true },
903
904    { "_Z11rsSetObjectP17rs_program_vertexS_", (void *)&SC_setObject, true },
905    { "_Z13rsClearObjectP17rs_program_vertex", (void *)&SC_clearObject, true },
906    { "_Z10rsIsObject17rs_program_vertex", (void *)&SC_isObject, true },
907
908    { "_Z11rsSetObjectP17rs_program_rasterS_", (void *)&SC_setObject, true },
909    { "_Z13rsClearObjectP17rs_program_raster", (void *)&SC_clearObject, true },
910    { "_Z10rsIsObject17rs_program_raster", (void *)&SC_isObject, true },
911
912    { "_Z11rsSetObjectP16rs_program_storeS_", (void *)&SC_setObject, true },
913    { "_Z13rsClearObjectP16rs_program_store", (void *)&SC_clearObject, true },
914    { "_Z10rsIsObject16rs_program_store", (void *)&SC_isObject, true },
915
916    { "_Z11rsSetObjectP7rs_fontS_", (void *)&SC_setObject, true },
917    { "_Z13rsClearObjectP7rs_font", (void *)&SC_clearObject, true },
918    { "_Z10rsIsObject7rs_font", (void *)&SC_isObject, true },
919
920
921    { "_Z21rsAllocationMarkDirty13rs_allocation", (void *)&SC_allocationMarkDirty, true },
922
923
924    // Debug
925    { "_Z7rsDebugPKcf", (void *)&SC_debugF, true },
926    { "_Z7rsDebugPKcff", (void *)&SC_debugFv2, true },
927    { "_Z7rsDebugPKcfff", (void *)&SC_debugFv3, true },
928    { "_Z7rsDebugPKcffff", (void *)&SC_debugFv4, true },
929    { "_Z7rsDebugPKcd", (void *)&SC_debugD, true },
930    { "_Z7rsDebugPKcPK12rs_matrix4x4", (void *)&SC_debugFM4v4, true },
931    { "_Z7rsDebugPKcPK12rs_matrix3x3", (void *)&SC_debugFM3v3, true },
932    { "_Z7rsDebugPKcPK12rs_matrix2x2", (void *)&SC_debugFM2v2, true },
933    { "_Z7rsDebugPKci", (void *)&SC_debugI32, true },
934    { "_Z7rsDebugPKcj", (void *)&SC_debugU32, true },
935    // Both "long" and "unsigned long" need to be redirected to their
936    // 64-bit counterparts, since we have hacked Slang to use 64-bit
937    // for "long" on Arm (to be similar to Java).
938    { "_Z7rsDebugPKcl", (void *)&SC_debugLL64, true },
939    { "_Z7rsDebugPKcm", (void *)&SC_debugULL64, true },
940    { "_Z7rsDebugPKcx", (void *)&SC_debugLL64, true },
941    { "_Z7rsDebugPKcy", (void *)&SC_debugULL64, true },
942    { "_Z7rsDebugPKcPKv", (void *)&SC_debugP, true },
943
944    // RS Math
945    { "_Z6rsRandi", (void *)&SC_randi, true },
946    { "_Z6rsRandii", (void *)&SC_randi2, true },
947    { "_Z6rsRandf", (void *)&SC_randf, true },
948    { "_Z6rsRandff", (void *)&SC_randf2, true },
949    { "_Z6rsFracf", (void *)&SC_frac, true },
950
951    // time
952    { "_Z6rsTimePi", (void *)&SC_time, true },
953    { "_Z11rsLocaltimeP5rs_tmPKi", (void *)&SC_localtime, true },
954    { "_Z14rsUptimeMillisv", (void*)&SC_uptimeMillis, true },
955    { "_Z13rsUptimeNanosv", (void*)&SC_uptimeNanos, true },
956    { "_Z7rsGetDtv", (void*)&SC_getDt, false },
957
958    { "_Z14rsSendToClienti", (void *)&SC_toClient, false },
959    { "_Z14rsSendToClientiPKvj", (void *)&SC_toClient2, false },
960    { "_Z22rsSendToClientBlockingi", (void *)&SC_toClientBlocking, false },
961    { "_Z22rsSendToClientBlockingiPKvj", (void *)&SC_toClientBlocking2, false },
962
963    // matrix
964    { "_Z20rsMatrixLoadIdentityP12rs_matrix4x4", (void *)&SC_MatrixLoadIdentity_4x4, true },
965    { "_Z20rsMatrixLoadIdentityP12rs_matrix3x3", (void *)&SC_MatrixLoadIdentity_3x3, true },
966    { "_Z20rsMatrixLoadIdentityP12rs_matrix2x2", (void *)&SC_MatrixLoadIdentity_2x2, true },
967
968    { "_Z12rsMatrixLoadP12rs_matrix4x4PKf", (void *)&SC_MatrixLoad_4x4_f, true },
969    { "_Z12rsMatrixLoadP12rs_matrix3x3PKf", (void *)&SC_MatrixLoad_3x3_f, true },
970    { "_Z12rsMatrixLoadP12rs_matrix2x2PKf", (void *)&SC_MatrixLoad_2x2_f, true },
971
972    { "_Z12rsMatrixLoadP12rs_matrix4x4PKS_", (void *)&SC_MatrixLoad_4x4_4x4, true },
973    { "_Z12rsMatrixLoadP12rs_matrix4x4PK12rs_matrix3x3", (void *)&SC_MatrixLoad_4x4_3x3, true },
974    { "_Z12rsMatrixLoadP12rs_matrix4x4PK12rs_matrix2x2", (void *)&SC_MatrixLoad_4x4_2x2, true },
975    { "_Z12rsMatrixLoadP12rs_matrix3x3PKS_", (void *)&SC_MatrixLoad_3x3_3x3, true },
976    { "_Z12rsMatrixLoadP12rs_matrix2x2PKS_", (void *)&SC_MatrixLoad_2x2_2x2, true },
977
978    { "_Z18rsMatrixLoadRotateP12rs_matrix4x4ffff", (void *)&SC_MatrixLoadRotate, true },
979    { "_Z17rsMatrixLoadScaleP12rs_matrix4x4fff", (void *)&SC_MatrixLoadScale, true },
980    { "_Z21rsMatrixLoadTranslateP12rs_matrix4x4fff", (void *)&SC_MatrixLoadTranslate, true },
981    { "_Z14rsMatrixRotateP12rs_matrix4x4ffff", (void *)&SC_MatrixRotate, true },
982    { "_Z13rsMatrixScaleP12rs_matrix4x4fff", (void *)&SC_MatrixScale, true },
983    { "_Z17rsMatrixTranslateP12rs_matrix4x4fff", (void *)&SC_MatrixTranslate, true },
984
985    { "_Z20rsMatrixLoadMultiplyP12rs_matrix4x4PKS_S2_", (void *)&SC_MatrixLoadMultiply_4x4_4x4_4x4, true },
986    { "_Z16rsMatrixMultiplyP12rs_matrix4x4PKS_", (void *)&SC_MatrixMultiply_4x4_4x4, true },
987    { "_Z20rsMatrixLoadMultiplyP12rs_matrix3x3PKS_S2_", (void *)&SC_MatrixLoadMultiply_3x3_3x3_3x3, true },
988    { "_Z16rsMatrixMultiplyP12rs_matrix3x3PKS_", (void *)&SC_MatrixMultiply_3x3_3x3, true },
989    { "_Z20rsMatrixLoadMultiplyP12rs_matrix2x2PKS_S2_", (void *)&SC_MatrixLoadMultiply_2x2_2x2_2x2, true },
990    { "_Z16rsMatrixMultiplyP12rs_matrix2x2PKS_", (void *)&SC_MatrixMultiply_2x2_2x2, true },
991
992    { "_Z17rsMatrixLoadOrthoP12rs_matrix4x4ffffff", (void *)&SC_MatrixLoadOrtho, true },
993    { "_Z19rsMatrixLoadFrustumP12rs_matrix4x4ffffff", (void *)&SC_MatrixLoadFrustum, true },
994    { "_Z23rsMatrixLoadPerspectiveP12rs_matrix4x4ffff", (void *)&SC_MatrixLoadPerspective, true },
995
996    { "_Z15rsMatrixInverseP12rs_matrix4x4", (void *)&SC_MatrixInverse_4x4, true },
997    { "_Z24rsMatrixInverseTransposeP12rs_matrix4x4", (void *)&SC_MatrixInverseTranspose_4x4, true },
998    { "_Z17rsMatrixTransposeP12rs_matrix4x4", (void *)&SC_MatrixTranspose_4x4, true },
999    { "_Z17rsMatrixTransposeP12rs_matrix4x4", (void *)&SC_MatrixTranspose_3x3, true },
1000    { "_Z17rsMatrixTransposeP12rs_matrix4x4", (void *)&SC_MatrixTranspose_2x2, true },
1001
1002    { "_Z9rsForEach9rs_script13rs_allocationS0_PKv", (void *)&SC_ForEach, false },
1003    //{ "_Z9rsForEach9rs_script13rs_allocationS0_PKv", (void *)&SC_ForEach2, true },
1004
1005////////////////////////////////////////////////////////////////////
1006
1007    //{ "sinf_fast", (void *)&SC_sinf_fast, true },
1008    //{ "cosf_fast", (void *)&SC_cosf_fast, true },
1009
1010    { NULL, NULL, false }
1011};
1012
1013const ScriptCState::SymbolTable_t * ScriptCState::lookupSymbol(const char *sym) {
1014    ScriptCState::SymbolTable_t *syms = gSyms;
1015
1016    while (syms->mPtr) {
1017        if (!strcmp(syms->mName, sym)) {
1018            return syms;
1019        }
1020        syms++;
1021    }
1022    return NULL;
1023}
1024