1 /*
2 * Copyright (C) 2011-2012 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 "rsdAllocation.h"
19 #include "rsdBcc.h"
20 #include "rsdGL.h"
21 #include "rsdPath.h"
22 #include "rsdProgramStore.h"
23 #include "rsdProgramRaster.h"
24 #include "rsdProgramVertex.h"
25 #include "rsdProgramFragment.h"
26 #include "rsdMesh.h"
27 #include "rsdSampler.h"
28 #include "rsdScriptGroup.h"
29 #include "rsdFrameBuffer.h"
30
31 #include <malloc.h>
32 #include "rsContext.h"
33
34 #include <sys/types.h>
35 #include <sys/resource.h>
36 #include <sched.h>
37 #include <cutils/properties.h>
38 #include <sys/syscall.h>
39 #include <string.h>
40
41 using namespace android;
42 using namespace android::renderscript;
43
44 static void Shutdown(Context *rsc);
45 static void SetPriority(const Context *rsc, int32_t priority);
46
47 static RsdHalFunctions FunctionTable = {
48 rsdGLInit,
49 rsdGLShutdown,
50 rsdGLSetSurface,
51 rsdGLSwap,
52
53 Shutdown,
54 NULL,
55 SetPriority,
56 {
57 rsdScriptInit,
58 rsdInitIntrinsic,
59 rsdScriptInvokeFunction,
60 rsdScriptInvokeRoot,
61 rsdScriptInvokeForEach,
62 rsdScriptInvokeInit,
63 rsdScriptInvokeFreeChildren,
64 rsdScriptSetGlobalVar,
65 rsdScriptSetGlobalVarWithElemDims,
66 rsdScriptSetGlobalBind,
67 rsdScriptSetGlobalObj,
68 rsdScriptDestroy
69 },
70
71 {
72 rsdAllocationInit,
73 rsdAllocationDestroy,
74 rsdAllocationResize,
75 rsdAllocationSyncAll,
76 rsdAllocationMarkDirty,
77 rsdAllocationInitSurfaceTexture,
78 rsdAllocationSetSurfaceTexture,
79 rsdAllocationIoSend,
80 rsdAllocationIoReceive,
81 rsdAllocationData1D,
82 rsdAllocationData2D,
83 rsdAllocationData3D,
84 rsdAllocationRead1D,
85 rsdAllocationRead2D,
86 rsdAllocationRead3D,
87 rsdAllocationLock1D,
88 rsdAllocationUnlock1D,
89 rsdAllocationData1D_alloc,
90 rsdAllocationData2D_alloc,
91 rsdAllocationData3D_alloc,
92 rsdAllocationElementData1D,
93 rsdAllocationElementData2D,
94 rsdAllocationGenerateMipmaps
95 },
96
97
98 {
99 rsdProgramStoreInit,
100 rsdProgramStoreSetActive,
101 rsdProgramStoreDestroy
102 },
103
104 {
105 rsdProgramRasterInit,
106 rsdProgramRasterSetActive,
107 rsdProgramRasterDestroy
108 },
109
110 {
111 rsdProgramVertexInit,
112 rsdProgramVertexSetActive,
113 rsdProgramVertexDestroy
114 },
115
116 {
117 rsdProgramFragmentInit,
118 rsdProgramFragmentSetActive,
119 rsdProgramFragmentDestroy
120 },
121
122 {
123 rsdMeshInit,
124 rsdMeshDraw,
125 rsdMeshDestroy
126 },
127
128 {
129 rsdPathInitStatic,
130 rsdPathInitDynamic,
131 rsdPathDraw,
132 rsdPathDestroy
133 },
134
135 {
136 rsdSamplerInit,
137 rsdSamplerDestroy
138 },
139
140 {
141 rsdFrameBufferInit,
142 rsdFrameBufferSetActive,
143 rsdFrameBufferDestroy
144 },
145
146 {
147 rsdScriptGroupInit,
148 rsdScriptGroupSetInput,
149 rsdScriptGroupSetOutput,
150 rsdScriptGroupExecute,
151 rsdScriptGroupDestroy
152 }
153
154
155 };
156
157 pthread_key_t rsdgThreadTLSKey = 0;
158 uint32_t rsdgThreadTLSKeyCount = 0;
159 pthread_mutex_t rsdgInitMutex = PTHREAD_MUTEX_INITIALIZER;
160
161
HelperThreadProc(void * vrsc)162 static void * HelperThreadProc(void *vrsc) {
163 Context *rsc = static_cast<Context *>(vrsc);
164 RsdHal *dc = (RsdHal *)rsc->mHal.drv;
165
166
167 uint32_t idx = (uint32_t)android_atomic_inc(&dc->mWorkers.mLaunchCount);
168
169 //ALOGV("RS helperThread starting %p idx=%i", rsc, idx);
170
171 dc->mWorkers.mLaunchSignals[idx].init();
172 dc->mWorkers.mNativeThreadId[idx] = gettid();
173
174 int status = pthread_setspecific(rsdgThreadTLSKey, &dc->mTlsStruct);
175 if (status) {
176 ALOGE("pthread_setspecific %i", status);
177 }
178
179 #if 0
180 typedef struct {uint64_t bits[1024 / 64]; } cpu_set_t;
181 cpu_set_t cpuset;
182 memset(&cpuset, 0, sizeof(cpuset));
183 cpuset.bits[idx / 64] |= 1ULL << (idx % 64);
184 int ret = syscall(241, rsc->mWorkers.mNativeThreadId[idx],
185 sizeof(cpuset), &cpuset);
186 ALOGE("SETAFFINITY ret = %i %s", ret, EGLUtils::strerror(ret));
187 #endif
188
189 while (!dc->mExit) {
190 dc->mWorkers.mLaunchSignals[idx].wait();
191 if (dc->mWorkers.mLaunchCallback) {
192 // idx +1 is used because the calling thread is always worker 0.
193 dc->mWorkers.mLaunchCallback(dc->mWorkers.mLaunchData, idx+1);
194 }
195 android_atomic_dec(&dc->mWorkers.mRunningCount);
196 dc->mWorkers.mCompleteSignal.set();
197 }
198
199 //ALOGV("RS helperThread exited %p idx=%i", rsc, idx);
200 return NULL;
201 }
202
rsdLaunchThreads(Context * rsc,WorkerCallback_t cbk,void * data)203 void rsdLaunchThreads(Context *rsc, WorkerCallback_t cbk, void *data) {
204 RsdHal *dc = (RsdHal *)rsc->mHal.drv;
205
206 dc->mWorkers.mLaunchData = data;
207 dc->mWorkers.mLaunchCallback = cbk;
208 android_atomic_release_store(dc->mWorkers.mCount, &dc->mWorkers.mRunningCount);
209 for (uint32_t ct = 0; ct < dc->mWorkers.mCount; ct++) {
210 dc->mWorkers.mLaunchSignals[ct].set();
211 }
212
213 // We use the calling thread as one of the workers so we can start without
214 // the delay of the thread wakeup.
215 if (dc->mWorkers.mLaunchCallback) {
216 dc->mWorkers.mLaunchCallback(dc->mWorkers.mLaunchData, 0);
217 }
218
219 while (android_atomic_acquire_load(&dc->mWorkers.mRunningCount) != 0) {
220 dc->mWorkers.mCompleteSignal.wait();
221 }
222 }
223
rsdHalInit(RsContext c,uint32_t version_major,uint32_t version_minor)224 extern "C" bool rsdHalInit(RsContext c, uint32_t version_major,
225 uint32_t version_minor) {
226 Context *rsc = (Context*) c;
227 rsc->mHal.funcs = FunctionTable;
228
229 RsdHal *dc = (RsdHal *)calloc(1, sizeof(RsdHal));
230 if (!dc) {
231 ALOGE("Calloc for driver hal failed.");
232 return false;
233 }
234 rsc->mHal.drv = dc;
235
236 pthread_mutex_lock(&rsdgInitMutex);
237 if (!rsdgThreadTLSKeyCount) {
238 int status = pthread_key_create(&rsdgThreadTLSKey, NULL);
239 if (status) {
240 ALOGE("Failed to init thread tls key.");
241 pthread_mutex_unlock(&rsdgInitMutex);
242 return false;
243 }
244 }
245 rsdgThreadTLSKeyCount++;
246 pthread_mutex_unlock(&rsdgInitMutex);
247
248 dc->mTlsStruct.mContext = rsc;
249 dc->mTlsStruct.mScript = NULL;
250 int status = pthread_setspecific(rsdgThreadTLSKey, &dc->mTlsStruct);
251 if (status) {
252 ALOGE("pthread_setspecific %i", status);
253 }
254
255
256 int cpu = sysconf(_SC_NPROCESSORS_ONLN);
257 if(rsc->props.mDebugMaxThreads) {
258 cpu = rsc->props.mDebugMaxThreads;
259 }
260 if (cpu < 2) {
261 dc->mWorkers.mCount = 0;
262 return true;
263 }
264 ALOGV("%p Launching thread(s), CPUs %i", rsc, cpu);
265
266 // Subtract one from the cpu count because we also use the command thread as a worker.
267 dc->mWorkers.mCount = (uint32_t)(cpu - 1);
268 dc->mWorkers.mThreadId = (pthread_t *) calloc(dc->mWorkers.mCount, sizeof(pthread_t));
269 dc->mWorkers.mNativeThreadId = (pid_t *) calloc(dc->mWorkers.mCount, sizeof(pid_t));
270 dc->mWorkers.mLaunchSignals = new Signal[dc->mWorkers.mCount];
271 dc->mWorkers.mLaunchCallback = NULL;
272
273 dc->mWorkers.mCompleteSignal.init();
274
275 android_atomic_release_store(dc->mWorkers.mCount, &dc->mWorkers.mRunningCount);
276 android_atomic_release_store(0, &dc->mWorkers.mLaunchCount);
277
278 pthread_attr_t threadAttr;
279 status = pthread_attr_init(&threadAttr);
280 if (status) {
281 ALOGE("Failed to init thread attribute.");
282 return false;
283 }
284
285 for (uint32_t ct=0; ct < dc->mWorkers.mCount; ct++) {
286 status = pthread_create(&dc->mWorkers.mThreadId[ct], &threadAttr, HelperThreadProc, rsc);
287 if (status) {
288 dc->mWorkers.mCount = ct;
289 ALOGE("Created fewer than expected number of RS threads.");
290 break;
291 }
292 }
293 while (android_atomic_acquire_load(&dc->mWorkers.mRunningCount) != 0) {
294 usleep(100);
295 }
296
297 pthread_attr_destroy(&threadAttr);
298 return true;
299 }
300
301
SetPriority(const Context * rsc,int32_t priority)302 void SetPriority(const Context *rsc, int32_t priority) {
303 RsdHal *dc = (RsdHal *)rsc->mHal.drv;
304 for (uint32_t ct=0; ct < dc->mWorkers.mCount; ct++) {
305 setpriority(PRIO_PROCESS, dc->mWorkers.mNativeThreadId[ct], priority);
306 }
307 if (dc->mHasGraphics) {
308 rsdGLSetPriority(rsc, priority);
309 }
310 }
311
Shutdown(Context * rsc)312 void Shutdown(Context *rsc) {
313 RsdHal *dc = (RsdHal *)rsc->mHal.drv;
314
315 dc->mExit = true;
316 dc->mWorkers.mLaunchData = NULL;
317 dc->mWorkers.mLaunchCallback = NULL;
318 android_atomic_release_store(dc->mWorkers.mCount, &dc->mWorkers.mRunningCount);
319 for (uint32_t ct = 0; ct < dc->mWorkers.mCount; ct++) {
320 dc->mWorkers.mLaunchSignals[ct].set();
321 }
322 void *res;
323 for (uint32_t ct = 0; ct < dc->mWorkers.mCount; ct++) {
324 pthread_join(dc->mWorkers.mThreadId[ct], &res);
325 }
326 rsAssert(android_atomic_acquire_load(&dc->mWorkers.mRunningCount) == 0);
327
328 // Global structure cleanup.
329 pthread_mutex_lock(&rsdgInitMutex);
330 --rsdgThreadTLSKeyCount;
331 if (!rsdgThreadTLSKeyCount) {
332 pthread_key_delete(rsdgThreadTLSKey);
333 }
334 pthread_mutex_unlock(&rsdgInitMutex);
335
336 }
337
338