rsScriptC.cpp revision 8f8a5724bee0f958ef81a7154e4fd40fb6f07a49
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 "../../../external/llvm/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())
60            continue;
61        void *ptr = mSlots[ct]->getPtr();
62        void **dest = ((void ***)mEnviroment.mFieldAddress)[ct];
63        //LOGE("setupScript %i %p = %p    %p %i", ct, dest, ptr, mSlots[ct]->getType(), mSlots[ct]->getType()->getDimX());
64
65        //const uint32_t *p32 = (const uint32_t *)ptr;
66        //for (uint32_t ct2=0; ct2 < mSlots[ct]->getType()->getDimX(); ct2++) {
67            //LOGE("  %i = 0x%08x ", ct2, p32[ct2]);
68        //}
69
70        if (dest) {
71            *dest = ptr;
72        } else {
73            LOGE("ScriptC::setupScript, NULL var binding address.");
74        }
75    }
76}
77
78const Allocation *ScriptC::ptrToAllocation(const void *ptr) const
79{
80    if (!ptr) {
81        return NULL;
82    }
83    for (uint32_t ct=0; ct < mEnviroment.mFieldCount; ct++) {
84        if (!mSlots[ct].get())
85            continue;
86        if (mSlots[ct]->getPtr() == ptr) {
87            return mSlots[ct].get();
88        }
89    }
90    LOGE("ScriptC::ptrToAllocation, failed to find %p", ptr);
91    return NULL;
92}
93
94Script * ScriptC::setTLS(Script *sc)
95{
96    Context::ScriptTLSStruct * tls = (Context::ScriptTLSStruct *)
97                                  pthread_getspecific(Context::gThreadTLSKey);
98    rsAssert(tls);
99    Script *old = tls->mScript;
100    tls->mScript = sc;
101    return old;
102}
103
104
105void ScriptC::setupGLState(Context *rsc)
106{
107    if (mEnviroment.mFragmentStore.get()) {
108        rsc->setFragmentStore(mEnviroment.mFragmentStore.get());
109    }
110    if (mEnviroment.mFragment.get()) {
111        rsc->setFragment(mEnviroment.mFragment.get());
112    }
113    if (mEnviroment.mVertex.get()) {
114        rsc->setVertex(mEnviroment.mVertex.get());
115    }
116    if (mEnviroment.mRaster.get()) {
117        rsc->setRaster(mEnviroment.mRaster.get());
118    }
119}
120
121uint32_t ScriptC::run(Context *rsc)
122{
123    if (mProgram.mRoot == NULL) {
124        rsc->setError(RS_ERROR_BAD_SCRIPT, "Attempted to run bad script");
125        return 0;
126    }
127
128    setupScript(rsc);
129
130    uint32_t ret = 0;
131    Script * oldTLS = setTLS(this);
132    //LOGE("ScriptC::run %p", mProgram.mRoot);
133    ret = mProgram.mRoot();
134    setTLS(oldTLS);
135    //LOGE("ScriptC::run ret %i", ret);
136    return ret;
137}
138
139
140void ScriptC::runForEach(Context *rsc,
141                         const Allocation * ain,
142                         Allocation * aout,
143                         const void * usr,
144                         const RsScriptCall *sc)
145{
146    uint32_t dimX = ain->getType()->getDimX();
147    uint32_t dimY = ain->getType()->getDimY();
148    uint32_t dimZ = ain->getType()->getDimZ();
149    uint32_t dimA = 0;//ain->getType()->getDimArray();
150
151    uint32_t xStart = 0;
152    uint32_t xEnd = 0;
153    uint32_t yStart = 0;
154    uint32_t yEnd = 0;
155    uint32_t zStart = 0;
156    uint32_t zEnd = 0;
157    uint32_t arrayStart = 0;
158    uint32_t arrayEnd = 0;
159
160    if (!sc || (sc->xEnd == 0)) {
161        xStart = 0;
162        xEnd = ain->getType()->getDimX();
163    } else {
164        rsAssert(xStart < dimX);
165        rsAssert(xEnd <= dimX);
166        rsAssert(sc->xStart < sc->xEnd);
167        xStart = rsMin(dimX, sc->xStart);
168        xEnd = rsMin(dimX, sc->xEnd);
169        if (xStart >= xEnd) return;
170    }
171
172    if (!sc || (sc->yEnd == 0)) {
173        yStart = 0;
174        yEnd = ain->getType()->getDimY();
175    } else {
176        rsAssert(yStart < dimY);
177        rsAssert(yEnd <= dimY);
178        rsAssert(sc->yStart < sc->yEnd);
179        yStart = rsMin(dimY, sc->yStart);
180        yEnd = rsMin(dimY, sc->yEnd);
181        if (yStart >= yEnd) return;
182    }
183
184    xEnd = rsMax((uint32_t)1, xEnd);
185    yEnd = rsMax((uint32_t)1, yEnd);
186    zEnd = rsMax((uint32_t)1, zEnd);
187    arrayEnd = rsMax((uint32_t)1, arrayEnd);
188
189    rsAssert(ain->getType()->getDimZ() == 0);
190
191    setupScript(rsc);
192    Script * oldTLS = setTLS(this);
193
194    typedef int (*rs_t)(const void *, void *, const void *, uint32_t, uint32_t, uint32_t, uint32_t);
195
196    const uint8_t *ptrIn = (const uint8_t *)ain->getPtr();
197    uint32_t eStrideIn = ain->getType()->getElementSizeBytes();
198
199    uint8_t *ptrOut = NULL;
200    uint32_t eStrideOut = 0;
201    if (aout) {
202        ptrOut = (uint8_t *)aout->getPtr();
203        eStrideOut = aout->getType()->getElementSizeBytes();
204    }
205
206    for (uint32_t ar = arrayStart; ar < arrayEnd; ar++) {
207        for (uint32_t z = zStart; z < zEnd; z++) {
208            for (uint32_t y = yStart; y < yEnd; y++) {
209                uint32_t offset = dimX * dimY * dimZ * ar +
210                                  dimX * dimY * z +
211                                  dimX * y;
212                uint8_t *xPtrOut = ptrOut + (eStrideOut * offset);
213                const uint8_t *xPtrIn = ptrIn + (eStrideIn * offset);
214
215                for (uint32_t x = xStart; x < xEnd; x++) {
216                    ((rs_t)mProgram.mRoot) (xPtrIn, xPtrOut, usr, x, y, z, ar);
217                    xPtrIn += eStrideIn;
218                    xPtrOut += eStrideOut;
219                }
220            }
221        }
222
223    }
224
225    setTLS(oldTLS);
226}
227
228void ScriptC::Invoke(Context *rsc, uint32_t slot, const void *data, uint32_t len)
229{
230    //LOGE("rsi_ScriptInvoke %i", slot);
231    if ((slot >= mEnviroment.mInvokeFunctionCount) ||
232        (mEnviroment.mInvokeFunctions[slot] == NULL)) {
233        rsc->setError(RS_ERROR_BAD_SCRIPT, "Calling invoke on bad script");
234        return;
235    }
236    setupScript(rsc);
237    Script * oldTLS = setTLS(this);
238
239    ((void (*)(const void *, uint32_t))
240        mEnviroment.mInvokeFunctions[slot])(data, len);
241
242    setTLS(oldTLS);
243}
244
245ScriptCState::ScriptCState()
246{
247    mScript = NULL;
248    clear();
249}
250
251ScriptCState::~ScriptCState()
252{
253    delete mScript;
254    mScript = NULL;
255}
256
257void ScriptCState::clear()
258{
259    for (uint32_t ct=0; ct < MAX_SCRIPT_BANKS; ct++) {
260        mConstantBufferTypes[ct].clear();
261        mSlotWritable[ct] = false;
262    }
263
264    delete mScript;
265    mScript = new ScriptC(NULL);
266}
267
268static BCCvoid* symbolLookup(BCCvoid* pContext, const BCCchar* name)
269{
270    const ScriptCState::SymbolTable_t *sym;
271    sym = ScriptCState::lookupSymbol(name);
272    if (sym) {
273        return sym->mPtr;
274    }
275    sym = ScriptCState::lookupSymbolCL(name);
276    if (sym) {
277        return sym->mPtr;
278    }
279    sym = ScriptCState::lookupSymbolGL(name);
280    if (sym) {
281        return sym->mPtr;
282    }
283    LOGE("ScriptC sym lookup failed for %s", name);
284    return NULL;
285}
286
287void ScriptCState::runCompiler(Context *rsc, ScriptC *s)
288{
289    LOGV("ScriptCState::runCompiler ");
290
291    s->mBccScript = bccCreateScript();
292    bccScriptBitcode(s->mBccScript, s->mEnviroment.mScriptText, s->mEnviroment.mScriptTextLength);
293    bccRegisterSymbolCallback(s->mBccScript, symbolLookup, NULL);
294    bccCompileScript(s->mBccScript);
295    bccGetScriptLabel(s->mBccScript, "root", (BCCvoid**) &s->mProgram.mRoot);
296    bccGetScriptLabel(s->mBccScript, "init", (BCCvoid**) &s->mProgram.mInit);
297    LOGV("root %p,  init %p", s->mProgram.mRoot, s->mProgram.mInit);
298
299    if (s->mProgram.mInit) {
300        s->mProgram.mInit();
301    }
302
303    bccGetExportFuncs(s->mBccScript, (BCCsizei*) &s->mEnviroment.mInvokeFunctionCount, 0, NULL);
304    if(s->mEnviroment.mInvokeFunctionCount <= 0)
305        s->mEnviroment.mInvokeFunctions = NULL;
306    else {
307        s->mEnviroment.mInvokeFunctions = (Script::InvokeFunc_t*) calloc(s->mEnviroment.mInvokeFunctionCount, sizeof(Script::InvokeFunc_t));
308        bccGetExportFuncs(s->mBccScript, NULL, s->mEnviroment.mInvokeFunctionCount, (BCCvoid **) s->mEnviroment.mInvokeFunctions);
309    }
310
311    s->mEnviroment.mFieldAddress = (void **)calloc(100, sizeof(void *));
312    bccGetExportVars(s->mBccScript, (BCCsizei *)&s->mEnviroment.mFieldCount,
313                     100, s->mEnviroment.mFieldAddress);
314
315    s->mEnviroment.mFragment.set(rsc->getDefaultProgramFragment());
316    s->mEnviroment.mVertex.set(rsc->getDefaultProgramVertex());
317    s->mEnviroment.mFragmentStore.set(rsc->getDefaultProgramStore());
318    s->mEnviroment.mRaster.set(rsc->getDefaultProgramRaster());
319
320    if (s->mProgram.mRoot) {
321        const static int pragmaMax = 16;
322        BCCsizei pragmaCount;
323        BCCchar * str[pragmaMax];
324        bccGetPragmas(s->mBccScript, &pragmaCount, pragmaMax, &str[0]);
325
326        for (int ct=0; ct < pragmaCount; ct+=2) {
327            //LOGE("pragme %s %s", str[ct], str[ct+1]);
328            if (!strcmp(str[ct], "version")) {
329                continue;
330            }
331
332            if (!strcmp(str[ct], "stateVertex")) {
333                if (!strcmp(str[ct+1], "default")) {
334                    continue;
335                }
336                if (!strcmp(str[ct+1], "parent")) {
337                    s->mEnviroment.mVertex.clear();
338                    continue;
339                }
340                LOGE("Unreconized value %s passed to stateVertex", str[ct+1]);
341            }
342
343            if (!strcmp(str[ct], "stateRaster")) {
344                if (!strcmp(str[ct+1], "default")) {
345                    continue;
346                }
347                if (!strcmp(str[ct+1], "parent")) {
348                    s->mEnviroment.mRaster.clear();
349                    continue;
350                }
351                LOGE("Unreconized value %s passed to stateRaster", str[ct+1]);
352            }
353
354            if (!strcmp(str[ct], "stateFragment")) {
355                if (!strcmp(str[ct+1], "default")) {
356                    continue;
357                }
358                if (!strcmp(str[ct+1], "parent")) {
359                    s->mEnviroment.mFragment.clear();
360                    continue;
361                }
362                LOGE("Unreconized value %s passed to stateFragment", str[ct+1]);
363            }
364
365            if (!strcmp(str[ct], "stateStore")) {
366                if (!strcmp(str[ct+1], "default")) {
367                    continue;
368                }
369                if (!strcmp(str[ct+1], "parent")) {
370                    s->mEnviroment.mFragmentStore.clear();
371                    continue;
372                }
373                LOGE("Unreconized value %s passed to stateStore", str[ct+1]);
374            }
375
376        }
377
378
379    } else {
380        // Deal with an error.
381    }
382}
383
384
385
386namespace android {
387namespace renderscript {
388
389void rsi_ScriptCBegin(Context * rsc)
390{
391    ScriptCState *ss = &rsc->mScriptC;
392    ss->clear();
393}
394
395void rsi_ScriptCSetScript(Context * rsc, void *vp)
396{
397    rsAssert(0);
398    //ScriptCState *ss = &rsc->mScriptC;
399    //ss->mProgram.mScript = reinterpret_cast<ScriptC::RunScript_t>(vp);
400}
401
402void rsi_ScriptCSetText(Context *rsc, const char *text, uint32_t len)
403{
404    ScriptCState *ss = &rsc->mScriptC;
405
406    char *t = (char *)malloc(len + 1);
407    memcpy(t, text, len);
408    t[len] = 0;
409    ss->mScript->mEnviroment.mScriptText = t;
410    ss->mScript->mEnviroment.mScriptTextLength = len;
411}
412
413
414RsScript rsi_ScriptCCreate(Context * rsc)
415{
416    ScriptCState *ss = &rsc->mScriptC;
417
418    ScriptC *s = ss->mScript;
419    ss->mScript = NULL;
420
421    ss->runCompiler(rsc, s);
422    s->incUserRef();
423    s->setContext(rsc);
424    for (int ct=0; ct < MAX_SCRIPT_BANKS; ct++) {
425        s->mTypes[ct].set(ss->mConstantBufferTypes[ct].get());
426        s->mSlotWritable[ct] = ss->mSlotWritable[ct];
427    }
428
429    ss->clear();
430    return s;
431}
432
433}
434}
435
436
437