rsdCore.cpp revision a04e30dbb5ab11592b03666bb3d102070759c58e
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 "rsdCore.h"
18#include "rsdBcc.h"
19#include "rsdGL.h"
20#include "rsdProgramStore.h"
21#include "rsdProgramRaster.h"
22#include "rsdProgramVertex.h"
23#include "rsdProgramFragment.h"
24#include "rsdMesh.h"
25
26#include <malloc.h>
27#include "rsContext.h"
28
29#include <sys/types.h>
30#include <sys/resource.h>
31#include <sched.h>
32#include <cutils/properties.h>
33#include <cutils/sched_policy.h>
34#include <sys/syscall.h>
35#include <string.h>
36
37using namespace android;
38using namespace android::renderscript;
39
40static void Shutdown(Context *rsc);
41static void SetPriority(const Context *rsc, int32_t priority);
42
43static RsdHalFunctions FunctionTable = {
44    rsdGLInit,
45    rsdGLShutdown,
46    rsdGLSetSurface,
47    rsdGLSwap,
48
49    Shutdown,
50    NULL,
51    SetPriority,
52    {
53        rsdScriptInit,
54        rsdScriptInvokeFunction,
55        rsdScriptInvokeRoot,
56        rsdScriptInvokeForEach,
57        rsdScriptInvokeInit,
58        rsdScriptSetGlobalVar,
59        rsdScriptSetGlobalBind,
60        rsdScriptSetGlobalObj,
61        rsdScriptDestroy
62    },
63
64
65    {
66        rsdProgramStoreInit,
67        rsdProgramStoreSetActive,
68        rsdProgramStoreDestroy
69    },
70
71    {
72        rsdProgramRasterInit,
73        rsdProgramRasterSetActive,
74        rsdProgramRasterDestroy
75    },
76
77    {
78        rsdProgramVertexInit,
79        rsdProgramVertexSetActive,
80        rsdProgramVertexDestroy
81    },
82
83    {
84        rsdProgramFragmentInit,
85        rsdProgramFragmentSetActive,
86        rsdProgramFragmentDestroy
87    },
88
89    {
90        rsdMeshInit,
91        rsdMeshDraw,
92        rsdMeshDestroy
93    }
94
95};
96
97pthread_key_t rsdgThreadTLSKey = 0;
98uint32_t rsdgThreadTLSKeyCount = 0;
99pthread_mutex_t rsdgInitMutex = PTHREAD_MUTEX_INITIALIZER;
100
101
102static void * HelperThreadProc(void *vrsc) {
103    Context *rsc = static_cast<Context *>(vrsc);
104    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
105
106
107    uint32_t idx = (uint32_t)android_atomic_inc(&dc->mWorkers.mLaunchCount);
108
109    //LOGV("RS helperThread starting %p idx=%i", rsc, idx);
110
111    dc->mWorkers.mLaunchSignals[idx].init();
112    dc->mWorkers.mNativeThreadId[idx] = gettid();
113
114    int status = pthread_setspecific(rsdgThreadTLSKey, &dc->mTlsStruct);
115    if (status) {
116        LOGE("pthread_setspecific %i", status);
117    }
118
119#if 0
120    typedef struct {uint64_t bits[1024 / 64]; } cpu_set_t;
121    cpu_set_t cpuset;
122    memset(&cpuset, 0, sizeof(cpuset));
123    cpuset.bits[idx / 64] |= 1ULL << (idx % 64);
124    int ret = syscall(241, rsc->mWorkers.mNativeThreadId[idx],
125              sizeof(cpuset), &cpuset);
126    LOGE("SETAFFINITY ret = %i %s", ret, EGLUtils::strerror(ret));
127#endif
128
129    while (!dc->mExit) {
130        dc->mWorkers.mLaunchSignals[idx].wait();
131        if (dc->mWorkers.mLaunchCallback) {
132           dc->mWorkers.mLaunchCallback(dc->mWorkers.mLaunchData, idx);
133        }
134        android_atomic_dec(&dc->mWorkers.mRunningCount);
135        dc->mWorkers.mCompleteSignal.set();
136    }
137
138    //LOGV("RS helperThread exited %p idx=%i", rsc, idx);
139    return NULL;
140}
141
142void rsdLaunchThreads(Context *rsc, WorkerCallback_t cbk, void *data) {
143    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
144
145    dc->mWorkers.mLaunchData = data;
146    dc->mWorkers.mLaunchCallback = cbk;
147    android_atomic_release_store(dc->mWorkers.mCount, &dc->mWorkers.mRunningCount);
148    for (uint32_t ct = 0; ct < dc->mWorkers.mCount; ct++) {
149        dc->mWorkers.mLaunchSignals[ct].set();
150    }
151    while (android_atomic_acquire_load(&dc->mWorkers.mRunningCount) != 0) {
152        dc->mWorkers.mCompleteSignal.wait();
153    }
154}
155
156bool rsdHalInit(Context *rsc, uint32_t version_major, uint32_t version_minor) {
157    rsc->mHal.funcs = FunctionTable;
158
159    RsdHal *dc = (RsdHal *)calloc(1, sizeof(RsdHal));
160    if (!dc) {
161        LOGE("Calloc for driver hal failed.");
162        return false;
163    }
164    rsc->mHal.drv = dc;
165
166    pthread_mutex_lock(&rsdgInitMutex);
167    if (!rsdgThreadTLSKeyCount) {
168        int status = pthread_key_create(&rsdgThreadTLSKey, NULL);
169        if (status) {
170            LOGE("Failed to init thread tls key.");
171            pthread_mutex_unlock(&rsdgInitMutex);
172            return false;
173        }
174    }
175    rsdgThreadTLSKeyCount++;
176    pthread_mutex_unlock(&rsdgInitMutex);
177
178    dc->mTlsStruct.mContext = rsc;
179    dc->mTlsStruct.mScript = NULL;
180    int status = pthread_setspecific(rsdgThreadTLSKey, &dc->mTlsStruct);
181    if (status) {
182        LOGE("pthread_setspecific %i", status);
183    }
184
185
186    int cpu = sysconf(_SC_NPROCESSORS_ONLN);
187    LOGV("RS Launching thread(s), reported CPU count %i", cpu);
188    if (cpu < 2) cpu = 0;
189
190    dc->mWorkers.mCount = (uint32_t)cpu;
191    dc->mWorkers.mThreadId = (pthread_t *) calloc(dc->mWorkers.mCount, sizeof(pthread_t));
192    dc->mWorkers.mNativeThreadId = (pid_t *) calloc(dc->mWorkers.mCount, sizeof(pid_t));
193    dc->mWorkers.mLaunchSignals = new Signal[dc->mWorkers.mCount];
194    dc->mWorkers.mLaunchCallback = NULL;
195
196    dc->mWorkers.mCompleteSignal.init();
197
198    android_atomic_release_store(dc->mWorkers.mCount, &dc->mWorkers.mRunningCount);
199    android_atomic_release_store(0, &dc->mWorkers.mLaunchCount);
200
201    pthread_attr_t threadAttr;
202    status = pthread_attr_init(&threadAttr);
203    if (status) {
204        LOGE("Failed to init thread attribute.");
205        return false;
206    }
207
208    for (uint32_t ct=0; ct < dc->mWorkers.mCount; ct++) {
209        status = pthread_create(&dc->mWorkers.mThreadId[ct], &threadAttr, HelperThreadProc, rsc);
210        if (status) {
211            dc->mWorkers.mCount = ct;
212            LOGE("Created fewer than expected number of RS threads.");
213            break;
214        }
215    }
216    while (android_atomic_acquire_load(&dc->mWorkers.mRunningCount) != 0) {
217        usleep(100);
218    }
219
220    pthread_attr_destroy(&threadAttr);
221    return true;
222}
223
224
225void SetPriority(const Context *rsc, int32_t priority) {
226    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
227    for (uint32_t ct=0; ct < dc->mWorkers.mCount; ct++) {
228        setpriority(PRIO_PROCESS, dc->mWorkers.mNativeThreadId[ct], priority);
229    }
230}
231
232void Shutdown(Context *rsc) {
233    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
234
235    dc->mExit = true;
236    dc->mWorkers.mLaunchData = NULL;
237    dc->mWorkers.mLaunchCallback = NULL;
238    android_atomic_release_store(dc->mWorkers.mCount, &dc->mWorkers.mRunningCount);
239    for (uint32_t ct = 0; ct < dc->mWorkers.mCount; ct++) {
240        dc->mWorkers.mLaunchSignals[ct].set();
241    }
242    int status;
243    void *res;
244    for (uint32_t ct = 0; ct < dc->mWorkers.mCount; ct++) {
245        status = pthread_join(dc->mWorkers.mThreadId[ct], &res);
246    }
247    rsAssert(android_atomic_acquire_load(&dc->mWorkers.mRunningCount) == 0);
248
249    // Global structure cleanup.
250    pthread_mutex_lock(&rsdgInitMutex);
251    --rsdgThreadTLSKeyCount;
252    if (!rsdgThreadTLSKeyCount) {
253        pthread_key_delete(rsdgThreadTLSKey);
254    }
255    pthread_mutex_unlock(&rsdgInitMutex);
256
257}
258
259
260