rsScriptC.cpp revision e4a06c5fc738bf219f2a495e12a637b2d0871651
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 "utils/Timers.h"
21#include "utils/StopWatch.h"
22
23#include <GLES/gl.h>
24#include <GLES/glext.h>
25
26#include <bcc/bcc.h>
27
28using namespace android;
29using namespace android::renderscript;
30
31#define GET_TLS()  Context::ScriptTLSStruct * tls = \
32    (Context::ScriptTLSStruct *)pthread_getspecific(Context::gThreadTLSKey); \
33    Context * rsc = tls->mContext; \
34    ScriptC * sc = (ScriptC *) tls->mScript
35
36ScriptC::ScriptC(Context *rsc) : Script(rsc) {
37}
38
39ScriptC::~ScriptC() {
40    mRSC->mHal.funcs.script.destroy(mRSC, this);
41
42    //free(mEnviroment.mScriptText);
43    //mEnviroment.mScriptText = NULL;
44}
45
46void ScriptC::setupScript(Context *rsc) {
47    mEnviroment.mStartTimeMillis
48                = nanoseconds_to_milliseconds(systemTime(SYSTEM_TIME_MONOTONIC));
49
50    for (uint32_t ct=0; ct < mHal.info.exportedVariableCount; ct++) {
51        if (mSlots[ct].get() && !mTypes[ct].get()) {
52            mTypes[ct].set(mSlots[ct]->getType());
53        }
54
55        if (!mTypes[ct].get())
56            continue;
57        void *ptr = NULL;
58        if (mSlots[ct].get()) {
59            ptr = mSlots[ct]->getPtr();
60        }
61
62        rsc->mHal.funcs.script.setGlobalBind(rsc, this, ct, ptr);
63    }
64}
65
66const Allocation *ScriptC::ptrToAllocation(const void *ptr) const {
67    //LOGE("ptr to alloc %p", ptr);
68    if (!ptr) {
69        return NULL;
70    }
71    for (uint32_t ct=0; ct < mHal.info.exportedVariableCount; ct++) {
72        if (!mSlots[ct].get())
73            continue;
74        if (mSlots[ct]->getPtr() == ptr) {
75            return mSlots[ct].get();
76        }
77    }
78    LOGE("ScriptC::ptrToAllocation, failed to find %p", ptr);
79    return NULL;
80}
81
82Script * ScriptC::setTLS(Script *sc) {
83    Context::ScriptTLSStruct * tls = (Context::ScriptTLSStruct *)
84                                  pthread_getspecific(Context::gThreadTLSKey);
85    rsAssert(tls);
86    Script *old = tls->mScript;
87    tls->mScript = sc;
88    return old;
89}
90
91void ScriptC::setupGLState(Context *rsc) {
92    if (mEnviroment.mFragmentStore.get()) {
93        rsc->setProgramStore(mEnviroment.mFragmentStore.get());
94    }
95    if (mEnviroment.mFragment.get()) {
96        rsc->setProgramFragment(mEnviroment.mFragment.get());
97    }
98    if (mEnviroment.mVertex.get()) {
99        rsc->setProgramVertex(mEnviroment.mVertex.get());
100    }
101    if (mEnviroment.mRaster.get()) {
102        rsc->setProgramRaster(mEnviroment.mRaster.get());
103    }
104}
105
106uint32_t ScriptC::run(Context *rsc) {
107    if (mHal.info.root == NULL) {
108        rsc->setError(RS_ERROR_BAD_SCRIPT, "Attempted to run bad script");
109        return 0;
110    }
111
112    setupGLState(rsc);
113    setupScript(rsc);
114
115    uint32_t ret = 0;
116    Script * oldTLS = setTLS(this);
117
118    if (rsc->props.mLogScripts) {
119        LOGV("%p ScriptC::run invoking root,  ptr %p", rsc, mHal.info.root);
120    }
121
122    ret = mHal.info.root();
123
124    if (rsc->props.mLogScripts) {
125        LOGV("%p ScriptC::run invoking complete, ret=%i", rsc, ret);
126    }
127
128    setTLS(oldTLS);
129    return ret;
130}
131
132typedef struct {
133    Context *rsc;
134    ScriptC *script;
135    const Allocation * ain;
136    Allocation * aout;
137    const void * usr;
138
139    uint32_t mSliceSize;
140    volatile int mSliceNum;
141
142    const uint8_t *ptrIn;
143    uint32_t eStrideIn;
144    uint8_t *ptrOut;
145    uint32_t eStrideOut;
146
147    uint32_t xStart;
148    uint32_t xEnd;
149    uint32_t yStart;
150    uint32_t yEnd;
151    uint32_t zStart;
152    uint32_t zEnd;
153    uint32_t arrayStart;
154    uint32_t arrayEnd;
155
156    uint32_t dimX;
157    uint32_t dimY;
158    uint32_t dimZ;
159    uint32_t dimArray;
160} MTLaunchStruct;
161typedef int (*rs_t)(const void *, void *, const void *, uint32_t, uint32_t, uint32_t, uint32_t);
162
163static void wc_xy(void *usr, uint32_t idx) {
164    MTLaunchStruct *mtls = (MTLaunchStruct *)usr;
165
166    while (1) {
167        uint32_t slice = (uint32_t)android_atomic_inc(&mtls->mSliceNum);
168        uint32_t yStart = mtls->yStart + slice * mtls->mSliceSize;
169        uint32_t yEnd = yStart + mtls->mSliceSize;
170        yEnd = rsMin(yEnd, mtls->yEnd);
171        if (yEnd <= yStart) {
172            return;
173        }
174
175        //LOGE("usr idx %i, x %i,%i  y %i,%i", idx, mtls->xStart, mtls->xEnd, yStart, yEnd);
176        //LOGE("usr ptr in %p,  out %p", mtls->ptrIn, mtls->ptrOut);
177        for (uint32_t y = yStart; y < yEnd; y++) {
178            uint32_t offset = mtls->dimX * y;
179            uint8_t *xPtrOut = mtls->ptrOut + (mtls->eStrideOut * offset);
180            const uint8_t *xPtrIn = mtls->ptrIn + (mtls->eStrideIn * offset);
181
182            for (uint32_t x = mtls->xStart; x < mtls->xEnd; x++) {
183                ((rs_t)mtls->script->mHal.info.root) (xPtrIn, xPtrOut, mtls->usr, x, y, 0, 0);
184                xPtrIn += mtls->eStrideIn;
185                xPtrOut += mtls->eStrideOut;
186            }
187        }
188    }
189}
190
191static void wc_x(void *usr, uint32_t idx) {
192    MTLaunchStruct *mtls = (MTLaunchStruct *)usr;
193
194    while (1) {
195        uint32_t slice = (uint32_t)android_atomic_inc(&mtls->mSliceNum);
196        uint32_t xStart = mtls->xStart + slice * mtls->mSliceSize;
197        uint32_t xEnd = xStart + mtls->mSliceSize;
198        xEnd = rsMin(xEnd, mtls->xEnd);
199        if (xEnd <= xStart) {
200            return;
201        }
202
203        //LOGE("usr idx %i, x %i,%i  y %i,%i", idx, mtls->xStart, mtls->xEnd, yStart, yEnd);
204        //LOGE("usr ptr in %p,  out %p", mtls->ptrIn, mtls->ptrOut);
205        uint8_t *xPtrOut = mtls->ptrOut + (mtls->eStrideOut * xStart);
206        const uint8_t *xPtrIn = mtls->ptrIn + (mtls->eStrideIn * xStart);
207        for (uint32_t x = xStart; x < xEnd; x++) {
208            ((rs_t)mtls->script->mHal.info.root) (xPtrIn, xPtrOut, mtls->usr, x, 0, 0, 0);
209            xPtrIn += mtls->eStrideIn;
210            xPtrOut += mtls->eStrideOut;
211        }
212    }
213}
214
215void ScriptC::runForEach(Context *rsc,
216                         const Allocation * ain,
217                         Allocation * aout,
218                         const void * usr,
219                         const RsScriptCall *sc) {
220    MTLaunchStruct mtls;
221    memset(&mtls, 0, sizeof(mtls));
222    Context::PushState ps(rsc);
223
224
225    if (ain) {
226        mtls.dimX = ain->getType()->getDimX();
227        mtls.dimY = ain->getType()->getDimY();
228        mtls.dimZ = ain->getType()->getDimZ();
229        //mtls.dimArray = ain->getType()->getDimArray();
230    } else if (aout) {
231        mtls.dimX = aout->getType()->getDimX();
232        mtls.dimY = aout->getType()->getDimY();
233        mtls.dimZ = aout->getType()->getDimZ();
234        //mtls.dimArray = aout->getType()->getDimArray();
235    } else {
236        rsc->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null allocations");
237        return;
238    }
239
240    if (!sc || (sc->xEnd == 0)) {
241        mtls.xEnd = mtls.dimX;
242    } else {
243        rsAssert(sc->xStart < mtls.dimX);
244        rsAssert(sc->xEnd <= mtls.dimX);
245        rsAssert(sc->xStart < sc->xEnd);
246        mtls.xStart = rsMin(mtls.dimX, sc->xStart);
247        mtls.xEnd = rsMin(mtls.dimX, sc->xEnd);
248        if (mtls.xStart >= mtls.xEnd) return;
249    }
250
251    if (!sc || (sc->yEnd == 0)) {
252        mtls.yEnd = mtls.dimY;
253    } else {
254        rsAssert(sc->yStart < mtls.dimY);
255        rsAssert(sc->yEnd <= mtls.dimY);
256        rsAssert(sc->yStart < sc->yEnd);
257        mtls.yStart = rsMin(mtls.dimY, sc->yStart);
258        mtls.yEnd = rsMin(mtls.dimY, sc->yEnd);
259        if (mtls.yStart >= mtls.yEnd) return;
260    }
261
262    mtls.xEnd = rsMax((uint32_t)1, mtls.xEnd);
263    mtls.yEnd = rsMax((uint32_t)1, mtls.yEnd);
264    mtls.zEnd = rsMax((uint32_t)1, mtls.zEnd);
265    mtls.arrayEnd = rsMax((uint32_t)1, mtls.arrayEnd);
266
267    rsAssert(ain->getType()->getDimZ() == 0);
268
269    setupGLState(rsc);
270    setupScript(rsc);
271    Script * oldTLS = setTLS(this);
272
273    mtls.rsc = rsc;
274    mtls.ain = ain;
275    mtls.aout = aout;
276    mtls.script = this;
277    mtls.usr = usr;
278    mtls.mSliceSize = 10;
279    mtls.mSliceNum = 0;
280
281    mtls.ptrIn = NULL;
282    mtls.eStrideIn = 0;
283    if (ain) {
284        mtls.ptrIn = (const uint8_t *)ain->getPtr();
285        mtls.eStrideIn = ain->getType()->getElementSizeBytes();
286    }
287
288    mtls.ptrOut = NULL;
289    mtls.eStrideOut = 0;
290    if (aout) {
291        mtls.ptrOut = (uint8_t *)aout->getPtr();
292        mtls.eStrideOut = aout->getType()->getElementSizeBytes();
293    }
294
295    if ((rsc->getWorkerPoolSize() > 1) && mHal.info.isThreadable) {
296        if (mtls.dimY > 1) {
297            rsc->launchThreads(wc_xy, &mtls);
298        } else {
299            rsc->launchThreads(wc_x, &mtls);
300        }
301
302        //LOGE("launch 1");
303    } else {
304        //LOGE("launch 3");
305        for (uint32_t ar = mtls.arrayStart; ar < mtls.arrayEnd; ar++) {
306            for (uint32_t z = mtls.zStart; z < mtls.zEnd; z++) {
307                for (uint32_t y = mtls.yStart; y < mtls.yEnd; y++) {
308                    uint32_t offset = mtls.dimX * mtls.dimY * mtls.dimZ * ar +
309                                      mtls.dimX * mtls.dimY * z +
310                                      mtls.dimX * y;
311                    uint8_t *xPtrOut = mtls.ptrOut + (mtls.eStrideOut * offset);
312                    const uint8_t *xPtrIn = mtls.ptrIn + (mtls.eStrideIn * offset);
313
314                    for (uint32_t x = mtls.xStart; x < mtls.xEnd; x++) {
315                        ((rs_t)mHal.info.root) (xPtrIn, xPtrOut, usr, x, y, z, ar);
316                        xPtrIn += mtls.eStrideIn;
317                        xPtrOut += mtls.eStrideOut;
318                    }
319                }
320            }
321        }
322    }
323
324    setTLS(oldTLS);
325}
326
327void ScriptC::Invoke(Context *rsc, uint32_t slot, const void *data, uint32_t len) {
328    if (slot >= mHal.info.exportedFunctionCount) {
329        rsc->setError(RS_ERROR_BAD_SCRIPT, "Calling invoke on bad script");
330        return;
331    }
332    setupScript(rsc);
333    Script * oldTLS = setTLS(this);
334
335    if (rsc->props.mLogScripts) {
336        LOGV("%p ScriptC::Invoke invoking slot %i,  ptr %p", rsc, slot, this);
337    }
338    rsc->mHal.funcs.script.invokeFunction(rsc, this, slot, data, len);
339
340    setTLS(oldTLS);
341}
342
343ScriptCState::ScriptCState() {
344}
345
346ScriptCState::~ScriptCState() {
347}
348
349static void* symbolLookup(void* pContext, char const* name) {
350    const ScriptCState::SymbolTable_t *sym;
351    ScriptC *s = (ScriptC *)pContext;
352    if (!strcmp(name, "__isThreadable")) {
353      return (void*) s->mHal.info.isThreadable;
354    } else if (!strcmp(name, "__clearThreadable")) {
355      s->mHal.info.isThreadable = false;
356      return NULL;
357    }
358    sym = ScriptCState::lookupSymbol(name);
359    if (!sym) {
360        sym = ScriptCState::lookupSymbolCL(name);
361    }
362    if (!sym) {
363        sym = ScriptCState::lookupSymbolGL(name);
364    }
365    if (sym) {
366        s->mHal.info.isThreadable &= sym->threadable;
367        return sym->mPtr;
368    }
369    LOGE("ScriptC sym lookup failed for %s", name);
370    return NULL;
371}
372
373#if 0
374extern const char rs_runtime_lib_bc[];
375extern unsigned rs_runtime_lib_bc_size;
376#endif
377
378bool ScriptC::runCompiler(Context *rsc,
379                          const char *resName,
380                          const char *cacheDir,
381                          const uint8_t *bitcode,
382                          size_t bitcodeLen) {
383
384    //LOGE("runCompiler %p %p %p %p %p %i", rsc, this, resName, cacheDir, bitcode, bitcodeLen);
385
386    rsc->mHal.funcs.script.scriptInit(rsc, this, resName, cacheDir, bitcode, bitcodeLen, 0, symbolLookup);
387
388    mEnviroment.mFragment.set(rsc->getDefaultProgramFragment());
389    mEnviroment.mVertex.set(rsc->getDefaultProgramVertex());
390    mEnviroment.mFragmentStore.set(rsc->getDefaultProgramStore());
391    mEnviroment.mRaster.set(rsc->getDefaultProgramRaster());
392
393    rsc->mHal.funcs.script.invokeInit(rsc, this);
394
395    for (size_t i=0; i < mHal.info.exportedPragmaCount; ++i) {
396        const char * key = mHal.info.exportedPragmaKeyList[i];
397        const char * value = mHal.info.exportedPragmaValueList[i];
398        //LOGE("pragma %s %s", keys[i], values[i]);
399        if (!strcmp(key, "version")) {
400            if (!strcmp(value, "1")) {
401                continue;
402            }
403            LOGE("Invalid version pragma value: %s\n", value);
404            return false;
405        }
406
407        if (!strcmp(key, "stateVertex")) {
408            if (!strcmp(value, "default")) {
409                continue;
410            }
411            if (!strcmp(value, "parent")) {
412                mEnviroment.mVertex.clear();
413                continue;
414            }
415            LOGE("Unrecognized value %s passed to stateVertex", value);
416            return false;
417        }
418
419        if (!strcmp(key, "stateRaster")) {
420            if (!strcmp(value, "default")) {
421                continue;
422            }
423            if (!strcmp(value, "parent")) {
424                mEnviroment.mRaster.clear();
425                continue;
426            }
427            LOGE("Unrecognized value %s passed to stateRaster", value);
428            return false;
429        }
430
431        if (!strcmp(key, "stateFragment")) {
432            if (!strcmp(value, "default")) {
433                continue;
434            }
435            if (!strcmp(value, "parent")) {
436                mEnviroment.mFragment.clear();
437                continue;
438            }
439            LOGE("Unrecognized value %s passed to stateFragment", value);
440            return false;
441        }
442
443        if (!strcmp(key, "stateStore")) {
444            if (!strcmp(value, "default")) {
445                continue;
446            }
447            if (!strcmp(value, "parent")) {
448                mEnviroment.mFragmentStore.clear();
449                continue;
450            }
451            LOGE("Unrecognized value %s passed to stateStore", value);
452            return false;
453        }
454    }
455
456    mSlots = new ObjectBaseRef<Allocation>[mHal.info.exportedVariableCount];
457    mTypes = new ObjectBaseRef<const Type>[mHal.info.exportedVariableCount];
458
459    return true;
460}
461
462namespace android {
463namespace renderscript {
464
465RsScript rsi_ScriptCCreate(Context *rsc,
466                           const char *resName, const char *cacheDir,
467                           const char *text, uint32_t len)
468{
469    ScriptC *s = new ScriptC(rsc);
470
471    if (!s->runCompiler(rsc, resName, cacheDir, (uint8_t *)text, len)) {
472        // Error during compile, destroy s and return null.
473        delete s;
474        return NULL;
475    }
476
477    s->incUserRef();
478    return s;
479}
480
481}
482}
483