Home | History | Annotate | Download | only in driver
      1 /*
      2  * Copyright (C) 2011 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 
     18 #include "rsdCore.h"
     19 #include "rsdBcc.h"
     20 #include "rsdRuntime.h"
     21 
     22 #include <bcinfo/MetadataExtractor.h>
     23 
     24 #include "rsContext.h"
     25 #include "rsScriptC.h"
     26 
     27 #include "utils/Timers.h"
     28 #include "utils/StopWatch.h"
     29 extern "C" {
     30 #include "libdex/ZipArchive.h"
     31 }
     32 
     33 
     34 using namespace android;
     35 using namespace android::renderscript;
     36 
     37 struct DrvScript {
     38     int (*mRoot)();
     39     void (*mInit)();
     40     void (*mFreeChildren)();
     41 
     42     BCCScriptRef mBccScript;
     43 
     44     bcinfo::MetadataExtractor *ME;
     45 
     46     InvokeFunc_t *mInvokeFunctions;
     47     void ** mFieldAddress;
     48     bool * mFieldIsObject;
     49     const uint32_t *mExportForEachSignatureList;
     50 
     51     const uint8_t * mScriptText;
     52     uint32_t mScriptTextLength;
     53 };
     54 
     55 
     56 static Script * setTLS(Script *sc) {
     57     ScriptTLSStruct * tls = (ScriptTLSStruct *)pthread_getspecific(rsdgThreadTLSKey);
     58     rsAssert(tls);
     59     Script *old = tls->mScript;
     60     tls->mScript = sc;
     61     return old;
     62 }
     63 
     64 
     65 bool rsdScriptInit(const Context *rsc,
     66                      ScriptC *script,
     67                      char const *resName,
     68                      char const *cacheDir,
     69                      uint8_t const *bitcode,
     70                      size_t bitcodeSize,
     71                      uint32_t flags) {
     72     //LOGE("rsdScriptCreate %p %p %p %p %i %i %p", rsc, resName, cacheDir, bitcode, bitcodeSize, flags, lookupFunc);
     73 
     74     pthread_mutex_lock(&rsdgInitMutex);
     75     char *cachePath = NULL;
     76     size_t exportFuncCount = 0;
     77     size_t exportVarCount = 0;
     78     size_t objectSlotCount = 0;
     79     size_t exportForEachSignatureCount = 0;
     80 
     81     DrvScript *drv = (DrvScript *)calloc(1, sizeof(DrvScript));
     82     if (drv == NULL) {
     83         goto error;
     84     }
     85     script->mHal.drv = drv;
     86 
     87     drv->mBccScript = bccCreateScript();
     88     script->mHal.info.isThreadable = true;
     89     drv->mScriptText = bitcode;
     90     drv->mScriptTextLength = bitcodeSize;
     91 
     92 
     93     drv->ME = new bcinfo::MetadataExtractor((const char*)drv->mScriptText,
     94                                             drv->mScriptTextLength);
     95     if (!drv->ME->extract()) {
     96       LOGE("bcinfo: failed to read script metadata");
     97       goto error;
     98     }
     99 
    100     //LOGE("mBccScript %p", script->mBccScript);
    101 
    102     if (bccRegisterSymbolCallback(drv->mBccScript, &rsdLookupRuntimeStub, script) != 0) {
    103         LOGE("bcc: FAILS to register symbol callback");
    104         goto error;
    105     }
    106 
    107     if (bccReadBC(drv->mBccScript,
    108                   resName,
    109                   (char const *)drv->mScriptText,
    110                   drv->mScriptTextLength, 0) != 0) {
    111         LOGE("bcc: FAILS to read bitcode");
    112         goto error;
    113     }
    114 
    115     if (bccLinkFile(drv->mBccScript, "/system/lib/libclcore.bc", 0) != 0) {
    116         LOGE("bcc: FAILS to link bitcode");
    117         goto error;
    118     }
    119 
    120     if (bccPrepareExecutable(drv->mBccScript, cacheDir, resName, 0) != 0) {
    121         LOGE("bcc: FAILS to prepare executable");
    122         goto error;
    123     }
    124 
    125     free(cachePath);
    126 
    127     drv->mRoot = reinterpret_cast<int (*)()>(bccGetFuncAddr(drv->mBccScript, "root"));
    128     drv->mInit = reinterpret_cast<void (*)()>(bccGetFuncAddr(drv->mBccScript, "init"));
    129     drv->mFreeChildren = reinterpret_cast<void (*)()>(bccGetFuncAddr(drv->mBccScript, ".rs.dtor"));
    130 
    131     exportFuncCount = drv->ME->getExportFuncCount();
    132     if (exportFuncCount > 0) {
    133         drv->mInvokeFunctions = (InvokeFunc_t*) calloc(exportFuncCount,
    134                                                        sizeof(InvokeFunc_t));
    135         bccGetExportFuncList(drv->mBccScript, exportFuncCount,
    136                              (void **) drv->mInvokeFunctions);
    137     } else {
    138         drv->mInvokeFunctions = NULL;
    139     }
    140 
    141     exportVarCount = drv->ME->getExportVarCount();
    142     if (exportVarCount > 0) {
    143         drv->mFieldAddress = (void **) calloc(exportVarCount, sizeof(void*));
    144         drv->mFieldIsObject = (bool *) calloc(exportVarCount, sizeof(bool));
    145         bccGetExportVarList(drv->mBccScript, exportVarCount,
    146                             (void **) drv->mFieldAddress);
    147     } else {
    148         drv->mFieldAddress = NULL;
    149         drv->mFieldIsObject = NULL;
    150     }
    151 
    152     objectSlotCount = drv->ME->getObjectSlotCount();
    153     if (objectSlotCount > 0) {
    154         const uint32_t *objectSlotList = drv->ME->getObjectSlotList();
    155         for (uint32_t ct=0; ct < objectSlotCount; ct++) {
    156             drv->mFieldIsObject[objectSlotList[ct]] = true;
    157         }
    158     }
    159 
    160     exportForEachSignatureCount = drv->ME->getExportForEachSignatureCount();
    161     rsAssert(exportForEachSignatureCount <= 1);
    162     drv->mExportForEachSignatureList = drv->ME->getExportForEachSignatureList();
    163 
    164     // Copy info over to runtime
    165     script->mHal.info.exportedFunctionCount = drv->ME->getExportFuncCount();
    166     script->mHal.info.exportedVariableCount = drv->ME->getExportVarCount();
    167     script->mHal.info.exportedPragmaCount = drv->ME->getPragmaCount();
    168     script->mHal.info.exportedPragmaKeyList = drv->ME->getPragmaKeyList();
    169     script->mHal.info.exportedPragmaValueList = drv->ME->getPragmaValueList();
    170     script->mHal.info.root = drv->mRoot;
    171 
    172     pthread_mutex_unlock(&rsdgInitMutex);
    173     return true;
    174 
    175 error:
    176 
    177     pthread_mutex_unlock(&rsdgInitMutex);
    178     if (drv->ME) {
    179         delete drv->ME;
    180         drv->ME = NULL;
    181     }
    182     free(drv);
    183     return false;
    184 
    185 }
    186 
    187 typedef struct {
    188     Context *rsc;
    189     Script *script;
    190     uint32_t sig;
    191     const Allocation * ain;
    192     Allocation * aout;
    193     const void * usr;
    194     size_t usrLen;
    195 
    196     uint32_t mSliceSize;
    197     volatile int mSliceNum;
    198 
    199     const uint8_t *ptrIn;
    200     uint32_t eStrideIn;
    201     uint8_t *ptrOut;
    202     uint32_t eStrideOut;
    203 
    204     uint32_t xStart;
    205     uint32_t xEnd;
    206     uint32_t yStart;
    207     uint32_t yEnd;
    208     uint32_t zStart;
    209     uint32_t zEnd;
    210     uint32_t arrayStart;
    211     uint32_t arrayEnd;
    212 
    213     uint32_t dimX;
    214     uint32_t dimY;
    215     uint32_t dimZ;
    216     uint32_t dimArray;
    217 } MTLaunchStruct;
    218 typedef void (*rs_t)(const void *, void *, const void *, uint32_t, uint32_t, uint32_t, uint32_t);
    219 
    220 static void wc_xy(void *usr, uint32_t idx) {
    221     MTLaunchStruct *mtls = (MTLaunchStruct *)usr;
    222     RsForEachStubParamStruct p;
    223     memset(&p, 0, sizeof(p));
    224     p.usr = mtls->usr;
    225     p.usr_len = mtls->usrLen;
    226     RsdHal * dc = (RsdHal *)mtls->rsc->mHal.drv;
    227     uint32_t sig = mtls->sig;
    228 
    229     outer_foreach_t fn = dc->mForEachLaunch[sig];
    230     while (1) {
    231         uint32_t slice = (uint32_t)android_atomic_inc(&mtls->mSliceNum);
    232         uint32_t yStart = mtls->yStart + slice * mtls->mSliceSize;
    233         uint32_t yEnd = yStart + mtls->mSliceSize;
    234         yEnd = rsMin(yEnd, mtls->yEnd);
    235         if (yEnd <= yStart) {
    236             return;
    237         }
    238 
    239         //LOGE("usr idx %i, x %i,%i  y %i,%i", idx, mtls->xStart, mtls->xEnd, yStart, yEnd);
    240         //LOGE("usr ptr in %p,  out %p", mtls->ptrIn, mtls->ptrOut);
    241         for (p.y = yStart; p.y < yEnd; p.y++) {
    242             uint32_t offset = mtls->dimX * p.y;
    243             p.out = mtls->ptrOut + (mtls->eStrideOut * offset);
    244             p.in = mtls->ptrIn + (mtls->eStrideIn * offset);
    245             fn(&mtls->script->mHal.info.root, &p, mtls->xStart, mtls->xEnd,
    246                mtls->eStrideIn, mtls->eStrideOut);
    247         }
    248     }
    249 }
    250 
    251 static void wc_x(void *usr, uint32_t idx) {
    252     MTLaunchStruct *mtls = (MTLaunchStruct *)usr;
    253     RsForEachStubParamStruct p;
    254     memset(&p, 0, sizeof(p));
    255     p.usr = mtls->usr;
    256     p.usr_len = mtls->usrLen;
    257     RsdHal * dc = (RsdHal *)mtls->rsc->mHal.drv;
    258     uint32_t sig = mtls->sig;
    259 
    260     outer_foreach_t fn = dc->mForEachLaunch[sig];
    261     while (1) {
    262         uint32_t slice = (uint32_t)android_atomic_inc(&mtls->mSliceNum);
    263         uint32_t xStart = mtls->xStart + slice * mtls->mSliceSize;
    264         uint32_t xEnd = xStart + mtls->mSliceSize;
    265         xEnd = rsMin(xEnd, mtls->xEnd);
    266         if (xEnd <= xStart) {
    267             return;
    268         }
    269 
    270         //LOGE("usr slice %i idx %i, x %i,%i", slice, idx, xStart, xEnd);
    271         //LOGE("usr ptr in %p,  out %p", mtls->ptrIn, mtls->ptrOut);
    272 
    273         p.out = mtls->ptrOut + (mtls->eStrideOut * xStart);
    274         p.in = mtls->ptrIn + (mtls->eStrideIn * xStart);
    275         fn(&mtls->script->mHal.info.root, &p, xStart, xEnd, mtls->eStrideIn, mtls->eStrideOut);
    276     }
    277 }
    278 
    279 void rsdScriptInvokeForEach(const Context *rsc,
    280                             Script *s,
    281                             uint32_t slot,
    282                             const Allocation * ain,
    283                             Allocation * aout,
    284                             const void * usr,
    285                             uint32_t usrLen,
    286                             const RsScriptCall *sc) {
    287 
    288     RsdHal * dc = (RsdHal *)rsc->mHal.drv;
    289 
    290     MTLaunchStruct mtls;
    291     memset(&mtls, 0, sizeof(mtls));
    292 
    293     DrvScript *drv = (DrvScript *)s->mHal.drv;
    294     // We only support slot 0 (root) at this point in time.
    295     rsAssert(slot == 0);
    296     mtls.sig = 0x1f;  // temp fix for old apps, full table in slang_rs_export_foreach.cpp
    297     if (drv->mExportForEachSignatureList) {
    298         mtls.sig = drv->mExportForEachSignatureList[slot];
    299     }
    300     if (ain) {
    301         mtls.dimX = ain->getType()->getDimX();
    302         mtls.dimY = ain->getType()->getDimY();
    303         mtls.dimZ = ain->getType()->getDimZ();
    304         //mtls.dimArray = ain->getType()->getDimArray();
    305     } else if (aout) {
    306         mtls.dimX = aout->getType()->getDimX();
    307         mtls.dimY = aout->getType()->getDimY();
    308         mtls.dimZ = aout->getType()->getDimZ();
    309         //mtls.dimArray = aout->getType()->getDimArray();
    310     } else {
    311         rsc->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null allocations");
    312         return;
    313     }
    314 
    315     if (!sc || (sc->xEnd == 0)) {
    316         mtls.xEnd = mtls.dimX;
    317     } else {
    318         rsAssert(sc->xStart < mtls.dimX);
    319         rsAssert(sc->xEnd <= mtls.dimX);
    320         rsAssert(sc->xStart < sc->xEnd);
    321         mtls.xStart = rsMin(mtls.dimX, sc->xStart);
    322         mtls.xEnd = rsMin(mtls.dimX, sc->xEnd);
    323         if (mtls.xStart >= mtls.xEnd) return;
    324     }
    325 
    326     if (!sc || (sc->yEnd == 0)) {
    327         mtls.yEnd = mtls.dimY;
    328     } else {
    329         rsAssert(sc->yStart < mtls.dimY);
    330         rsAssert(sc->yEnd <= mtls.dimY);
    331         rsAssert(sc->yStart < sc->yEnd);
    332         mtls.yStart = rsMin(mtls.dimY, sc->yStart);
    333         mtls.yEnd = rsMin(mtls.dimY, sc->yEnd);
    334         if (mtls.yStart >= mtls.yEnd) return;
    335     }
    336 
    337     mtls.xEnd = rsMax((uint32_t)1, mtls.xEnd);
    338     mtls.yEnd = rsMax((uint32_t)1, mtls.yEnd);
    339     mtls.zEnd = rsMax((uint32_t)1, mtls.zEnd);
    340     mtls.arrayEnd = rsMax((uint32_t)1, mtls.arrayEnd);
    341 
    342     rsAssert(!ain || (ain->getType()->getDimZ() == 0));
    343 
    344     Context *mrsc = (Context *)rsc;
    345     Script * oldTLS = setTLS(s);
    346 
    347     mtls.rsc = mrsc;
    348     mtls.ain = ain;
    349     mtls.aout = aout;
    350     mtls.script = s;
    351     mtls.usr = usr;
    352     mtls.usrLen = usrLen;
    353     mtls.mSliceSize = 10;
    354     mtls.mSliceNum = 0;
    355 
    356     mtls.ptrIn = NULL;
    357     mtls.eStrideIn = 0;
    358     if (ain) {
    359         mtls.ptrIn = (const uint8_t *)ain->getPtr();
    360         mtls.eStrideIn = ain->getType()->getElementSizeBytes();
    361     }
    362 
    363     mtls.ptrOut = NULL;
    364     mtls.eStrideOut = 0;
    365     if (aout) {
    366         mtls.ptrOut = (uint8_t *)aout->getPtr();
    367         mtls.eStrideOut = aout->getType()->getElementSizeBytes();
    368     }
    369 
    370     if ((dc->mWorkers.mCount > 1) && s->mHal.info.isThreadable) {
    371         if (mtls.dimY > 1) {
    372             rsdLaunchThreads(mrsc, wc_xy, &mtls);
    373         } else {
    374             rsdLaunchThreads(mrsc, wc_x, &mtls);
    375         }
    376 
    377         //LOGE("launch 1");
    378     } else {
    379         RsForEachStubParamStruct p;
    380         memset(&p, 0, sizeof(p));
    381         p.usr = mtls.usr;
    382         p.usr_len = mtls.usrLen;
    383         uint32_t sig = mtls.sig;
    384 
    385         //LOGE("launch 3");
    386         outer_foreach_t fn = dc->mForEachLaunch[sig];
    387         for (p.ar[0] = mtls.arrayStart; p.ar[0] < mtls.arrayEnd; p.ar[0]++) {
    388             for (p.z = mtls.zStart; p.z < mtls.zEnd; p.z++) {
    389                 for (p.y = mtls.yStart; p.y < mtls.yEnd; p.y++) {
    390                     uint32_t offset = mtls.dimX * mtls.dimY * mtls.dimZ * p.ar[0] +
    391                                       mtls.dimX * mtls.dimY * p.z +
    392                                       mtls.dimX * p.y;
    393                     p.out = mtls.ptrOut + (mtls.eStrideOut * offset);
    394                     p.in = mtls.ptrIn + (mtls.eStrideIn * offset);
    395                     fn(&mtls.script->mHal.info.root, &p, mtls.xStart, mtls.xEnd,
    396                        mtls.eStrideIn, mtls.eStrideOut);
    397                 }
    398             }
    399         }
    400     }
    401 
    402     setTLS(oldTLS);
    403 }
    404 
    405 
    406 int rsdScriptInvokeRoot(const Context *dc, Script *script) {
    407     DrvScript *drv = (DrvScript *)script->mHal.drv;
    408 
    409     Script * oldTLS = setTLS(script);
    410     int ret = drv->mRoot();
    411     setTLS(oldTLS);
    412 
    413     return ret;
    414 }
    415 
    416 void rsdScriptInvokeInit(const Context *dc, Script *script) {
    417     DrvScript *drv = (DrvScript *)script->mHal.drv;
    418 
    419     if (drv->mInit) {
    420         drv->mInit();
    421     }
    422 }
    423 
    424 void rsdScriptInvokeFreeChildren(const Context *dc, Script *script) {
    425     DrvScript *drv = (DrvScript *)script->mHal.drv;
    426 
    427     if (drv->mFreeChildren) {
    428         drv->mFreeChildren();
    429     }
    430 }
    431 
    432 void rsdScriptInvokeFunction(const Context *dc, Script *script,
    433                             uint32_t slot,
    434                             const void *params,
    435                             size_t paramLength) {
    436     DrvScript *drv = (DrvScript *)script->mHal.drv;
    437     //LOGE("invoke %p %p %i %p %i", dc, script, slot, params, paramLength);
    438 
    439     Script * oldTLS = setTLS(script);
    440     ((void (*)(const void *, uint32_t))
    441         drv->mInvokeFunctions[slot])(params, paramLength);
    442     setTLS(oldTLS);
    443 }
    444 
    445 void rsdScriptSetGlobalVar(const Context *dc, const Script *script,
    446                            uint32_t slot, void *data, size_t dataLength) {
    447     DrvScript *drv = (DrvScript *)script->mHal.drv;
    448     //rsAssert(!script->mFieldIsObject[slot]);
    449     //LOGE("setGlobalVar %p %p %i %p %i", dc, script, slot, data, dataLength);
    450 
    451     int32_t *destPtr = ((int32_t **)drv->mFieldAddress)[slot];
    452     if (!destPtr) {
    453         //LOGV("Calling setVar on slot = %i which is null", slot);
    454         return;
    455     }
    456 
    457     memcpy(destPtr, data, dataLength);
    458 }
    459 
    460 void rsdScriptSetGlobalBind(const Context *dc, const Script *script, uint32_t slot, void *data) {
    461     DrvScript *drv = (DrvScript *)script->mHal.drv;
    462     //rsAssert(!script->mFieldIsObject[slot]);
    463     //LOGE("setGlobalBind %p %p %i %p", dc, script, slot, data);
    464 
    465     int32_t *destPtr = ((int32_t **)drv->mFieldAddress)[slot];
    466     if (!destPtr) {
    467         //LOGV("Calling setVar on slot = %i which is null", slot);
    468         return;
    469     }
    470 
    471     memcpy(destPtr, &data, sizeof(void *));
    472 }
    473 
    474 void rsdScriptSetGlobalObj(const Context *dc, const Script *script, uint32_t slot, ObjectBase *data) {
    475     DrvScript *drv = (DrvScript *)script->mHal.drv;
    476     //rsAssert(script->mFieldIsObject[slot]);
    477     //LOGE("setGlobalObj %p %p %i %p", dc, script, slot, data);
    478 
    479     int32_t *destPtr = ((int32_t **)drv->mFieldAddress)[slot];
    480     if (!destPtr) {
    481         //LOGV("Calling setVar on slot = %i which is null", slot);
    482         return;
    483     }
    484 
    485     rsrSetObject(dc, script, (ObjectBase **)destPtr, data);
    486 }
    487 
    488 void rsdScriptDestroy(const Context *dc, Script *script) {
    489     DrvScript *drv = (DrvScript *)script->mHal.drv;
    490 
    491     if (drv->mFieldAddress) {
    492         size_t exportVarCount = drv->ME->getExportVarCount();
    493         for (size_t ct = 0; ct < exportVarCount; ct++) {
    494             if (drv->mFieldIsObject[ct]) {
    495                 // The field address can be NULL if the script-side has
    496                 // optimized the corresponding global variable away.
    497                 if (drv->mFieldAddress[ct]) {
    498                     rsrClearObject(dc, script, (ObjectBase **)drv->mFieldAddress[ct]);
    499                 }
    500             }
    501         }
    502         free(drv->mFieldAddress);
    503         drv->mFieldAddress = NULL;
    504         free(drv->mFieldIsObject);
    505         drv->mFieldIsObject = NULL;    }
    506 
    507     if (drv->mInvokeFunctions) {
    508         free(drv->mInvokeFunctions);
    509         drv->mInvokeFunctions = NULL;
    510     }
    511 
    512     delete drv->ME;
    513     drv->ME = NULL;
    514 
    515     free(drv);
    516     script->mHal.drv = NULL;
    517 
    518 }
    519 
    520 
    521