/* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "rsContext.h" #include "rsScriptC.h" #include "rsMatrix.h" #include "acc/acc.h" #include "utils/Timers.h" #include #include using namespace android; using namespace android::renderscript; #define GET_TLS() Context::ScriptTLSStruct * tls = \ (Context::ScriptTLSStruct *)pthread_getspecific(Context::gThreadTLSKey); \ Context * rsc = tls->mContext; \ ScriptC * sc = (ScriptC *) tls->mScript ScriptC::ScriptC(Context *rsc) : Script(rsc) { mAllocFile = __FILE__; mAllocLine = __LINE__; mAccScript = NULL; memset(&mProgram, 0, sizeof(mProgram)); } ScriptC::~ScriptC() { if (mAccScript) { accDeleteScript(mAccScript); } free(mEnviroment.mScriptText); mEnviroment.mScriptText = NULL; } void ScriptC::setupScript() { for (int ct=0; ct < MAX_SCRIPT_BANKS; ct++) { if (mProgram.mSlotPointers[ct]) { *mProgram.mSlotPointers[ct] = mSlots[ct]->getPtr(); } } } bool ScriptC::run(Context *rsc, uint32_t launchIndex) { Context::ScriptTLSStruct * tls = (Context::ScriptTLSStruct *)pthread_getspecific(Context::gThreadTLSKey); rsAssert(tls); if (mEnviroment.mFragmentStore.get()) { rsc->setFragmentStore(mEnviroment.mFragmentStore.get()); } if (mEnviroment.mFragment.get()) { rsc->setFragment(mEnviroment.mFragment.get()); } if (mEnviroment.mVertex.get()) { rsc->setVertex(mEnviroment.mVertex.get()); } if (mEnviroment.mRaster.get()) { rsc->setRaster(mEnviroment.mRaster.get()); } if (launchIndex == 0) { mEnviroment.mStartTimeMillis = nanoseconds_to_milliseconds(systemTime(SYSTEM_TIME_MONOTONIC)); } setupScript(); bool ret = false; tls->mScript = this; ret = mProgram.mScript(launchIndex) != 0; tls->mScript = NULL; return ret; } ScriptCState::ScriptCState() { mScript = NULL; clear(); } ScriptCState::~ScriptCState() { delete mScript; mScript = NULL; } void ScriptCState::clear() { for (uint32_t ct=0; ct < MAX_SCRIPT_BANKS; ct++) { mConstantBufferTypes[ct].clear(); mSlotNames[ct].setTo(""); mInvokableNames[ct].setTo(""); mSlotWritable[ct] = false; } delete mScript; mScript = new ScriptC(NULL); mInt32Defines.clear(); mFloatDefines.clear(); } static ACCvoid* symbolLookup(ACCvoid* pContext, const ACCchar* name) { const ScriptCState::SymbolTable_t *sym = ScriptCState::lookupSymbol(name); if (sym) { return sym->mPtr; } LOGE("ScriptC sym lookup failed for %s", name); return NULL; } void ScriptCState::runCompiler(Context *rsc, ScriptC *s) { s->mAccScript = accCreateScript(); String8 tmp; rsc->appendNameDefines(&tmp); appendDecls(&tmp); rsc->appendVarDefines(&tmp); appendVarDefines(rsc, &tmp); appendTypes(rsc, &tmp); tmp.append("#line 1\n"); const char* scriptSource[] = {tmp.string(), s->mEnviroment.mScriptText}; int scriptLength[] = {tmp.length(), s->mEnviroment.mScriptTextLength} ; accScriptSource(s->mAccScript, sizeof(scriptLength) / sizeof(int), scriptSource, scriptLength); accRegisterSymbolCallback(s->mAccScript, symbolLookup, NULL); accCompileScript(s->mAccScript); accGetScriptLabel(s->mAccScript, "main", (ACCvoid**) &s->mProgram.mScript); accGetScriptLabel(s->mAccScript, "init", (ACCvoid**) &s->mProgram.mInit); rsAssert(s->mProgram.mScript); if (!s->mProgram.mScript) { ACCchar buf[4096]; ACCsizei len; accGetScriptInfoLog(s->mAccScript, sizeof(buf), &len, buf); LOGV(buf); } if (s->mProgram.mInit) { s->mProgram.mInit(); } for (int ct=0; ct < MAX_SCRIPT_BANKS; ct++) { if (mSlotNames[ct].length() > 0) { accGetScriptLabel(s->mAccScript, mSlotNames[ct].string(), (ACCvoid**) &s->mProgram.mSlotPointers[ct]); } } for (int ct=0; ct < MAX_SCRIPT_BANKS; ct++) { if (mInvokableNames[ct].length() > 0) { accGetScriptLabel(s->mAccScript, mInvokableNames[ct].string(), (ACCvoid**) &s->mEnviroment.mInvokables[ct]); } } s->mEnviroment.mFragment.set(rsc->getDefaultProgramFragment()); s->mEnviroment.mVertex.set(rsc->getDefaultProgramVertex()); s->mEnviroment.mFragmentStore.set(rsc->getDefaultProgramFragmentStore()); s->mEnviroment.mRaster.set(rsc->getDefaultProgramRaster()); if (s->mProgram.mScript) { const static int pragmaMax = 16; ACCsizei pragmaCount; ACCchar * str[pragmaMax]; accGetPragmas(s->mAccScript, &pragmaCount, pragmaMax, &str[0]); for (int ct=0; ct < pragmaCount; ct+=2) { if (!strcmp(str[ct], "version")) { continue; } if (!strcmp(str[ct], "stateVertex")) { if (!strcmp(str[ct+1], "default")) { continue; } if (!strcmp(str[ct+1], "parent")) { s->mEnviroment.mVertex.clear(); continue; } ProgramVertex * pv = (ProgramVertex *)rsc->lookupName(str[ct+1]); if (pv != NULL) { s->mEnviroment.mVertex.set(pv); continue; } LOGE("Unreconized value %s passed to stateVertex", str[ct+1]); } if (!strcmp(str[ct], "stateRaster")) { if (!strcmp(str[ct+1], "default")) { continue; } if (!strcmp(str[ct+1], "parent")) { s->mEnviroment.mRaster.clear(); continue; } ProgramRaster * pr = (ProgramRaster *)rsc->lookupName(str[ct+1]); if (pr != NULL) { s->mEnviroment.mRaster.set(pr); continue; } LOGE("Unreconized value %s passed to stateRaster", str[ct+1]); } if (!strcmp(str[ct], "stateFragment")) { if (!strcmp(str[ct+1], "default")) { continue; } if (!strcmp(str[ct+1], "parent")) { s->mEnviroment.mFragment.clear(); continue; } ProgramFragment * pf = (ProgramFragment *)rsc->lookupName(str[ct+1]); if (pf != NULL) { s->mEnviroment.mFragment.set(pf); continue; } LOGE("Unreconized value %s passed to stateFragment", str[ct+1]); } if (!strcmp(str[ct], "stateStore")) { if (!strcmp(str[ct+1], "default")) { continue; } if (!strcmp(str[ct+1], "parent")) { s->mEnviroment.mFragmentStore.clear(); continue; } ProgramFragmentStore * pfs = (ProgramFragmentStore *)rsc->lookupName(str[ct+1]); if (pfs != NULL) { s->mEnviroment.mFragmentStore.set(pfs); continue; } LOGE("Unreconized value %s passed to stateStore", str[ct+1]); } } } else { // Deal with an error. } } static void appendElementBody(String8 *s, const Element *e) { s->append(" {\n"); for (size_t ct2=0; ct2 < e->getComponentCount(); ct2++) { const Component *c = e->getComponent(ct2); s->append(" "); s->append(c->getCType()); s->append(" "); s->append(c->getComponentName()); s->append(";\n"); } s->append("}"); } void ScriptCState::appendVarDefines(const Context *rsc, String8 *str) { char buf[256]; if (rsc->props.mLogScripts) { LOGD("appendVarDefines mInt32Defines.size()=%d mFloatDefines.size()=%d\n", mInt32Defines.size(), mFloatDefines.size()); } for (size_t ct=0; ct < mInt32Defines.size(); ct++) { str->append("#define "); str->append(mInt32Defines.keyAt(ct)); str->append(" "); sprintf(buf, "%i\n", (int)mInt32Defines.valueAt(ct)); str->append(buf); } for (size_t ct=0; ct < mFloatDefines.size(); ct++) { str->append("#define "); str->append(mFloatDefines.keyAt(ct)); str->append(" "); sprintf(buf, "%ff\n", mFloatDefines.valueAt(ct)); str->append(buf); } } void ScriptCState::appendTypes(const Context *rsc, String8 *str) { char buf[256]; String8 tmp; str->append("struct vec2_s {float x; float y;};"); str->append("struct vec3_s {float x; float y; float z;};"); str->append("struct vec4_s {float x; float y; float z; float w;};"); for (size_t ct=0; ct < MAX_SCRIPT_BANKS; ct++) { const Type *t = mConstantBufferTypes[ct].get(); if (!t) { continue; } const Element *e = t->getElement(); if (e->getName() && (e->getComponentCount() > 1)) { String8 s("struct struct_"); s.append(e->getName()); appendElementBody(&s, e); s.append(";\n"); s.append("#define "); s.append(e->getName()); s.append("_t struct struct_"); s.append(e->getName()); s.append("\n\n"); if (rsc->props.mLogScripts) { LOGV(s); } str->append(s); } if (t->getName()) { for (size_t ct2=0; ct2 < e->getComponentCount(); ct2++) { const Component *c = e->getComponent(ct2); tmp.setTo("#define OFFSETOF_"); tmp.append(t->getName()); tmp.append("_"); tmp.append(c->getComponentName()); sprintf(buf, " %i\n", ct2); tmp.append(buf); if (rsc->props.mLogScripts) { LOGV(tmp); } str->append(tmp); } } if (mSlotNames[ct].length() > 0) { String8 s; if (e->getComponentCount() > 1) { if (e->getName()) { // Use the named struct s.setTo(e->getName()); s.append("_t *"); } else { // create an struct named from the slot. s.setTo("struct "); s.append(mSlotNames[ct]); s.append("_s"); appendElementBody(&s, e); s.append(";\n"); s.append("struct "); s.append(mSlotNames[ct]); s.append("_s * "); } } else { // Just make an array s.setTo(e->getComponent(0)->getCType()); s.append("_t *"); } s.append(mSlotNames[ct]); s.append(";\n"); if (rsc->props.mLogScripts) { LOGV(s); } str->append(s); } } } namespace android { namespace renderscript { void rsi_ScriptCBegin(Context * rsc) { ScriptCState *ss = &rsc->mScriptC; ss->clear(); } void rsi_ScriptCSetScript(Context * rsc, void *vp) { rsAssert(0); //ScriptCState *ss = &rsc->mScriptC; //ss->mProgram.mScript = reinterpret_cast(vp); } void rsi_ScriptCSetText(Context *rsc, const char *text, uint32_t len) { ScriptCState *ss = &rsc->mScriptC; char *t = (char *)malloc(len + 1); memcpy(t, text, len); t[len] = 0; ss->mScript->mEnviroment.mScriptText = t; ss->mScript->mEnviroment.mScriptTextLength = len; } RsScript rsi_ScriptCCreate(Context * rsc) { ScriptCState *ss = &rsc->mScriptC; ScriptC *s = ss->mScript; ss->mScript = NULL; ss->runCompiler(rsc, s); s->incUserRef(); s->setContext(rsc); for (int ct=0; ct < MAX_SCRIPT_BANKS; ct++) { s->mTypes[ct].set(ss->mConstantBufferTypes[ct].get()); s->mSlotNames[ct] = ss->mSlotNames[ct]; s->mSlotWritable[ct] = ss->mSlotWritable[ct]; } ss->clear(); return s; } void rsi_ScriptCSetDefineF(Context *rsc, const char* name, float value) { ScriptCState *ss = &rsc->mScriptC; ss->mFloatDefines.add(String8(name), value); } void rsi_ScriptCSetDefineI32(Context *rsc, const char* name, int32_t value) { ScriptCState *ss = &rsc->mScriptC; ss->mInt32Defines.add(String8(name), value); } } }