rsScriptC.cpp revision 1030893d9b99b72468034da13df025bda479bb97
1/*
2 * Copyright (C) 2009 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 "rsContext.h"
18#include "rsScriptC.h"
19#include "rsMatrix.h"
20
21#include "acc/acc.h"
22
23using namespace android;
24using namespace android::renderscript;
25
26
27ScriptC::ScriptC()
28{
29    mAccScript = NULL;
30    memset(&mProgram, 0, sizeof(mProgram));
31}
32
33ScriptC::~ScriptC()
34{
35    if (mAccScript) {
36        accDeleteScript(mAccScript);
37    }
38}
39
40extern "C" void matrixLoadIdentity(void *con, rsc_Matrix *mat)
41{
42    Matrix *m = reinterpret_cast<Matrix *>(mat);
43    m->loadIdentity();
44}
45
46extern "C" void matrixLoadFloat(void *con, rsc_Matrix *mat, const float *f)
47{
48    Matrix *m = reinterpret_cast<Matrix *>(mat);
49    m->load(f);
50}
51
52extern "C" void matrixLoadMat(void *con, rsc_Matrix *mat, const rsc_Matrix *newmat)
53{
54    Matrix *m = reinterpret_cast<Matrix *>(mat);
55    m->load(reinterpret_cast<const Matrix *>(newmat));
56}
57
58extern "C" void matrixLoadRotate(void *con, rsc_Matrix *mat, float rot, float x, float y, float z)
59{
60    Matrix *m = reinterpret_cast<Matrix *>(mat);
61    m->loadRotate(rot, x, y, z);
62}
63
64extern "C" void matrixLoadScale(void *con, rsc_Matrix *mat, float x, float y, float z)
65{
66    Matrix *m = reinterpret_cast<Matrix *>(mat);
67    m->loadScale(x, y, z);
68}
69
70extern "C" void matrixLoadTranslate(void *con, rsc_Matrix *mat, float x, float y, float z)
71{
72    Matrix *m = reinterpret_cast<Matrix *>(mat);
73    m->loadTranslate(x, y, z);
74}
75
76extern "C" void matrixLoadMultiply(void *con, rsc_Matrix *mat, const rsc_Matrix *lhs, const rsc_Matrix *rhs)
77{
78    Matrix *m = reinterpret_cast<Matrix *>(mat);
79    m->loadMultiply(reinterpret_cast<const Matrix *>(lhs),
80                    reinterpret_cast<const Matrix *>(rhs));
81}
82
83extern "C" void matrixMultiply(void *con, rsc_Matrix *mat, const rsc_Matrix *rhs)
84{
85    Matrix *m = reinterpret_cast<Matrix *>(mat);
86    m->multiply(reinterpret_cast<const Matrix *>(rhs));
87}
88
89extern "C" void matrixRotate(void *con, rsc_Matrix *mat, float rot, float x, float y, float z)
90{
91    Matrix *m = reinterpret_cast<Matrix *>(mat);
92    m->rotate(rot, x, y, z);
93}
94
95extern "C" void matrixScale(void *con, rsc_Matrix *mat, float x, float y, float z)
96{
97    Matrix *m = reinterpret_cast<Matrix *>(mat);
98    m->scale(x, y, z);
99}
100
101extern "C" void matrixTranslate(void *con, rsc_Matrix *mat, float x, float y, float z)
102{
103    Matrix *m = reinterpret_cast<Matrix *>(mat);
104    m->translate(x, y, z);
105}
106
107
108extern "C" const void * loadVp(void *vp, uint32_t bank, uint32_t offset)
109{
110    ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
111    return &static_cast<const uint8_t *>(env->mScript->mSlots[bank]->getPtr())[offset];
112}
113
114extern "C" float loadF(void *vp, uint32_t bank, uint32_t offset)
115{
116    ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
117    //LOGE("bank %i, offset %i", bank, offset);
118    //LOGE("%p", env->mScript->mSlots[bank]->getPtr());
119    return static_cast<const float *>(env->mScript->mSlots[bank]->getPtr())[offset];
120}
121
122extern "C" int32_t loadI32(void *vp, uint32_t bank, uint32_t offset)
123{
124    ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
125    return static_cast<const int32_t *>(env->mScript->mSlots[bank]->getPtr())[offset];
126}
127
128extern "C" uint32_t loadU32(void *vp, uint32_t bank, uint32_t offset)
129{
130    ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
131    return static_cast<const uint32_t *>(env->mScript->mSlots[bank]->getPtr())[offset];
132}
133
134extern "C" void loadEnvVec4(void *vp, uint32_t bank, uint32_t offset, rsc_Vector4 *v)
135{
136    ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
137    memcpy(v, &static_cast<const float *>(env->mScript->mSlots[bank]->getPtr())[offset], sizeof(rsc_Vector4));
138}
139
140extern "C" void loadEnvMatrix(void *vp, uint32_t bank, uint32_t offset, rsc_Matrix *m)
141{
142    ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
143    memcpy(m, &static_cast<const float *>(env->mScript->mSlots[bank]->getPtr())[offset], sizeof(rsc_Matrix));
144}
145
146
147extern "C" void storeF(void *vp, uint32_t bank, uint32_t offset, float v)
148{
149    ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
150    static_cast<float *>(env->mScript->mSlots[bank]->getPtr())[offset] = v;
151}
152
153extern "C" void storeI32(void *vp, uint32_t bank, uint32_t offset, int32_t v)
154{
155    ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
156    static_cast<int32_t *>(env->mScript->mSlots[bank]->getPtr())[offset] = v;
157}
158
159extern "C" void storeU32(void *vp, uint32_t bank, uint32_t offset, uint32_t v)
160{
161    ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
162    static_cast<uint32_t *>(env->mScript->mSlots[bank]->getPtr())[offset] = v;
163}
164
165extern "C" void storeEnvVec4(void *vp, uint32_t bank, uint32_t offset, const rsc_Vector4 *v)
166{
167    ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
168    memcpy(&static_cast<float *>(env->mScript->mSlots[bank]->getPtr())[offset], v, sizeof(rsc_Vector4));
169}
170
171extern "C" void storeEnvMatrix(void *vp, uint32_t bank, uint32_t offset, const rsc_Matrix *m)
172{
173    ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
174    memcpy(&static_cast<float *>(env->mScript->mSlots[bank]->getPtr())[offset], m, sizeof(rsc_Matrix));
175}
176
177
178extern "C" void color(void *vp, float r, float g, float b, float a)
179{
180    ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
181    glColor4f(r, g, b, a);
182}
183
184extern "C" void renderTriangleMesh(void *vp, RsTriangleMesh mesh)
185{
186    ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
187    rsi_TriangleMeshRender(env->mContext, mesh);
188}
189
190extern "C" void renderTriangleMeshRange(void *vp, RsTriangleMesh mesh, uint32_t start, uint32_t count)
191{
192    ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
193    rsi_TriangleMeshRenderRange(env->mContext, mesh, start, count);
194}
195
196extern "C" void materialDiffuse(void *vp, float r, float g, float b, float a)
197{
198    ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
199    float v[] = {r, g, b, a};
200    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, v);
201}
202
203extern "C" void materialSpecular(void *vp, float r, float g, float b, float a)
204{
205    ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
206    float v[] = {r, g, b, a};
207    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, v);
208}
209
210extern "C" void lightPosition(void *vp, float x, float y, float z, float w)
211{
212    ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
213    float v[] = {x, y, z, w};
214    glLightfv(GL_LIGHT0, GL_POSITION, v);
215}
216
217extern "C" void materialShininess(void *vp, float s)
218{
219    ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
220    glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &s);
221}
222
223extern "C" void uploadToTexture(void *vp, RsAllocation va, uint32_t baseMipLevel)
224{
225    ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
226    rsi_AllocationUploadToTexture(env->mContext, va, baseMipLevel);
227}
228
229extern "C" void enable(void *vp, uint32_t p)
230{
231    ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
232    glEnable(p);
233}
234
235extern "C" void disable(void *vp, uint32_t p)
236{
237    ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
238    glDisable(p);
239}
240
241extern "C" uint32_t scriptRand(void *vp, uint32_t max)
242{
243    return (uint32_t)(((float)rand()) * max / RAND_MAX);
244}
245
246// Assumes (GL_FIXED) x,y,z (GL_UNSIGNED_BYTE)r,g,b,a
247extern "C" void drawTriangleArray(void *vp, RsAllocation alloc, uint32_t count)
248{
249    const Allocation *a = (const Allocation *)alloc;
250    const uint32_t *ptr = (const uint32_t *)a->getPtr();
251
252    ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
253    env->mContext->setupCheck();
254
255    glBindBuffer(GL_ARRAY_BUFFER, 0);
256    //glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, tm->mBufferObjects[1]);
257
258    glEnableClientState(GL_VERTEX_ARRAY);
259    glDisableClientState(GL_NORMAL_ARRAY);
260    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
261    glEnableClientState(GL_COLOR_ARRAY);
262
263    glVertexPointer(2, GL_FIXED, 12, ptr + 1);
264    //glTexCoordPointer(2, GL_FIXED, 24, ptr + 1);
265    glColorPointer(4, GL_UNSIGNED_BYTE, 12, ptr);
266
267    glDrawArrays(GL_TRIANGLES, 0, count * 3);
268}
269
270extern "C" void drawRect(void *vp, int32_t x1, int32_t x2, int32_t y1, int32_t y2)
271{
272    x1 = (x1 << 16);
273    x2 = (x2 << 16);
274    y1 = (y1 << 16);
275    y2 = (y2 << 16);
276
277    int32_t vtx[] = {x1,y1, x1,y2, x2,y1, x2,y2};
278    static const int32_t tex[] = {0,0, 0,0x10000, 0x10000,0, 0x10000,0x10000};
279
280
281    ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
282    env->mContext->setupCheck();
283
284    glBindBuffer(GL_ARRAY_BUFFER, 0);
285    //glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, tm->mBufferObjects[1]);
286
287    glEnableClientState(GL_VERTEX_ARRAY);
288    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
289    glDisableClientState(GL_NORMAL_ARRAY);
290    glDisableClientState(GL_COLOR_ARRAY);
291
292    glVertexPointer(2, GL_FIXED, 8, vtx);
293    glTexCoordPointer(2, GL_FIXED, 8, tex);
294    //glColorPointer(4, GL_UNSIGNED_BYTE, 12, ptr);
295
296    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
297}
298
299extern "C" void pfBindTexture(void *vp, RsProgramFragment vpf, uint32_t slot, RsAllocation va)
300{
301    //LOGE("pfBindTexture %p", vpf);
302    ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
303    rsi_ProgramFragmentBindTexture(env->mContext,
304                                   static_cast<ProgramFragment *>(vpf),
305                                   slot,
306                                   static_cast<Allocation *>(va));
307
308}
309
310extern "C" void pfBindSampler(void *vp, RsProgramFragment vpf, uint32_t slot, RsSampler vs)
311{
312    ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
313    rsi_ProgramFragmentBindSampler(env->mContext,
314                                   static_cast<ProgramFragment *>(vpf),
315                                   slot,
316                                   static_cast<Sampler *>(vs));
317
318}
319
320extern "C" void contextBindProgramFragmentStore(void *vp, RsProgramFragmentStore pfs)
321{
322    //LOGE("contextBindProgramFragmentStore %p", pfs);
323    ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
324    rsi_ContextBindProgramFragmentStore(env->mContext, pfs);
325
326}
327
328extern "C" void contextBindProgramFragment(void *vp, RsProgramFragment pf)
329{
330    //LOGE("contextBindProgramFragment %p", pf);
331    ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
332    rsi_ContextBindProgramFragment(env->mContext, pf);
333
334}
335
336
337static rsc_FunctionTable scriptCPtrTable = {
338    loadVp,
339    loadF,
340    loadI32,
341    loadU32,
342    loadEnvVec4,
343    loadEnvMatrix,
344
345    storeF,
346    storeI32,
347    storeU32,
348    storeEnvVec4,
349    storeEnvMatrix,
350
351    matrixLoadIdentity,
352    matrixLoadFloat,
353    matrixLoadMat,
354    matrixLoadRotate,
355    matrixLoadScale,
356    matrixLoadTranslate,
357    matrixLoadMultiply,
358    matrixMultiply,
359    matrixRotate,
360    matrixScale,
361    matrixTranslate,
362
363    color,
364
365    pfBindTexture,
366    pfBindSampler,
367
368    materialDiffuse,
369    materialSpecular,
370    lightPosition,
371    materialShininess,
372    uploadToTexture,
373    enable,
374    disable,
375
376    scriptRand,
377    contextBindProgramFragment,
378    contextBindProgramFragmentStore,
379
380
381    renderTriangleMesh,
382    renderTriangleMeshRange,
383
384    drawTriangleArray,
385    drawRect
386
387};
388
389
390bool ScriptC::run(Context *rsc, uint32_t launchID)
391{
392    Env e = {rsc, this};
393    return mProgram.mScript(&e, &scriptCPtrTable, launchID) != 0;
394}
395
396ScriptCState::ScriptCState()
397{
398    clear();
399}
400
401ScriptCState::~ScriptCState()
402{
403    if (mAccScript) {
404        accDeleteScript(mAccScript);
405    }
406}
407
408void ScriptCState::clear()
409{
410    memset(&mProgram, 0, sizeof(mProgram));
411
412    mConstantBufferTypes.clear();
413
414    memset(&mEnviroment, 0, sizeof(mEnviroment));
415    mEnviroment.mClearColor[0] = 0;
416    mEnviroment.mClearColor[1] = 0;
417    mEnviroment.mClearColor[2] = 0;
418    mEnviroment.mClearColor[3] = 1;
419    mEnviroment.mClearDepth = 1;
420    mEnviroment.mClearStencil = 0;
421    mEnviroment.mIsRoot = false;
422    mEnviroment.mIsOrtho = true;
423
424    mAccScript = NULL;
425
426}
427
428void ScriptCState::runCompiler()
429{
430    mAccScript = accCreateScript();
431
432    const char* scriptSource[] = {mProgram.mScriptText};
433    int scriptLength[] = {mProgram.mScriptTextLength} ;
434    accScriptSource(mAccScript, 1, scriptSource, scriptLength);
435    accCompileScript(mAccScript);
436    accGetScriptLabel(mAccScript, "main", (ACCvoid**) &mProgram.mScript);
437    rsAssert(mProgram.mScript);
438
439    if (mProgram.mScript) {
440        const static int pragmaMax = 16;
441        ACCsizei pragmaCount;
442        ACCchar * str[pragmaMax];
443        accGetPragmas(mAccScript, &pragmaCount, pragmaMax, &str[0]);
444
445        // Start with defaults
446        mEnviroment.mStateVertex =
447            Script::Enviroment_t::VTX_ORTHO_WINDOW;
448        mEnviroment.mStateRaster =
449            Script::Enviroment_t::RASTER_FLAT;
450        mEnviroment.mStateFragment =
451            Script::Enviroment_t::FRAGMENT_COLOR;
452        mEnviroment.mStateFragmentStore =
453            Script::Enviroment_t::FRAGMENT_STORE_ALWAYS_REPLACE;
454
455        for (int ct=0; ct < pragmaCount; ct+=2) {
456            LOGE("pragma %i %s %s", ct, str[ct], str[ct+1]);
457
458            if (!strcmp(str[ct], "version")) {
459                continue;
460
461            }
462
463
464            if (!strcmp(str[ct], "stateVertex")) {
465                if (!strcmp(str[ct+1], "orthoWindow")) {
466                    mEnviroment.mStateVertex =
467                        Script::Enviroment_t::VTX_ORTHO_WINDOW;
468                    continue;
469                }
470                if (!strcmp(str[ct+1], "orthoNormalized")) {
471                    mEnviroment.mStateVertex =
472                        Script::Enviroment_t::VTX_ORTHO_NORMALIZED;
473                    continue;
474                }
475                if (!strcmp(str[ct+1], "projection")) {
476                    mEnviroment.mStateVertex =
477                        Script::Enviroment_t::VTX_PROJECTION;
478                    continue;
479                }
480                if (!strcmp(str[ct+1], "parent")) {
481                    mEnviroment.mStateVertex =
482                        Script::Enviroment_t::VTX_PARENT;
483                    continue;
484                }
485                LOGE("Unreconized value %s passed to stateVertex", str[ct+1]);
486            }
487
488            if (!strcmp(str[ct], "stateRaster")) {
489                if (!strcmp(str[ct+1], "flat")) {
490                    mEnviroment.mStateRaster =
491                        Script::Enviroment_t::RASTER_FLAT;
492                    continue;
493                }
494                if (!strcmp(str[ct+1], "smooth")) {
495                    mEnviroment.mStateRaster =
496                        Script::Enviroment_t::RASTER_SMOOTH;
497                    continue;
498                }
499                if (!strcmp(str[ct+1], "parent")) {
500                    mEnviroment.mStateRaster =
501                        Script::Enviroment_t::RASTER_PARENT;
502                    continue;
503                }
504                LOGE("Unreconized value %s passed to stateRaster", str[ct+1]);
505            }
506
507            if (!strcmp(str[ct], "stateFragment")) {
508                if (!strcmp(str[ct+1], "color")) {
509                    mEnviroment.mStateFragment =
510                        Script::Enviroment_t::FRAGMENT_COLOR;
511                    continue;
512                }
513                if (!strcmp(str[ct+1], "texReplace")) {
514                    mEnviroment.mStateFragment =
515                        Script::Enviroment_t::FRAGMENT_TEX_REPLACE;
516                    continue;
517                }
518                if (!strcmp(str[ct+1], "texModulate")) {
519                    mEnviroment.mStateFragment =
520                        Script::Enviroment_t::FRAGMENT_TEX_MODULATE;
521                    continue;
522                }
523                if (!strcmp(str[ct+1], "parent")) {
524                    mEnviroment.mStateFragment =
525                        Script::Enviroment_t::FRAGMENT_PARENT;
526                    continue;
527                }
528                LOGE("Unreconized value %s passed to stateFragment", str[ct+1]);
529            }
530
531            if (!strcmp(str[ct], "stateFragmentStore")) {
532                if (!strcmp(str[ct+1], "alwaysReplace")) {
533                    mEnviroment.mStateFragmentStore =
534                        Script::Enviroment_t::FRAGMENT_STORE_ALWAYS_REPLACE;
535                    continue;
536                }
537                if (!strcmp(str[ct+1], "alwaysBlend")) {
538                    mEnviroment.mStateFragmentStore =
539                        Script::Enviroment_t::FRAGMENT_STORE_ALWAYS_BLEND;
540                    continue;
541                }
542                if (!strcmp(str[ct+1], "depthLessReplace")) {
543                    mEnviroment.mStateFragmentStore =
544                        Script::Enviroment_t::FRAGMENT_STORE_DEPTH_LESS_REPLACE;
545                    continue;
546                }
547                if (!strcmp(str[ct+1], "depthLessBlend")) {
548                    mEnviroment.mStateFragmentStore =
549                        Script::Enviroment_t::FRAGMENT_STORE_DEPTH_LESS_BLEND;
550                    continue;
551                }
552                if (!strcmp(str[ct+1], "parent")) {
553                    mEnviroment.mStateFragmentStore =
554                        Script::Enviroment_t::FRAGMENT_STORE_PARENT;
555                    continue;
556                }
557                LOGE("Unreconized value %s passed to stateFragmentStore", str[ct+1]);
558            }
559
560        }
561
562
563    } else {
564        // Deal with an error.
565    }
566
567}
568
569namespace android {
570namespace renderscript {
571
572void rsi_ScriptCBegin(Context * rsc)
573{
574    ScriptCState *ss = &rsc->mScriptC;
575    ss->clear();
576}
577
578void rsi_ScriptCSetClearColor(Context * rsc, float r, float g, float b, float a)
579{
580    ScriptCState *ss = &rsc->mScriptC;
581    ss->mEnviroment.mClearColor[0] = r;
582    ss->mEnviroment.mClearColor[1] = g;
583    ss->mEnviroment.mClearColor[2] = b;
584    ss->mEnviroment.mClearColor[3] = a;
585}
586
587void rsi_ScriptCSetClearDepth(Context * rsc, float v)
588{
589    ScriptCState *ss = &rsc->mScriptC;
590    ss->mEnviroment.mClearDepth = v;
591}
592
593void rsi_ScriptCSetClearStencil(Context * rsc, uint32_t v)
594{
595    ScriptCState *ss = &rsc->mScriptC;
596    ss->mEnviroment.mClearStencil = v;
597}
598
599void rsi_ScriptCAddType(Context * rsc, RsType vt)
600{
601    ScriptCState *ss = &rsc->mScriptC;
602    ss->mConstantBufferTypes.add(static_cast<const Type *>(vt));
603}
604
605void rsi_ScriptCSetScript(Context * rsc, void *vp)
606{
607    ScriptCState *ss = &rsc->mScriptC;
608    ss->mProgram.mScript = reinterpret_cast<rsc_RunScript>(vp);
609}
610
611void rsi_ScriptCSetRoot(Context * rsc, bool isRoot)
612{
613    ScriptCState *ss = &rsc->mScriptC;
614    ss->mEnviroment.mIsRoot = isRoot;
615}
616
617void rsi_ScriptCSetOrtho(Context * rsc, bool isOrtho)
618{
619    ScriptCState *ss = &rsc->mScriptC;
620    ss->mEnviroment.mIsOrtho = isOrtho;
621}
622
623void rsi_ScriptCSetText(Context *rsc, const char *text, uint32_t len)
624{
625    ScriptCState *ss = &rsc->mScriptC;
626    ss->mProgram.mScriptText = text;
627    ss->mProgram.mScriptTextLength = len;
628}
629
630
631RsScript rsi_ScriptCCreate(Context * rsc)
632{
633    ScriptCState *ss = &rsc->mScriptC;
634
635    ss->runCompiler();
636
637    ScriptC *s = new ScriptC();
638    s->incRef();
639    s->mAccScript = ss->mAccScript;
640    ss->mAccScript = NULL;
641    s->mEnviroment = ss->mEnviroment;
642    s->mProgram = ss->mProgram;
643    ss->clear();
644
645    return s;
646}
647
648}
649}
650
651
652