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
41using namespace android;
42using namespace android::renderscript;
43
44static void Shutdown(Context *rsc);
45static void SetPriority(const Context *rsc, int32_t priority);
46
47static 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
157pthread_key_t rsdgThreadTLSKey = 0;
158uint32_t rsdgThreadTLSKeyCount = 0;
159pthread_mutex_t rsdgInitMutex = PTHREAD_MUTEX_INITIALIZER;
160
161
162static 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
203void 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
224extern "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
302void 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
312void 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