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