rsContext.cpp revision 9e4e13d87e834b1cb770407cef0778c262b02b72
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 "rsDevice.h" 18#include "rsContext.h" 19#include "rsThreadIO.h" 20#include <ui/FramebufferNativeWindow.h> 21#include <ui/EGLUtils.h> 22 23#include <cutils/properties.h> 24 25#include <GLES/gl.h> 26#include <GLES/glext.h> 27 28using namespace android; 29using namespace android::renderscript; 30 31pthread_key_t Context::gThreadTLSKey = 0; 32 33void Context::initEGL() 34{ 35 mEGL.mNumConfigs = -1; 36 EGLint configAttribs[128]; 37 EGLint *configAttribsPtr = configAttribs; 38 39 memset(configAttribs, 0, sizeof(configAttribs)); 40 41 configAttribsPtr[0] = EGL_SURFACE_TYPE; 42 configAttribsPtr[1] = EGL_WINDOW_BIT; 43 configAttribsPtr += 2; 44 45 if (mUseDepth) { 46 configAttribsPtr[0] = EGL_DEPTH_SIZE; 47 configAttribsPtr[1] = 16; 48 configAttribsPtr += 2; 49 } 50 51 if (mDev->mForceSW) { 52 configAttribsPtr[0] = EGL_CONFIG_CAVEAT; 53 configAttribsPtr[1] = EGL_SLOW_CONFIG; 54 configAttribsPtr += 2; 55 } 56 57 configAttribsPtr[0] = EGL_NONE; 58 rsAssert(configAttribsPtr < (configAttribs + (sizeof(configAttribs) / sizeof(EGLint)))); 59 60 mEGL.mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); 61 eglInitialize(mEGL.mDisplay, &mEGL.mMajorVersion, &mEGL.mMinorVersion); 62 63 status_t err = EGLUtils::selectConfigForNativeWindow(mEGL.mDisplay, configAttribs, mWndSurface, &mEGL.mConfig); 64 if (err) { 65 LOGE("couldn't find an EGLConfig matching the screen format\n"); 66 } 67 //eglChooseConfig(mEGL.mDisplay, configAttribs, &mEGL.mConfig, 1, &mEGL.mNumConfigs); 68 69 if (mWndSurface) { 70 mEGL.mSurface = eglCreateWindowSurface(mEGL.mDisplay, mEGL.mConfig, mWndSurface, NULL); 71 } else { 72 mEGL.mSurface = eglCreateWindowSurface(mEGL.mDisplay, mEGL.mConfig, 73 android_createDisplaySurface(), 74 NULL); 75 } 76 77 mEGL.mContext = eglCreateContext(mEGL.mDisplay, mEGL.mConfig, NULL, NULL); 78 eglMakeCurrent(mEGL.mDisplay, mEGL.mSurface, mEGL.mSurface, mEGL.mContext); 79 eglQuerySurface(mEGL.mDisplay, mEGL.mSurface, EGL_WIDTH, &mEGL.mWidth); 80 eglQuerySurface(mEGL.mDisplay, mEGL.mSurface, EGL_HEIGHT, &mEGL.mHeight); 81 82 83 mGL.mVersion = glGetString(GL_VERSION); 84 mGL.mVendor = glGetString(GL_VENDOR); 85 mGL.mRenderer = glGetString(GL_RENDERER); 86 mGL.mExtensions = glGetString(GL_EXTENSIONS); 87 88 LOGV("EGL Version %i %i", mEGL.mMajorVersion, mEGL.mMinorVersion); 89 LOGV("GL Version %s", mGL.mVersion); 90 LOGV("GL Vendor %s", mGL.mVendor); 91 LOGV("GL Renderer %s", mGL.mRenderer); 92 LOGV("GL Extensions %s", mGL.mExtensions); 93 94 if ((strlen((const char *)mGL.mVersion) < 12) || memcmp(mGL.mVersion, "OpenGL ES-CM", 12)) { 95 LOGE("Error, OpenGL ES Lite not supported"); 96 } else { 97 sscanf((const char *)mGL.mVersion + 13, "%i.%i", &mGL.mMajorVersion, &mGL.mMinorVersion); 98 } 99} 100 101bool Context::runScript(Script *s, uint32_t launchID) 102{ 103 ObjectBaseRef<ProgramFragment> frag(mFragment); 104 ObjectBaseRef<ProgramVertex> vtx(mVertex); 105 ObjectBaseRef<ProgramFragmentStore> store(mFragmentStore); 106 ObjectBaseRef<ProgramRaster> raster(mRaster); 107 108 bool ret = s->run(this, launchID); 109 110 mFragment.set(frag); 111 mVertex.set(vtx); 112 mFragmentStore.set(store); 113 mRaster.set(raster); 114 return ret; 115} 116 117 118bool Context::runRootScript() 119{ 120 if (props.mLogTimes) { 121 timerSet(RS_TIMER_CLEAR_SWAP); 122 } 123 rsAssert(mRootScript->mEnviroment.mIsRoot); 124 125 eglQuerySurface(mEGL.mDisplay, mEGL.mSurface, EGL_WIDTH, &mEGL.mWidth); 126 eglQuerySurface(mEGL.mDisplay, mEGL.mSurface, EGL_HEIGHT, &mEGL.mHeight); 127 glViewport(0, 0, mEGL.mWidth, mEGL.mHeight); 128 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); 129 130 glClearColor(mRootScript->mEnviroment.mClearColor[0], 131 mRootScript->mEnviroment.mClearColor[1], 132 mRootScript->mEnviroment.mClearColor[2], 133 mRootScript->mEnviroment.mClearColor[3]); 134 if (mUseDepth) { 135 glDepthMask(GL_TRUE); 136 glClearDepthf(mRootScript->mEnviroment.mClearDepth); 137 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 138 } else { 139 glClear(GL_COLOR_BUFFER_BIT); 140 } 141 142 if (this->props.mLogTimes) { 143 timerSet(RS_TIMER_SCRIPT); 144 } 145 mStateFragmentStore.mLast.clear(); 146 bool ret = runScript(mRootScript.get(), 0); 147 return ret; 148} 149 150uint64_t Context::getTime() const 151{ 152 struct timespec t; 153 clock_gettime(CLOCK_MONOTONIC, &t); 154 return t.tv_nsec + ((uint64_t)t.tv_sec * 1000 * 1000 * 1000); 155} 156 157void Context::timerReset() 158{ 159 for (int ct=0; ct < _RS_TIMER_TOTAL; ct++) { 160 mTimers[ct] = 0; 161 } 162} 163 164void Context::timerInit() 165{ 166 mTimeLast = getTime(); 167 mTimeFrame = mTimeLast; 168 mTimeLastFrame = mTimeLast; 169 mTimerActive = RS_TIMER_INTERNAL; 170 timerReset(); 171} 172 173void Context::timerFrame() 174{ 175 mTimeLastFrame = mTimeFrame; 176 mTimeFrame = getTime(); 177} 178 179void Context::timerSet(Timers tm) 180{ 181 uint64_t last = mTimeLast; 182 mTimeLast = getTime(); 183 mTimers[mTimerActive] += mTimeLast - last; 184 mTimerActive = tm; 185} 186 187void Context::timerPrint() 188{ 189 double total = 0; 190 for (int ct = 0; ct < _RS_TIMER_TOTAL; ct++) { 191 total += mTimers[ct]; 192 } 193 uint64_t frame = mTimeFrame - mTimeLastFrame; 194 195 LOGV("RS: Frame (%lli), Script %2.1f (%lli), Clear & Swap %2.1f (%lli), Idle %2.1f (%lli), Internal %2.1f (%lli)", 196 frame / 1000000, 197 100.0 * mTimers[RS_TIMER_SCRIPT] / total, mTimers[RS_TIMER_SCRIPT] / 1000000, 198 100.0 * mTimers[RS_TIMER_CLEAR_SWAP] / total, mTimers[RS_TIMER_CLEAR_SWAP] / 1000000, 199 100.0 * mTimers[RS_TIMER_IDLE] / total, mTimers[RS_TIMER_IDLE] / 1000000, 200 100.0 * mTimers[RS_TIMER_INTERNAL] / total, mTimers[RS_TIMER_INTERNAL] / 1000000); 201} 202 203void Context::setupCheck() 204{ 205 mFragmentStore->setupGL(this, &mStateFragmentStore); 206 mFragment->setupGL(this, &mStateFragment); 207 mRaster->setupGL(this, &mStateRaster); 208 mVertex->setupGL(this, &mStateVertex); 209} 210 211static bool getProp(const char *str) 212{ 213 char buf[PROPERTY_VALUE_MAX]; 214 property_get(str, buf, "0"); 215 return 0 != strcmp(buf, "0"); 216} 217 218void * Context::threadProc(void *vrsc) 219{ 220 Context *rsc = static_cast<Context *>(vrsc); 221 222 rsc->props.mLogTimes = getProp("debug.rs.profile"); 223 rsc->props.mLogScripts = getProp("debug.rs.script"); 224 rsc->props.mLogObjects = getProp("debug.rs.objects"); 225 226 rsc->initEGL(); 227 228 ScriptTLSStruct *tlsStruct = new ScriptTLSStruct; 229 if (!tlsStruct) { 230 LOGE("Error allocating tls storage"); 231 return NULL; 232 } 233 tlsStruct->mContext = rsc; 234 tlsStruct->mScript = NULL; 235 int status = pthread_setspecific(rsc->gThreadTLSKey, tlsStruct); 236 if (status) { 237 LOGE("pthread_setspecific %i", status); 238 } 239 240 rsc->mStateRaster.init(rsc, rsc->mEGL.mWidth, rsc->mEGL.mHeight); 241 rsc->setRaster(NULL); 242 rsc->mStateVertex.init(rsc, rsc->mEGL.mWidth, rsc->mEGL.mHeight); 243 rsc->setVertex(NULL); 244 rsc->mStateFragment.init(rsc, rsc->mEGL.mWidth, rsc->mEGL.mHeight); 245 rsc->setFragment(NULL); 246 rsc->mStateFragmentStore.init(rsc, rsc->mEGL.mWidth, rsc->mEGL.mHeight); 247 rsc->setFragmentStore(NULL); 248 249 rsc->mRunning = true; 250 bool mDraw = true; 251 while (!rsc->mExit) { 252 mDraw |= rsc->mIO.playCoreCommands(rsc, !mDraw); 253 mDraw &= (rsc->mRootScript.get() != NULL); 254 255 if (mDraw) { 256 mDraw = rsc->runRootScript() && !rsc->mPaused; 257 if (rsc->props.mLogTimes) { 258 rsc->timerSet(RS_TIMER_CLEAR_SWAP); 259 } 260 eglSwapBuffers(rsc->mEGL.mDisplay, rsc->mEGL.mSurface); 261 if (rsc->props.mLogTimes) { 262 rsc->timerFrame(); 263 rsc->timerSet(RS_TIMER_INTERNAL); 264 rsc->timerPrint(); 265 rsc->timerReset(); 266 } 267 } 268 if (rsc->mObjDestroy.mNeedToEmpty) { 269 rsc->objDestroyOOBRun(); 270 } 271 } 272 273 LOGV("RS Thread exiting"); 274 rsc->mRaster.clear(); 275 rsc->mFragment.clear(); 276 rsc->mVertex.clear(); 277 rsc->mFragmentStore.clear(); 278 rsc->mRootScript.clear(); 279 rsc->mStateRaster.deinit(rsc); 280 rsc->mStateVertex.deinit(rsc); 281 rsc->mStateFragment.deinit(rsc); 282 rsc->mStateFragmentStore.deinit(rsc); 283 ObjectBase::zeroAllUserRef(rsc); 284 285 glClearColor(0,0,0,0); 286 glClear(GL_COLOR_BUFFER_BIT); 287 eglSwapBuffers(rsc->mEGL.mDisplay, rsc->mEGL.mSurface); 288 eglTerminate(rsc->mEGL.mDisplay); 289 rsc->objDestroyOOBRun(); 290 LOGV("RS Thread exited"); 291 return NULL; 292} 293 294Context::Context(Device *dev, Surface *sur, bool useDepth) 295{ 296 dev->addContext(this); 297 mDev = dev; 298 mRunning = false; 299 mExit = false; 300 mUseDepth = useDepth; 301 mPaused = false; 302 mObjHead = NULL; 303 304 int status; 305 pthread_attr_t threadAttr; 306 307 if (!gThreadTLSKey) { 308 status = pthread_key_create(&gThreadTLSKey, NULL); 309 if (status) { 310 LOGE("Failed to init thread tls key."); 311 return; 312 } 313 } else { 314 // HACK: workaround gl hang on start 315 exit(-1); 316 } 317 318 status = pthread_attr_init(&threadAttr); 319 if (status) { 320 LOGE("Failed to init thread attribute."); 321 return; 322 } 323 324 sched_param sparam; 325 sparam.sched_priority = ANDROID_PRIORITY_DISPLAY; 326 pthread_attr_setschedparam(&threadAttr, &sparam); 327 328 mWndSurface = sur; 329 330 objDestroyOOBInit(); 331 timerInit(); 332 timerSet(RS_TIMER_INTERNAL); 333 334 LOGV("RS Launching thread"); 335 status = pthread_create(&mThreadId, &threadAttr, threadProc, this); 336 if (status) { 337 LOGE("Failed to start rs context thread."); 338 } 339 340 while(!mRunning) { 341 usleep(100); 342 } 343 344 pthread_attr_destroy(&threadAttr); 345} 346 347Context::~Context() 348{ 349 LOGV("Context::~Context"); 350 mExit = true; 351 mPaused = false; 352 void *res; 353 354 mIO.shutdown(); 355 int status = pthread_join(mThreadId, &res); 356 objDestroyOOBRun(); 357 358 if (mDev) { 359 mDev->removeContext(this); 360 pthread_key_delete(gThreadTLSKey); 361 } 362 363 objDestroyOOBDestroy(); 364} 365 366void Context::pause() 367{ 368 mPaused = true; 369} 370 371void Context::resume() 372{ 373 mPaused = false; 374} 375 376void Context::setRootScript(Script *s) 377{ 378 mRootScript.set(s); 379} 380 381void Context::setFragmentStore(ProgramFragmentStore *pfs) 382{ 383 if (pfs == NULL) { 384 mFragmentStore.set(mStateFragmentStore.mDefault); 385 } else { 386 mFragmentStore.set(pfs); 387 } 388} 389 390void Context::setFragment(ProgramFragment *pf) 391{ 392 if (pf == NULL) { 393 mFragment.set(mStateFragment.mDefault); 394 } else { 395 mFragment.set(pf); 396 } 397} 398 399void Context::setRaster(ProgramRaster *pr) 400{ 401 if (pr == NULL) { 402 mRaster.set(mStateRaster.mDefault); 403 } else { 404 mRaster.set(pr); 405 } 406} 407 408void Context::allocationCheck(const Allocation *a) 409{ 410 mVertex->checkUpdatedAllocation(a); 411 mFragment->checkUpdatedAllocation(a); 412 mFragmentStore->checkUpdatedAllocation(a); 413} 414 415void Context::setVertex(ProgramVertex *pv) 416{ 417 if (pv == NULL) { 418 mVertex.set(mStateVertex.mDefault); 419 } else { 420 mVertex.set(pv); 421 } 422} 423 424void Context::assignName(ObjectBase *obj, const char *name, uint32_t len) 425{ 426 rsAssert(!obj->getName()); 427 obj->setName(name, len); 428 mNames.add(obj); 429} 430 431void Context::removeName(ObjectBase *obj) 432{ 433 for(size_t ct=0; ct < mNames.size(); ct++) { 434 if (obj == mNames[ct]) { 435 mNames.removeAt(ct); 436 return; 437 } 438 } 439} 440 441ObjectBase * Context::lookupName(const char *name) const 442{ 443 for(size_t ct=0; ct < mNames.size(); ct++) { 444 if (!strcmp(name, mNames[ct]->getName())) { 445 return mNames[ct]; 446 } 447 } 448 return NULL; 449} 450 451void Context::appendNameDefines(String8 *str) const 452{ 453 char buf[256]; 454 for (size_t ct=0; ct < mNames.size(); ct++) { 455 str->append("#define NAMED_"); 456 str->append(mNames[ct]->getName()); 457 str->append(" "); 458 sprintf(buf, "%i\n", (int)mNames[ct]); 459 str->append(buf); 460 } 461} 462 463void Context::appendVarDefines(String8 *str) const 464{ 465 char buf[256]; 466 for (size_t ct=0; ct < mInt32Defines.size(); ct++) { 467 str->append("#define "); 468 str->append(mInt32Defines.keyAt(ct)); 469 str->append(" "); 470 sprintf(buf, "%i\n", (int)mInt32Defines.valueAt(ct)); 471 str->append(buf); 472 473 } 474 for (size_t ct=0; ct < mFloatDefines.size(); ct++) { 475 str->append("#define "); 476 str->append(mFloatDefines.keyAt(ct)); 477 str->append(" "); 478 sprintf(buf, "%ff\n", mFloatDefines.valueAt(ct)); 479 str->append(buf); 480 } 481} 482 483bool Context::objDestroyOOBInit() 484{ 485 int status = pthread_mutex_init(&mObjDestroy.mMutex, NULL); 486 if (status) { 487 LOGE("Context::ObjDestroyOOBInit mutex init failure"); 488 return false; 489 } 490 return true; 491} 492 493void Context::objDestroyOOBRun() 494{ 495 if (mObjDestroy.mNeedToEmpty) { 496 int status = pthread_mutex_lock(&mObjDestroy.mMutex); 497 if (status) { 498 LOGE("Context::ObjDestroyOOBRun: error %i locking for OOBRun.", status); 499 return; 500 } 501 502 for (size_t ct = 0; ct < mObjDestroy.mDestroyList.size(); ct++) { 503 mObjDestroy.mDestroyList[ct]->decUserRef(); 504 } 505 mObjDestroy.mDestroyList.clear(); 506 mObjDestroy.mNeedToEmpty = false; 507 508 status = pthread_mutex_unlock(&mObjDestroy.mMutex); 509 if (status) { 510 LOGE("Context::ObjDestroyOOBRun: error %i unlocking for set condition.", status); 511 } 512 } 513} 514 515void Context::objDestroyOOBDestroy() 516{ 517 rsAssert(!mObjDestroy.mNeedToEmpty); 518 pthread_mutex_destroy(&mObjDestroy.mMutex); 519} 520 521void Context::objDestroyAdd(ObjectBase *obj) 522{ 523 int status = pthread_mutex_lock(&mObjDestroy.mMutex); 524 if (status) { 525 LOGE("Context::ObjDestroyOOBRun: error %i locking for OOBRun.", status); 526 return; 527 } 528 529 mObjDestroy.mNeedToEmpty = true; 530 mObjDestroy.mDestroyList.add(obj); 531 532 status = pthread_mutex_unlock(&mObjDestroy.mMutex); 533 if (status) { 534 LOGE("Context::ObjDestroyOOBRun: error %i unlocking for set condition.", status); 535 } 536} 537 538uint32_t Context::getMessageToClient(void *data, size_t *receiveLen, size_t bufferLen, bool wait) 539{ 540 //LOGE("getMessageToClient %i %i", bufferLen, wait); 541 if (!wait) { 542 if (mIO.mToClient.isEmpty()) { 543 // No message to get and not going to wait for one. 544 receiveLen = 0; 545 return 0; 546 } 547 } 548 549 //LOGE("getMessageToClient 2 con=%p", this); 550 uint32_t bytesData = 0; 551 uint32_t commandID = 0; 552 const void *d = mIO.mToClient.get(&commandID, &bytesData); 553 //LOGE("getMessageToClient 3 %i %i", commandID, bytesData); 554 555 *receiveLen = bytesData; 556 if (bufferLen >= bytesData) { 557 memcpy(data, d, bytesData); 558 mIO.mToClient.next(); 559 return commandID; 560 } 561 return 0; 562} 563 564bool Context::sendMessageToClient(void *data, uint32_t cmdID, size_t len, bool waitForSpace) 565{ 566 //LOGE("sendMessageToClient %i %i %i", cmdID, len, waitForSpace); 567 if (cmdID == 0) { 568 LOGE("Attempting to send invalid command 0 to client."); 569 return false; 570 } 571 if (!waitForSpace) { 572 if (mIO.mToClient.getFreeSpace() < len) { 573 // Not enough room, and not waiting. 574 return false; 575 } 576 } 577 //LOGE("sendMessageToClient 2"); 578 void *p = mIO.mToClient.reserve(len); 579 memcpy(p, data, len); 580 mIO.mToClient.commit(cmdID, len); 581 //LOGE("sendMessageToClient 3"); 582 return true; 583} 584 585void Context::initToClient() 586{ 587 while(!mRunning) { 588 usleep(100); 589 } 590} 591 592void Context::deinitToClient() 593{ 594 mIO.mToClient.shutdown(); 595} 596 597 598/////////////////////////////////////////////////////////////////////////////////////////// 599// 600 601namespace android { 602namespace renderscript { 603 604 605void rsi_ContextBindRootScript(Context *rsc, RsScript vs) 606{ 607 Script *s = static_cast<Script *>(vs); 608 rsc->setRootScript(s); 609} 610 611void rsi_ContextBindSampler(Context *rsc, uint32_t slot, RsSampler vs) 612{ 613 Sampler *s = static_cast<Sampler *>(vs); 614 615 if (slot > RS_MAX_SAMPLER_SLOT) { 616 LOGE("Invalid sampler slot"); 617 return; 618 } 619 620 s->bindToContext(&rsc->mStateSampler, slot); 621} 622 623void rsi_ContextBindProgramFragmentStore(Context *rsc, RsProgramFragmentStore vpfs) 624{ 625 ProgramFragmentStore *pfs = static_cast<ProgramFragmentStore *>(vpfs); 626 rsc->setFragmentStore(pfs); 627} 628 629void rsi_ContextBindProgramFragment(Context *rsc, RsProgramFragment vpf) 630{ 631 ProgramFragment *pf = static_cast<ProgramFragment *>(vpf); 632 rsc->setFragment(pf); 633} 634 635void rsi_ContextBindProgramRaster(Context *rsc, RsProgramRaster vpr) 636{ 637 ProgramRaster *pr = static_cast<ProgramRaster *>(vpr); 638 rsc->setRaster(pr); 639} 640 641void rsi_ContextBindProgramVertex(Context *rsc, RsProgramVertex vpv) 642{ 643 ProgramVertex *pv = static_cast<ProgramVertex *>(vpv); 644 rsc->setVertex(pv); 645} 646 647void rsi_AssignName(Context *rsc, void * obj, const char *name, uint32_t len) 648{ 649 ObjectBase *ob = static_cast<ObjectBase *>(obj); 650 rsc->assignName(ob, name, len); 651} 652 653void rsi_ObjDestroy(Context *rsc, void *obj) 654{ 655 ObjectBase *ob = static_cast<ObjectBase *>(obj); 656 rsc->removeName(ob); 657 ob->decUserRef(); 658} 659 660void rsi_ContextSetDefineF(Context *rsc, const char* name, float value) 661{ 662 rsc->addInt32Define(name, value); 663} 664 665void rsi_ContextSetDefineI32(Context *rsc, const char* name, int32_t value) 666{ 667 rsc->addFloatDefine(name, value); 668} 669 670void rsi_ContextPause(Context *rsc) 671{ 672 rsc->pause(); 673} 674 675void rsi_ContextResume(Context *rsc) 676{ 677 rsc->resume(); 678} 679 680} 681} 682 683 684RsContext rsContextCreate(RsDevice vdev, void *sur, uint32_t version, bool useDepth) 685{ 686 Device * dev = static_cast<Device *>(vdev); 687 Context *rsc = new Context(dev, (Surface *)sur, useDepth); 688 return rsc; 689} 690 691void rsContextDestroy(RsContext vrsc) 692{ 693 Context * rsc = static_cast<Context *>(vrsc); 694 delete rsc; 695} 696 697void rsObjDestroyOOB(RsContext vrsc, void *obj) 698{ 699 Context * rsc = static_cast<Context *>(vrsc); 700 rsc->objDestroyAdd(static_cast<ObjectBase *>(obj)); 701} 702 703uint32_t rsContextGetMessage(RsContext vrsc, void *data, size_t *receiveLen, size_t bufferLen, bool wait) 704{ 705 Context * rsc = static_cast<Context *>(vrsc); 706 return rsc->getMessageToClient(data, receiveLen, bufferLen, wait); 707} 708 709void rsContextInitToClient(RsContext vrsc) 710{ 711 Context * rsc = static_cast<Context *>(vrsc); 712 rsc->initToClient(); 713} 714 715void rsContextDeinitToClient(RsContext vrsc) 716{ 717 Context * rsc = static_cast<Context *>(vrsc); 718 rsc->deinitToClient(); 719} 720 721