rsScriptC.cpp revision 900f1616bf33c7ba13cf2a737832a95bcd176388
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#include "../../compile/libbcc/include/bcc/bcc.h"
21#include "utils/Timers.h"
22
23#include <GLES/gl.h>
24#include <GLES/glext.h>
25
26using namespace android;
27using namespace android::renderscript;
28
29#define GET_TLS()  Context::ScriptTLSStruct * tls = \
30    (Context::ScriptTLSStruct *)pthread_getspecific(Context::gThreadTLSKey); \
31    Context * rsc = tls->mContext; \
32    ScriptC * sc = (ScriptC *) tls->mScript
33
34
35ScriptC::ScriptC(Context *rsc) : Script(rsc)
36{
37    mAllocFile = __FILE__;
38    mAllocLine = __LINE__;
39    mBccScript = NULL;
40    memset(&mProgram, 0, sizeof(mProgram));
41}
42
43ScriptC::~ScriptC()
44{
45    if (mBccScript) {
46        bccDeleteScript(mBccScript);
47    }
48    free(mEnviroment.mScriptText);
49    mEnviroment.mScriptText = NULL;
50}
51
52void ScriptC::setupScript(Context *rsc)
53{
54    setupGLState(rsc);
55    mEnviroment.mStartTimeMillis
56                = nanoseconds_to_milliseconds(systemTime(SYSTEM_TIME_MONOTONIC));
57
58    for (uint32_t ct=0; ct < mEnviroment.mFieldCount; ct++) {
59        if (mSlots[ct].get() && !mTypes[ct].get()) {
60            mTypes[ct].set(mSlots[ct]->getType());
61        }
62
63        if (!mTypes[ct].get())
64            continue;
65        void *ptr = NULL;
66        if (mSlots[ct].get()) {
67            ptr = mSlots[ct]->getPtr();
68        }
69        void **dest = ((void ***)mEnviroment.mFieldAddress)[ct];
70        //LOGE("setupScript %i %p = %p    %p %i", ct, dest, ptr, mSlots[ct]->getType(), mSlots[ct]->getType()->getDimX());
71
72        //const uint32_t *p32 = (const uint32_t *)ptr;
73        //for (uint32_t ct2=0; ct2 < mSlots[ct]->getType()->getDimX(); ct2++) {
74            //LOGE("  %i = 0x%08x ", ct2, p32[ct2]);
75        //}
76
77        if (dest) {
78            *dest = ptr;
79        } else {
80            LOGE("ScriptC::setupScript, NULL var binding address.");
81        }
82    }
83}
84
85const Allocation *ScriptC::ptrToAllocation(const void *ptr) const
86{
87    if (!ptr) {
88        return NULL;
89    }
90    for (uint32_t ct=0; ct < mEnviroment.mFieldCount; ct++) {
91        if (!mSlots[ct].get())
92            continue;
93        if (mSlots[ct]->getPtr() == ptr) {
94            return mSlots[ct].get();
95        }
96    }
97    LOGE("ScriptC::ptrToAllocation, failed to find %p", ptr);
98    return NULL;
99}
100
101Script * ScriptC::setTLS(Script *sc)
102{
103    Context::ScriptTLSStruct * tls = (Context::ScriptTLSStruct *)
104                                  pthread_getspecific(Context::gThreadTLSKey);
105    rsAssert(tls);
106    Script *old = tls->mScript;
107    tls->mScript = sc;
108    return old;
109}
110
111
112void ScriptC::setupGLState(Context *rsc)
113{
114    if (mEnviroment.mFragmentStore.get()) {
115        rsc->setFragmentStore(mEnviroment.mFragmentStore.get());
116    }
117    if (mEnviroment.mFragment.get()) {
118        rsc->setFragment(mEnviroment.mFragment.get());
119    }
120    if (mEnviroment.mVertex.get()) {
121        rsc->setVertex(mEnviroment.mVertex.get());
122    }
123    if (mEnviroment.mRaster.get()) {
124        rsc->setRaster(mEnviroment.mRaster.get());
125    }
126}
127
128uint32_t ScriptC::run(Context *rsc)
129{
130    if (mProgram.mRoot == NULL) {
131        rsc->setError(RS_ERROR_BAD_SCRIPT, "Attempted to run bad script");
132        return 0;
133    }
134
135    setupScript(rsc);
136
137    uint32_t ret = 0;
138    Script * oldTLS = setTLS(this);
139    //LOGE("ScriptC::run %p", mProgram.mRoot);
140    ret = mProgram.mRoot();
141    setTLS(oldTLS);
142    //LOGE("ScriptC::run ret %i", ret);
143    return ret;
144}
145
146
147typedef struct {
148    Context *rsc;
149    ScriptC *script;
150    const Allocation * ain;
151    Allocation * aout;
152    const void * usr;
153
154    uint32_t mSliceSize;
155    volatile int mSliceNum;
156
157    const uint8_t *ptrIn;
158    uint32_t eStrideIn;
159    uint8_t *ptrOut;
160    uint32_t eStrideOut;
161
162    uint32_t xStart;
163    uint32_t xEnd;
164    uint32_t yStart;
165    uint32_t yEnd;
166    uint32_t zStart;
167    uint32_t zEnd;
168    uint32_t arrayStart;
169    uint32_t arrayEnd;
170
171    uint32_t dimX;
172    uint32_t dimY;
173    uint32_t dimZ;
174    uint32_t dimArray;
175} MTLaunchStruct;
176typedef int (*rs_t)(const void *, void *, const void *, uint32_t, uint32_t, uint32_t, uint32_t);
177
178static void wc_xy(void *usr, uint32_t idx)
179{
180    MTLaunchStruct *mtls = (MTLaunchStruct *)usr;
181
182    while (1) {
183        uint32_t slice = (uint32_t)android_atomic_inc(&mtls->mSliceNum);
184        uint32_t yStart = mtls->yStart + slice * mtls->mSliceSize;
185        uint32_t yEnd = yStart + mtls->mSliceSize;
186        yEnd = rsMin(yEnd, mtls->yEnd);
187        if (yEnd <= yStart) {
188            return;
189        }
190
191        //LOGE("usr idx %i, x %i,%i  y %i,%i", idx, mtls->xStart, mtls->xEnd, yStart, yEnd);
192
193        for (uint32_t y = yStart; y < yEnd; y++) {
194            uint32_t offset = mtls->dimX * y;
195            uint8_t *xPtrOut = mtls->ptrOut + (mtls->eStrideOut * offset);
196            const uint8_t *xPtrIn = mtls->ptrIn + (mtls->eStrideIn * offset);
197
198            for (uint32_t x = mtls->xStart; x < mtls->xEnd; x++) {
199                ((rs_t)mtls->script->mProgram.mRoot) (xPtrIn, xPtrOut, mtls->usr, x, y, 0, 0);
200                xPtrIn += mtls->eStrideIn;
201                xPtrOut += mtls->eStrideOut;
202            }
203        }
204    }
205
206}
207
208void ScriptC::runForEach(Context *rsc,
209                         const Allocation * ain,
210                         Allocation * aout,
211                         const void * usr,
212                         const RsScriptCall *sc)
213{
214    MTLaunchStruct mtls;
215    memset(&mtls, 0, sizeof(mtls));
216
217    if (ain) {
218        mtls.dimX = ain->getType()->getDimX();
219        mtls.dimY = ain->getType()->getDimY();
220        mtls.dimZ = ain->getType()->getDimZ();
221        //mtls.dimArray = ain->getType()->getDimArray();
222    } else if (aout) {
223        mtls.dimX = aout->getType()->getDimX();
224        mtls.dimY = aout->getType()->getDimY();
225        mtls.dimZ = aout->getType()->getDimZ();
226        //mtls.dimArray = aout->getType()->getDimArray();
227    } else {
228        rsc->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null allocations");
229        return;
230    }
231
232    if (!sc || (sc->xEnd == 0)) {
233        mtls.xEnd = mtls.dimX;
234    } else {
235        rsAssert(sc->xStart < mtls.dimX);
236        rsAssert(sc->xEnd <= mtls.dimX);
237        rsAssert(sc->xStart < sc->xEnd);
238        mtls.xStart = rsMin(mtls.dimX, sc->xStart);
239        mtls.xEnd = rsMin(mtls.dimX, sc->xEnd);
240        if (mtls.xStart >= mtls.xEnd) return;
241    }
242
243    if (!sc || (sc->yEnd == 0)) {
244        mtls.yEnd = mtls.dimY;
245    } else {
246        rsAssert(sc->yStart < mtls.dimY);
247        rsAssert(sc->yEnd <= mtls.dimY);
248        rsAssert(sc->yStart < sc->yEnd);
249        mtls.yStart = rsMin(mtls.dimY, sc->yStart);
250        mtls.yEnd = rsMin(mtls.dimY, sc->yEnd);
251        if (mtls.yStart >= mtls.yEnd) return;
252    }
253
254    mtls.xEnd = rsMax((uint32_t)1, mtls.xEnd);
255    mtls.yEnd = rsMax((uint32_t)1, mtls.yEnd);
256    mtls.zEnd = rsMax((uint32_t)1, mtls.zEnd);
257    mtls.arrayEnd = rsMax((uint32_t)1, mtls.arrayEnd);
258
259    rsAssert(ain->getType()->getDimZ() == 0);
260
261    setupScript(rsc);
262    Script * oldTLS = setTLS(this);
263
264
265    mtls.rsc = rsc;
266    mtls.ain = ain;
267    mtls.aout = aout;
268    mtls.script = this;
269    mtls.usr = usr;
270    mtls.mSliceSize = 10;
271    mtls.mSliceNum = 0;
272
273    mtls.ptrIn = NULL;
274    mtls.eStrideIn = 0;
275    if (ain) {
276        mtls.ptrIn = (const uint8_t *)ain->getPtr();
277        mtls.eStrideIn = ain->getType()->getElementSizeBytes();
278    }
279
280    mtls.ptrOut = NULL;
281    mtls.eStrideOut = 0;
282    if (aout) {
283        mtls.ptrOut = (uint8_t *)aout->getPtr();
284        mtls.eStrideOut = aout->getType()->getElementSizeBytes();
285    }
286
287
288    if ((rsc->getWorkerPoolSize() > 1) && mEnviroment.mIsThreadable &&
289        ((mtls.dimY * mtls.dimZ * mtls.dimArray) > 1)) {
290
291        //LOGE("launch 1");
292        rsc->launchThreads(wc_xy, &mtls);
293        //LOGE("launch 2");
294    } else {
295        for (uint32_t ar = mtls.arrayStart; ar < mtls.arrayEnd; ar++) {
296            for (uint32_t z = mtls.zStart; z < mtls.zEnd; z++) {
297                for (uint32_t y = mtls.yStart; y < mtls.yEnd; y++) {
298                    uint32_t offset = mtls.dimX * mtls.dimY * mtls.dimZ * ar +
299                                      mtls.dimX * mtls.dimY * z +
300                                      mtls.dimX * y;
301                    uint8_t *xPtrOut = mtls.ptrOut + (mtls.eStrideOut * offset);
302                    const uint8_t *xPtrIn = mtls.ptrIn + (mtls.eStrideIn * offset);
303
304                    for (uint32_t x = mtls.xStart; x < mtls.xEnd; x++) {
305                        ((rs_t)mProgram.mRoot) (xPtrIn, xPtrOut, usr, x, y, z, ar);
306                        xPtrIn += mtls.eStrideIn;
307                        xPtrOut += mtls.eStrideOut;
308                    }
309                }
310            }
311        }
312    }
313
314    setTLS(oldTLS);
315}
316
317void ScriptC::Invoke(Context *rsc, uint32_t slot, const void *data, uint32_t len)
318{
319    //LOGE("rsi_ScriptInvoke %i", slot);
320    if ((slot >= mEnviroment.mInvokeFunctionCount) ||
321        (mEnviroment.mInvokeFunctions[slot] == NULL)) {
322        rsc->setError(RS_ERROR_BAD_SCRIPT, "Calling invoke on bad script");
323        return;
324    }
325    setupScript(rsc);
326    Script * oldTLS = setTLS(this);
327
328    ((void (*)(const void *, uint32_t))
329        mEnviroment.mInvokeFunctions[slot])(data, len);
330
331    setTLS(oldTLS);
332}
333
334ScriptCState::ScriptCState()
335{
336    mScript = NULL;
337    clear();
338}
339
340ScriptCState::~ScriptCState()
341{
342    delete mScript;
343    mScript = NULL;
344}
345
346void ScriptCState::clear()
347{
348    for (uint32_t ct=0; ct < MAX_SCRIPT_BANKS; ct++) {
349        mConstantBufferTypes[ct].clear();
350        mSlotWritable[ct] = false;
351    }
352
353    delete mScript;
354    mScript = new ScriptC(NULL);
355}
356
357static BCCvoid* symbolLookup(BCCvoid* pContext, const BCCchar* name)
358{
359    const ScriptCState::SymbolTable_t *sym;
360    ScriptC *s = (ScriptC *)pContext;
361    sym = ScriptCState::lookupSymbol(name);
362    if (sym) {
363        return sym->mPtr;
364    }
365    s->mEnviroment.mIsThreadable = false;
366    sym = ScriptCState::lookupSymbolCL(name);
367    if (sym) {
368        return sym->mPtr;
369    }
370    sym = ScriptCState::lookupSymbolGL(name);
371    if (sym) {
372        return sym->mPtr;
373    }
374    LOGE("ScriptC sym lookup failed for %s", name);
375    return NULL;
376}
377
378void ScriptCState::runCompiler(Context *rsc, ScriptC *s)
379{
380    LOGV("ScriptCState::runCompiler ");
381
382    s->mBccScript = bccCreateScript();
383    s->mEnviroment.mIsThreadable = true;
384    bccScriptBitcode(s->mBccScript, s->mEnviroment.mScriptText, s->mEnviroment.mScriptTextLength);
385    bccRegisterSymbolCallback(s->mBccScript, symbolLookup, s);
386    bccCompileScript(s->mBccScript);
387    bccGetScriptLabel(s->mBccScript, "root", (BCCvoid**) &s->mProgram.mRoot);
388    bccGetScriptLabel(s->mBccScript, "init", (BCCvoid**) &s->mProgram.mInit);
389    LOGV("root %p,  init %p", s->mProgram.mRoot, s->mProgram.mInit);
390
391    if (s->mProgram.mInit) {
392        s->mProgram.mInit();
393    }
394
395    bccGetExportFuncs(s->mBccScript, (BCCsizei*) &s->mEnviroment.mInvokeFunctionCount, 0, NULL);
396    if(s->mEnviroment.mInvokeFunctionCount <= 0)
397        s->mEnviroment.mInvokeFunctions = NULL;
398    else {
399        s->mEnviroment.mInvokeFunctions = (Script::InvokeFunc_t*) calloc(s->mEnviroment.mInvokeFunctionCount, sizeof(Script::InvokeFunc_t));
400        bccGetExportFuncs(s->mBccScript, NULL, s->mEnviroment.mInvokeFunctionCount, (BCCvoid **) s->mEnviroment.mInvokeFunctions);
401    }
402
403    bccGetExportVars(s->mBccScript, (BCCsizei*) &s->mEnviroment.mFieldCount, 0, NULL);
404    if(s->mEnviroment.mFieldCount <= 0)
405        s->mEnviroment.mFieldAddress = NULL;
406    else {
407        s->mEnviroment.mFieldAddress = (void **) calloc(s->mEnviroment.mFieldCount, sizeof(void *));
408        bccGetExportVars(s->mBccScript, NULL, s->mEnviroment.mFieldCount, (BCCvoid **) s->mEnviroment.mFieldAddress);
409    }
410    //for (int ct2=0; ct2 < s->mEnviroment.mFieldCount; ct2++ ) {
411        //LOGE("Script field %i = %p", ct2, s->mEnviroment.mFieldAddress[ct2]);
412    //}
413
414    s->mEnviroment.mFragment.set(rsc->getDefaultProgramFragment());
415    s->mEnviroment.mVertex.set(rsc->getDefaultProgramVertex());
416    s->mEnviroment.mFragmentStore.set(rsc->getDefaultProgramStore());
417    s->mEnviroment.mRaster.set(rsc->getDefaultProgramRaster());
418
419    if (s->mProgram.mRoot) {
420        const static int pragmaMax = 16;
421        BCCsizei pragmaCount;
422        BCCchar * str[pragmaMax];
423        bccGetPragmas(s->mBccScript, &pragmaCount, pragmaMax, &str[0]);
424
425        for (int ct=0; ct < pragmaCount; ct+=2) {
426            //LOGE("pragme %s %s", str[ct], str[ct+1]);
427            if (!strcmp(str[ct], "version")) {
428                continue;
429            }
430
431            if (!strcmp(str[ct], "stateVertex")) {
432                if (!strcmp(str[ct+1], "default")) {
433                    continue;
434                }
435                if (!strcmp(str[ct+1], "parent")) {
436                    s->mEnviroment.mVertex.clear();
437                    continue;
438                }
439                LOGE("Unreconized value %s passed to stateVertex", str[ct+1]);
440            }
441
442            if (!strcmp(str[ct], "stateRaster")) {
443                if (!strcmp(str[ct+1], "default")) {
444                    continue;
445                }
446                if (!strcmp(str[ct+1], "parent")) {
447                    s->mEnviroment.mRaster.clear();
448                    continue;
449                }
450                LOGE("Unreconized value %s passed to stateRaster", str[ct+1]);
451            }
452
453            if (!strcmp(str[ct], "stateFragment")) {
454                if (!strcmp(str[ct+1], "default")) {
455                    continue;
456                }
457                if (!strcmp(str[ct+1], "parent")) {
458                    s->mEnviroment.mFragment.clear();
459                    continue;
460                }
461                LOGE("Unreconized value %s passed to stateFragment", str[ct+1]);
462            }
463
464            if (!strcmp(str[ct], "stateStore")) {
465                if (!strcmp(str[ct+1], "default")) {
466                    continue;
467                }
468                if (!strcmp(str[ct+1], "parent")) {
469                    s->mEnviroment.mFragmentStore.clear();
470                    continue;
471                }
472                LOGE("Unreconized value %s passed to stateStore", str[ct+1]);
473            }
474
475        }
476
477
478    } else {
479        // Deal with an error.
480    }
481}
482
483
484
485namespace android {
486namespace renderscript {
487
488void rsi_ScriptCBegin(Context * rsc)
489{
490    ScriptCState *ss = &rsc->mScriptC;
491    ss->clear();
492}
493
494void rsi_ScriptCSetScript(Context * rsc, void *vp)
495{
496    rsAssert(0);
497    //ScriptCState *ss = &rsc->mScriptC;
498    //ss->mProgram.mScript = reinterpret_cast<ScriptC::RunScript_t>(vp);
499}
500
501void rsi_ScriptCSetText(Context *rsc, const char *text, uint32_t len)
502{
503    ScriptCState *ss = &rsc->mScriptC;
504
505    char *t = (char *)malloc(len + 1);
506    memcpy(t, text, len);
507    t[len] = 0;
508    ss->mScript->mEnviroment.mScriptText = t;
509    ss->mScript->mEnviroment.mScriptTextLength = len;
510}
511
512
513RsScript rsi_ScriptCCreate(Context * rsc)
514{
515    ScriptCState *ss = &rsc->mScriptC;
516
517    ScriptC *s = ss->mScript;
518    ss->mScript = NULL;
519
520    ss->runCompiler(rsc, s);
521    s->incUserRef();
522    s->setContext(rsc);
523    for (int ct=0; ct < MAX_SCRIPT_BANKS; ct++) {
524        s->mTypes[ct].set(ss->mConstantBufferTypes[ct].get());
525        s->mSlotWritable[ct] = ss->mSlotWritable[ct];
526    }
527
528    ss->clear();
529    return s;
530}
531
532}
533}
534
535
536