rsContext.cpp revision 8c401effb0837155fc39ca0364f57a882d127d38
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 status = pthread_key_create(&gThreadTLSKey, NULL); 308 if (status) { 309 LOGE("Failed to init thread tls key."); 310 return; 311 } 312 313 status = pthread_attr_init(&threadAttr); 314 if (status) { 315 LOGE("Failed to init thread attribute."); 316 return; 317 } 318 319 sched_param sparam; 320 sparam.sched_priority = ANDROID_PRIORITY_DISPLAY; 321 pthread_attr_setschedparam(&threadAttr, &sparam); 322 323 mWndSurface = sur; 324 325 objDestroyOOBInit(); 326 timerInit(); 327 timerSet(RS_TIMER_INTERNAL); 328 329 LOGV("RS Launching thread"); 330 status = pthread_create(&mThreadId, &threadAttr, threadProc, this); 331 if (status) { 332 LOGE("Failed to start rs context thread."); 333 } 334 335 while(!mRunning) { 336 usleep(100); 337 } 338 339 pthread_attr_destroy(&threadAttr); 340} 341 342Context::~Context() 343{ 344 LOGV("Context::~Context"); 345 mExit = true; 346 mPaused = false; 347 void *res; 348 349 mIO.shutdown(); 350 int status = pthread_join(mThreadId, &res); 351 objDestroyOOBRun(); 352 353 if (mDev) { 354 mDev->removeContext(this); 355 pthread_key_delete(gThreadTLSKey); 356 } 357 358 objDestroyOOBDestroy(); 359} 360 361void Context::pause() 362{ 363 mPaused = true; 364} 365 366void Context::resume() 367{ 368 mPaused = false; 369} 370 371void Context::setRootScript(Script *s) 372{ 373 mRootScript.set(s); 374} 375 376void Context::setFragmentStore(ProgramFragmentStore *pfs) 377{ 378 if (pfs == NULL) { 379 mFragmentStore.set(mStateFragmentStore.mDefault); 380 } else { 381 mFragmentStore.set(pfs); 382 } 383} 384 385void Context::setFragment(ProgramFragment *pf) 386{ 387 if (pf == NULL) { 388 mFragment.set(mStateFragment.mDefault); 389 } else { 390 mFragment.set(pf); 391 } 392} 393 394void Context::setRaster(ProgramRaster *pr) 395{ 396 if (pr == NULL) { 397 mRaster.set(mStateRaster.mDefault); 398 } else { 399 mRaster.set(pr); 400 } 401} 402 403void Context::allocationCheck(const Allocation *a) 404{ 405 mVertex->checkUpdatedAllocation(a); 406 mFragment->checkUpdatedAllocation(a); 407 mFragmentStore->checkUpdatedAllocation(a); 408} 409 410void Context::setVertex(ProgramVertex *pv) 411{ 412 if (pv == NULL) { 413 mVertex.set(mStateVertex.mDefault); 414 } else { 415 mVertex.set(pv); 416 } 417} 418 419void Context::assignName(ObjectBase *obj, const char *name, uint32_t len) 420{ 421 rsAssert(!obj->getName()); 422 obj->setName(name, len); 423 mNames.add(obj); 424} 425 426void Context::removeName(ObjectBase *obj) 427{ 428 for(size_t ct=0; ct < mNames.size(); ct++) { 429 if (obj == mNames[ct]) { 430 mNames.removeAt(ct); 431 return; 432 } 433 } 434} 435 436ObjectBase * Context::lookupName(const char *name) const 437{ 438 for(size_t ct=0; ct < mNames.size(); ct++) { 439 if (!strcmp(name, mNames[ct]->getName())) { 440 return mNames[ct]; 441 } 442 } 443 return NULL; 444} 445 446void Context::appendNameDefines(String8 *str) const 447{ 448 char buf[256]; 449 for (size_t ct=0; ct < mNames.size(); ct++) { 450 str->append("#define NAMED_"); 451 str->append(mNames[ct]->getName()); 452 str->append(" "); 453 sprintf(buf, "%i\n", (int)mNames[ct]); 454 str->append(buf); 455 } 456} 457 458void Context::appendVarDefines(String8 *str) const 459{ 460 char buf[256]; 461 for (size_t ct=0; ct < mInt32Defines.size(); ct++) { 462 str->append("#define "); 463 str->append(mInt32Defines.keyAt(ct)); 464 str->append(" "); 465 sprintf(buf, "%i\n", (int)mInt32Defines.valueAt(ct)); 466 str->append(buf); 467 468 } 469 for (size_t ct=0; ct < mFloatDefines.size(); ct++) { 470 str->append("#define "); 471 str->append(mFloatDefines.keyAt(ct)); 472 str->append(" "); 473 sprintf(buf, "%ff\n", mFloatDefines.valueAt(ct)); 474 str->append(buf); 475 } 476} 477 478bool Context::objDestroyOOBInit() 479{ 480 int status = pthread_mutex_init(&mObjDestroy.mMutex, NULL); 481 if (status) { 482 LOGE("Context::ObjDestroyOOBInit mutex init failure"); 483 return false; 484 } 485 return true; 486} 487 488void Context::objDestroyOOBRun() 489{ 490 if (mObjDestroy.mNeedToEmpty) { 491 int status = pthread_mutex_lock(&mObjDestroy.mMutex); 492 if (status) { 493 LOGE("Context::ObjDestroyOOBRun: error %i locking for OOBRun.", status); 494 return; 495 } 496 497 for (size_t ct = 0; ct < mObjDestroy.mDestroyList.size(); ct++) { 498 mObjDestroy.mDestroyList[ct]->decUserRef(); 499 } 500 mObjDestroy.mDestroyList.clear(); 501 mObjDestroy.mNeedToEmpty = false; 502 503 status = pthread_mutex_unlock(&mObjDestroy.mMutex); 504 if (status) { 505 LOGE("Context::ObjDestroyOOBRun: error %i unlocking for set condition.", status); 506 } 507 } 508} 509 510void Context::objDestroyOOBDestroy() 511{ 512 rsAssert(!mObjDestroy.mNeedToEmpty); 513 pthread_mutex_destroy(&mObjDestroy.mMutex); 514} 515 516void Context::objDestroyAdd(ObjectBase *obj) 517{ 518 int status = pthread_mutex_lock(&mObjDestroy.mMutex); 519 if (status) { 520 LOGE("Context::ObjDestroyOOBRun: error %i locking for OOBRun.", status); 521 return; 522 } 523 524 mObjDestroy.mNeedToEmpty = true; 525 mObjDestroy.mDestroyList.add(obj); 526 527 status = pthread_mutex_unlock(&mObjDestroy.mMutex); 528 if (status) { 529 LOGE("Context::ObjDestroyOOBRun: error %i unlocking for set condition.", status); 530 } 531} 532 533uint32_t Context::getMessageToClient(void *data, size_t *receiveLen, size_t bufferLen, bool wait) 534{ 535 //LOGE("getMessageToClient %i %i", bufferLen, wait); 536 if (!wait) { 537 if (mIO.mToClient.isEmpty()) { 538 // No message to get and not going to wait for one. 539 receiveLen = 0; 540 return 0; 541 } 542 } 543 544 //LOGE("getMessageToClient 2 con=%p", this); 545 uint32_t bytesData = 0; 546 uint32_t commandID = 0; 547 const void *d = mIO.mToClient.get(&commandID, &bytesData); 548 //LOGE("getMessageToClient 3 %i %i", commandID, bytesData); 549 550 *receiveLen = bytesData; 551 if (bufferLen >= bytesData) { 552 memcpy(data, d, bytesData); 553 mIO.mToClient.next(); 554 return commandID; 555 } 556 return 0; 557} 558 559bool Context::sendMessageToClient(void *data, uint32_t cmdID, size_t len, bool waitForSpace) 560{ 561 //LOGE("sendMessageToClient %i %i %i", cmdID, len, waitForSpace); 562 if (cmdID == 0) { 563 LOGE("Attempting to send invalid command 0 to client."); 564 return false; 565 } 566 if (!waitForSpace) { 567 if (mIO.mToClient.getFreeSpace() < len) { 568 // Not enough room, and not waiting. 569 return false; 570 } 571 } 572 //LOGE("sendMessageToClient 2"); 573 void *p = mIO.mToClient.reserve(len); 574 memcpy(p, data, len); 575 mIO.mToClient.commit(cmdID, len); 576 //LOGE("sendMessageToClient 3"); 577 return true; 578} 579 580void Context::initToClient() 581{ 582 while(!mRunning) { 583 usleep(100); 584 } 585} 586 587void Context::deinitToClient() 588{ 589 mIO.mToClient.shutdown(); 590} 591 592 593/////////////////////////////////////////////////////////////////////////////////////////// 594// 595 596namespace android { 597namespace renderscript { 598 599 600void rsi_ContextBindRootScript(Context *rsc, RsScript vs) 601{ 602 Script *s = static_cast<Script *>(vs); 603 rsc->setRootScript(s); 604} 605 606void rsi_ContextBindSampler(Context *rsc, uint32_t slot, RsSampler vs) 607{ 608 Sampler *s = static_cast<Sampler *>(vs); 609 610 if (slot > RS_MAX_SAMPLER_SLOT) { 611 LOGE("Invalid sampler slot"); 612 return; 613 } 614 615 s->bindToContext(&rsc->mStateSampler, slot); 616} 617 618void rsi_ContextBindProgramFragmentStore(Context *rsc, RsProgramFragmentStore vpfs) 619{ 620 ProgramFragmentStore *pfs = static_cast<ProgramFragmentStore *>(vpfs); 621 rsc->setFragmentStore(pfs); 622} 623 624void rsi_ContextBindProgramFragment(Context *rsc, RsProgramFragment vpf) 625{ 626 ProgramFragment *pf = static_cast<ProgramFragment *>(vpf); 627 rsc->setFragment(pf); 628} 629 630void rsi_ContextBindProgramRaster(Context *rsc, RsProgramRaster vpr) 631{ 632 ProgramRaster *pr = static_cast<ProgramRaster *>(vpr); 633 rsc->setRaster(pr); 634} 635 636void rsi_ContextBindProgramVertex(Context *rsc, RsProgramVertex vpv) 637{ 638 ProgramVertex *pv = static_cast<ProgramVertex *>(vpv); 639 rsc->setVertex(pv); 640} 641 642void rsi_AssignName(Context *rsc, void * obj, const char *name, uint32_t len) 643{ 644 ObjectBase *ob = static_cast<ObjectBase *>(obj); 645 rsc->assignName(ob, name, len); 646} 647 648void rsi_ObjDestroy(Context *rsc, void *obj) 649{ 650 ObjectBase *ob = static_cast<ObjectBase *>(obj); 651 rsc->removeName(ob); 652 ob->decUserRef(); 653} 654 655void rsi_ContextSetDefineF(Context *rsc, const char* name, float value) 656{ 657 rsc->addInt32Define(name, value); 658} 659 660void rsi_ContextSetDefineI32(Context *rsc, const char* name, int32_t value) 661{ 662 rsc->addFloatDefine(name, value); 663} 664 665void rsi_ContextPause(Context *rsc) 666{ 667 rsc->pause(); 668} 669 670void rsi_ContextResume(Context *rsc) 671{ 672 rsc->resume(); 673} 674 675} 676} 677 678 679RsContext rsContextCreate(RsDevice vdev, void *sur, uint32_t version, bool useDepth) 680{ 681 Device * dev = static_cast<Device *>(vdev); 682 Context *rsc = new Context(dev, (Surface *)sur, useDepth); 683 return rsc; 684} 685 686void rsContextDestroy(RsContext vrsc) 687{ 688 Context * rsc = static_cast<Context *>(vrsc); 689 delete rsc; 690} 691 692void rsObjDestroyOOB(RsContext vrsc, void *obj) 693{ 694 Context * rsc = static_cast<Context *>(vrsc); 695 rsc->objDestroyAdd(static_cast<ObjectBase *>(obj)); 696} 697 698uint32_t rsContextGetMessage(RsContext vrsc, void *data, size_t *receiveLen, size_t bufferLen, bool wait) 699{ 700 Context * rsc = static_cast<Context *>(vrsc); 701 return rsc->getMessageToClient(data, receiveLen, bufferLen, wait); 702} 703 704void rsContextInitToClient(RsContext vrsc) 705{ 706 Context * rsc = static_cast<Context *>(vrsc); 707 rsc->initToClient(); 708} 709 710void rsContextDeinitToClient(RsContext vrsc) 711{ 712 Context * rsc = static_cast<Context *>(vrsc); 713 rsc->deinitToClient(); 714} 715 716