rsContext.cpp revision 59f6142d7657e43b4d21e077a28387431db02edf
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 "rsgApiStructs.h"
23
24#if !defined(RS_VENDOR_LIB) && !defined(RS_COMPATIBILITY_LIB)
25#include "rsMesh.h"
26#include <gui/DisplayEventReceiver.h>
27#endif
28
29#include <sys/types.h>
30#include <sys/resource.h>
31#include <sched.h>
32
33#include <sys/syscall.h>
34#include <string.h>
35#include <dlfcn.h>
36#include <inttypes.h>
37#include <unistd.h>
38
39#ifdef RS_COMPATIBILITY_LIB
40#include "rsCompatibilityLib.h"
41#endif
42
43namespace android {
44namespace renderscript {
45
46pthread_mutex_t Context::gInitMutex = PTHREAD_MUTEX_INITIALIZER;
47pthread_mutex_t Context::gMessageMutex = PTHREAD_MUTEX_INITIALIZER;
48pthread_mutex_t Context::gLibMutex = PTHREAD_MUTEX_INITIALIZER;
49
50bool Context::initGLThread() {
51    pthread_mutex_lock(&gInitMutex);
52
53    if (!mHal.funcs.initGraphics(this)) {
54        pthread_mutex_unlock(&gInitMutex);
55        ALOGE("%p initGraphics failed", this);
56        return false;
57    }
58
59    pthread_mutex_unlock(&gInitMutex);
60    return true;
61}
62
63void Context::deinitEGL() {
64#ifndef RS_COMPATIBILITY_LIB
65    mHal.funcs.shutdownGraphics(this);
66#endif
67}
68
69Context::PushState::PushState(Context *con) {
70    mRsc = con;
71#if !defined(RS_VENDOR_LIB) && !defined(RS_COMPATIBILITY_LIB)
72    if (con->mIsGraphicsContext) {
73        mFragment.set(con->getProgramFragment());
74        mVertex.set(con->getProgramVertex());
75        mStore.set(con->getProgramStore());
76        mRaster.set(con->getProgramRaster());
77        mFont.set(con->getFont());
78    }
79#endif
80}
81
82Context::PushState::~PushState() {
83#if !defined(RS_VENDOR_LIB) && !defined(RS_COMPATIBILITY_LIB)
84    if (mRsc->mIsGraphicsContext) {
85        mRsc->setProgramFragment(mFragment.get());
86        mRsc->setProgramVertex(mVertex.get());
87        mRsc->setProgramStore(mStore.get());
88        mRsc->setProgramRaster(mRaster.get());
89        mRsc->setFont(mFont.get());
90    }
91#endif
92}
93
94
95uint32_t Context::runScript(Script *s) {
96    PushState ps(this);
97
98    uint32_t ret = s->run(this);
99    return ret;
100}
101
102uint32_t Context::runRootScript() {
103    timerSet(RS_TIMER_SCRIPT);
104#if !defined(RS_VENDOR_LIB) && !defined(RS_COMPATIBILITY_LIB)
105    mStateFragmentStore.mLast.clear();
106#endif
107    watchdog.inRoot = true;
108    uint32_t ret = runScript(mRootScript.get());
109    watchdog.inRoot = false;
110
111    return ret;
112}
113
114uint64_t Context::getTime() const {
115    struct timespec t;
116    clock_gettime(CLOCK_MONOTONIC, &t);
117    return t.tv_nsec + ((uint64_t)t.tv_sec * 1000 * 1000 * 1000);
118}
119
120void Context::timerReset() {
121    for (int ct=0; ct < _RS_TIMER_TOTAL; ct++) {
122        mTimers[ct] = 0;
123    }
124}
125
126void Context::timerInit() {
127    mTimeLast = getTime();
128    mTimeFrame = mTimeLast;
129    mTimeLastFrame = mTimeLast;
130    mTimerActive = RS_TIMER_INTERNAL;
131    mAverageFPSFrameCount = 0;
132    mAverageFPSStartTime = mTimeLast;
133    mAverageFPS = 0;
134    timerReset();
135}
136
137void Context::timerFrame() {
138    mTimeLastFrame = mTimeFrame;
139    mTimeFrame = getTime();
140    // Update average fps
141    const uint64_t averageFramerateInterval = 1000 * 1000000;
142    mAverageFPSFrameCount ++;
143    uint64_t inverval = mTimeFrame - mAverageFPSStartTime;
144    if (inverval >= averageFramerateInterval) {
145        inverval = inverval / 1000000;
146        mAverageFPS = (mAverageFPSFrameCount * 1000) / inverval;
147        mAverageFPSFrameCount = 0;
148        mAverageFPSStartTime = mTimeFrame;
149    }
150}
151
152void Context::timerSet(Timers tm) {
153    uint64_t last = mTimeLast;
154    mTimeLast = getTime();
155    mTimers[mTimerActive] += mTimeLast - last;
156    mTimerActive = tm;
157}
158
159void Context::timerPrint() {
160    double total = 0;
161    for (int ct = 0; ct < _RS_TIMER_TOTAL; ct++) {
162        total += mTimers[ct];
163    }
164    uint64_t frame = mTimeFrame - mTimeLastFrame;
165    mTimeMSLastFrame = frame / 1000000;
166    mTimeMSLastScript = mTimers[RS_TIMER_SCRIPT] / 1000000;
167    mTimeMSLastSwap = mTimers[RS_TIMER_CLEAR_SWAP] / 1000000;
168
169
170    if (props.mLogTimes) {
171        ALOGV("RS: Frame (%i),   Script %2.1f%% (%i),  Swap %2.1f%% (%i),  Idle %2.1f%% (%" PRIi64 "),  "
172              "Internal %2.1f%% (%" PRIi64 "), Avg fps: %u",
173             mTimeMSLastFrame,
174             100.0 * mTimers[RS_TIMER_SCRIPT] / total, mTimeMSLastScript,
175             100.0 * mTimers[RS_TIMER_CLEAR_SWAP] / total, mTimeMSLastSwap,
176             100.0 * mTimers[RS_TIMER_IDLE] / total, mTimers[RS_TIMER_IDLE] / 1000000,
177             100.0 * mTimers[RS_TIMER_INTERNAL] / total, mTimers[RS_TIMER_INTERNAL] / 1000000,
178             mAverageFPS);
179    }
180}
181
182bool Context::setupCheck() {
183#if !defined(RS_VENDOR_LIB) && !defined(RS_COMPATIBILITY_LIB)
184    mFragmentStore->setup(this, &mStateFragmentStore);
185    mFragment->setup(this, &mStateFragment);
186    mRaster->setup(this, &mStateRaster);
187    mVertex->setup(this, &mStateVertex);
188    mFBOCache.setup(this);
189#endif
190    return true;
191}
192
193#if !defined(RS_VENDOR_LIB) && !defined(RS_COMPATIBILITY_LIB)
194void Context::setupProgramStore() {
195    mFragmentStore->setup(this, &mStateFragmentStore);
196}
197#endif
198
199static uint32_t getProp(const char *str) {
200#ifdef __ANDROID__
201    char buf[PROP_VALUE_MAX];
202    property_get(str, buf, "0");
203    return atoi(buf);
204#else
205    return 0;
206#endif
207}
208
209void Context::displayDebugStats() {
210#if !defined(RS_VENDOR_LIB) && !defined(RS_COMPATIBILITY_LIB)
211    char buffer[128];
212    snprintf(buffer, sizeof(buffer), "Avg fps %u, Frame %i ms, Script %i ms",
213             mAverageFPS, mTimeMSLastFrame, mTimeMSLastScript);
214    float oldR, oldG, oldB, oldA;
215    mStateFont.getFontColor(&oldR, &oldG, &oldB, &oldA);
216    uint32_t bufferLen = strlen(buffer);
217
218    ObjectBaseRef<Font> lastFont(getFont());
219    setFont(nullptr);
220    float shadowCol = 0.1f;
221    mStateFont.setFontColor(shadowCol, shadowCol, shadowCol, 1.0f);
222    mStateFont.renderText(buffer, bufferLen, 5, getHeight() - 6);
223
224    mStateFont.setFontColor(1.0f, 0.7f, 0.0f, 1.0f);
225    mStateFont.renderText(buffer, bufferLen, 4, getHeight() - 7);
226
227    setFont(lastFont.get());
228    mStateFont.setFontColor(oldR, oldG, oldB, oldA);
229#endif
230}
231
232void * Context::threadProc(void *vrsc) {
233    Context *rsc = static_cast<Context *>(vrsc);
234
235    rsc->mNativeThreadId = gettid();
236    rsc->props.mLogTimes = getProp("debug.rs.profile") != 0;
237    rsc->props.mLogScripts = getProp("debug.rs.script") != 0;
238    rsc->props.mLogShaders = getProp("debug.rs.shader") != 0;
239    rsc->props.mLogShadersAttr = getProp("debug.rs.shader.attributes") != 0;
240    rsc->props.mLogShadersUniforms = getProp("debug.rs.shader.uniforms") != 0;
241    rsc->props.mLogVisual = getProp("debug.rs.visual") != 0;
242    rsc->props.mLogReduce = getProp("debug.rs.reduce");
243    rsc->props.mDebugReduceSplitAccum = getProp("debug.rs.reduce-split-accum") != 0;
244    rsc->props.mDebugMaxThreads = getProp("debug.rs.max-threads");
245
246    if (getProp("debug.rs.debug") != 0) {
247        ALOGD("Forcing debug context due to debug.rs.debug.");
248        rsc->mContextType = RS_CONTEXT_TYPE_DEBUG;
249        rsc->mForceCpu = true;
250    }
251
252    bool forceRSoV = getProp("debug.rs.rsov") != 0;
253    if (forceRSoV) {
254        ALOGD("Force the use of RSoV driver");
255        rsc->mForceRSoV = true;
256    }
257
258    bool forceCpu = getProp("debug.rs.default-CPU-driver") != 0;
259    if (forceCpu) {
260        ALOGD("Skipping hardware driver and loading default CPU driver");
261        rsc->mForceCpu = true;
262    }
263
264    rsc->mForceCpu |= rsc->mIsGraphicsContext;
265    if (!rsc->loadDriver(rsc->mForceCpu, rsc->mForceRSoV)) {
266      rsc->setError(RS_ERROR_DRIVER, "Failed loading driver");
267      return nullptr;
268    }
269
270    if (!rsc->isSynchronous()) {
271        // Due to legacy we default to normal_graphics
272        // setPriority will make the adjustments as needed.
273        rsc->setPriority(RS_THREAD_PRIORITY_NORMAL_GRAPHICS);
274    }
275
276#if !defined(RS_VENDOR_LIB) && !defined(RS_COMPATIBILITY_LIB)
277    if (rsc->mIsGraphicsContext) {
278        if (!rsc->initGLThread()) {
279            rsc->setError(RS_ERROR_OUT_OF_MEMORY, "Failed initializing GL");
280            return nullptr;
281        }
282
283        rsc->mStateRaster.init(rsc);
284        rsc->setProgramRaster(nullptr);
285        rsc->mStateVertex.init(rsc);
286        rsc->setProgramVertex(nullptr);
287        rsc->mStateFragment.init(rsc);
288        rsc->setProgramFragment(nullptr);
289        rsc->mStateFragmentStore.init(rsc);
290        rsc->setProgramStore(nullptr);
291        rsc->mStateFont.init(rsc);
292        rsc->setFont(nullptr);
293        rsc->mStateSampler.init(rsc);
294        rsc->mFBOCache.init(rsc);
295    }
296#endif
297
298    rsc->mRunning = true;
299
300    if (rsc->isSynchronous()) {
301        return nullptr;
302    }
303
304    if (!rsc->mIsGraphicsContext) {
305        while (!rsc->mExit) {
306            rsc->mIO.playCoreCommands(rsc, -1);
307        }
308#if !defined(RS_VENDOR_LIB) && !defined(RS_COMPATIBILITY_LIB)
309    } else {
310        DisplayEventReceiver displayEvent;
311        DisplayEventReceiver::Event eventBuffer[1];
312
313        int vsyncRate = 0;
314        int targetRate = 0;
315
316        bool drawOnce = false;
317        while (!rsc->mExit) {
318            rsc->timerSet(RS_TIMER_IDLE);
319
320            if (!rsc->mRootScript.get() || !rsc->mHasSurface || rsc->mPaused) {
321                targetRate = 0;
322            }
323
324            if (vsyncRate != targetRate) {
325                displayEvent.setVsyncRate(targetRate);
326                vsyncRate = targetRate;
327            }
328            if (targetRate) {
329                drawOnce |= rsc->mIO.playCoreCommands(rsc, displayEvent.getFd());
330                while (displayEvent.getEvents(eventBuffer, 1) != 0) {
331                    //ALOGE("vs2 time past %lld", (rsc->getTime() - eventBuffer[0].header.timestamp) / 1000000);
332                }
333            } else {
334                drawOnce |= rsc->mIO.playCoreCommands(rsc, -1);
335            }
336
337            if ((rsc->mRootScript.get() != nullptr) && rsc->mHasSurface &&
338                (targetRate || drawOnce) && !rsc->mPaused) {
339
340                drawOnce = false;
341                targetRate = ((rsc->runRootScript() + 15) / 16);
342
343                if (rsc->props.mLogVisual) {
344                    rsc->displayDebugStats();
345                }
346
347                rsc->timerSet(RS_TIMER_CLEAR_SWAP);
348                rsc->mHal.funcs.swap(rsc);
349                rsc->timerFrame();
350                rsc->timerSet(RS_TIMER_INTERNAL);
351                rsc->timerPrint();
352                rsc->timerReset();
353            }
354        }
355#endif
356    }
357
358    //ALOGV("%p RS Thread exiting", rsc);
359
360#if !defined(RS_VENDOR_LIB) && !defined(RS_COMPATIBILITY_LIB)
361    if (rsc->mIsGraphicsContext) {
362        pthread_mutex_lock(&gInitMutex);
363        rsc->deinitEGL();
364        pthread_mutex_unlock(&gInitMutex);
365    }
366#endif
367
368    //ALOGV("%p RS Thread exited", rsc);
369    return nullptr;
370}
371
372void Context::destroyWorkerThreadResources() {
373    //ALOGV("destroyWorkerThreadResources 1");
374    ObjectBase::zeroAllUserRef(this);
375#if !defined(RS_VENDOR_LIB) && !defined(RS_COMPATIBILITY_LIB)
376    if (mIsGraphicsContext) {
377         mRaster.clear();
378         mFragment.clear();
379         mVertex.clear();
380         mFragmentStore.clear();
381         mFont.clear();
382         mRootScript.clear();
383         mStateRaster.deinit(this);
384         mStateVertex.deinit(this);
385         mStateFragment.deinit(this);
386         mStateFragmentStore.deinit(this);
387         mStateFont.deinit(this);
388         mStateSampler.deinit(this);
389         mFBOCache.deinit(this);
390    }
391#endif
392    ObjectBase::freeAllChildren(this);
393    mExit = true;
394    //ALOGV("destroyWorkerThreadResources 2");
395}
396
397void Context::printWatchdogInfo(void *ctx) {
398    Context *rsc = (Context *)ctx;
399    if (rsc->watchdog.command && rsc->watchdog.file) {
400        ALOGE("RS watchdog timeout: %i  %s  line %i %s", rsc->watchdog.inRoot,
401             rsc->watchdog.command, rsc->watchdog.line, rsc->watchdog.file);
402    } else {
403        ALOGE("RS watchdog timeout: %i", rsc->watchdog.inRoot);
404    }
405}
406
407
408void Context::setPriority(int32_t p) {
409    switch (p) {
410    // The public API will always send NORMAL_GRAPHICS
411    // for normal, we adjust here
412    case RS_THREAD_PRIORITY_NORMAL_GRAPHICS:
413        if (mIsGraphicsContext) {
414            break;
415        } else {
416            if (mHal.flags & RS_CONTEXT_LOW_LATENCY) {
417                p = RS_THREAD_PRIORITY_LOW_LATENCY;
418            } else {
419                p = RS_THREAD_PRIORITY_NORMAL;
420            }
421        }
422    case RS_THREAD_PRIORITY_LOW:
423        break;
424    }
425
426    // Note: If we put this in the proper "background" policy
427    // the wallpapers can become completly unresponsive at times.
428    // This is probably not what we want for something the user is actively
429    // looking at.
430    mThreadPriority = p;
431    setpriority(PRIO_PROCESS, mNativeThreadId, p);
432    mHal.funcs.setPriority(this, mThreadPriority);
433}
434
435Context::Context() {
436    mDev = nullptr;
437    mRunning = false;
438    mExit = false;
439    mPaused = false;
440    mObjHead = nullptr;
441    mError = RS_ERROR_NONE;
442    mTargetSdkVersion = 14;
443    mDPI = 96;
444    mIsContextLite = false;
445    memset(&watchdog, 0, sizeof(watchdog));
446    memset(&mHal, 0, sizeof(mHal));
447    mForceCpu = false;
448    mForceRSoV = false;
449    mContextType = RS_CONTEXT_TYPE_NORMAL;
450    mOptLevel = 3;
451    mSynchronous = false;
452    mFatalErrorOccured = false;
453
454    memset(mCacheDir, 0, sizeof(mCacheDir));
455#ifdef RS_COMPATIBILITY_LIB
456    memset(nativeLibDir, 0, sizeof(nativeLibDir));
457#endif
458}
459
460void Context::setCacheDir(const char * cacheDir_arg, uint32_t length) {
461    if (!hasSetCacheDir) {
462        if (length <= PATH_MAX) {
463            memcpy(mCacheDir, cacheDir_arg, length);
464            mCacheDir[length] = 0;
465            hasSetCacheDir = true;
466        } else {
467            setError(RS_ERROR_BAD_VALUE, "Invalid path");
468        }
469    }
470}
471
472Context * Context::createContext(Device *dev, const RsSurfaceConfig *sc,
473                                 RsContextType ct, uint32_t flags) {
474    Context * rsc = new Context();
475
476    if (flags & RS_CONTEXT_LOW_LATENCY) {
477        rsc->mForceCpu = true;
478    }
479    if (flags & RS_CONTEXT_SYNCHRONOUS) {
480        rsc->mSynchronous = true;
481    }
482    rsc->mContextType = ct;
483    rsc->mHal.flags = flags;
484
485    if (!rsc->initContext(dev, sc)) {
486        delete rsc;
487        return nullptr;
488    }
489
490    return rsc;
491}
492
493Context * Context::createContextLite() {
494    Context * rsc = new Context();
495    rsc->mIsContextLite = true;
496    return rsc;
497}
498
499bool Context::initContext(Device *dev, const RsSurfaceConfig *sc) {
500    pthread_mutex_lock(&gInitMutex);
501
502    mIO.init();
503    mIO.setTimeoutCallback(printWatchdogInfo, this, 2e9);
504
505    if (sc) {
506        mUserSurfaceConfig = *sc;
507    } else {
508        memset(&mUserSurfaceConfig, 0, sizeof(mUserSurfaceConfig));
509    }
510
511    mIsGraphicsContext = sc != nullptr;
512
513    int status;
514    pthread_attr_t threadAttr;
515
516    pthread_mutex_unlock(&gInitMutex);
517
518    // Global init done at this point.
519
520    status = pthread_attr_init(&threadAttr);
521    if (status) {
522        ALOGE("Failed to init thread attribute.");
523        return false;
524    }
525
526    mHasSurface = false;
527    mDriverName = NULL;
528
529    timerInit();
530    timerSet(RS_TIMER_INTERNAL);
531    if (mSynchronous) {
532        threadProc(this);
533
534        if (mError != RS_ERROR_NONE) {
535            ALOGE("Errors during thread init (sync mode)");
536            return false;
537        }
538    } else {
539        status = pthread_create(&mThreadId, &threadAttr, threadProc, this);
540        if (status) {
541            ALOGE("Failed to start rs context thread.");
542            return false;
543        }
544        while (!mRunning && (mError == RS_ERROR_NONE)) {
545            usleep(100);
546        }
547
548        if (mError != RS_ERROR_NONE) {
549            ALOGE("Errors during thread init");
550            return false;
551        }
552
553        pthread_attr_destroy(&threadAttr);
554    }
555    return true;
556}
557
558Context::~Context() {
559    if (!mIsContextLite) {
560        mPaused = false;
561        void *res;
562
563        mIO.shutdown();
564        if (!mSynchronous) {
565            pthread_join(mThreadId, &res);
566        }
567        rsAssert(mExit);
568
569        if (mHal.funcs.shutdownDriver && mHal.drv) {
570            mHal.funcs.shutdownDriver(this);
571        }
572    }
573}
574
575#if !defined(RS_VENDOR_LIB) && !defined(RS_COMPATIBILITY_LIB)
576void Context::setSurface(uint32_t w, uint32_t h, RsNativeWindow sur) {
577    rsAssert(mIsGraphicsContext);
578    mHal.funcs.setSurface(this, w, h, sur);
579
580    mHasSurface = sur != nullptr;
581    mWidth = w;
582    mHeight = h;
583
584    if (mWidth && mHeight) {
585        mStateVertex.updateSize(this);
586        mFBOCache.updateSize();
587    }
588}
589
590uint32_t Context::getCurrentSurfaceWidth() const {
591    for (uint32_t i = 0; i < mFBOCache.mHal.state.colorTargetsCount; i ++) {
592        if (mFBOCache.mHal.state.colorTargets[i] != nullptr) {
593            return mFBOCache.mHal.state.colorTargets[i]->getType()->getDimX();
594        }
595    }
596    if (mFBOCache.mHal.state.depthTarget != nullptr) {
597        return mFBOCache.mHal.state.depthTarget->getType()->getDimX();
598    }
599    return mWidth;
600}
601
602uint32_t Context::getCurrentSurfaceHeight() const {
603    for (uint32_t i = 0; i < mFBOCache.mHal.state.colorTargetsCount; i ++) {
604        if (mFBOCache.mHal.state.colorTargets[i] != nullptr) {
605            return mFBOCache.mHal.state.colorTargets[i]->getType()->getDimY();
606        }
607    }
608    if (mFBOCache.mHal.state.depthTarget != nullptr) {
609        return mFBOCache.mHal.state.depthTarget->getType()->getDimY();
610    }
611    return mHeight;
612}
613
614void Context::pause() {
615    rsAssert(mIsGraphicsContext);
616    mPaused = true;
617}
618
619void Context::resume() {
620    rsAssert(mIsGraphicsContext);
621    mPaused = false;
622}
623
624void Context::setRootScript(Script *s) {
625    rsAssert(mIsGraphicsContext);
626    mRootScript.set(s);
627}
628
629void Context::setProgramStore(ProgramStore *pfs) {
630    rsAssert(mIsGraphicsContext);
631    if (pfs == nullptr) {
632        mFragmentStore.set(mStateFragmentStore.mDefault);
633    } else {
634        mFragmentStore.set(pfs);
635    }
636}
637
638void Context::setProgramFragment(ProgramFragment *pf) {
639    rsAssert(mIsGraphicsContext);
640    if (pf == nullptr) {
641        mFragment.set(mStateFragment.mDefault);
642    } else {
643        mFragment.set(pf);
644    }
645}
646
647void Context::setProgramRaster(ProgramRaster *pr) {
648    rsAssert(mIsGraphicsContext);
649    if (pr == nullptr) {
650        mRaster.set(mStateRaster.mDefault);
651    } else {
652        mRaster.set(pr);
653    }
654}
655
656void Context::setProgramVertex(ProgramVertex *pv) {
657    rsAssert(mIsGraphicsContext);
658    if (pv == nullptr) {
659        mVertex.set(mStateVertex.mDefault);
660    } else {
661        mVertex.set(pv);
662    }
663}
664
665void Context::setFont(Font *f) {
666    rsAssert(mIsGraphicsContext);
667    if (f == nullptr) {
668        mFont.set(mStateFont.mDefault);
669    } else {
670        mFont.set(f);
671    }
672}
673#endif
674
675void Context::finish() {
676    if (mHal.funcs.finish) {
677        mHal.funcs.finish(this);
678    }
679}
680
681void Context::assignName(ObjectBase *obj, const char *name, uint32_t len) {
682    rsAssert(!obj->getName());
683    obj->setName(name, len);
684    mNames.push_back(obj);
685}
686
687void Context::removeName(ObjectBase *obj) {
688    for (size_t ct=0; ct < mNames.size(); ct++) {
689        if (obj == mNames[ct]) {
690            mNames.erase(mNames.begin() + ct);
691            return;
692        }
693    }
694}
695
696RsMessageToClientType Context::peekMessageToClient(size_t *receiveLen, uint32_t *subID) {
697    return (RsMessageToClientType)mIO.getClientHeader(receiveLen, subID);
698}
699
700RsMessageToClientType Context::getMessageToClient(void *data, size_t *receiveLen, uint32_t *subID, size_t bufferLen) {
701    return (RsMessageToClientType)mIO.getClientPayload(data, receiveLen, subID, bufferLen);
702}
703
704bool Context::sendMessageToClient(const void *data, RsMessageToClientType cmdID,
705                                  uint32_t subID, size_t len, bool waitForSpace) const {
706
707    pthread_mutex_lock(&gMessageMutex);
708    bool ret = mIO.sendToClient(cmdID, subID, data, len, waitForSpace);
709    pthread_mutex_unlock(&gMessageMutex);
710    return ret;
711}
712
713void Context::initToClient() {
714    while (!mRunning) {
715        usleep(100);
716    }
717}
718
719void Context::deinitToClient() {
720    mIO.clientShutdown();
721}
722
723void Context::setError(RsError e, const char *msg) const {
724    mError = e;
725
726    if (mError >= RS_ERROR_FATAL_DEBUG) {
727        // If a FATAL error occurred, set the flag to indicate the process
728        // will be goign down
729        mFatalErrorOccured = true;
730    }
731
732    sendMessageToClient(msg, RS_MESSAGE_TO_CLIENT_ERROR, e, strlen(msg) + 1, true);
733}
734
735
736void Context::dumpDebug() const {
737    ALOGE("RS Context debug %p", this);
738    ALOGE("RS Context debug");
739
740    ALOGE(" RS width %i, height %i", mWidth, mHeight);
741    ALOGE(" RS running %i, exit %i, paused %i", mRunning, mExit, mPaused);
742    ALOGE(" RS pThreadID %li, nativeThreadID %i", (long int)mThreadId, mNativeThreadId);
743}
744
745///////////////////////////////////////////////////////////////////////////////////////////
746//
747
748void rsi_ContextFinish(Context *rsc) {
749    rsc->finish();
750}
751
752void rsi_ContextBindRootScript(Context *rsc, RsScript vs) {
753#if !defined(RS_VENDOR_LIB) && !defined(RS_COMPATIBILITY_LIB)
754    Script *s = static_cast<Script *>(vs);
755    rsc->setRootScript(s);
756#endif
757}
758
759void rsi_ContextSetCacheDir(Context *rsc, const char *cacheDir, size_t cacheDir_length) {
760    rsc->setCacheDir(cacheDir, cacheDir_length);
761}
762
763void rsi_ContextBindSampler(Context *rsc, uint32_t slot, RsSampler vs) {
764    Sampler *s = static_cast<Sampler *>(vs);
765
766    if (slot > RS_MAX_SAMPLER_SLOT) {
767        ALOGE("Invalid sampler slot");
768        return;
769    }
770
771    s->bindToContext(&rsc->mStateSampler, slot);
772}
773
774#if !defined(RS_VENDOR_LIB) && !defined(RS_COMPATIBILITY_LIB)
775void rsi_ContextBindProgramStore(Context *rsc, RsProgramStore vpfs) {
776    ProgramStore *pfs = static_cast<ProgramStore *>(vpfs);
777    rsc->setProgramStore(pfs);
778}
779
780void rsi_ContextBindProgramFragment(Context *rsc, RsProgramFragment vpf) {
781    ProgramFragment *pf = static_cast<ProgramFragment *>(vpf);
782    rsc->setProgramFragment(pf);
783}
784
785void rsi_ContextBindProgramRaster(Context *rsc, RsProgramRaster vpr) {
786    ProgramRaster *pr = static_cast<ProgramRaster *>(vpr);
787    rsc->setProgramRaster(pr);
788}
789
790void rsi_ContextBindProgramVertex(Context *rsc, RsProgramVertex vpv) {
791    ProgramVertex *pv = static_cast<ProgramVertex *>(vpv);
792    rsc->setProgramVertex(pv);
793}
794
795void rsi_ContextBindFont(Context *rsc, RsFont vfont) {
796    Font *font = static_cast<Font *>(vfont);
797    rsc->setFont(font);
798}
799#endif
800
801void rsi_AssignName(Context *rsc, RsObjectBase obj, const char *name, size_t name_length) {
802    ObjectBase *ob = static_cast<ObjectBase *>(obj);
803    rsc->assignName(ob, name, name_length);
804}
805
806void rsi_ObjDestroy(Context *rsc, void *optr) {
807    ObjectBase *ob = static_cast<ObjectBase *>(optr);
808    rsc->removeName(ob);
809    ob->decUserRef();
810}
811
812#if !defined(RS_VENDOR_LIB) && !defined(RS_COMPATIBILITY_LIB)
813void rsi_ContextPause(Context *rsc) {
814    rsc->pause();
815}
816
817void rsi_ContextResume(Context *rsc) {
818    rsc->resume();
819}
820
821void rsi_ContextSetSurface(Context *rsc, uint32_t w, uint32_t h, RsNativeWindow sur) {
822    rsc->setSurface(w, h, sur);
823}
824#endif
825
826void rsi_ContextSetPriority(Context *rsc, int32_t p) {
827    rsc->setPriority(p);
828}
829
830void rsi_ContextDump(Context *rsc, int32_t bits) {
831    ObjectBase::dumpAll(rsc);
832}
833
834void rsi_ContextDestroyWorker(Context *rsc) {
835    rsc->destroyWorkerThreadResources();
836}
837
838void rsi_ContextDestroy(Context *rsc) {
839    //ALOGE("%p rsContextDestroy", rsc);
840    rsc->destroyWorkerThreadResources();
841    delete rsc;
842    //ALOGV("%p rsContextDestroy done", rsc);
843}
844
845RsMessageToClientType rsi_ContextPeekMessage(Context *rsc,
846                                           size_t * receiveLen, size_t receiveLen_length,
847                                           uint32_t * subID, size_t subID_length) {
848    return rsc->peekMessageToClient(receiveLen, subID);
849}
850
851RsMessageToClientType rsi_ContextGetMessage(Context *rsc, void * data, size_t data_length,
852                                          size_t * receiveLen, size_t receiveLen_length,
853                                          uint32_t * subID, size_t subID_length) {
854    rsAssert(subID_length == sizeof(uint32_t));
855    rsAssert(receiveLen_length == sizeof(size_t));
856    return rsc->getMessageToClient(data, receiveLen, subID, data_length);
857}
858
859void rsi_ContextInitToClient(Context *rsc) {
860    rsc->initToClient();
861}
862
863void rsi_ContextDeinitToClient(Context *rsc) {
864    rsc->deinitToClient();
865}
866
867void rsi_ContextSendMessage(Context *rsc, uint32_t id, const uint8_t *data, size_t len) {
868    rsc->sendMessageToClient(data, RS_MESSAGE_TO_CLIENT_USER, id, len, true);
869}
870
871// implementation of handcode LF_ObjDestroy
872// required so nObjDestroy can be run from finalizer without blocking
873void LF_ObjDestroy_handcode(const Context *rsc, RsAsyncVoidPtr objPtr) {
874    if (((Context *)rsc)->isSynchronous()) {
875        rsi_ObjDestroy((Context *)rsc, objPtr);
876        return;
877    }
878
879    // struct has two parts:
880    // RsPlaybackRemoteHeader (cmdID and bytes)
881    // RS_CMD_ObjDestroy (ptr)
882    struct destroyCmd {
883        uint32_t cmdID;
884        uint32_t bytes;
885        RsAsyncVoidPtr ptr;
886     };
887
888    destroyCmd cmd;
889    cmd.cmdID = RS_CMD_ID_ObjDestroy;
890    cmd.bytes = sizeof(RsAsyncVoidPtr);
891    cmd.ptr = objPtr;
892    ThreadIO *io = &((Context *)rsc)->mIO;
893    io->coreWrite((void*)&cmd, sizeof(destroyCmd));
894
895}
896
897} // namespace renderscript
898} // namespace android
899