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#include "rs.h" 18#include "rsDevice.h" 19#include "rsContext.h" 20#include "rsThreadIO.h" 21 22#include <sys/types.h> 23#include <sys/resource.h> 24#include <sched.h> 25 26#include <cutils/properties.h> 27 28#include <sys/syscall.h> 29#include <string.h> 30 31using namespace android; 32using namespace android::renderscript; 33 34pthread_mutex_t Context::gInitMutex = PTHREAD_MUTEX_INITIALIZER; 35pthread_mutex_t Context::gLibMutex = PTHREAD_MUTEX_INITIALIZER; 36 37bool Context::initGLThread() { 38 pthread_mutex_lock(&gInitMutex); 39 40 if (!mHal.funcs.initGraphics(this)) { 41 pthread_mutex_unlock(&gInitMutex); 42 ALOGE("%p initGraphics failed", this); 43 return false; 44 } 45 46 pthread_mutex_unlock(&gInitMutex); 47 return true; 48} 49 50void Context::deinitEGL() { 51 //mHal.funcs.shutdownGraphics(this); 52} 53 54Context::PushState::PushState(Context *con) { 55 mRsc = con; 56} 57 58Context::PushState::~PushState() { 59} 60 61 62uint32_t Context::runScript(Script *s) { 63 PushState ps(this); 64 65 uint32_t ret = s->run(this); 66 return ret; 67} 68 69uint32_t Context::runRootScript() { 70 timerSet(RS_TIMER_SCRIPT); 71 watchdog.inRoot = true; 72 uint32_t ret = runScript(mRootScript.get()); 73 watchdog.inRoot = false; 74 75 return ret; 76} 77 78uint64_t Context::getTime() const { 79#ifndef ANDROID_RS_SERIALIZE 80 struct timespec t; 81 clock_gettime(CLOCK_MONOTONIC, &t); 82 return t.tv_nsec + ((uint64_t)t.tv_sec * 1000 * 1000 * 1000); 83#else 84 return 0; 85#endif //ANDROID_RS_SERIALIZE 86} 87 88void Context::timerReset() { 89 for (int ct=0; ct < _RS_TIMER_TOTAL; ct++) { 90 mTimers[ct] = 0; 91 } 92} 93 94void Context::timerInit() { 95 mTimeLast = getTime(); 96 mTimeFrame = mTimeLast; 97 mTimeLastFrame = mTimeLast; 98 mTimerActive = RS_TIMER_INTERNAL; 99 mAverageFPSFrameCount = 0; 100 mAverageFPSStartTime = mTimeLast; 101 mAverageFPS = 0; 102 timerReset(); 103} 104 105void Context::timerFrame() { 106 mTimeLastFrame = mTimeFrame; 107 mTimeFrame = getTime(); 108 // Update average fps 109 const uint64_t averageFramerateInterval = 1000 * 1000000; 110 mAverageFPSFrameCount ++; 111 uint64_t inverval = mTimeFrame - mAverageFPSStartTime; 112 if (inverval >= averageFramerateInterval) { 113 inverval = inverval / 1000000; 114 mAverageFPS = (mAverageFPSFrameCount * 1000) / inverval; 115 mAverageFPSFrameCount = 0; 116 mAverageFPSStartTime = mTimeFrame; 117 } 118} 119 120void Context::timerSet(Timers tm) { 121 uint64_t last = mTimeLast; 122 mTimeLast = getTime(); 123 mTimers[mTimerActive] += mTimeLast - last; 124 mTimerActive = tm; 125} 126 127void Context::timerPrint() { 128 double total = 0; 129 for (int ct = 0; ct < _RS_TIMER_TOTAL; ct++) { 130 total += mTimers[ct]; 131 } 132 uint64_t frame = mTimeFrame - mTimeLastFrame; 133 mTimeMSLastFrame = frame / 1000000; 134 mTimeMSLastScript = mTimers[RS_TIMER_SCRIPT] / 1000000; 135 mTimeMSLastSwap = mTimers[RS_TIMER_CLEAR_SWAP] / 1000000; 136 137 138 if (props.mLogTimes) { 139 ALOGV("RS: Frame (%i), Script %2.1f%% (%i), Swap %2.1f%% (%i), Idle %2.1f%% (%lli), Internal %2.1f%% (%lli), Avg fps: %u", 140 mTimeMSLastFrame, 141 100.0 * mTimers[RS_TIMER_SCRIPT] / total, mTimeMSLastScript, 142 100.0 * mTimers[RS_TIMER_CLEAR_SWAP] / total, mTimeMSLastSwap, 143 100.0 * mTimers[RS_TIMER_IDLE] / total, mTimers[RS_TIMER_IDLE] / 1000000, 144 100.0 * mTimers[RS_TIMER_INTERNAL] / total, mTimers[RS_TIMER_INTERNAL] / 1000000, 145 mAverageFPS); 146 } 147} 148 149bool Context::setupCheck() { 150 151 return true; 152} 153 154static uint32_t getProp(const char *str) { 155 char buf[PROPERTY_VALUE_MAX]; 156 property_get(str, buf, "0"); 157 return atoi(buf); 158} 159 160void Context::displayDebugStats() { 161} 162 163void * Context::threadProc(void *vrsc) { 164 Context *rsc = static_cast<Context *>(vrsc); 165#ifndef ANDROID_RS_SERIALIZE 166 rsc->mNativeThreadId = gettid(); 167 // TODO: Use proper ANDROID_PRIORITY_DISPLAY 168 setpriority(PRIO_PROCESS, rsc->mNativeThreadId, /* ANDROID_PRIORITY_DISPLAY */ -4); 169 rsc->mThreadPriority = /* ANDROID_PRIORITY_DISPLAY */ -4; 170#endif //ANDROID_RS_SERIALIZE 171 rsc->props.mLogTimes = getProp("debug.rs.profile") != 0; 172 rsc->props.mLogScripts = getProp("debug.rs.script") != 0; 173 rsc->props.mLogObjects = getProp("debug.rs.object") != 0; 174 rsc->props.mLogShaders = getProp("debug.rs.shader") != 0; 175 rsc->props.mLogShadersAttr = getProp("debug.rs.shader.attributes") != 0; 176 rsc->props.mLogShadersUniforms = getProp("debug.rs.shader.uniforms") != 0; 177 rsc->props.mLogVisual = getProp("debug.rs.visual") != 0; 178 rsc->props.mDebugMaxThreads = getProp("debug.rs.max-threads"); 179 180 if (!rsdHalInit(rsc, 0, 0)) { 181 rsc->setError(RS_ERROR_FATAL_DRIVER, "Failed initializing GL"); 182 ALOGE("Hal init failed"); 183 return NULL; 184 } 185 rsc->mHal.funcs.setPriority(rsc, rsc->mThreadPriority); 186 187 rsc->mRunning = true; 188 if (!rsc->mIsGraphicsContext) { 189 while (!rsc->mExit) { 190 rsc->mIO.playCoreCommands(rsc, -1); 191 } 192 } 193 ALOGV("%p RS Thread exiting", rsc); 194 195 ALOGV("%p RS Thread exited", rsc); 196 return NULL; 197} 198 199void Context::destroyWorkerThreadResources() { 200 //ALOGV("destroyWorkerThreadResources 1"); 201 ObjectBase::zeroAllUserRef(this); 202 ObjectBase::freeAllChildren(this); 203 mExit = true; 204 //ALOGV("destroyWorkerThreadResources 2"); 205} 206 207void Context::printWatchdogInfo(void *ctx) { 208 Context *rsc = (Context *)ctx; 209 if (rsc->watchdog.command && rsc->watchdog.file) { 210 ALOGE("RS watchdog timeout: %i %s line %i %s", rsc->watchdog.inRoot, 211 rsc->watchdog.command, rsc->watchdog.line, rsc->watchdog.file); 212 } else { 213 ALOGE("RS watchdog timeout: %i", rsc->watchdog.inRoot); 214 } 215} 216 217 218void Context::setPriority(int32_t p) { 219 // Note: If we put this in the proper "background" policy 220 // the wallpapers can become completly unresponsive at times. 221 // This is probably not what we want for something the user is actively 222 // looking at. 223 mThreadPriority = p; 224 setpriority(PRIO_PROCESS, mNativeThreadId, p); 225 mHal.funcs.setPriority(this, mThreadPriority); 226} 227 228Context::Context() { 229 mDev = NULL; 230 mRunning = false; 231 mExit = false; 232 mPaused = false; 233 mObjHead = NULL; 234 mError = RS_ERROR_NONE; 235 mTargetSdkVersion = 14; 236 mDPI = 96; 237 mIsContextLite = false; 238 memset(&watchdog, 0, sizeof(watchdog)); 239} 240 241Context * Context::createContext(Device *dev, const RsSurfaceConfig *sc) { 242 Context * rsc = new Context(); 243 244 if (!rsc->initContext(dev, sc)) { 245 delete rsc; 246 return NULL; 247 } 248 return rsc; 249} 250 251Context * Context::createContextLite() { 252 Context * rsc = new Context(); 253 rsc->mIsContextLite = true; 254 return rsc; 255} 256 257bool Context::initContext(Device *dev, const RsSurfaceConfig *sc) { 258 pthread_mutex_lock(&gInitMutex); 259 260 mIO.init(); 261 mIO.setTimeoutCallback(printWatchdogInfo, this, 2e9); 262 263 dev->addContext(this); 264 mDev = dev; 265 if (sc) { 266 mUserSurfaceConfig = *sc; 267 } else { 268 memset(&mUserSurfaceConfig, 0, sizeof(mUserSurfaceConfig)); 269 } 270 271 mIsGraphicsContext = sc != NULL; 272 273 int status; 274 pthread_attr_t threadAttr; 275 276 pthread_mutex_unlock(&gInitMutex); 277 278 // Global init done at this point. 279 280 status = pthread_attr_init(&threadAttr); 281 if (status) { 282 ALOGE("Failed to init thread attribute."); 283 return false; 284 } 285 286 mHasSurface = false; 287 288 timerInit(); 289 timerSet(RS_TIMER_INTERNAL); 290 291 status = pthread_create(&mThreadId, &threadAttr, threadProc, this); 292 if (status) { 293 ALOGE("Failed to start rs context thread."); 294 return false; 295 } 296 while (!mRunning && (mError == RS_ERROR_NONE)) { 297 usleep(100); 298 } 299 300 if (mError != RS_ERROR_NONE) { 301 ALOGE("Errors during thread init"); 302 return false; 303 } 304 305 pthread_attr_destroy(&threadAttr); 306 return true; 307} 308 309Context::~Context() { 310 ALOGV("%p Context::~Context", this); 311 312 if (!mIsContextLite) { 313 mPaused = false; 314 void *res; 315 316 mIO.shutdown(); 317 int status = pthread_join(mThreadId, &res); 318 rsAssert(mExit); 319 320 if (mHal.funcs.shutdownDriver) { 321 mHal.funcs.shutdownDriver(this); 322 } 323 324 // Global structure cleanup. 325 pthread_mutex_lock(&gInitMutex); 326 if (mDev) { 327 mDev->removeContext(this); 328 mDev = NULL; 329 } 330 pthread_mutex_unlock(&gInitMutex); 331 } 332 ALOGV("%p Context::~Context done", this); 333} 334 335void Context::assignName(ObjectBase *obj, const char *name, uint32_t len) { 336 rsAssert(!obj->getName()); 337 obj->setName(name, len); 338 mNames.add(obj); 339} 340 341void Context::removeName(ObjectBase *obj) { 342 for (size_t ct=0; ct < mNames.size(); ct++) { 343 if (obj == mNames[ct]) { 344 mNames.removeAt(ct); 345 return; 346 } 347 } 348} 349 350RsMessageToClientType Context::peekMessageToClient(size_t *receiveLen, uint32_t *subID) { 351 return (RsMessageToClientType)mIO.getClientHeader(receiveLen, subID); 352} 353 354RsMessageToClientType Context::getMessageToClient(void *data, size_t *receiveLen, uint32_t *subID, size_t bufferLen) { 355 return (RsMessageToClientType)mIO.getClientPayload(data, receiveLen, subID, bufferLen); 356} 357 358bool Context::sendMessageToClient(const void *data, RsMessageToClientType cmdID, 359 uint32_t subID, size_t len, bool waitForSpace) const { 360 361 return mIO.sendToClient(cmdID, subID, data, len, waitForSpace); 362} 363 364void Context::initToClient() { 365 while (!mRunning) { 366 usleep(100); 367 } 368} 369 370void Context::deinitToClient() { 371 mIO.clientShutdown(); 372} 373 374void Context::setError(RsError e, const char *msg) const { 375 mError = e; 376 sendMessageToClient(msg, RS_MESSAGE_TO_CLIENT_ERROR, e, strlen(msg) + 1, true); 377} 378 379 380void Context::dumpDebug() const { 381 ALOGE("RS Context debug %p", this); 382 ALOGE("RS Context debug"); 383 384 ALOGE(" RS width %i, height %i", mWidth, mHeight); 385 ALOGE(" RS running %i, exit %i, paused %i", mRunning, mExit, mPaused); 386 ALOGE(" RS pThreadID %li, nativeThreadID %i", (long int)mThreadId, mNativeThreadId); 387} 388 389/////////////////////////////////////////////////////////////////////////////////////////// 390// 391 392namespace android { 393namespace renderscript { 394 395void rsi_ContextFinish(Context *rsc) { 396} 397 398void rsi_ContextBindRootScript(Context *rsc, RsScript vs) { 399 Script *s = static_cast<Script *>(vs); 400 //rsc->setRootScript(s); 401} 402 403void rsi_ContextBindSampler(Context *rsc, uint32_t slot, RsSampler vs) { 404 Sampler *s = static_cast<Sampler *>(vs); 405 406 if (slot > RS_MAX_SAMPLER_SLOT) { 407 ALOGE("Invalid sampler slot"); 408 return; 409 } 410 411 s->bindToContext(&rsc->mStateSampler, slot); 412} 413 414void rsi_AssignName(Context *rsc, RsObjectBase obj, const char *name, size_t name_length) { 415 ObjectBase *ob = static_cast<ObjectBase *>(obj); 416 rsc->assignName(ob, name, name_length); 417} 418 419void rsi_ObjDestroy(Context *rsc, void *optr) { 420 ObjectBase *ob = static_cast<ObjectBase *>(optr); 421 rsc->removeName(ob); 422 ob->decUserRef(); 423} 424 425void rsi_ContextSetPriority(Context *rsc, int32_t p) { 426 rsc->setPriority(p); 427} 428 429void rsi_ContextDump(Context *rsc, int32_t bits) { 430 ObjectBase::dumpAll(rsc); 431} 432 433void rsi_ContextDestroyWorker(Context *rsc) { 434 rsc->destroyWorkerThreadResources(); 435} 436 437void rsi_ContextDestroy(Context *rsc) { 438 ALOGV("%p rsContextDestroy", rsc); 439 rsContextDestroyWorker(rsc); 440 delete rsc; 441 ALOGV("%p rsContextDestroy done", rsc); 442} 443 444 445RsMessageToClientType rsi_ContextPeekMessage(Context *rsc, 446 size_t * receiveLen, size_t receiveLen_length, 447 uint32_t * subID, size_t subID_length) { 448 return rsc->peekMessageToClient(receiveLen, subID); 449} 450 451RsMessageToClientType rsi_ContextGetMessage(Context *rsc, void * data, size_t data_length, 452 size_t * receiveLen, size_t receiveLen_length, 453 uint32_t * subID, size_t subID_length) { 454 rsAssert(subID_length == sizeof(uint32_t)); 455 rsAssert(receiveLen_length == sizeof(size_t)); 456 return rsc->getMessageToClient(data, receiveLen, subID, data_length); 457} 458 459void rsi_ContextInitToClient(Context *rsc) { 460 rsc->initToClient(); 461} 462 463void rsi_ContextDeinitToClient(Context *rsc) { 464 rsc->deinitToClient(); 465} 466 467} 468} 469 470RsContext rsContextCreate(RsDevice vdev, uint32_t version, 471 uint32_t sdkVersion) { 472 ALOGV("rsContextCreate dev=%p", vdev); 473 Device * dev = static_cast<Device *>(vdev); 474 Context *rsc = Context::createContext(dev, NULL); 475 if (rsc) { 476 rsc->setTargetSdkVersion(sdkVersion); 477 } 478 return rsc; 479} 480 481// Only to be called at a3d load time, before object is visible to user 482// not thread safe 483void rsaGetName(RsContext con, void * obj, const char **name) { 484 ObjectBase *ob = static_cast<ObjectBase *>(obj); 485 (*name) = ob->getName(); 486} 487