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           dc->mWorkers.mLaunchCallback(dc->mWorkers.mLaunchData, idx);
193        }
194        android_atomic_dec(&dc->mWorkers.mRunningCount);
195        dc->mWorkers.mCompleteSignal.set();
196    }
197
198    //ALOGV("RS helperThread exited %p idx=%i", rsc, idx);
199    return NULL;
200}
201
202void rsdLaunchThreads(Context *rsc, WorkerCallback_t cbk, void *data) {
203    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
204
205    dc->mWorkers.mLaunchData = data;
206    dc->mWorkers.mLaunchCallback = cbk;
207    android_atomic_release_store(dc->mWorkers.mCount, &dc->mWorkers.mRunningCount);
208    for (uint32_t ct = 0; ct < dc->mWorkers.mCount; ct++) {
209        dc->mWorkers.mLaunchSignals[ct].set();
210    }
211    while (android_atomic_acquire_load(&dc->mWorkers.mRunningCount) != 0) {
212        dc->mWorkers.mCompleteSignal.wait();
213    }
214}
215
216extern "C" bool rsdHalInit(RsContext c, uint32_t version_major,
217                           uint32_t version_minor) {
218    Context *rsc = (Context*) c;
219    rsc->mHal.funcs = FunctionTable;
220
221    RsdHal *dc = (RsdHal *)calloc(1, sizeof(RsdHal));
222    if (!dc) {
223        ALOGE("Calloc for driver hal failed.");
224        return false;
225    }
226    rsc->mHal.drv = dc;
227
228    pthread_mutex_lock(&rsdgInitMutex);
229    if (!rsdgThreadTLSKeyCount) {
230        int status = pthread_key_create(&rsdgThreadTLSKey, NULL);
231        if (status) {
232            ALOGE("Failed to init thread tls key.");
233            pthread_mutex_unlock(&rsdgInitMutex);
234            return false;
235        }
236    }
237    rsdgThreadTLSKeyCount++;
238    pthread_mutex_unlock(&rsdgInitMutex);
239
240    dc->mTlsStruct.mContext = rsc;
241    dc->mTlsStruct.mScript = NULL;
242    int status = pthread_setspecific(rsdgThreadTLSKey, &dc->mTlsStruct);
243    if (status) {
244        ALOGE("pthread_setspecific %i", status);
245    }
246
247
248    int cpu = sysconf(_SC_NPROCESSORS_ONLN);
249    if(rsc->props.mDebugMaxThreads) {
250        cpu = rsc->props.mDebugMaxThreads;
251    }
252    if (cpu < 2) {
253        cpu = 0;
254    }
255    ALOGV("%p Launching thread(s), CPUs %i", rsc, cpu);
256
257    dc->mWorkers.mCount = (uint32_t)cpu;
258    dc->mWorkers.mThreadId = (pthread_t *) calloc(dc->mWorkers.mCount, sizeof(pthread_t));
259    dc->mWorkers.mNativeThreadId = (pid_t *) calloc(dc->mWorkers.mCount, sizeof(pid_t));
260    dc->mWorkers.mLaunchSignals = new Signal[dc->mWorkers.mCount];
261    dc->mWorkers.mLaunchCallback = NULL;
262
263    dc->mWorkers.mCompleteSignal.init();
264
265    android_atomic_release_store(dc->mWorkers.mCount, &dc->mWorkers.mRunningCount);
266    android_atomic_release_store(0, &dc->mWorkers.mLaunchCount);
267
268    pthread_attr_t threadAttr;
269    status = pthread_attr_init(&threadAttr);
270    if (status) {
271        ALOGE("Failed to init thread attribute.");
272        return false;
273    }
274
275    for (uint32_t ct=0; ct < dc->mWorkers.mCount; ct++) {
276        status = pthread_create(&dc->mWorkers.mThreadId[ct], &threadAttr, HelperThreadProc, rsc);
277        if (status) {
278            dc->mWorkers.mCount = ct;
279            ALOGE("Created fewer than expected number of RS threads.");
280            break;
281        }
282    }
283    while (android_atomic_acquire_load(&dc->mWorkers.mRunningCount) != 0) {
284        usleep(100);
285    }
286
287    pthread_attr_destroy(&threadAttr);
288    return true;
289}
290
291
292void SetPriority(const Context *rsc, int32_t priority) {
293    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
294    for (uint32_t ct=0; ct < dc->mWorkers.mCount; ct++) {
295        setpriority(PRIO_PROCESS, dc->mWorkers.mNativeThreadId[ct], priority);
296    }
297    if (dc->mHasGraphics) {
298        rsdGLSetPriority(rsc, priority);
299    }
300}
301
302void Shutdown(Context *rsc) {
303    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
304
305    dc->mExit = true;
306    dc->mWorkers.mLaunchData = NULL;
307    dc->mWorkers.mLaunchCallback = NULL;
308    android_atomic_release_store(dc->mWorkers.mCount, &dc->mWorkers.mRunningCount);
309    for (uint32_t ct = 0; ct < dc->mWorkers.mCount; ct++) {
310        dc->mWorkers.mLaunchSignals[ct].set();
311    }
312    void *res;
313    for (uint32_t ct = 0; ct < dc->mWorkers.mCount; ct++) {
314        pthread_join(dc->mWorkers.mThreadId[ct], &res);
315    }
316    rsAssert(android_atomic_acquire_load(&dc->mWorkers.mRunningCount) == 0);
317
318    // Global structure cleanup.
319    pthread_mutex_lock(&rsdgInitMutex);
320    --rsdgThreadTLSKeyCount;
321    if (!rsdgThreadTLSKeyCount) {
322        pthread_key_delete(rsdgThreadTLSKey);
323    }
324    pthread_mutex_unlock(&rsdgInitMutex);
325
326}
327
328