Home | History | Annotate | Download | only in Renderscript
      1 /*
      2  * Copyright 2012, 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 //#define LOG_NDEBUG 0
     18 #include "bcc/Renderscript/RSInfo.h"
     19 
     20 #include <dlfcn.h>
     21 
     22 #include <cstring>
     23 #include <new>
     24 #include <string>
     25 
     26 #include "bcc/Support/FileBase.h"
     27 #include "bcc/Support/Log.h"
     28 
     29 #include <cutils/properties.h>
     30 
     31 using namespace bcc;
     32 
     33 const char RSInfo::LibBCCPath[] = "/system/lib/libbcc.so";
     34 const char RSInfo::LibCompilerRTPath[] = "/system/lib/libcompiler_rt.so";
     35 const char RSInfo::LibRSPath[] = "/system/lib/libRS.so";
     36 const char RSInfo::LibCLCorePath[] = "/system/lib/libclcore.bc";
     37 const char RSInfo::LibCLCoreDebugPath[] = "/system/lib/libclcore_debug.bc";
     38 #if defined(ARCH_X86_HAVE_SSE2)
     39 const char RSInfo::LibCLCoreX86Path[] = "/system/lib/libclcore_x86.bc";
     40 #endif
     41 #if defined(ARCH_ARM_HAVE_NEON)
     42 const char RSInfo::LibCLCoreNEONPath[] = "/system/lib/libclcore_neon.bc";
     43 #endif
     44 
     45 const uint8_t *RSInfo::LibBCCSHA1 = NULL;
     46 const uint8_t *RSInfo::LibCompilerRTSHA1 = NULL;
     47 const uint8_t *RSInfo::LibRSSHA1 = NULL;
     48 const uint8_t *RSInfo::LibCLCoreSHA1 = NULL;
     49 const uint8_t *RSInfo::LibCLCoreDebugSHA1 = NULL;
     50 #if defined(ARCH_ARM_HAVE_NEON)
     51 const uint8_t *RSInfo::LibCLCoreNEONSHA1 = NULL;
     52 #endif
     53 
     54 bool RSInfo::LoadBuiltInSHA1Information() {
     55 #ifdef TARGET_BUILD
     56   if (LibBCCSHA1 != NULL) {
     57     // Loaded before.
     58     return true;
     59   }
     60 
     61   void *h = ::dlopen("/system/lib/libbcc.sha1.so", RTLD_LAZY | RTLD_NOW);
     62   if (h == NULL) {
     63     ALOGE("Failed to load SHA-1 information from shared library '"
     64           "/system/lib/libbcc.sha1.so'! (%s)", ::dlerror());
     65     return false;
     66   }
     67 
     68   LibBCCSHA1 = reinterpret_cast<const uint8_t *>(::dlsym(h, "libbcc_so_SHA1"));
     69   LibCompilerRTSHA1 =
     70       reinterpret_cast<const uint8_t *>(::dlsym(h, "libcompiler_rt_so_SHA1"));
     71   LibRSSHA1 = reinterpret_cast<const uint8_t *>(::dlsym(h, "libRS_so_SHA1"));
     72   LibCLCoreSHA1 =
     73       reinterpret_cast<const uint8_t *>(::dlsym(h, "libclcore_bc_SHA1"));
     74   LibCLCoreDebugSHA1 =
     75       reinterpret_cast<const uint8_t *>(::dlsym(h, "libclcore_debug_bc_SHA1"));
     76 #if defined(ARCH_ARM_HAVE_NEON)
     77   LibCLCoreNEONSHA1 =
     78       reinterpret_cast<const uint8_t *>(::dlsym(h, "libclcore_neon_bc_SHA1"));
     79 #endif
     80 
     81   return true;
     82 #else  // TARGET_BUILD
     83   return false;
     84 #endif  // TARGET_BUILD
     85 }
     86 
     87 android::String8 RSInfo::GetPath(const FileBase &pFile) {
     88   android::String8 result(pFile.getName().c_str());
     89   result.append(".info");
     90   return result;
     91 }
     92 
     93 #define PRINT_DEPENDENCY(PREFIX, N, X) \
     94         ALOGV("\t" PREFIX "Source name: %s, "                                 \
     95                           "SHA-1: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"   \
     96                                  "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",  \
     97               (N), (X)[ 0], (X)[ 1], (X)[ 2], (X)[ 3], (X)[ 4], (X)[ 5],      \
     98                    (X)[ 6], (X)[ 7], (X)[ 8], (X)[ 9], (X)[10], (X)[11],      \
     99                    (X)[12], (X)[13], (X)[14], (X)[15], (X)[16], (X)[17],      \
    100                    (X)[18], (X)[19]);
    101 
    102 bool RSInfo::CheckDependency(const RSInfo &pInfo,
    103                              const char *pInputFilename,
    104                              const DependencyTableTy &pDeps) {
    105   // Built-in dependencies are libbcc.so, libRS.so and libclcore.bc plus
    106   // libclcore_neon.bc if NEON is available on the target device.
    107 #if !defined(ARCH_ARM_HAVE_NEON)
    108   static const unsigned NumBuiltInDependencies = 5;
    109 #else
    110   static const unsigned NumBuiltInDependencies = 6;
    111 #endif
    112 
    113   LoadBuiltInSHA1Information();
    114 
    115   if (pInfo.mDependencyTable.size() != (pDeps.size() + NumBuiltInDependencies)) {
    116     ALOGD("Number of dependencies recorded mismatch (%lu v.s. %lu) in %s!",
    117           static_cast<unsigned long>(pInfo.mDependencyTable.size()),
    118           static_cast<unsigned long>(pDeps.size()), pInputFilename);
    119     return false;
    120   } else {
    121     // Built-in dependencies always go first.
    122     const std::pair<const char *, const uint8_t *> &cache_libbcc_dep =
    123         pInfo.mDependencyTable[0];
    124     const std::pair<const char *, const uint8_t *> &cache_libcompiler_rt_dep =
    125         pInfo.mDependencyTable[1];
    126     const std::pair<const char *, const uint8_t *> &cache_libRS_dep =
    127         pInfo.mDependencyTable[2];
    128     const std::pair<const char *, const uint8_t *> &cache_libclcore_dep =
    129         pInfo.mDependencyTable[3];
    130     const std::pair<const char *, const uint8_t *> &cache_libclcore_debug_dep =
    131         pInfo.mDependencyTable[4];
    132 #if defined(ARCH_ARM_HAVE_NEON)
    133     const std::pair<const char *, const uint8_t *> &cache_libclcore_neon_dep =
    134         pInfo.mDependencyTable[5];
    135 #endif
    136 
    137     // Check libbcc.so.
    138     if (::memcmp(cache_libbcc_dep.second, LibBCCSHA1, SHA1_DIGEST_LENGTH) != 0) {
    139         ALOGD("Cache %s is dirty due to %s has been updated.", pInputFilename,
    140               LibBCCPath);
    141         PRINT_DEPENDENCY("current - ", LibBCCPath, LibBCCSHA1);
    142         PRINT_DEPENDENCY("cache - ", cache_libbcc_dep.first,
    143                                      cache_libbcc_dep.second);
    144         return false;
    145     }
    146 
    147     // Check libcompiler_rt.so.
    148     if (::memcmp(cache_libcompiler_rt_dep.second, LibCompilerRTSHA1,
    149                  SHA1_DIGEST_LENGTH) != 0) {
    150         ALOGD("Cache %s is dirty due to %s has been updated.", pInputFilename,
    151               LibCompilerRTPath);
    152         PRINT_DEPENDENCY("current - ", LibCompilerRTPath, LibCompilerRTSHA1);
    153         PRINT_DEPENDENCY("cache - ", cache_libcompiler_rt_dep.first,
    154                                      cache_libcompiler_rt_dep.second);
    155         return false;
    156     }
    157 
    158     // Check libRS.so.
    159     if (::memcmp(cache_libRS_dep.second, LibRSSHA1, SHA1_DIGEST_LENGTH) != 0) {
    160         ALOGD("Cache %s is dirty due to %s has been updated.", pInputFilename,
    161               LibRSPath);
    162         PRINT_DEPENDENCY("current - ", LibRSPath, LibRSSHA1);
    163         PRINT_DEPENDENCY("cache - ", cache_libRS_dep.first,
    164                                      cache_libRS_dep.second);
    165         return false;
    166     }
    167 
    168     // Check libclcore.bc.
    169     if (::memcmp(cache_libclcore_dep.second, LibCLCoreSHA1,
    170                  SHA1_DIGEST_LENGTH) != 0) {
    171         ALOGD("Cache %s is dirty due to %s has been updated.", pInputFilename,
    172               LibCLCorePath);
    173         PRINT_DEPENDENCY("current - ", LibCLCorePath, LibCLCoreSHA1);
    174         PRINT_DEPENDENCY("cache - ", cache_libclcore_dep.first,
    175                                      cache_libclcore_dep.second);
    176         return false;
    177     }
    178 
    179     // Check libclcore_debug.bc.
    180     if (::memcmp(cache_libclcore_debug_dep.second, LibCLCoreDebugSHA1,
    181                  SHA1_DIGEST_LENGTH) != 0) {
    182         ALOGD("Cache %s is dirty due to %s has been updated.", pInputFilename,
    183               LibCLCoreDebugPath);
    184         PRINT_DEPENDENCY("current - ", LibCLCoreDebugPath, LibCLCoreDebugSHA1);
    185         PRINT_DEPENDENCY("cache - ", cache_libclcore_debug_dep.first,
    186                                      cache_libclcore_debug_dep.second);
    187         return false;
    188     }
    189 
    190 #if defined(ARCH_ARM_HAVE_NEON)
    191     // Check libclcore_neon.bc if NEON is available.
    192     if (::memcmp(cache_libclcore_neon_dep.second, LibCLCoreNEONSHA1,
    193                  SHA1_DIGEST_LENGTH) != 0) {
    194         ALOGD("Cache %s is dirty due to %s has been updated.", pInputFilename,
    195               LibCLCoreNEONPath);
    196         PRINT_DEPENDENCY("current - ", LibCLCoreNEONPath, LibCLCoreNEONSHA1);
    197         PRINT_DEPENDENCY("cache - ", cache_libclcore_neon_dep.first,
    198                                      cache_libclcore_neon_dep.second);
    199         return false;
    200     }
    201 #endif
    202 
    203     for (unsigned i = 0; i < pDeps.size(); i++) {
    204       const std::pair<const char *, const uint8_t *> &cache_dep =
    205           pInfo.mDependencyTable[i + NumBuiltInDependencies];
    206 
    207       if ((::strcmp(pDeps[i].first, cache_dep.first) != 0) ||
    208           (::memcmp(pDeps[i].second, cache_dep.second,
    209                     SHA1_DIGEST_LENGTH) != 0)) {
    210         ALOGD("Cache %s is dirty due to the source it dependends on has been "
    211               "changed:", pInputFilename);
    212         PRINT_DEPENDENCY("given - ", pDeps[i].first, pDeps[i].second);
    213         PRINT_DEPENDENCY("cache - ", cache_dep.first, cache_dep.second);
    214         return false;
    215       }
    216     }
    217   }
    218 
    219   return true;
    220 }
    221 
    222 RSInfo::RSInfo(size_t pStringPoolSize) : mStringPool(NULL) {
    223   ::memset(&mHeader, 0, sizeof(mHeader));
    224 
    225   ::memcpy(mHeader.magic, RSINFO_MAGIC, sizeof(mHeader.magic));
    226   ::memcpy(mHeader.version, RSINFO_VERSION, sizeof(mHeader.version));
    227 
    228   mHeader.headerSize = sizeof(mHeader);
    229 
    230   mHeader.dependencyTable.itemSize = sizeof(rsinfo::DependencyTableItem);
    231   mHeader.pragmaList.itemSize = sizeof(rsinfo::PragmaItem);
    232   mHeader.objectSlotList.itemSize = sizeof(rsinfo::ObjectSlotItem);
    233   mHeader.exportVarNameList.itemSize = sizeof(rsinfo::ExportVarNameItem);
    234   mHeader.exportFuncNameList.itemSize = sizeof(rsinfo::ExportFuncNameItem);
    235   mHeader.exportForeachFuncList.itemSize = sizeof(rsinfo::ExportForeachFuncItem);
    236 
    237   if (pStringPoolSize > 0) {
    238     mHeader.strPoolSize = pStringPoolSize;
    239     mStringPool = new (std::nothrow) char [ mHeader.strPoolSize ];
    240     if (mStringPool == NULL) {
    241       ALOGE("Out of memory when allocate memory for string pool in RSInfo "
    242             "constructor (size: %u)!", mHeader.strPoolSize);
    243     }
    244   }
    245 }
    246 
    247 RSInfo::~RSInfo() {
    248   delete [] mStringPool;
    249 }
    250 
    251 bool RSInfo::layout(off_t initial_offset) {
    252   mHeader.dependencyTable.offset = initial_offset +
    253                                    mHeader.headerSize +
    254                                    mHeader.strPoolSize;
    255   mHeader.dependencyTable.count = mDependencyTable.size();
    256 
    257 #define AFTER(_list) ((_list).offset + (_list).itemSize * (_list).count)
    258   mHeader.pragmaList.offset = AFTER(mHeader.dependencyTable);
    259   mHeader.pragmaList.count = mPragmas.size();
    260 
    261   mHeader.objectSlotList.offset = AFTER(mHeader.pragmaList);
    262   mHeader.objectSlotList.count = mObjectSlots.size();
    263 
    264   mHeader.exportVarNameList.offset = AFTER(mHeader.objectSlotList);
    265   mHeader.exportVarNameList.count = mExportVarNames.size();
    266 
    267   mHeader.exportFuncNameList.offset = AFTER(mHeader.exportVarNameList);
    268   mHeader.exportFuncNameList.count = mExportFuncNames.size();
    269 
    270   mHeader.exportForeachFuncList.offset = AFTER(mHeader.exportFuncNameList);
    271   mHeader.exportForeachFuncList.count = mExportForeachFuncs.size();
    272 #undef AFTER
    273 
    274   return true;
    275 }
    276 
    277 void RSInfo::dump() const {
    278   // Hide the codes to save the code size when debugging is disabled.
    279 #if !LOG_NDEBUG
    280 
    281   // Dump header
    282   ALOGV("RSInfo Header:");
    283   ALOGV("\tIs threadable: %s", ((mHeader.isThreadable) ? "true" : "false"));
    284   ALOGV("\tHeader size: %u", mHeader.headerSize);
    285   ALOGV("\tString pool size: %u", mHeader.strPoolSize);
    286 
    287 #define DUMP_LIST_HEADER(_name, _header) do { \
    288   ALOGV(_name ":"); \
    289   ALOGV("\toffset: %u", (_header).offset);  \
    290   ALOGV("\t# of item: %u", (_header).count);  \
    291   ALOGV("\tsize of each item: %u", (_header).itemSize); \
    292 } while (false)
    293   DUMP_LIST_HEADER("Dependency table", mHeader.dependencyTable);
    294   for (DependencyTableTy::const_iterator dep_iter = mDependencyTable.begin(),
    295           dep_end = mDependencyTable.end(); dep_iter != dep_end; dep_iter++) {
    296     PRINT_DEPENDENCY("", dep_iter->first, dep_iter->second);
    297   }
    298 
    299   DUMP_LIST_HEADER("Pragma list", mHeader.pragmaList);
    300   for (PragmaListTy::const_iterator pragma_iter = mPragmas.begin(),
    301         pragma_end = mPragmas.end(); pragma_iter != pragma_end; pragma_iter++) {
    302     ALOGV("\tkey: %s, value: %s", pragma_iter->first, pragma_iter->second);
    303   }
    304 
    305   DUMP_LIST_HEADER("RS object slots", mHeader.objectSlotList);
    306   for (ObjectSlotListTy::const_iterator slot_iter = mObjectSlots.begin(),
    307           slot_end = mObjectSlots.end(); slot_iter != slot_end; slot_iter++) {
    308     ALOGV("slot: %u", *slot_iter);
    309   }
    310 
    311   DUMP_LIST_HEADER("RS export variables", mHeader.exportVarNameList);
    312   for (ExportVarNameListTy::const_iterator var_iter = mExportVarNames.begin(),
    313           var_end = mExportVarNames.end(); var_iter != var_end; var_iter++) {
    314     ALOGV("name: %s", *var_iter);
    315   }
    316 
    317   DUMP_LIST_HEADER("RS export functions", mHeader.exportFuncNameList);
    318   for (ExportFuncNameListTy::const_iterator func_iter = mExportFuncNames.begin(),
    319         func_end = mExportFuncNames.end(); func_iter != func_end; func_iter++) {
    320     ALOGV("name: %s", *func_iter);
    321   }
    322 
    323   DUMP_LIST_HEADER("RS foreach list", mHeader.exportForeachFuncList);
    324   for (ExportForeachFuncListTy::const_iterator
    325           foreach_iter = mExportForeachFuncs.begin(),
    326           foreach_end = mExportForeachFuncs.end(); foreach_iter != foreach_end;
    327           foreach_iter++) {
    328     ALOGV("name: %s, signature: %05x", foreach_iter->first,
    329                                        foreach_iter->second);
    330   }
    331 #undef DUMP_LIST_HEADER
    332 
    333 #endif // LOG_NDEBUG
    334   return;
    335 }
    336 
    337 const char *RSInfo::getStringFromPool(rsinfo::StringIndexTy pStrIdx) const {
    338   // String pool uses direct indexing. Ensure that the pStrIdx is within the
    339   // range.
    340   if (pStrIdx >= mHeader.strPoolSize) {
    341     ALOGE("String index #%u is out of range in string pool (size: %u)!",
    342           pStrIdx, mHeader.strPoolSize);
    343     return NULL;
    344   }
    345   return &mStringPool[ pStrIdx ];
    346 }
    347 
    348 rsinfo::StringIndexTy RSInfo::getStringIdxInPool(const char *pStr) const {
    349   // Assume we are on the flat memory architecture (i.e., the memory space is
    350   // continuous.)
    351   if ((mStringPool + mHeader.strPoolSize) < pStr) {
    352     ALOGE("String %s does not in the string pool!", pStr);
    353     return rsinfo::gInvalidStringIndex;
    354   }
    355   return (pStr - mStringPool);
    356 }
    357 
    358 RSInfo::FloatPrecision RSInfo::getFloatPrecisionRequirement() const {
    359   // Check to see if we have any FP precision-related pragmas.
    360   std::string relaxed_pragma("rs_fp_relaxed");
    361   std::string imprecise_pragma("rs_fp_imprecise");
    362   std::string full_pragma("rs_fp_full");
    363   bool relaxed_pragma_seen = false;
    364   bool imprecise_pragma_seen = false;
    365   RSInfo::FloatPrecision result = FP_Full;
    366 
    367   for (PragmaListTy::const_iterator pragma_iter = mPragmas.begin(),
    368            pragma_end = mPragmas.end(); pragma_iter != pragma_end;
    369        pragma_iter++) {
    370     const char *pragma_key = pragma_iter->first;
    371     if (!relaxed_pragma.compare(pragma_key)) {
    372       if (relaxed_pragma_seen || imprecise_pragma_seen) {
    373         ALOGE("Multiple float precision pragmas specified!");
    374       }
    375       relaxed_pragma_seen = true;
    376     } else if (!imprecise_pragma.compare(pragma_key)) {
    377       if (relaxed_pragma_seen || imprecise_pragma_seen) {
    378         ALOGE("Multiple float precision pragmas specified!");
    379       }
    380       imprecise_pragma_seen = true;
    381     }
    382   }
    383 
    384   // Imprecise is selected over Relaxed precision.
    385   // In the absence of both, we stick to the default Full precision.
    386   if (imprecise_pragma_seen) {
    387     result = FP_Imprecise;
    388   } else if (relaxed_pragma_seen) {
    389     result = FP_Relaxed;
    390   }
    391 
    392   // Provide an override for precsion via adb shell setprop
    393   // adb shell setprop debug.rs.precision rs_fp_full
    394   // adb shell setprop debug.rs.precision rs_fp_relaxed
    395   // adb shell setprop debug.rs.precision rs_fp_imprecise
    396   char precision_prop_buf[PROPERTY_VALUE_MAX];
    397   property_get("debug.rs.precision", precision_prop_buf, "");
    398 
    399   if (precision_prop_buf[0]) {
    400     if (!relaxed_pragma.compare(precision_prop_buf)) {
    401       ALOGI("Switching to RS FP relaxed mode via setprop");
    402       result = FP_Relaxed;
    403     } else if (!imprecise_pragma.compare(precision_prop_buf)) {
    404       ALOGI("Switching to RS FP imprecise mode via setprop");
    405       result = FP_Imprecise;
    406     } else if (!full_pragma.compare(precision_prop_buf)) {
    407       ALOGI("Switching to RS FP full mode via setprop");
    408       result = FP_Full;
    409     }
    410   }
    411 
    412   return result;
    413 }
    414