1/*
2 * Copyright (C) 2013 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 <malloc.h>
18#include <string.h>
19#include <pthread.h>
20
21#include "RenderScript.h"
22#include "rsCppStructs.h"
23#include "rsCppInternal.h"
24
25#include <dlfcn.h>
26#include <unistd.h>
27
28#if !defined(RS_SERVER) && !defined(RS_COMPATIBILITY_LIB) && defined(HAVE_ANDROID_OS)
29#include <cutils/properties.h>
30#else
31#include "rsCompatibilityLib.h"
32#endif
33
34
35using namespace android;
36using namespace RSC;
37
38bool RS::gInitialized = false;
39bool RS::usingNative = false;
40pthread_mutex_t RS::gInitMutex = PTHREAD_MUTEX_INITIALIZER;
41dispatchTable* RS::dispatch = NULL;
42static int gInitError = 0;
43
44RS::RS() {
45    mDev = NULL;
46    mContext = NULL;
47    mErrorFunc = NULL;
48    mMessageFunc = NULL;
49    mMessageRun = false;
50    mInit = false;
51    mCurrentError = RS_SUCCESS;
52
53    memset(&mElements, 0, sizeof(mElements));
54    memset(&mSamplers, 0, sizeof(mSamplers));
55}
56
57RS::~RS() {
58    if (mInit == true) {
59        mMessageRun = false;
60
61        if (mContext) {
62            RS::dispatch->ContextDeinitToClient(mContext);
63
64            void *res = NULL;
65            int status = pthread_join(mMessageThreadId, &res);
66
67            RS::dispatch->ContextDestroy(mContext);
68            mContext = NULL;
69        }
70        if (mDev) {
71            RS::dispatch->DeviceDestroy(mDev);
72            mDev = NULL;
73        }
74    }
75}
76
77bool RS::init(std::string name, uint32_t flags) {
78    return RS::init(name, RS_VERSION, flags);
79}
80
81static bool loadSymbols(void* handle) {
82
83    RS::dispatch->AllocationGetType = (AllocationGetTypeFnPtr)dlsym(handle, "rsaAllocationGetType");
84    if (RS::dispatch->AllocationGetType == NULL) {
85        ALOGV("Couldn't initialize RS::dispatch->AllocationGetType");
86        return false;
87    }
88    RS::dispatch->TypeGetNativeData = (TypeGetNativeDataFnPtr)dlsym(handle, "rsaTypeGetNativeData");
89    if (RS::dispatch->TypeGetNativeData == NULL) {
90        ALOGV("Couldn't initialize RS::dispatch->TypeGetNativeData");
91        return false;
92    }
93    RS::dispatch->ElementGetNativeData = (ElementGetNativeDataFnPtr)dlsym(handle, "rsaElementGetNativeData");
94    if (RS::dispatch->ElementGetNativeData == NULL) {
95        ALOGV("Couldn't initialize RS::dispatch->ElementGetNativeData");
96        return false;
97    }
98    RS::dispatch->ElementGetSubElements = (ElementGetSubElementsFnPtr)dlsym(handle, "rsaElementGetSubElements");
99    if (RS::dispatch->ElementGetSubElements == NULL) {
100        ALOGV("Couldn't initialize RS::dispatch->ElementGetSubElements");
101        return false;
102    }
103    RS::dispatch->DeviceCreate = (DeviceCreateFnPtr)dlsym(handle, "rsDeviceCreate");
104    if (RS::dispatch->DeviceCreate == NULL) {
105        ALOGV("Couldn't initialize RS::dispatch->DeviceCreate");
106        return false;
107    }
108    RS::dispatch->DeviceDestroy = (DeviceDestroyFnPtr)dlsym(handle, "rsDeviceDestroy");
109    if (RS::dispatch->DeviceDestroy == NULL) {
110        ALOGV("Couldn't initialize RS::dispatch->DeviceDestroy");
111        return false;
112    }
113    RS::dispatch->DeviceSetConfig = (DeviceSetConfigFnPtr)dlsym(handle, "rsDeviceSetConfig");
114    if (RS::dispatch->DeviceSetConfig == NULL) {
115        ALOGV("Couldn't initialize RS::dispatch->DeviceSetConfig");
116        return false;
117    }
118    RS::dispatch->ContextCreate = (ContextCreateFnPtr)dlsym(handle, "rsContextCreate");;
119    if (RS::dispatch->ContextCreate == NULL) {
120        ALOGV("Couldn't initialize RS::dispatch->ContextCreate");
121        return false;
122    }
123    RS::dispatch->GetName = (GetNameFnPtr)dlsym(handle, "rsaGetName");;
124    if (RS::dispatch->GetName == NULL) {
125        ALOGV("Couldn't initialize RS::dispatch->GetName");
126        return false;
127    }
128    RS::dispatch->ContextDestroy = (ContextDestroyFnPtr)dlsym(handle, "rsContextDestroy");
129    if (RS::dispatch->ContextDestroy == NULL) {
130        ALOGV("Couldn't initialize RS::dispatch->ContextDestroy");
131        return false;
132    }
133    RS::dispatch->ContextGetMessage = (ContextGetMessageFnPtr)dlsym(handle, "rsContextGetMessage");
134    if (RS::dispatch->ContextGetMessage == NULL) {
135        ALOGV("Couldn't initialize RS::dispatch->ContextGetMessage");
136        return false;
137    }
138    RS::dispatch->ContextPeekMessage = (ContextPeekMessageFnPtr)dlsym(handle, "rsContextPeekMessage");
139    if (RS::dispatch->ContextPeekMessage == NULL) {
140        ALOGV("Couldn't initialize RS::dispatch->ContextPeekMessage");
141        return false;
142    }
143    RS::dispatch->ContextSendMessage = (ContextSendMessageFnPtr)dlsym(handle, "rsContextSendMessage");
144    if (RS::dispatch->ContextSendMessage == NULL) {
145        ALOGV("Couldn't initialize RS::dispatch->ContextSendMessage");
146        return false;
147    }
148    RS::dispatch->ContextInitToClient = (ContextInitToClientFnPtr)dlsym(handle, "rsContextInitToClient");
149    if (RS::dispatch->ContextInitToClient == NULL) {
150        ALOGV("Couldn't initialize RS::dispatch->ContextInitToClient");
151        return false;
152    }
153    RS::dispatch->ContextDeinitToClient = (ContextDeinitToClientFnPtr)dlsym(handle, "rsContextDeinitToClient");
154    if (RS::dispatch->ContextDeinitToClient == NULL) {
155        ALOGV("Couldn't initialize RS::dispatch->ContextDeinitToClient");
156        return false;
157    }
158    RS::dispatch->TypeCreate = (TypeCreateFnPtr)dlsym(handle, "rsTypeCreate");
159    if (RS::dispatch->TypeCreate == NULL) {
160        ALOGV("Couldn't initialize RS::dispatch->TypeCreate");
161        return false;
162    }
163    RS::dispatch->AllocationCreateTyped = (AllocationCreateTypedFnPtr)dlsym(handle, "rsAllocationCreateTyped");
164    if (RS::dispatch->AllocationCreateTyped == NULL) {
165        ALOGV("Couldn't initialize RS::dispatch->AllocationCreateTyped");
166        return false;
167    }
168    RS::dispatch->AllocationCreateFromBitmap = (AllocationCreateFromBitmapFnPtr)dlsym(handle, "rsAllocationCreateFromBitmap");
169    if (RS::dispatch->AllocationCreateFromBitmap == NULL) {
170        ALOGV("Couldn't initialize RS::dispatch->AllocationCreateFromBitmap");
171        return false;
172    }
173    RS::dispatch->AllocationCubeCreateFromBitmap = (AllocationCubeCreateFromBitmapFnPtr)dlsym(handle, "rsAllocationCubeCreateFromBitmap");
174    if (RS::dispatch->AllocationCubeCreateFromBitmap == NULL) {
175        ALOGV("Couldn't initialize RS::dispatch->AllocationCubeCreateFromBitmap");
176        return false;
177    }
178    RS::dispatch->AllocationGetSurface = (AllocationGetSurfaceFnPtr)dlsym(handle, "rsAllocationGetSurface");
179    if (RS::dispatch->AllocationGetSurface == NULL) {
180        ALOGV("Couldn't initialize RS::dispatch->AllocationGetSurface");
181        return false;
182    }
183    RS::dispatch->AllocationSetSurface = (AllocationSetSurfaceFnPtr)dlsym(handle, "rsAllocationSetSurface");
184    if (RS::dispatch->AllocationSetSurface == NULL) {
185        ALOGV("Couldn't initialize RS::dispatch->AllocationSetSurface");
186        return false;
187    }
188    RS::dispatch->ContextFinish = (ContextFinishFnPtr)dlsym(handle, "rsContextFinish");
189    if (RS::dispatch->ContextFinish == NULL) {
190        ALOGV("Couldn't initialize RS::dispatch->ContextFinish");
191        return false;
192    }
193    RS::dispatch->ContextDump = (ContextDumpFnPtr)dlsym(handle, "rsContextDump");
194    if (RS::dispatch->ContextDump == NULL) {
195        ALOGV("Couldn't initialize RS::dispatch->ContextDump");
196        return false;
197    }
198    RS::dispatch->ContextSetPriority = (ContextSetPriorityFnPtr)dlsym(handle, "rsContextSetPriority");
199    if (RS::dispatch->ContextSetPriority == NULL) {
200        ALOGV("Couldn't initialize RS::dispatch->ContextSetPriority");
201        return false;
202    }
203    RS::dispatch->AssignName = (AssignNameFnPtr)dlsym(handle, "rsAssignName");
204    if (RS::dispatch->AssignName == NULL) {
205        ALOGV("Couldn't initialize RS::dispatch->AssignName");
206        return false;
207    }
208    RS::dispatch->ObjDestroy = (ObjDestroyFnPtr)dlsym(handle, "rsObjDestroy");
209    if (RS::dispatch->ObjDestroy == NULL) {
210        ALOGV("Couldn't initialize RS::dispatch->ObjDestroy");
211        return false;
212    }
213    RS::dispatch->ElementCreate = (ElementCreateFnPtr)dlsym(handle, "rsElementCreate");
214    if (RS::dispatch->ElementCreate == NULL) {
215        ALOGV("Couldn't initialize RS::dispatch->ElementCreate");
216        return false;
217    }
218    RS::dispatch->ElementCreate2 = (ElementCreate2FnPtr)dlsym(handle, "rsElementCreate2");
219    if (RS::dispatch->ElementCreate2 == NULL) {
220        ALOGV("Couldn't initialize RS::dispatch->ElementCreate2");
221        return false;
222    }
223    RS::dispatch->AllocationCopyToBitmap = (AllocationCopyToBitmapFnPtr)dlsym(handle, "rsAllocationCopyToBitmap");
224    if (RS::dispatch->AllocationCopyToBitmap == NULL) {
225        ALOGV("Couldn't initialize RS::dispatch->AllocationCopyToBitmap");
226        return false;
227    }
228    RS::dispatch->Allocation1DData = (Allocation1DDataFnPtr)dlsym(handle, "rsAllocation1DData");
229    if (RS::dispatch->Allocation1DData == NULL) {
230        ALOGV("Couldn't initialize RS::dispatch->Allocation1DData");
231        return false;
232    }
233    RS::dispatch->Allocation1DElementData = (Allocation1DElementDataFnPtr)dlsym(handle, "rsAllocation1DElementData");
234    if (RS::dispatch->Allocation1DElementData == NULL) {
235        ALOGV("Couldn't initialize RS::dispatch->Allocation1DElementData");
236        return false;
237    }
238    RS::dispatch->Allocation2DData = (Allocation2DDataFnPtr)dlsym(handle, "rsAllocation2DData");
239    if (RS::dispatch->Allocation2DData == NULL) {
240        ALOGV("Couldn't initialize RS::dispatch->Allocation2DData");
241        return false;
242    }
243    RS::dispatch->Allocation3DData = (Allocation3DDataFnPtr)dlsym(handle, "rsAllocation3DData");
244    if (RS::dispatch->Allocation3DData == NULL) {
245        ALOGV("Couldn't initialize RS::dispatch->Allocation3DData");
246        return false;
247    }
248    RS::dispatch->AllocationGenerateMipmaps = (AllocationGenerateMipmapsFnPtr)dlsym(handle, "rsAllocationGenerateMipmaps");
249    if (RS::dispatch->AllocationGenerateMipmaps == NULL) {
250        ALOGV("Couldn't initialize RS::dispatch->AllocationGenerateMipmaps");
251        return false;
252    }
253    RS::dispatch->AllocationRead = (AllocationReadFnPtr)dlsym(handle, "rsAllocationRead");
254    if (RS::dispatch->AllocationRead == NULL) {
255        ALOGV("Couldn't initialize RS::dispatch->AllocationRead");
256        return false;
257    }
258    RS::dispatch->Allocation1DRead = (Allocation1DReadFnPtr)dlsym(handle, "rsAllocation1DRead");
259    if (RS::dispatch->Allocation1DRead == NULL) {
260        ALOGV("Couldn't initialize RS::dispatch->Allocation1DRead");
261        return false;
262    }
263    RS::dispatch->Allocation2DRead = (Allocation2DReadFnPtr)dlsym(handle, "rsAllocation2DRead");
264    if (RS::dispatch->Allocation2DRead == NULL) {
265        ALOGV("Couldn't initialize RS::dispatch->Allocation2DRead");
266        return false;
267    }
268    RS::dispatch->AllocationSyncAll = (AllocationSyncAllFnPtr)dlsym(handle, "rsAllocationSyncAll");
269    if (RS::dispatch->AllocationSyncAll == NULL) {
270        ALOGV("Couldn't initialize RS::dispatch->AllocationSyncAll");
271        return false;
272    }
273    RS::dispatch->AllocationResize1D = (AllocationResize1DFnPtr)dlsym(handle, "rsAllocationResize1D");
274    if (RS::dispatch->AllocationResize1D == NULL) {
275        ALOGV("Couldn't initialize RS::dispatch->AllocationResize1D");
276        return false;
277    }
278    RS::dispatch->AllocationCopy2DRange = (AllocationCopy2DRangeFnPtr)dlsym(handle, "rsAllocationCopy2DRange");
279    if (RS::dispatch->AllocationCopy2DRange == NULL) {
280        ALOGV("Couldn't initialize RS::dispatch->AllocationCopy2DRange");
281        return false;
282    }
283    RS::dispatch->AllocationCopy3DRange = (AllocationCopy3DRangeFnPtr)dlsym(handle, "rsAllocationCopy3DRange");
284    if (RS::dispatch->AllocationCopy3DRange == NULL) {
285        ALOGV("Couldn't initialize RS::dispatch->AllocationCopy3DRange");
286        return false;
287    }
288    RS::dispatch->SamplerCreate = (SamplerCreateFnPtr)dlsym(handle, "rsSamplerCreate");
289    if (RS::dispatch->SamplerCreate == NULL) {
290        ALOGV("Couldn't initialize RS::dispatch->SamplerCreate");
291        return false;
292    }
293    RS::dispatch->ScriptBindAllocation = (ScriptBindAllocationFnPtr)dlsym(handle, "rsScriptBindAllocation");
294    if (RS::dispatch->ScriptBindAllocation == NULL) {
295        ALOGV("Couldn't initialize RS::dispatch->ScriptBindAllocation");
296        return false;
297    }
298    RS::dispatch->ScriptSetTimeZone = (ScriptSetTimeZoneFnPtr)dlsym(handle, "rsScriptSetTimeZone");
299    if (RS::dispatch->ScriptSetTimeZone == NULL) {
300        ALOGV("Couldn't initialize RS::dispatch->ScriptSetTimeZone");
301        return false;
302    }
303    RS::dispatch->ScriptInvoke = (ScriptInvokeFnPtr)dlsym(handle, "rsScriptInvoke");
304    if (RS::dispatch->ScriptInvoke == NULL) {
305        ALOGV("Couldn't initialize RS::dispatch->ScriptInvoke");
306        return false;
307    }
308    RS::dispatch->ScriptInvokeV = (ScriptInvokeVFnPtr)dlsym(handle, "rsScriptInvokeV");
309    if (RS::dispatch->ScriptInvokeV == NULL) {
310        ALOGV("Couldn't initialize RS::dispatch->ScriptInvokeV");
311        return false;
312    }
313    RS::dispatch->ScriptForEach = (ScriptForEachFnPtr)dlsym(handle, "rsScriptForEach");
314    if (RS::dispatch->ScriptForEach == NULL) {
315        ALOGV("Couldn't initialize RS::dispatch->ScriptForEach");
316        return false;
317    }
318    RS::dispatch->ScriptSetVarI = (ScriptSetVarIFnPtr)dlsym(handle, "rsScriptSetVarI");
319    if (RS::dispatch->ScriptSetVarI == NULL) {
320        ALOGV("Couldn't initialize RS::dispatch->ScriptSetVarI");
321        return false;
322    }
323    RS::dispatch->ScriptSetVarObj = (ScriptSetVarObjFnPtr)dlsym(handle, "rsScriptSetVarObj");
324    if (RS::dispatch->ScriptSetVarObj == NULL) {
325        ALOGV("Couldn't initialize RS::dispatch->ScriptSetVarObj");
326        return false;
327    }
328    RS::dispatch->ScriptSetVarJ = (ScriptSetVarJFnPtr)dlsym(handle, "rsScriptSetVarJ");
329    if (RS::dispatch->ScriptSetVarJ == NULL) {
330        ALOGV("Couldn't initialize RS::dispatch->ScriptSetVarJ");
331        return false;
332    }
333    RS::dispatch->ScriptSetVarF = (ScriptSetVarFFnPtr)dlsym(handle, "rsScriptSetVarF");
334    if (RS::dispatch->ScriptSetVarF == NULL) {
335        ALOGV("Couldn't initialize RS::dispatch->ScriptSetVarF");
336        return false;
337    }
338    RS::dispatch->ScriptSetVarD = (ScriptSetVarDFnPtr)dlsym(handle, "rsScriptSetVarD");
339    if (RS::dispatch->ScriptSetVarD == NULL) {
340        ALOGV("Couldn't initialize RS::dispatch->ScriptSetVarD");
341        return false;
342    }
343    RS::dispatch->ScriptSetVarV = (ScriptSetVarVFnPtr)dlsym(handle, "rsScriptSetVarV");
344    if (RS::dispatch->ScriptSetVarV == NULL) {
345        ALOGV("Couldn't initialize RS::dispatch->ScriptSetVarV");
346        return false;
347    }
348    RS::dispatch->ScriptGetVarV = (ScriptGetVarVFnPtr)dlsym(handle, "rsScriptGetVarV");
349    if (RS::dispatch->ScriptGetVarV == NULL) {
350        ALOGV("Couldn't initialize RS::dispatch->ScriptGetVarV");
351        return false;
352    }
353    RS::dispatch->ScriptSetVarVE = (ScriptSetVarVEFnPtr)dlsym(handle, "rsScriptSetVarVE");
354    if (RS::dispatch->ScriptSetVarVE == NULL) {
355        ALOGV("Couldn't initialize RS::dispatch->ScriptSetVarVE");
356        return false;
357    }
358    RS::dispatch->ScriptCCreate = (ScriptCCreateFnPtr)dlsym(handle, "rsScriptCCreate");
359    if (RS::dispatch->ScriptCCreate == NULL) {
360        ALOGV("Couldn't initialize RS::dispatch->ScriptCCreate");
361        return false;
362    }
363    RS::dispatch->ScriptIntrinsicCreate = (ScriptIntrinsicCreateFnPtr)dlsym(handle, "rsScriptIntrinsicCreate");
364    if (RS::dispatch->ScriptIntrinsicCreate == NULL) {
365        ALOGV("Couldn't initialize RS::dispatch->ScriptIntrinsicCreate");
366        return false;
367    }
368    RS::dispatch->ScriptKernelIDCreate = (ScriptKernelIDCreateFnPtr)dlsym(handle, "rsScriptKernelIDCreate");
369    if (RS::dispatch->ScriptKernelIDCreate == NULL) {
370        ALOGV("Couldn't initialize RS::dispatch->ScriptKernelIDCreate");
371        return false;
372    }
373    RS::dispatch->ScriptFieldIDCreate = (ScriptFieldIDCreateFnPtr)dlsym(handle, "rsScriptFieldIDCreate");
374    if (RS::dispatch->ScriptFieldIDCreate == NULL) {
375        ALOGV("Couldn't initialize RS::dispatch->ScriptFieldIDCreate");
376        return false;
377    }
378    RS::dispatch->ScriptGroupCreate = (ScriptGroupCreateFnPtr)dlsym(handle, "rsScriptGroupCreate");
379    if (RS::dispatch->ScriptGroupCreate == NULL) {
380        ALOGV("Couldn't initialize RS::dispatch->ScriptGroupCreate");
381        return false;
382    }
383    RS::dispatch->ScriptGroupSetOutput = (ScriptGroupSetOutputFnPtr)dlsym(handle, "rsScriptGroupSetOutput");
384    if (RS::dispatch->ScriptGroupSetOutput == NULL) {
385        ALOGV("Couldn't initialize RS::dispatch->ScriptGroupSetOutput");
386        return false;
387    }
388    RS::dispatch->ScriptGroupSetInput = (ScriptGroupSetInputFnPtr)dlsym(handle, "rsScriptGroupSetInput");
389    if (RS::dispatch->ScriptGroupSetInput == NULL) {
390        ALOGV("Couldn't initialize RS::dispatch->ScriptGroupSetInput");
391        return false;
392    }
393    RS::dispatch->ScriptGroupExecute = (ScriptGroupExecuteFnPtr)dlsym(handle, "rsScriptGroupExecute");
394    if (RS::dispatch->ScriptGroupExecute == NULL) {
395        ALOGV("Couldn't initialize RS::dispatch->ScriptGroupExecute");
396        return false;
397    }
398    RS::dispatch->AllocationIoSend = (AllocationIoSendFnPtr)dlsym(handle, "rsAllocationIoSend");
399    if (RS::dispatch->AllocationIoSend == NULL) {
400        ALOGV("Couldn't initialize RS::dispatch->AllocationIoSend");
401        return false;
402    }
403    RS::dispatch->AllocationIoReceive = (AllocationIoReceiveFnPtr)dlsym(handle, "rsAllocationIoReceive");
404    if (RS::dispatch->AllocationIoReceive == NULL) {
405        ALOGV("Couldn't initialize RS::dispatch->AllocationIoReceive");
406        return false;
407    }
408    RS::dispatch->AllocationGetPointer = (AllocationGetPointerFnPtr)dlsym(handle, "rsAllocationGetPointer");
409    if (RS::dispatch->AllocationGetPointer == NULL) {
410        ALOGV("Couldn't initialize RS::dispatch->AllocationGetPointer");
411        //return false;
412    }
413
414    return true;
415}
416
417// this will only open API 19+ libRS
418// because that's when we changed libRS to extern "C" entry points
419static bool loadSO(const char* filename) {
420    void* handle = dlopen(filename, RTLD_LAZY | RTLD_LOCAL);
421    if (handle == NULL) {
422        ALOGV("couldn't dlopen %s, %s", filename, dlerror());
423        return false;
424    }
425
426    if (loadSymbols(handle) == false) {
427        ALOGV("%s init failed!", filename);
428        return false;
429    }
430    //ALOGE("Successfully loaded %s", filename);
431    return true;
432}
433
434static uint32_t getProp(const char *str) {
435#if !defined(__LP64__) && !defined(RS_SERVER) && defined(HAVE_ANDROID_OS)
436    char buf[256];
437    property_get(str, buf, "0");
438    return atoi(buf);
439#else
440    return 0;
441#endif
442}
443
444bool RS::initDispatch(int targetApi) {
445    pthread_mutex_lock(&gInitMutex);
446    if (gInitError) {
447        goto error;
448    } else if (gInitialized) {
449        pthread_mutex_unlock(&gInitMutex);
450        return true;
451    }
452
453    RS::dispatch = new dispatchTable;
454
455    // attempt to load libRS, load libRSSupport on failure
456    // if property is set, proceed directly to libRSSupport
457    if (getProp("debug.rs.forcecompat") == 0) {
458        usingNative = loadSO("libRS.so");
459    }
460    if (usingNative == false) {
461        if (loadSO("libRSSupport.so") == false) {
462            ALOGE("Failed to load libRS.so and libRSSupport.so");
463            goto error;
464        }
465    }
466
467    gInitialized = true;
468
469    pthread_mutex_unlock(&gInitMutex);
470    return true;
471
472 error:
473    gInitError = 1;
474    pthread_mutex_unlock(&gInitMutex);
475    return false;
476}
477
478bool RS::init(std::string &name, int targetApi, uint32_t flags) {
479    if (mInit) {
480        return true;
481    }
482
483    if (initDispatch(targetApi) == false) {
484        ALOGE("Couldn't initialize dispatch table");
485        return false;
486    }
487
488    mCacheDir = name;
489
490    mDev = RS::dispatch->DeviceCreate();
491    if (mDev == 0) {
492        ALOGE("Device creation failed");
493        return false;
494    }
495
496    if (flags & ~(RS_CONTEXT_SYNCHRONOUS | RS_CONTEXT_LOW_LATENCY |
497                  RS_CONTEXT_LOW_POWER)) {
498        ALOGE("Invalid flags passed");
499        return false;
500    }
501
502    mContext = RS::dispatch->ContextCreate(mDev, 0, targetApi, RS_CONTEXT_TYPE_NORMAL, flags);
503    if (mContext == 0) {
504        ALOGE("Context creation failed");
505        return false;
506    }
507
508    pid_t mNativeMessageThreadId;
509
510    int status = pthread_create(&mMessageThreadId, NULL, threadProc, this);
511    if (status) {
512        ALOGE("Failed to start RS message thread.");
513        return false;
514    }
515    // Wait for the message thread to be active.
516    while (!mMessageRun) {
517        usleep(1000);
518    }
519
520    mInit = true;
521
522    return true;
523}
524
525void RS::throwError(RSError error, const char *errMsg) {
526    if (mCurrentError == RS_SUCCESS) {
527        mCurrentError = error;
528        ALOGE("RS CPP error: %s", errMsg);
529    } else {
530        ALOGE("RS CPP error (masked by previous error): %s", errMsg);
531    }
532}
533
534RSError RS::getError() {
535    return mCurrentError;
536}
537
538
539void * RS::threadProc(void *vrsc) {
540    RS *rs = static_cast<RS *>(vrsc);
541    size_t rbuf_size = 256;
542    void * rbuf = malloc(rbuf_size);
543
544    RS::dispatch->ContextInitToClient(rs->mContext);
545    rs->mMessageRun = true;
546
547    while (rs->mMessageRun) {
548        size_t receiveLen = 0;
549        uint32_t usrID = 0;
550        uint32_t subID = 0;
551        RsMessageToClientType r = RS::dispatch->ContextPeekMessage(rs->mContext,
552                                                                   &receiveLen, sizeof(receiveLen),
553                                                                   &usrID, sizeof(usrID));
554
555        if (receiveLen >= rbuf_size) {
556            rbuf_size = receiveLen + 32;
557            rbuf = realloc(rbuf, rbuf_size);
558        }
559        if (!rbuf) {
560            ALOGE("RS::message handler realloc error %zu", rbuf_size);
561            // No clean way to recover now?
562        }
563        RS::dispatch->ContextGetMessage(rs->mContext, rbuf, rbuf_size, &receiveLen, sizeof(receiveLen),
564                            &subID, sizeof(subID));
565
566        switch(r) {
567        case RS_MESSAGE_TO_CLIENT_ERROR:
568            ALOGE("RS Error %s", (const char *)rbuf);
569            rs->throwError(RS_ERROR_RUNTIME_ERROR, "Error returned from runtime");
570            if(rs->mMessageFunc != NULL) {
571                rs->mErrorFunc(usrID, (const char *)rbuf);
572            }
573            break;
574        case RS_MESSAGE_TO_CLIENT_NONE:
575        case RS_MESSAGE_TO_CLIENT_EXCEPTION:
576        case RS_MESSAGE_TO_CLIENT_RESIZE:
577            // teardown. But we want to avoid starving other threads during
578            // teardown by yielding until the next line in the destructor can
579            // execute to set mRun = false. Note that the FIFO sends an
580            // empty NONE message when it reaches its destructor.
581            usleep(1000);
582            break;
583        case RS_MESSAGE_TO_CLIENT_USER:
584            if(rs->mMessageFunc != NULL) {
585                rs->mMessageFunc(usrID, rbuf, receiveLen);
586            } else {
587                ALOGE("Received a message from the script with no message handler installed.");
588            }
589            break;
590
591        default:
592            ALOGE("RS unknown message type %i", r);
593        }
594    }
595
596    if (rbuf) {
597        free(rbuf);
598    }
599    ALOGV("RS Message thread exiting.");
600    return NULL;
601}
602
603void RS::setErrorHandler(ErrorHandlerFunc_t func) {
604    mErrorFunc = func;
605}
606
607void RS::setMessageHandler(MessageHandlerFunc_t func) {
608    mMessageFunc  = func;
609}
610
611void RS::finish() {
612    RS::dispatch->ContextFinish(mContext);
613}
614