diff options
Diffstat (limited to 'libs/rs/driver')
32 files changed, 5512 insertions, 0 deletions
diff --git a/libs/rs/driver/rsdAllocation.cpp b/libs/rs/driver/rsdAllocation.cpp new file mode 100644 index 0000000..2e13e9d --- /dev/null +++ b/libs/rs/driver/rsdAllocation.cpp @@ -0,0 +1,423 @@ +/* + * Copyright (C) 2011 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 "rsdCore.h" +#include "rsdBcc.h" +#include "rsdRuntime.h" +#include "rsdAllocation.h" + +#include "rsAllocation.h" + +#include <GLES/gl.h> +#include <GLES2/gl2.h> +#include <GLES/glext.h> + +using namespace android; +using namespace android::renderscript; + + + +const static GLenum gFaceOrder[] = { + GL_TEXTURE_CUBE_MAP_POSITIVE_X, + GL_TEXTURE_CUBE_MAP_NEGATIVE_X, + GL_TEXTURE_CUBE_MAP_POSITIVE_Y, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, + GL_TEXTURE_CUBE_MAP_POSITIVE_Z, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Z +}; + + +GLenum rsdTypeToGLType(RsDataType t) { + switch (t) { + case RS_TYPE_UNSIGNED_5_6_5: return GL_UNSIGNED_SHORT_5_6_5; + case RS_TYPE_UNSIGNED_5_5_5_1: return GL_UNSIGNED_SHORT_5_5_5_1; + case RS_TYPE_UNSIGNED_4_4_4_4: return GL_UNSIGNED_SHORT_4_4_4_4; + + //case RS_TYPE_FLOAT_16: return GL_HALF_FLOAT; + case RS_TYPE_FLOAT_32: return GL_FLOAT; + case RS_TYPE_UNSIGNED_8: return GL_UNSIGNED_BYTE; + case RS_TYPE_UNSIGNED_16: return GL_UNSIGNED_SHORT; + case RS_TYPE_SIGNED_8: return GL_BYTE; + case RS_TYPE_SIGNED_16: return GL_SHORT; + default: break; + } + return 0; +} + +GLenum rsdKindToGLFormat(RsDataKind k) { + switch (k) { + case RS_KIND_PIXEL_L: return GL_LUMINANCE; + case RS_KIND_PIXEL_A: return GL_ALPHA; + case RS_KIND_PIXEL_LA: return GL_LUMINANCE_ALPHA; + case RS_KIND_PIXEL_RGB: return GL_RGB; + case RS_KIND_PIXEL_RGBA: return GL_RGBA; + case RS_KIND_PIXEL_DEPTH: return GL_DEPTH_COMPONENT16; + default: break; + } + return 0; +} + + +static void Update2DTexture(const Allocation *alloc, const void *ptr, uint32_t xoff, uint32_t yoff, + uint32_t lod, RsAllocationCubemapFace face, + uint32_t w, uint32_t h) { + DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; + + rsAssert(drv->textureID); + glBindTexture(drv->glTarget, drv->textureID); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + GLenum t = GL_TEXTURE_2D; + if (alloc->mHal.state.hasFaces) { + t = gFaceOrder[face]; + } + glTexSubImage2D(t, lod, xoff, yoff, w, h, drv->glFormat, drv->glType, ptr); +} + + +static void Upload2DTexture(const Context *rsc, const Allocation *alloc, bool isFirstUpload) { + DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; + + glBindTexture(drv->glTarget, drv->textureID); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + uint32_t faceCount = 1; + if (alloc->mHal.state.hasFaces) { + faceCount = 6; + } + + rsdGLCheckError(rsc, "Upload2DTexture 1 "); + for (uint32_t face = 0; face < faceCount; face ++) { + for (uint32_t lod = 0; lod < alloc->mHal.state.type->getLODCount(); lod++) { + const uint8_t *p = (const uint8_t *)drv->mallocPtr; + p += alloc->mHal.state.type->getLODFaceOffset(lod, (RsAllocationCubemapFace)face, 0, 0); + + GLenum t = GL_TEXTURE_2D; + if (alloc->mHal.state.hasFaces) { + t = gFaceOrder[face]; + } + + if (isFirstUpload) { + glTexImage2D(t, lod, drv->glFormat, + alloc->mHal.state.type->getLODDimX(lod), + alloc->mHal.state.type->getLODDimY(lod), + 0, drv->glFormat, drv->glType, p); + } else { + glTexSubImage2D(t, lod, 0, 0, + alloc->mHal.state.type->getLODDimX(lod), + alloc->mHal.state.type->getLODDimY(lod), + drv->glFormat, drv->glType, p); + } + } + } + + if (alloc->mHal.state.mipmapControl == RS_ALLOCATION_MIPMAP_ON_SYNC_TO_TEXTURE) { + glGenerateMipmap(drv->glTarget); + } + rsdGLCheckError(rsc, "Upload2DTexture"); +} + +static void UploadToTexture(const Context *rsc, const Allocation *alloc) { + DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; + + if (!drv->glType || !drv->glFormat) { + return; + } + + if (!alloc->getPtr()) { + return; + } + + bool isFirstUpload = false; + + if (!drv->textureID) { + glGenTextures(1, &drv->textureID); + isFirstUpload = true; + } + + Upload2DTexture(rsc, alloc, isFirstUpload); + + if (!(alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_SCRIPT)) { + if (drv->mallocPtr) { + free(drv->mallocPtr); + drv->mallocPtr = NULL; + } + } + rsdGLCheckError(rsc, "UploadToTexture"); +} + +static void AllocateRenderTarget(const Context *rsc, const Allocation *alloc) { + DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; + + if (!drv->glFormat) { + return; + } + + if (!drv->renderTargetID) { + glGenRenderbuffers(1, &drv->renderTargetID); + + if (!drv->renderTargetID) { + // This should generally not happen + LOGE("allocateRenderTarget failed to gen mRenderTargetID"); + rsc->dumpDebug(); + return; + } + glBindRenderbuffer(GL_RENDERBUFFER, drv->renderTargetID); + glRenderbufferStorage(GL_RENDERBUFFER, drv->glFormat, + alloc->mHal.state.dimensionX, alloc->mHal.state.dimensionY); + } + rsdGLCheckError(rsc, "AllocateRenderTarget"); +} + +static void UploadToBufferObject(const Context *rsc, const Allocation *alloc) { + DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; + + rsAssert(!alloc->mHal.state.type->getDimY()); + rsAssert(!alloc->mHal.state.type->getDimZ()); + + //alloc->mHal.state.usageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_VERTEX; + + if (!drv->bufferID) { + glGenBuffers(1, &drv->bufferID); + } + if (!drv->bufferID) { + LOGE("Upload to buffer object failed"); + drv->uploadDeferred = true; + return; + } + glBindBuffer(drv->glTarget, drv->bufferID); + glBufferData(drv->glTarget, alloc->mHal.state.type->getSizeBytes(), + drv->mallocPtr, GL_DYNAMIC_DRAW); + glBindBuffer(drv->glTarget, 0); + rsdGLCheckError(rsc, "UploadToBufferObject"); +} + +bool rsdAllocationInit(const Context *rsc, Allocation *alloc, bool forceZero) { + DrvAllocation *drv = (DrvAllocation *)calloc(1, sizeof(DrvAllocation)); + if (!drv) { + return false; + } + + void * ptr = malloc(alloc->mHal.state.type->getSizeBytes()); + if (!ptr) { + free(drv); + return false; + } + + drv->glTarget = GL_NONE; + if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE) { + if (alloc->mHal.state.hasFaces) { + drv->glTarget = GL_TEXTURE_CUBE_MAP; + } else { + drv->glTarget = GL_TEXTURE_2D; + } + } else { + if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_VERTEX) { + drv->glTarget = GL_ARRAY_BUFFER; + } + } + + drv->glType = rsdTypeToGLType(alloc->mHal.state.type->getElement()->getComponent().getType()); + drv->glFormat = rsdKindToGLFormat(alloc->mHal.state.type->getElement()->getComponent().getKind()); + + + alloc->mHal.drvState.mallocPtr = ptr; + drv->mallocPtr = (uint8_t *)ptr; + alloc->mHal.drv = drv; + if (forceZero) { + memset(ptr, 0, alloc->mHal.state.type->getSizeBytes()); + } + + if (alloc->mHal.state.usageFlags & ~RS_ALLOCATION_USAGE_SCRIPT) { + drv->uploadDeferred = true; + } + return true; +} + +void rsdAllocationDestroy(const Context *rsc, Allocation *alloc) { + DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; + + if (drv->bufferID) { + // Causes a SW crash.... + //LOGV(" mBufferID %i", mBufferID); + //glDeleteBuffers(1, &mBufferID); + //mBufferID = 0; + } + if (drv->textureID) { + glDeleteTextures(1, &drv->textureID); + drv->textureID = 0; + } + if (drv->renderTargetID) { + glDeleteRenderbuffers(1, &drv->renderTargetID); + drv->renderTargetID = 0; + } + + if (drv->mallocPtr) { + free(drv->mallocPtr); + drv->mallocPtr = NULL; + } + free(drv); + alloc->mHal.drv = NULL; +} + +void rsdAllocationResize(const Context *rsc, const Allocation *alloc, + const Type *newType, bool zeroNew) { + DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; + + drv->mallocPtr = (uint8_t *)realloc(drv->mallocPtr, newType->getSizeBytes()); + + // fixme + ((Allocation *)alloc)->mHal.drvState.mallocPtr = drv->mallocPtr; + + const uint32_t oldDimX = alloc->mHal.state.dimensionX; + const uint32_t dimX = newType->getDimX(); + + if (dimX > oldDimX) { + const Element *e = alloc->mHal.state.type->getElement(); + uint32_t stride = e->getSizeBytes(); + memset(((uint8_t *)drv->mallocPtr) + stride * oldDimX, 0, stride * (dimX - oldDimX)); + } +} + + + +void rsdAllocationSyncAll(const Context *rsc, const Allocation *alloc, + RsAllocationUsageType src) { + DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; + + if (!drv->uploadDeferred) { + return; + } + + rsAssert(src == RS_ALLOCATION_USAGE_SCRIPT); + + if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE) { + UploadToTexture(rsc, alloc); + } else { + if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET) { + AllocateRenderTarget(rsc, alloc); + } + } + if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_VERTEX) { + UploadToBufferObject(rsc, alloc); + } + + drv->uploadDeferred = false; +} + +void rsdAllocationMarkDirty(const Context *rsc, const Allocation *alloc) { + DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; + drv->uploadDeferred = true; +} + +void rsdAllocationData1D(const Context *rsc, const Allocation *alloc, + uint32_t xoff, uint32_t lod, uint32_t count, + const void *data, uint32_t sizeBytes) { + DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; + + const uint32_t eSize = alloc->mHal.state.type->getElementSizeBytes(); + uint8_t * ptr = drv->mallocPtr; + ptr += eSize * xoff; + uint32_t size = count * eSize; + + if (alloc->mHal.state.hasReferences) { + alloc->incRefs(data, count); + alloc->decRefs(ptr, count); + } + + memcpy(ptr, data, size); + drv->uploadDeferred = true; +} + +void rsdAllocationData2D(const Context *rsc, const Allocation *alloc, + uint32_t xoff, uint32_t yoff, uint32_t lod, RsAllocationCubemapFace face, + uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes) { + DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; + + uint32_t eSize = alloc->mHal.state.elementSizeBytes; + uint32_t lineSize = eSize * w; + uint32_t destW = alloc->mHal.state.dimensionX; + + if (drv->mallocPtr) { + const uint8_t *src = static_cast<const uint8_t *>(data); + uint8_t *dst = drv->mallocPtr; + dst += alloc->mHal.state.type->getLODFaceOffset(lod, face, xoff, yoff); + + for (uint32_t line=yoff; line < (yoff+h); line++) { + if (alloc->mHal.state.hasReferences) { + alloc->incRefs(src, w); + alloc->decRefs(dst, w); + } + memcpy(dst, src, lineSize); + src += lineSize; + dst += destW * eSize; + } + drv->uploadDeferred = true; + } else { + Update2DTexture(alloc, data, xoff, yoff, lod, face, w, h); + } +} + +void rsdAllocationData3D(const Context *rsc, const Allocation *alloc, + uint32_t xoff, uint32_t yoff, uint32_t zoff, + uint32_t lod, RsAllocationCubemapFace face, + uint32_t w, uint32_t h, uint32_t d, const void *data, uint32_t sizeBytes) { + +} + +void rsdAllocationElementData1D(const Context *rsc, const Allocation *alloc, + uint32_t x, + const void *data, uint32_t cIdx, uint32_t sizeBytes) { + DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; + + uint32_t eSize = alloc->mHal.state.elementSizeBytes; + uint8_t * ptr = drv->mallocPtr; + ptr += eSize * x; + + const Element * e = alloc->mHal.state.type->getElement()->getField(cIdx); + ptr += alloc->mHal.state.type->getElement()->getFieldOffsetBytes(cIdx); + + if (alloc->mHal.state.hasReferences) { + e->incRefs(data); + e->decRefs(ptr); + } + + memcpy(ptr, data, sizeBytes); + drv->uploadDeferred = true; +} + +void rsdAllocationElementData2D(const Context *rsc, const Allocation *alloc, + uint32_t x, uint32_t y, + const void *data, uint32_t cIdx, uint32_t sizeBytes) { + DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; + + uint32_t eSize = alloc->mHal.state.elementSizeBytes; + uint8_t * ptr = drv->mallocPtr; + ptr += eSize * (x + y * alloc->mHal.state.dimensionX); + + const Element * e = alloc->mHal.state.type->getElement()->getField(cIdx); + ptr += alloc->mHal.state.type->getElement()->getFieldOffsetBytes(cIdx); + + if (alloc->mHal.state.hasReferences) { + e->incRefs(data); + e->decRefs(ptr); + } + + memcpy(ptr, data, sizeBytes); + drv->uploadDeferred = true; +} + + diff --git a/libs/rs/driver/rsdAllocation.h b/libs/rs/driver/rsdAllocation.h new file mode 100644 index 0000000..d7385ce --- /dev/null +++ b/libs/rs/driver/rsdAllocation.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2011 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. + */ + +#ifndef RSD_ALLOCATION_H +#define RSD_ALLOCATION_H + +#include <rs_hal.h> +#include <rsRuntime.h> + +#include <GLES/gl.h> +#include <GLES2/gl2.h> + +struct DrvAllocation { + // Is this a legal structure to be used as a texture source. + // Initially this will require 1D or 2D and color data + uint32_t textureID; + + // Is this a legal structure to be used as a vertex source. + // Initially this will require 1D and x(yzw). Additional per element data + // is allowed. + uint32_t bufferID; + + // Is this a legal structure to be used as an FBO render target + uint32_t renderTargetID; + + uint8_t * mallocPtr; + + GLenum glTarget; + GLenum glType; + GLenum glFormat; + + + bool uploadDeferred; +}; + +GLenum rsdTypeToGLType(RsDataType t); +GLenum rsdKindToGLFormat(RsDataKind k); + + +bool rsdAllocationInit(const android::renderscript::Context *rsc, + android::renderscript::Allocation *alloc, + bool forceZero); +void rsdAllocationDestroy(const android::renderscript::Context *rsc, + android::renderscript::Allocation *alloc); + +void rsdAllocationResize(const android::renderscript::Context *rsc, + const android::renderscript::Allocation *alloc, + const android::renderscript::Type *newType, bool zeroNew); +void rsdAllocationSyncAll(const android::renderscript::Context *rsc, + const android::renderscript::Allocation *alloc, + RsAllocationUsageType src); +void rsdAllocationMarkDirty(const android::renderscript::Context *rsc, + const android::renderscript::Allocation *alloc); + +void rsdAllocationData1D(const android::renderscript::Context *rsc, + const android::renderscript::Allocation *alloc, + uint32_t xoff, uint32_t lod, uint32_t count, + const void *data, uint32_t sizeBytes); +void rsdAllocationData2D(const android::renderscript::Context *rsc, + const android::renderscript::Allocation *alloc, + uint32_t xoff, uint32_t yoff, uint32_t lod, RsAllocationCubemapFace face, + uint32_t w, uint32_t h, + const void *data, uint32_t sizeBytes); +void rsdAllocationData3D(const android::renderscript::Context *rsc, + const android::renderscript::Allocation *alloc, + uint32_t xoff, uint32_t yoff, uint32_t zoff, + uint32_t lod, RsAllocationCubemapFace face, + uint32_t w, uint32_t h, uint32_t d, const void *data, uint32_t sizeBytes); + +void rsdAllocationElementData1D(const android::renderscript::Context *rsc, + const android::renderscript::Allocation *alloc, + uint32_t x, + const void *data, uint32_t elementOff, uint32_t sizeBytes); +void rsdAllocationElementData2D(const android::renderscript::Context *rsc, + const android::renderscript::Allocation *alloc, + uint32_t x, uint32_t y, + const void *data, uint32_t elementOff, uint32_t sizeBytes); + + + + +#endif diff --git a/libs/rs/driver/rsdBcc.cpp b/libs/rs/driver/rsdBcc.cpp new file mode 100644 index 0000000..8120864 --- /dev/null +++ b/libs/rs/driver/rsdBcc.cpp @@ -0,0 +1,553 @@ +/* + * Copyright (C) 2011 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 "rsdCore.h" +#include "rsdBcc.h" +#include "rsdRuntime.h" + +#include "rsContext.h" +#include "rsScriptC.h" + +#include "utils/Timers.h" +#include "utils/StopWatch.h" +extern "C" { +#include "libdex/ZipArchive.h" +} + + +using namespace android; +using namespace android::renderscript; + +struct DrvScript { + int (*mRoot)(); + void (*mInit)(); + + BCCScriptRef mBccScript; + + uint32_t mInvokeFunctionCount; + InvokeFunc_t *mInvokeFunctions; + uint32_t mFieldCount; + void ** mFieldAddress; + bool * mFieldIsObject; + + const uint8_t * mScriptText; + uint32_t mScriptTextLength; + + //uint32_t * mObjectSlots; + //uint32_t mObjectSlotCount; + + uint32_t mPragmaCount; + const char ** mPragmaKeys; + const char ** mPragmaValues; + +}; + + +static Script * setTLS(Script *sc) { + ScriptTLSStruct * tls = (ScriptTLSStruct *)pthread_getspecific(rsdgThreadTLSKey); + rsAssert(tls); + Script *old = tls->mScript; + tls->mScript = sc; + return old; +} + + +// Input: cacheDir +// Input: resName +// Input: extName +// +// Note: cacheFile = resName + extName +// +// Output: Returns cachePath == cacheDir + cacheFile +static char *genCacheFileName(const char *cacheDir, + const char *resName, + const char *extName) { + char cachePath[512]; + char cacheFile[sizeof(cachePath)]; + const size_t kBufLen = sizeof(cachePath) - 1; + + cacheFile[0] = '\0'; + // Note: resName today is usually something like + // "/com.android.fountain:raw/fountain" + if (resName[0] != '/') { + // Get the absolute path of the raw/***.bc file. + + // Generate the absolute path. This doesn't do everything it + // should, e.g. if resName is "./out/whatever" it doesn't crunch + // the leading "./" out because this if-block is not triggered, + // but it'll make do. + // + if (getcwd(cacheFile, kBufLen) == NULL) { + LOGE("Can't get CWD while opening raw/***.bc file\n"); + return NULL; + } + // Append "/" at the end of cacheFile so far. + strncat(cacheFile, "/", kBufLen); + } + + // cacheFile = resName + extName + // + strncat(cacheFile, resName, kBufLen); + if (extName != NULL) { + // TODO(srhines): strncat() is a bit dangerous + strncat(cacheFile, extName, kBufLen); + } + + // Turn the path into a flat filename by replacing + // any slashes after the first one with '@' characters. + char *cp = cacheFile + 1; + while (*cp != '\0') { + if (*cp == '/') { + *cp = '@'; + } + cp++; + } + + // Tack on the file name for the actual cache file path. + strncpy(cachePath, cacheDir, kBufLen); + strncat(cachePath, cacheFile, kBufLen); + + LOGV("Cache file for '%s' '%s' is '%s'\n", resName, extName, cachePath); + return strdup(cachePath); +} + +bool rsdScriptInit(const Context *rsc, + ScriptC *script, + char const *resName, + char const *cacheDir, + uint8_t const *bitcode, + size_t bitcodeSize, + uint32_t flags) { + //LOGE("rsdScriptCreate %p %p %p %p %i %i %p", rsc, resName, cacheDir, bitcode, bitcodeSize, flags, lookupFunc); + + pthread_mutex_lock(&rsdgInitMutex); + char *cachePath = NULL; + uint32_t objectSlotCount = 0; + + DrvScript *drv = (DrvScript *)calloc(1, sizeof(DrvScript)); + if (drv == NULL) { + goto error; + } + script->mHal.drv = drv; + + drv->mBccScript = bccCreateScript(); + script->mHal.info.isThreadable = true; + drv->mScriptText = bitcode; + drv->mScriptTextLength = bitcodeSize; + + //LOGE("mBccScript %p", script->mBccScript); + + if (bccRegisterSymbolCallback(drv->mBccScript, &rsdLookupRuntimeStub, script) != 0) { + LOGE("bcc: FAILS to register symbol callback"); + goto error; + } + + if (bccReadBC(drv->mBccScript, + resName, + (char const *)drv->mScriptText, + drv->mScriptTextLength, 0) != 0) { + LOGE("bcc: FAILS to read bitcode"); + goto error; + } + +#if 1 + if (bccLinkFile(drv->mBccScript, "/system/lib/libclcore.bc", 0) != 0) { + LOGE("bcc: FAILS to link bitcode"); + goto error; + } +#endif + cachePath = genCacheFileName(cacheDir, resName, ".oBCC"); + + if (bccPrepareExecutable(drv->mBccScript, cachePath, 0) != 0) { + LOGE("bcc: FAILS to prepare executable"); + goto error; + } + + free(cachePath); + + drv->mRoot = reinterpret_cast<int (*)()>(bccGetFuncAddr(drv->mBccScript, "root")); + drv->mInit = reinterpret_cast<void (*)()>(bccGetFuncAddr(drv->mBccScript, "init")); + + drv->mInvokeFunctionCount = bccGetExportFuncCount(drv->mBccScript); + if (drv->mInvokeFunctionCount <= 0) + drv->mInvokeFunctions = NULL; + else { + drv->mInvokeFunctions = (InvokeFunc_t*) calloc(drv->mInvokeFunctionCount, sizeof(InvokeFunc_t)); + bccGetExportFuncList(drv->mBccScript, drv->mInvokeFunctionCount, (void **) drv->mInvokeFunctions); + } + + drv->mFieldCount = bccGetExportVarCount(drv->mBccScript); + if (drv->mFieldCount <= 0) { + drv->mFieldAddress = NULL; + drv->mFieldIsObject = NULL; + } else { + drv->mFieldAddress = (void **) calloc(drv->mFieldCount, sizeof(void *)); + drv->mFieldIsObject = (bool *) calloc(drv->mFieldCount, sizeof(bool)); + bccGetExportVarList(drv->mBccScript, drv->mFieldCount, (void **) drv->mFieldAddress); + } + + objectSlotCount = bccGetObjectSlotCount(drv->mBccScript); + if (objectSlotCount) { + uint32_t * slots = new uint32_t[objectSlotCount]; + bccGetObjectSlotList(drv->mBccScript, objectSlotCount, slots); + for (uint32_t ct=0; ct < objectSlotCount; ct++) { + drv->mFieldIsObject[slots[ct]] = true; + } + delete [] slots; + } + + uint32_t mPragmaCount; + const char ** mPragmaKeys; + const char ** mPragmaValues; + + const static int pragmaMax = 16; + drv->mPragmaCount = bccGetPragmaCount(drv->mBccScript); + if (drv->mPragmaCount <= 0) { + drv->mPragmaKeys = NULL; + drv->mPragmaValues = NULL; + } else { + drv->mPragmaKeys = (const char **) calloc(drv->mFieldCount, sizeof(const char *)); + drv->mPragmaValues = (const char **) calloc(drv->mFieldCount, sizeof(const char *)); + bccGetPragmaList(drv->mBccScript, drv->mPragmaCount, drv->mPragmaKeys, drv->mPragmaValues); + } + + + + // Copy info over to runtime + script->mHal.info.exportedFunctionCount = drv->mInvokeFunctionCount; + script->mHal.info.exportedVariableCount = drv->mFieldCount; + script->mHal.info.exportedPragmaCount = drv->mPragmaCount; + script->mHal.info.exportedPragmaKeyList = drv->mPragmaKeys; + script->mHal.info.exportedPragmaValueList = drv->mPragmaValues; + script->mHal.info.root = drv->mRoot; + + + pthread_mutex_unlock(&rsdgInitMutex); + return true; + +error: + + pthread_mutex_unlock(&rsdgInitMutex); + free(drv); + return false; + +} + +typedef struct { + Context *rsc; + Script *script; + const Allocation * ain; + Allocation * aout; + const void * usr; + + uint32_t mSliceSize; + volatile int mSliceNum; + + const uint8_t *ptrIn; + uint32_t eStrideIn; + uint8_t *ptrOut; + uint32_t eStrideOut; + + uint32_t xStart; + uint32_t xEnd; + uint32_t yStart; + uint32_t yEnd; + uint32_t zStart; + uint32_t zEnd; + uint32_t arrayStart; + uint32_t arrayEnd; + + uint32_t dimX; + uint32_t dimY; + uint32_t dimZ; + uint32_t dimArray; +} MTLaunchStruct; +typedef int (*rs_t)(const void *, void *, const void *, uint32_t, uint32_t, uint32_t, uint32_t); + +static void wc_xy(void *usr, uint32_t idx) { + MTLaunchStruct *mtls = (MTLaunchStruct *)usr; + + while (1) { + uint32_t slice = (uint32_t)android_atomic_inc(&mtls->mSliceNum); + uint32_t yStart = mtls->yStart + slice * mtls->mSliceSize; + uint32_t yEnd = yStart + mtls->mSliceSize; + yEnd = rsMin(yEnd, mtls->yEnd); + if (yEnd <= yStart) { + return; + } + + //LOGE("usr idx %i, x %i,%i y %i,%i", idx, mtls->xStart, mtls->xEnd, yStart, yEnd); + //LOGE("usr ptr in %p, out %p", mtls->ptrIn, mtls->ptrOut); + for (uint32_t y = yStart; y < yEnd; y++) { + uint32_t offset = mtls->dimX * y; + uint8_t *xPtrOut = mtls->ptrOut + (mtls->eStrideOut * offset); + const uint8_t *xPtrIn = mtls->ptrIn + (mtls->eStrideIn * offset); + + for (uint32_t x = mtls->xStart; x < mtls->xEnd; x++) { + ((rs_t)mtls->script->mHal.info.root) (xPtrIn, xPtrOut, mtls->usr, x, y, 0, 0); + xPtrIn += mtls->eStrideIn; + xPtrOut += mtls->eStrideOut; + } + } + } +} + +static void wc_x(void *usr, uint32_t idx) { + MTLaunchStruct *mtls = (MTLaunchStruct *)usr; + + while (1) { + uint32_t slice = (uint32_t)android_atomic_inc(&mtls->mSliceNum); + uint32_t xStart = mtls->xStart + slice * mtls->mSliceSize; + uint32_t xEnd = xStart + mtls->mSliceSize; + xEnd = rsMin(xEnd, mtls->xEnd); + if (xEnd <= xStart) { + return; + } + + //LOGE("usr idx %i, x %i,%i y %i,%i", idx, mtls->xStart, mtls->xEnd, yStart, yEnd); + //LOGE("usr ptr in %p, out %p", mtls->ptrIn, mtls->ptrOut); + uint8_t *xPtrOut = mtls->ptrOut + (mtls->eStrideOut * xStart); + const uint8_t *xPtrIn = mtls->ptrIn + (mtls->eStrideIn * xStart); + for (uint32_t x = xStart; x < xEnd; x++) { + ((rs_t)mtls->script->mHal.info.root) (xPtrIn, xPtrOut, mtls->usr, x, 0, 0, 0); + xPtrIn += mtls->eStrideIn; + xPtrOut += mtls->eStrideOut; + } + } +} + +void rsdScriptInvokeForEach(const Context *rsc, + Script *s, + const Allocation * ain, + Allocation * aout, + const void * usr, + uint32_t usrLen, + const RsScriptCall *sc) { + + RsdHal * dc = (RsdHal *)rsc->mHal.drv; + + MTLaunchStruct mtls; + memset(&mtls, 0, sizeof(mtls)); + + if (ain) { + mtls.dimX = ain->getType()->getDimX(); + mtls.dimY = ain->getType()->getDimY(); + mtls.dimZ = ain->getType()->getDimZ(); + //mtls.dimArray = ain->getType()->getDimArray(); + } else if (aout) { + mtls.dimX = aout->getType()->getDimX(); + mtls.dimY = aout->getType()->getDimY(); + mtls.dimZ = aout->getType()->getDimZ(); + //mtls.dimArray = aout->getType()->getDimArray(); + } else { + rsc->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null allocations"); + return; + } + + if (!sc || (sc->xEnd == 0)) { + mtls.xEnd = mtls.dimX; + } else { + rsAssert(sc->xStart < mtls.dimX); + rsAssert(sc->xEnd <= mtls.dimX); + rsAssert(sc->xStart < sc->xEnd); + mtls.xStart = rsMin(mtls.dimX, sc->xStart); + mtls.xEnd = rsMin(mtls.dimX, sc->xEnd); + if (mtls.xStart >= mtls.xEnd) return; + } + + if (!sc || (sc->yEnd == 0)) { + mtls.yEnd = mtls.dimY; + } else { + rsAssert(sc->yStart < mtls.dimY); + rsAssert(sc->yEnd <= mtls.dimY); + rsAssert(sc->yStart < sc->yEnd); + mtls.yStart = rsMin(mtls.dimY, sc->yStart); + mtls.yEnd = rsMin(mtls.dimY, sc->yEnd); + if (mtls.yStart >= mtls.yEnd) return; + } + + mtls.xEnd = rsMax((uint32_t)1, mtls.xEnd); + mtls.yEnd = rsMax((uint32_t)1, mtls.yEnd); + mtls.zEnd = rsMax((uint32_t)1, mtls.zEnd); + mtls.arrayEnd = rsMax((uint32_t)1, mtls.arrayEnd); + + rsAssert(!ain || (ain->getType()->getDimZ() == 0)); + + Context *mrsc = (Context *)rsc; + Script * oldTLS = setTLS(s); + + mtls.rsc = mrsc; + mtls.ain = ain; + mtls.aout = aout; + mtls.script = s; + mtls.usr = usr; + mtls.mSliceSize = 10; + mtls.mSliceNum = 0; + + mtls.ptrIn = NULL; + mtls.eStrideIn = 0; + if (ain) { + mtls.ptrIn = (const uint8_t *)ain->getPtr(); + mtls.eStrideIn = ain->getType()->getElementSizeBytes(); + } + + mtls.ptrOut = NULL; + mtls.eStrideOut = 0; + if (aout) { + mtls.ptrOut = (uint8_t *)aout->getPtr(); + mtls.eStrideOut = aout->getType()->getElementSizeBytes(); + } + + if ((dc->mWorkers.mCount > 1) && s->mHal.info.isThreadable) { + if (mtls.dimY > 1) { + rsdLaunchThreads(mrsc, wc_xy, &mtls); + } else { + rsdLaunchThreads(mrsc, wc_x, &mtls); + } + + //LOGE("launch 1"); + } else { + //LOGE("launch 3"); + for (uint32_t ar = mtls.arrayStart; ar < mtls.arrayEnd; ar++) { + for (uint32_t z = mtls.zStart; z < mtls.zEnd; z++) { + for (uint32_t y = mtls.yStart; y < mtls.yEnd; y++) { + uint32_t offset = mtls.dimX * mtls.dimY * mtls.dimZ * ar + + mtls.dimX * mtls.dimY * z + + mtls.dimX * y; + uint8_t *xPtrOut = mtls.ptrOut + (mtls.eStrideOut * offset); + const uint8_t *xPtrIn = mtls.ptrIn + (mtls.eStrideIn * offset); + + for (uint32_t x = mtls.xStart; x < mtls.xEnd; x++) { + ((rs_t)s->mHal.info.root) (xPtrIn, xPtrOut, usr, x, y, z, ar); + xPtrIn += mtls.eStrideIn; + xPtrOut += mtls.eStrideOut; + } + } + } + } + } + + setTLS(oldTLS); +} + + +int rsdScriptInvokeRoot(const Context *dc, Script *script) { + DrvScript *drv = (DrvScript *)script->mHal.drv; + + Script * oldTLS = setTLS(script); + int ret = drv->mRoot(); + setTLS(oldTLS); + + return ret; +} + +void rsdScriptInvokeInit(const Context *dc, Script *script) { + DrvScript *drv = (DrvScript *)script->mHal.drv; + + if (drv->mInit) { + drv->mInit(); + } +} + + +void rsdScriptInvokeFunction(const Context *dc, Script *script, + uint32_t slot, + const void *params, + size_t paramLength) { + DrvScript *drv = (DrvScript *)script->mHal.drv; + //LOGE("invoke %p %p %i %p %i", dc, script, slot, params, paramLength); + + Script * oldTLS = setTLS(script); + ((void (*)(const void *, uint32_t)) + drv->mInvokeFunctions[slot])(params, paramLength); + setTLS(oldTLS); +} + +void rsdScriptSetGlobalVar(const Context *dc, const Script *script, + uint32_t slot, void *data, size_t dataLength) { + DrvScript *drv = (DrvScript *)script->mHal.drv; + //rsAssert(!script->mFieldIsObject[slot]); + //LOGE("setGlobalVar %p %p %i %p %i", dc, script, slot, data, dataLength); + + int32_t *destPtr = ((int32_t **)drv->mFieldAddress)[slot]; + if (!destPtr) { + //LOGV("Calling setVar on slot = %i which is null", slot); + return; + } + + memcpy(destPtr, data, dataLength); +} + +void rsdScriptSetGlobalBind(const Context *dc, const Script *script, uint32_t slot, void *data) { + DrvScript *drv = (DrvScript *)script->mHal.drv; + //rsAssert(!script->mFieldIsObject[slot]); + //LOGE("setGlobalBind %p %p %i %p", dc, script, slot, data); + + int32_t *destPtr = ((int32_t **)drv->mFieldAddress)[slot]; + if (!destPtr) { + //LOGV("Calling setVar on slot = %i which is null", slot); + return; + } + + memcpy(destPtr, &data, sizeof(void *)); +} + +void rsdScriptSetGlobalObj(const Context *dc, const Script *script, uint32_t slot, ObjectBase *data) { + DrvScript *drv = (DrvScript *)script->mHal.drv; + //rsAssert(script->mFieldIsObject[slot]); + //LOGE("setGlobalObj %p %p %i %p", dc, script, slot, data); + + int32_t *destPtr = ((int32_t **)drv->mFieldAddress)[slot]; + if (!destPtr) { + //LOGV("Calling setVar on slot = %i which is null", slot); + return; + } + + rsrSetObject(dc, script, (ObjectBase **)destPtr, data); +} + +void rsdScriptDestroy(const Context *dc, Script *script) { + DrvScript *drv = (DrvScript *)script->mHal.drv; + + if (drv->mFieldAddress) { + for (size_t ct=0; ct < drv->mFieldCount; ct++) { + if (drv->mFieldIsObject[ct]) { + // The field address can be NULL if the script-side has + // optimized the corresponding global variable away. + if (drv->mFieldAddress[ct]) { + rsrClearObject(dc, script, (ObjectBase **)drv->mFieldAddress[ct]); + } + } + } + delete [] drv->mFieldAddress; + delete [] drv->mFieldIsObject; + drv->mFieldAddress = NULL; + drv->mFieldIsObject = NULL; + drv->mFieldCount = 0; + } + + if (drv->mInvokeFunctions) { + delete [] drv->mInvokeFunctions; + drv->mInvokeFunctions = NULL; + drv->mInvokeFunctionCount = 0; + } + free(drv); + script->mHal.drv = NULL; + +} + + diff --git a/libs/rs/driver/rsdBcc.h b/libs/rs/driver/rsdBcc.h new file mode 100644 index 0000000..62b50f4 --- /dev/null +++ b/libs/rs/driver/rsdBcc.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2011 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. + */ + +#ifndef RSD_BCC_H +#define RSD_BCC_H + +#include <rs_hal.h> +#include <rsRuntime.h> + + +bool rsdScriptInit(const android::renderscript::Context *, android::renderscript::ScriptC *, + char const *resName, char const *cacheDir, + uint8_t const *bitcode, size_t bitcodeSize, uint32_t flags); +void rsdScriptInvokeFunction(const android::renderscript::Context *dc, + android::renderscript::Script *script, + uint32_t slot, + const void *params, + size_t paramLength); + +void rsdScriptInvokeForEach(const android::renderscript::Context *rsc, + android::renderscript::Script *s, + const android::renderscript::Allocation * ain, + android::renderscript::Allocation * aout, + const void * usr, + uint32_t usrLen, + const RsScriptCall *sc); + +int rsdScriptInvokeRoot(const android::renderscript::Context *dc, + android::renderscript::Script *script); +void rsdScriptInvokeInit(const android::renderscript::Context *dc, + android::renderscript::Script *script); + +void rsdScriptSetGlobalVar(const android::renderscript::Context *, + const android::renderscript::Script *, + uint32_t slot, void *data, size_t dataLen); +void rsdScriptSetGlobalBind(const android::renderscript::Context *, + const android::renderscript::Script *, + uint32_t slot, void *data); +void rsdScriptSetGlobalObj(const android::renderscript::Context *, + const android::renderscript::Script *, + uint32_t slot, android::renderscript::ObjectBase *data); + +void rsdScriptSetGlobal(const android::renderscript::Context *dc, + const android::renderscript::Script *script, + uint32_t slot, + void *data, + size_t dataLength); +void rsdScriptGetGlobal(const android::renderscript::Context *dc, + const android::renderscript::Script *script, + uint32_t slot, + void *data, + size_t dataLength); +void rsdScriptDestroy(const android::renderscript::Context *dc, + android::renderscript::Script *script); + + +#endif diff --git a/libs/rs/driver/rsdCore.cpp b/libs/rs/driver/rsdCore.cpp new file mode 100644 index 0000000..01cc369 --- /dev/null +++ b/libs/rs/driver/rsdCore.cpp @@ -0,0 +1,287 @@ +/* + * Copyright (C) 2011 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 "rsdCore.h" +#include "rsdAllocation.h" +#include "rsdBcc.h" +#include "rsdGL.h" +#include "rsdProgramStore.h" +#include "rsdProgramRaster.h" +#include "rsdProgramVertex.h" +#include "rsdProgramFragment.h" +#include "rsdMesh.h" +#include "rsdSampler.h" +#include "rsdFrameBuffer.h" + +#include <malloc.h> +#include "rsContext.h" + +#include <sys/types.h> +#include <sys/resource.h> +#include <sched.h> +#include <cutils/properties.h> +#include <cutils/sched_policy.h> +#include <sys/syscall.h> +#include <string.h> +#include <bcc/bcc.h> + +using namespace android; +using namespace android::renderscript; + +static void Shutdown(Context *rsc); +static void SetPriority(const Context *rsc, int32_t priority); + +static RsdHalFunctions FunctionTable = { + rsdGLInit, + rsdGLShutdown, + rsdGLSetSurface, + rsdGLSwap, + + Shutdown, + NULL, + SetPriority, + { + rsdScriptInit, + rsdScriptInvokeFunction, + rsdScriptInvokeRoot, + rsdScriptInvokeForEach, + rsdScriptInvokeInit, + rsdScriptSetGlobalVar, + rsdScriptSetGlobalBind, + rsdScriptSetGlobalObj, + rsdScriptDestroy + }, + + { + rsdAllocationInit, + rsdAllocationDestroy, + rsdAllocationResize, + rsdAllocationSyncAll, + rsdAllocationMarkDirty, + rsdAllocationData1D, + rsdAllocationData2D, + rsdAllocationData3D, + rsdAllocationElementData1D, + rsdAllocationElementData2D + }, + + + { + rsdProgramStoreInit, + rsdProgramStoreSetActive, + rsdProgramStoreDestroy + }, + + { + rsdProgramRasterInit, + rsdProgramRasterSetActive, + rsdProgramRasterDestroy + }, + + { + rsdProgramVertexInit, + rsdProgramVertexSetActive, + rsdProgramVertexDestroy + }, + + { + rsdProgramFragmentInit, + rsdProgramFragmentSetActive, + rsdProgramFragmentDestroy + }, + + { + rsdMeshInit, + rsdMeshDraw, + rsdMeshDestroy + }, + + { + rsdSamplerInit, + rsdSamplerDestroy + }, + + { + rsdFrameBufferInit, + rsdFrameBufferSetActive, + rsdFrameBufferDestroy + }, + +}; + +pthread_key_t rsdgThreadTLSKey = 0; +uint32_t rsdgThreadTLSKeyCount = 0; +pthread_mutex_t rsdgInitMutex = PTHREAD_MUTEX_INITIALIZER; + + +static void * HelperThreadProc(void *vrsc) { + Context *rsc = static_cast<Context *>(vrsc); + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + + + uint32_t idx = (uint32_t)android_atomic_inc(&dc->mWorkers.mLaunchCount); + + //LOGV("RS helperThread starting %p idx=%i", rsc, idx); + + dc->mWorkers.mLaunchSignals[idx].init(); + dc->mWorkers.mNativeThreadId[idx] = gettid(); + + int status = pthread_setspecific(rsdgThreadTLSKey, &dc->mTlsStruct); + if (status) { + LOGE("pthread_setspecific %i", status); + } + +#if 0 + typedef struct {uint64_t bits[1024 / 64]; } cpu_set_t; + cpu_set_t cpuset; + memset(&cpuset, 0, sizeof(cpuset)); + cpuset.bits[idx / 64] |= 1ULL << (idx % 64); + int ret = syscall(241, rsc->mWorkers.mNativeThreadId[idx], + sizeof(cpuset), &cpuset); + LOGE("SETAFFINITY ret = %i %s", ret, EGLUtils::strerror(ret)); +#endif + + while (!dc->mExit) { + dc->mWorkers.mLaunchSignals[idx].wait(); + if (dc->mWorkers.mLaunchCallback) { + dc->mWorkers.mLaunchCallback(dc->mWorkers.mLaunchData, idx); + } + android_atomic_dec(&dc->mWorkers.mRunningCount); + dc->mWorkers.mCompleteSignal.set(); + } + + //LOGV("RS helperThread exited %p idx=%i", rsc, idx); + return NULL; +} + +void rsdLaunchThreads(Context *rsc, WorkerCallback_t cbk, void *data) { + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + + dc->mWorkers.mLaunchData = data; + dc->mWorkers.mLaunchCallback = cbk; + android_atomic_release_store(dc->mWorkers.mCount, &dc->mWorkers.mRunningCount); + for (uint32_t ct = 0; ct < dc->mWorkers.mCount; ct++) { + dc->mWorkers.mLaunchSignals[ct].set(); + } + while (android_atomic_acquire_load(&dc->mWorkers.mRunningCount) != 0) { + dc->mWorkers.mCompleteSignal.wait(); + } +} + +bool rsdHalInit(Context *rsc, uint32_t version_major, uint32_t version_minor) { + rsc->mHal.funcs = FunctionTable; + + RsdHal *dc = (RsdHal *)calloc(1, sizeof(RsdHal)); + if (!dc) { + LOGE("Calloc for driver hal failed."); + return false; + } + rsc->mHal.drv = dc; + + pthread_mutex_lock(&rsdgInitMutex); + if (!rsdgThreadTLSKeyCount) { + int status = pthread_key_create(&rsdgThreadTLSKey, NULL); + if (status) { + LOGE("Failed to init thread tls key."); + pthread_mutex_unlock(&rsdgInitMutex); + return false; + } + } + rsdgThreadTLSKeyCount++; + pthread_mutex_unlock(&rsdgInitMutex); + + dc->mTlsStruct.mContext = rsc; + dc->mTlsStruct.mScript = NULL; + int status = pthread_setspecific(rsdgThreadTLSKey, &dc->mTlsStruct); + if (status) { + LOGE("pthread_setspecific %i", status); + } + + + int cpu = sysconf(_SC_NPROCESSORS_ONLN); + LOGV("RS Launching thread(s), reported CPU count %i", cpu); + if (cpu < 2) cpu = 0; + + dc->mWorkers.mCount = (uint32_t)cpu; + dc->mWorkers.mThreadId = (pthread_t *) calloc(dc->mWorkers.mCount, sizeof(pthread_t)); + dc->mWorkers.mNativeThreadId = (pid_t *) calloc(dc->mWorkers.mCount, sizeof(pid_t)); + dc->mWorkers.mLaunchSignals = new Signal[dc->mWorkers.mCount]; + dc->mWorkers.mLaunchCallback = NULL; + + dc->mWorkers.mCompleteSignal.init(); + + android_atomic_release_store(dc->mWorkers.mCount, &dc->mWorkers.mRunningCount); + android_atomic_release_store(0, &dc->mWorkers.mLaunchCount); + + pthread_attr_t threadAttr; + status = pthread_attr_init(&threadAttr); + if (status) { + LOGE("Failed to init thread attribute."); + return false; + } + + for (uint32_t ct=0; ct < dc->mWorkers.mCount; ct++) { + status = pthread_create(&dc->mWorkers.mThreadId[ct], &threadAttr, HelperThreadProc, rsc); + if (status) { + dc->mWorkers.mCount = ct; + LOGE("Created fewer than expected number of RS threads."); + break; + } + } + while (android_atomic_acquire_load(&dc->mWorkers.mRunningCount) != 0) { + usleep(100); + } + + pthread_attr_destroy(&threadAttr); + return true; +} + + +void SetPriority(const Context *rsc, int32_t priority) { + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + for (uint32_t ct=0; ct < dc->mWorkers.mCount; ct++) { + setpriority(PRIO_PROCESS, dc->mWorkers.mNativeThreadId[ct], priority); + } +} + +void Shutdown(Context *rsc) { + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + + dc->mExit = true; + dc->mWorkers.mLaunchData = NULL; + dc->mWorkers.mLaunchCallback = NULL; + android_atomic_release_store(dc->mWorkers.mCount, &dc->mWorkers.mRunningCount); + for (uint32_t ct = 0; ct < dc->mWorkers.mCount; ct++) { + dc->mWorkers.mLaunchSignals[ct].set(); + } + int status; + void *res; + for (uint32_t ct = 0; ct < dc->mWorkers.mCount; ct++) { + status = pthread_join(dc->mWorkers.mThreadId[ct], &res); + } + rsAssert(android_atomic_acquire_load(&dc->mWorkers.mRunningCount) == 0); + + // Global structure cleanup. + pthread_mutex_lock(&rsdgInitMutex); + --rsdgThreadTLSKeyCount; + if (!rsdgThreadTLSKeyCount) { + pthread_key_delete(rsdgThreadTLSKey); + } + pthread_mutex_unlock(&rsdgInitMutex); + +} + + diff --git a/libs/rs/driver/rsdCore.h b/libs/rs/driver/rsdCore.h new file mode 100644 index 0000000..f393b60 --- /dev/null +++ b/libs/rs/driver/rsdCore.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2011 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. + */ + +#ifndef RSD_CORE_H +#define RSD_CORE_H + +#include <rs_hal.h> + +#include "rsMutex.h" +#include "rsSignal.h" + +#include "rsdGL.h" + +typedef void (* InvokeFunc_t)(void); +typedef void (*WorkerCallback_t)(void *usr, uint32_t idx); + +typedef struct RsdSymbolTableRec { + const char * mName; + void * mPtr; + bool threadable; +} RsdSymbolTable; + +typedef struct ScriptTLSStructRec { + android::renderscript::Context * mContext; + android::renderscript::Script * mScript; +} ScriptTLSStruct; + +typedef struct RsdHalRec { + uint32_t version_major; + uint32_t version_minor; + + struct Workers { + volatile int mRunningCount; + volatile int mLaunchCount; + uint32_t mCount; + pthread_t *mThreadId; + pid_t *mNativeThreadId; + android::renderscript::Signal mCompleteSignal; + + android::renderscript::Signal *mLaunchSignals; + WorkerCallback_t mLaunchCallback; + void *mLaunchData; + }; + Workers mWorkers; + bool mExit; + + ScriptTLSStruct mTlsStruct; + + RsdGL gl; +} RsdHal; + +extern pthread_key_t rsdgThreadTLSKey; +extern uint32_t rsdgThreadTLSKeyCount; +extern pthread_mutex_t rsdgInitMutex; + + +void rsdLaunchThreads(android::renderscript::Context *rsc, WorkerCallback_t cbk, void *data); + +#endif + diff --git a/libs/rs/driver/rsdFrameBuffer.cpp b/libs/rs/driver/rsdFrameBuffer.cpp new file mode 100644 index 0000000..ce72b5d --- /dev/null +++ b/libs/rs/driver/rsdFrameBuffer.cpp @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2011 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 "rsdCore.h" +#include "rsdFrameBuffer.h" +#include "rsdAllocation.h" + +#include "rsContext.h" +#include "rsFBOCache.h" + +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +using namespace android; +using namespace android::renderscript; + +struct DrvFrameBuffer { + GLuint mFBOId; +}; + +void checkError(const Context *rsc) { + GLenum status; + status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + switch (status) { + case GL_FRAMEBUFFER_COMPLETE: + break; + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: + rsc->setError(RS_ERROR_BAD_VALUE, + "Unable to set up render Target: RFRAMEBUFFER_INCOMPLETE_ATTACHMENT"); + break; + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: + rsc->setError(RS_ERROR_BAD_VALUE, + "Unable to set up render Target: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"); + break; + case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: + rsc->setError(RS_ERROR_BAD_VALUE, + "Unable to set up render Target: GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS"); + break; + case GL_FRAMEBUFFER_UNSUPPORTED: + rsc->setError(RS_ERROR_BAD_VALUE, + "Unable to set up render Target: GL_FRAMEBUFFER_UNSUPPORTED"); + break; + } +} + + +void setDepthAttachment(const Context *rsc, const FBOCache *fb) { + if (fb->mHal.state.depthTarget.get() != NULL) { + DrvAllocation *drv = (DrvAllocation *)fb->mHal.state.depthTarget->mHal.drv; + + if (drv->textureID) { + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_TEXTURE_2D, drv->textureID, 0); + } else { + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, drv->renderTargetID); + } + } else { + // Reset last attachment + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0); + } +} + +void setColorAttachment(const Context *rsc, const FBOCache *fb) { + // Now attach color targets + for (uint32_t i = 0; i < fb->mHal.state.colorTargetsCount; i ++) { + uint32_t texID = 0; + if (fb->mHal.state.colorTargets[i].get() != NULL) { + DrvAllocation *drv = (DrvAllocation *)fb->mHal.state.colorTargets[i]->mHal.drv; + + if (drv->textureID) { + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, + GL_TEXTURE_2D, drv->textureID, 0); + } else { + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, + GL_RENDERBUFFER, drv->renderTargetID); + } + } else { + // Reset last attachment + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, + GL_RENDERBUFFER, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, + GL_TEXTURE_2D, 0, 0); + } + } +} + +bool renderToFramebuffer(const FBOCache *fb) { + if (fb->mHal.state.depthTarget.get() != NULL) { + return false; + } + + for (uint32_t i = 0; i < fb->mHal.state.colorTargetsCount; i ++) { + if (fb->mHal.state.colorTargets[i].get() != NULL) { + return false; + } + } + return true; +} + + +bool rsdFrameBufferInit(const Context *rsc, const FBOCache *fb) { + DrvFrameBuffer *drv = (DrvFrameBuffer *)calloc(1, sizeof(DrvFrameBuffer)); + if (drv == NULL) { + return false; + } + fb->mHal.drv = drv; + drv->mFBOId = 0; + + return true; +} + +void rsdFrameBufferSetActive(const Context *rsc, const FBOCache *fb) { + DrvFrameBuffer *drv = (DrvFrameBuffer *)fb->mHal.drv; + + bool framebuffer = renderToFramebuffer(fb); + if (!framebuffer) { + if(drv->mFBOId == 0) { + glGenFramebuffers(1, &drv->mFBOId); + } + glBindFramebuffer(GL_FRAMEBUFFER, drv->mFBOId); + + setDepthAttachment(rsc, fb); + setColorAttachment(rsc, fb); + + glViewport(0, 0, fb->mHal.state.colorTargets[0]->getType()->getDimX(), + fb->mHal.state.colorTargets[0]->getType()->getDimY()); + + checkError(rsc); + } else { + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glViewport(0, 0, rsc->getWidth(), rsc->getHeight()); + } +} + +void rsdFrameBufferDestroy(const Context *rsc, const FBOCache *fb) { + DrvFrameBuffer *drv = (DrvFrameBuffer *)fb->mHal.drv; + if(drv->mFBOId != 0) { + glDeleteFramebuffers(1, &drv->mFBOId); + } + + free(fb->mHal.drv); + fb->mHal.drv = NULL; +} + + diff --git a/libs/rs/driver/rsdFrameBuffer.h b/libs/rs/driver/rsdFrameBuffer.h new file mode 100644 index 0000000..dec59fc --- /dev/null +++ b/libs/rs/driver/rsdFrameBuffer.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2011 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. + */ + +#ifndef RSD_FRAME_BUFFER_H +#define RSD_FRAME_BUFFER_H + +#include <rs_hal.h> + +bool rsdFrameBufferInit(const android::renderscript::Context *rsc, + const android::renderscript::FBOCache *fb); +void rsdFrameBufferSetActive(const android::renderscript::Context *rsc, + const android::renderscript::FBOCache *fb); +void rsdFrameBufferDestroy(const android::renderscript::Context *rsc, + const android::renderscript::FBOCache *fb); + + +#endif // RSD_FRAME_BUFFER_H diff --git a/libs/rs/driver/rsdGL.cpp b/libs/rs/driver/rsdGL.cpp new file mode 100644 index 0000000..a70589b --- /dev/null +++ b/libs/rs/driver/rsdGL.cpp @@ -0,0 +1,369 @@ +/* + * Copyright (C) 2011 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 <ui/FramebufferNativeWindow.h> +#include <ui/PixelFormat.h> +#include <ui/EGLUtils.h> +#include <ui/egl/android_natives.h> + +#include <sys/types.h> +#include <sys/resource.h> +#include <sched.h> + +#include <cutils/properties.h> + +#include <GLES/gl.h> +#include <GLES/glext.h> +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +#include <string.h> + +#include "rsdCore.h" +#include "rsdGL.h" + +#include <malloc.h> +#include "rsContext.h" +#include "rsdShaderCache.h" +#include "rsdVertexArray.h" + +using namespace android; +using namespace android::renderscript; + +static int32_t gGLContextCount = 0; + +static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) { + if (returnVal != EGL_TRUE) { + fprintf(stderr, "%s() returned %d\n", op, returnVal); + } + + for (EGLint error = eglGetError(); error != EGL_SUCCESS; error + = eglGetError()) { + fprintf(stderr, "after %s() eglError %s (0x%x)\n", op, EGLUtils::strerror(error), + error); + } +} + +static void printEGLConfiguration(EGLDisplay dpy, EGLConfig config) { + +#define X(VAL) {VAL, #VAL} + struct {EGLint attribute; const char* name;} names[] = { + X(EGL_BUFFER_SIZE), + X(EGL_ALPHA_SIZE), + X(EGL_BLUE_SIZE), + X(EGL_GREEN_SIZE), + X(EGL_RED_SIZE), + X(EGL_DEPTH_SIZE), + X(EGL_STENCIL_SIZE), + X(EGL_CONFIG_CAVEAT), + X(EGL_CONFIG_ID), + X(EGL_LEVEL), + X(EGL_MAX_PBUFFER_HEIGHT), + X(EGL_MAX_PBUFFER_PIXELS), + X(EGL_MAX_PBUFFER_WIDTH), + X(EGL_NATIVE_RENDERABLE), + X(EGL_NATIVE_VISUAL_ID), + X(EGL_NATIVE_VISUAL_TYPE), + X(EGL_SAMPLES), + X(EGL_SAMPLE_BUFFERS), + X(EGL_SURFACE_TYPE), + X(EGL_TRANSPARENT_TYPE), + X(EGL_TRANSPARENT_RED_VALUE), + X(EGL_TRANSPARENT_GREEN_VALUE), + X(EGL_TRANSPARENT_BLUE_VALUE), + X(EGL_BIND_TO_TEXTURE_RGB), + X(EGL_BIND_TO_TEXTURE_RGBA), + X(EGL_MIN_SWAP_INTERVAL), + X(EGL_MAX_SWAP_INTERVAL), + X(EGL_LUMINANCE_SIZE), + X(EGL_ALPHA_MASK_SIZE), + X(EGL_COLOR_BUFFER_TYPE), + X(EGL_RENDERABLE_TYPE), + X(EGL_CONFORMANT), + }; +#undef X + + for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) { + EGLint value = -1; + EGLint returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value); + EGLint error = eglGetError(); + if (returnVal && error == EGL_SUCCESS) { + LOGV(" %s: %d (0x%x)", names[j].name, value, value); + } + } +} + +static void DumpDebug(RsdHal *dc) { + LOGE(" EGL ver %i %i", dc->gl.egl.majorVersion, dc->gl.egl.minorVersion); + LOGE(" EGL context %p surface %p, Display=%p", dc->gl.egl.context, dc->gl.egl.surface, + dc->gl.egl.display); + LOGE(" GL vendor: %s", dc->gl.gl.vendor); + LOGE(" GL renderer: %s", dc->gl.gl.renderer); + LOGE(" GL Version: %s", dc->gl.gl.version); + LOGE(" GL Extensions: %s", dc->gl.gl.extensions); + LOGE(" GL int Versions %i %i", dc->gl.gl.majorVersion, dc->gl.gl.minorVersion); + + LOGV("MAX Textures %i, %i %i", dc->gl.gl.maxVertexTextureUnits, + dc->gl.gl.maxFragmentTextureImageUnits, dc->gl.gl.maxTextureImageUnits); + LOGV("MAX Attribs %i", dc->gl.gl.maxVertexAttribs); + LOGV("MAX Uniforms %i, %i", dc->gl.gl.maxVertexUniformVectors, + dc->gl.gl.maxFragmentUniformVectors); + LOGV("MAX Varyings %i", dc->gl.gl.maxVaryingVectors); +} + +void rsdGLShutdown(const Context *rsc) { + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + + dc->gl.shaderCache->cleanupAll(); + delete dc->gl.shaderCache; + + delete dc->gl.vertexArrayState; + + LOGV("%p, deinitEGL", rsc); + + if (dc->gl.egl.context != EGL_NO_CONTEXT) { + eglMakeCurrent(dc->gl.egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroySurface(dc->gl.egl.display, dc->gl.egl.surfaceDefault); + if (dc->gl.egl.surface != EGL_NO_SURFACE) { + eglDestroySurface(dc->gl.egl.display, dc->gl.egl.surface); + } + eglDestroyContext(dc->gl.egl.display, dc->gl.egl.context); + checkEglError("eglDestroyContext"); + } + + gGLContextCount--; + if (!gGLContextCount) { + eglTerminate(dc->gl.egl.display); + } +} + +bool rsdGLInit(const Context *rsc) { + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + + dc->gl.egl.numConfigs = -1; + EGLint configAttribs[128]; + EGLint *configAttribsPtr = configAttribs; + EGLint context_attribs2[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; + + memset(configAttribs, 0, sizeof(configAttribs)); + + configAttribsPtr[0] = EGL_SURFACE_TYPE; + configAttribsPtr[1] = EGL_WINDOW_BIT; + configAttribsPtr += 2; + + configAttribsPtr[0] = EGL_RENDERABLE_TYPE; + configAttribsPtr[1] = EGL_OPENGL_ES2_BIT; + configAttribsPtr += 2; + + if (rsc->mUserSurfaceConfig.depthMin > 0) { + configAttribsPtr[0] = EGL_DEPTH_SIZE; + configAttribsPtr[1] = rsc->mUserSurfaceConfig.depthMin; + configAttribsPtr += 2; + } + + if (rsc->mDev->mForceSW) { + configAttribsPtr[0] = EGL_CONFIG_CAVEAT; + configAttribsPtr[1] = EGL_SLOW_CONFIG; + configAttribsPtr += 2; + } + + configAttribsPtr[0] = EGL_NONE; + rsAssert(configAttribsPtr < (configAttribs + (sizeof(configAttribs) / sizeof(EGLint)))); + + LOGV("%p initEGL start", rsc); + dc->gl.egl.display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + checkEglError("eglGetDisplay"); + + eglInitialize(dc->gl.egl.display, &dc->gl.egl.majorVersion, &dc->gl.egl.minorVersion); + checkEglError("eglInitialize"); + + PixelFormat pf = PIXEL_FORMAT_RGBA_8888; + if (rsc->mUserSurfaceConfig.alphaMin == 0) { + pf = PIXEL_FORMAT_RGBX_8888; + } + + status_t err = EGLUtils::selectConfigForPixelFormat(dc->gl.egl.display, configAttribs, + pf, &dc->gl.egl.config); + if (err) { + LOGE("%p, couldn't find an EGLConfig matching the screen format\n", rsc); + } + //if (props.mLogVisual) { + if (0) { + printEGLConfiguration(dc->gl.egl.display, dc->gl.egl.config); + } + //} + + dc->gl.egl.context = eglCreateContext(dc->gl.egl.display, dc->gl.egl.config, + EGL_NO_CONTEXT, context_attribs2); + checkEglError("eglCreateContext"); + if (dc->gl.egl.context == EGL_NO_CONTEXT) { + LOGE("%p, eglCreateContext returned EGL_NO_CONTEXT", rsc); + return false; + } + gGLContextCount++; + + + EGLint pbuffer_attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE }; + dc->gl.egl.surfaceDefault = eglCreatePbufferSurface(dc->gl.egl.display, dc->gl.egl.config, + pbuffer_attribs); + checkEglError("eglCreatePbufferSurface"); + if (dc->gl.egl.surfaceDefault == EGL_NO_SURFACE) { + LOGE("eglCreatePbufferSurface returned EGL_NO_SURFACE"); + rsdGLShutdown(rsc); + return false; + } + + EGLBoolean ret = eglMakeCurrent(dc->gl.egl.display, dc->gl.egl.surfaceDefault, + dc->gl.egl.surfaceDefault, dc->gl.egl.context); + if (ret == EGL_FALSE) { + LOGE("eglMakeCurrent returned EGL_FALSE"); + checkEglError("eglMakeCurrent", ret); + rsdGLShutdown(rsc); + return false; + } + + dc->gl.gl.version = glGetString(GL_VERSION); + dc->gl.gl.vendor = glGetString(GL_VENDOR); + dc->gl.gl.renderer = glGetString(GL_RENDERER); + dc->gl.gl.extensions = glGetString(GL_EXTENSIONS); + + //LOGV("EGL Version %i %i", mEGL.mMajorVersion, mEGL.mMinorVersion); + //LOGV("GL Version %s", mGL.mVersion); + //LOGV("GL Vendor %s", mGL.mVendor); + //LOGV("GL Renderer %s", mGL.mRenderer); + //LOGV("GL Extensions %s", mGL.mExtensions); + + const char *verptr = NULL; + if (strlen((const char *)dc->gl.gl.version) > 9) { + if (!memcmp(dc->gl.gl.version, "OpenGL ES-CM", 12)) { + verptr = (const char *)dc->gl.gl.version + 12; + } + if (!memcmp(dc->gl.gl.version, "OpenGL ES ", 10)) { + verptr = (const char *)dc->gl.gl.version + 9; + } + } + + if (!verptr) { + LOGE("Error, OpenGL ES Lite not supported"); + rsdGLShutdown(rsc); + return false; + } else { + sscanf(verptr, " %i.%i", &dc->gl.gl.majorVersion, &dc->gl.gl.minorVersion); + } + + glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &dc->gl.gl.maxVertexAttribs); + glGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, &dc->gl.gl.maxVertexUniformVectors); + glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &dc->gl.gl.maxVertexTextureUnits); + + glGetIntegerv(GL_MAX_VARYING_VECTORS, &dc->gl.gl.maxVaryingVectors); + glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &dc->gl.gl.maxTextureImageUnits); + + glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &dc->gl.gl.maxFragmentTextureImageUnits); + glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, &dc->gl.gl.maxFragmentUniformVectors); + + dc->gl.gl.OES_texture_npot = NULL != strstr((const char *)dc->gl.gl.extensions, + "GL_OES_texture_npot"); + dc->gl.gl.GL_IMG_texture_npot = NULL != strstr((const char *)dc->gl.gl.extensions, + "GL_IMG_texture_npot"); + dc->gl.gl.GL_NV_texture_npot_2D_mipmap = NULL != strstr((const char *)dc->gl.gl.extensions, + "GL_NV_texture_npot_2D_mipmap"); + dc->gl.gl.EXT_texture_max_aniso = 1.0f; + bool hasAniso = NULL != strstr((const char *)dc->gl.gl.extensions, + "GL_EXT_texture_filter_anisotropic"); + if (hasAniso) { + glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &dc->gl.gl.EXT_texture_max_aniso); + } + + if (0) { + DumpDebug(dc); + } + + dc->gl.shaderCache = new RsdShaderCache(); + dc->gl.vertexArrayState = new RsdVertexArrayState(); + dc->gl.vertexArrayState->init(dc->gl.gl.maxVertexAttribs); + + LOGV("initGLThread end %p", rsc); + return true; +} + + +bool rsdGLSetSurface(const Context *rsc, uint32_t w, uint32_t h, RsNativeWindow sur) { + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + + EGLBoolean ret; + // WAR: Some drivers fail to handle 0 size surfaces correcntly. + // Use the pbuffer to avoid this pitfall. + if ((dc->gl.egl.surface != NULL) || (w == 0) || (h == 0)) { + ret = eglMakeCurrent(dc->gl.egl.display, dc->gl.egl.surfaceDefault, + dc->gl.egl.surfaceDefault, dc->gl.egl.context); + checkEglError("eglMakeCurrent", ret); + + ret = eglDestroySurface(dc->gl.egl.display, dc->gl.egl.surface); + checkEglError("eglDestroySurface", ret); + + dc->gl.egl.surface = NULL; + dc->gl.width = 1; + dc->gl.height = 1; + } + + dc->gl.wndSurface = (ANativeWindow *)sur; + if (dc->gl.wndSurface != NULL) { + dc->gl.width = w; + dc->gl.height = h; + + dc->gl.egl.surface = eglCreateWindowSurface(dc->gl.egl.display, dc->gl.egl.config, + dc->gl.wndSurface, NULL); + checkEglError("eglCreateWindowSurface"); + if (dc->gl.egl.surface == EGL_NO_SURFACE) { + LOGE("eglCreateWindowSurface returned EGL_NO_SURFACE"); + } + + ret = eglMakeCurrent(dc->gl.egl.display, dc->gl.egl.surface, + dc->gl.egl.surface, dc->gl.egl.context); + checkEglError("eglMakeCurrent", ret); + } + return true; +} + +void rsdGLSwap(const android::renderscript::Context *rsc) { + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + eglSwapBuffers(dc->gl.egl.display, dc->gl.egl.surface); +} + +void rsdGLCheckError(const android::renderscript::Context *rsc, + const char *msg, bool isFatal) { + GLenum err = glGetError(); + if (err != GL_NO_ERROR) { + char buf[1024]; + snprintf(buf, sizeof(buf), "GL Error = 0x%08x, from: %s", err, msg); + + if (isFatal) { + rsc->setError(RS_ERROR_FATAL_DRIVER, buf); + } else { + switch (err) { + case GL_OUT_OF_MEMORY: + rsc->setError(RS_ERROR_OUT_OF_MEMORY, buf); + break; + default: + rsc->setError(RS_ERROR_DRIVER, buf); + break; + } + } + + LOGE("%p, %s", rsc, buf); + } + +} diff --git a/libs/rs/driver/rsdGL.h b/libs/rs/driver/rsdGL.h new file mode 100644 index 0000000..01c8438 --- /dev/null +++ b/libs/rs/driver/rsdGL.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2011 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. + */ + +#ifndef RSD_GL_H +#define RSD_GL_H + +#include <rs_hal.h> +#include <EGL/egl.h> + +class RsdShaderCache; +class RsdVertexArrayState; + +typedef void (* InvokeFunc_t)(void); +typedef void (*WorkerCallback_t)(void *usr, uint32_t idx); + +typedef struct RsdGLRec { + struct { + EGLint numConfigs; + EGLint majorVersion; + EGLint minorVersion; + EGLConfig config; + EGLContext context; + EGLSurface surface; + EGLSurface surfaceDefault; + EGLDisplay display; + } egl; + + struct { + const uint8_t * vendor; + const uint8_t * renderer; + const uint8_t * version; + const uint8_t * extensions; + + uint32_t majorVersion; + uint32_t minorVersion; + + int32_t maxVaryingVectors; + int32_t maxTextureImageUnits; + + int32_t maxFragmentTextureImageUnits; + int32_t maxFragmentUniformVectors; + + int32_t maxVertexAttribs; + int32_t maxVertexUniformVectors; + int32_t maxVertexTextureUnits; + + bool OES_texture_npot; + bool GL_IMG_texture_npot; + bool GL_NV_texture_npot_2D_mipmap; + float EXT_texture_max_aniso; + } gl; + + ANativeWindow *wndSurface; + uint32_t width; + uint32_t height; + RsdShaderCache *shaderCache; + RsdVertexArrayState *vertexArrayState; +} RsdGL; + + + +bool rsdGLInit(const android::renderscript::Context *rsc); +void rsdGLShutdown(const android::renderscript::Context *rsc); +bool rsdGLSetSurface(const android::renderscript::Context *rsc, + uint32_t w, uint32_t h, RsNativeWindow sur); +void rsdGLSwap(const android::renderscript::Context *rsc); +void rsdGLCheckError(const android::renderscript::Context *rsc, + const char *msg, bool isFatal = false); + +#endif + diff --git a/libs/rs/driver/rsdMesh.cpp b/libs/rs/driver/rsdMesh.cpp new file mode 100644 index 0000000..eb62ddb --- /dev/null +++ b/libs/rs/driver/rsdMesh.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2011 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 <rs_hal.h> +#include <rsContext.h> +#include <rsMesh.h> + +#include "rsdCore.h" +#include "rsdMesh.h" +#include "rsdMeshObj.h" +#include "rsdShaderCache.h" + +using namespace android; +using namespace android::renderscript; + +bool rsdMeshInit(const Context *rsc, const Mesh *m) { + RsdMeshObj *drv = NULL; + if(m->mHal.drv) { + drv = (RsdMeshObj*)m->mHal.drv; + delete drv; + } + drv = new RsdMeshObj(rsc, m); + m->mHal.drv = drv; + return drv->init(); +} + +void rsdMeshDraw(const Context *rsc, const Mesh *m, uint32_t primIndex, uint32_t start, uint32_t len) { + if(m->mHal.drv) { + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + if (!dc->gl.shaderCache->setup(rsc)) { + return; + } + + RsdMeshObj *drv = (RsdMeshObj*)m->mHal.drv; + drv->renderPrimitiveRange(rsc, primIndex, start, len); + } +} + +void rsdMeshDestroy(const Context *rsc, const Mesh *m) { + if(m->mHal.drv) { + RsdMeshObj *drv = (RsdMeshObj*)m->mHal.drv; + delete drv; + } +} + + diff --git a/libs/rs/driver/rsdMesh.h b/libs/rs/driver/rsdMesh.h new file mode 100644 index 0000000..d2714fd --- /dev/null +++ b/libs/rs/driver/rsdMesh.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2011 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. + */ + +#ifndef RSD_MESH_H +#define RSD_MESH_H + +#include <rs_hal.h> + + +bool rsdMeshInit(const android::renderscript::Context *rsc, + const android::renderscript::Mesh *m); +void rsdMeshDraw(const android::renderscript::Context *rsc, + const android::renderscript::Mesh *m, + uint32_t primIndex, uint32_t start, uint32_t len); +void rsdMeshDestroy(const android::renderscript::Context *rsc, + const android::renderscript::Mesh *m); + + +#endif diff --git a/libs/rs/driver/rsdMeshObj.cpp b/libs/rs/driver/rsdMeshObj.cpp new file mode 100644 index 0000000..c220ac1 --- /dev/null +++ b/libs/rs/driver/rsdMeshObj.cpp @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2011 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 <GLES/gl.h> +#include <GLES2/gl2.h> +#include <GLES/glext.h> + +#include <rs_hal.h> +#include <rsContext.h> +#include <rsMesh.h> + +#include "rsdAllocation.h" +#include "rsdMeshObj.h" +#include "rsdGL.h" + +using namespace android; +using namespace android::renderscript; + +RsdMeshObj::RsdMeshObj(const Context *rsc, const Mesh *rsMesh) { + mRSMesh = rsMesh; + + mAttribs = NULL; + mAttribAllocationIndex = NULL; + mGLPrimitives = NULL; + + mAttribCount = 0; +} + +RsdMeshObj::~RsdMeshObj() { + if (mAttribs) { + delete[] mAttribs; + delete[] mAttribAllocationIndex; + } + if (mGLPrimitives) { + delete[] mGLPrimitives; + } +} + +bool RsdMeshObj::isValidGLComponent(const Element *elem, uint32_t fieldIdx) { + // Do not create attribs for padding + if (elem->getFieldName(fieldIdx)[0] == '#') { + return false; + } + + // Only GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_FIXED, GL_FLOAT are accepted. + // Filter rs types accordingly + RsDataType dt = elem->getField(fieldIdx)->getComponent().getType(); + if (dt != RS_TYPE_FLOAT_32 && dt != RS_TYPE_UNSIGNED_8 && + dt != RS_TYPE_UNSIGNED_16 && dt != RS_TYPE_SIGNED_8 && + dt != RS_TYPE_SIGNED_16) { + return false; + } + + // Now make sure they are not arrays + uint32_t arraySize = elem->getFieldArraySize(fieldIdx); + if (arraySize != 1) { + return false; + } + + return true; +} + +bool RsdMeshObj::init() { + + updateGLPrimitives(); + + // Count the number of gl attrs to initialize + mAttribCount = 0; + for (uint32_t ct=0; ct < mRSMesh->mHal.state.vertexBuffersCount; ct++) { + const Element *elem = mRSMesh->mHal.state.vertexBuffers[ct]->getType()->getElement(); + for (uint32_t ct=0; ct < elem->getFieldCount(); ct++) { + if (isValidGLComponent(elem, ct)) { + mAttribCount ++; + } + } + } + + if (mAttribs) { + delete [] mAttribs; + delete [] mAttribAllocationIndex; + mAttribs = NULL; + mAttribAllocationIndex = NULL; + } + if (!mAttribCount) { + return false; + } + + mAttribs = new RsdVertexArray::Attrib[mAttribCount]; + mAttribAllocationIndex = new uint32_t[mAttribCount]; + + uint32_t userNum = 0; + for (uint32_t ct=0; ct < mRSMesh->mHal.state.vertexBuffersCount; ct++) { + const Element *elem = mRSMesh->mHal.state.vertexBuffers[ct]->getType()->getElement(); + uint32_t stride = elem->getSizeBytes(); + for (uint32_t fieldI=0; fieldI < elem->getFieldCount(); fieldI++) { + const Component &c = elem->getField(fieldI)->getComponent(); + + if (!isValidGLComponent(elem, fieldI)) { + continue; + } + + mAttribs[userNum].size = c.getVectorSize(); + mAttribs[userNum].offset = elem->getFieldOffsetBytes(fieldI); + mAttribs[userNum].type = rsdTypeToGLType(c.getType()); + mAttribs[userNum].normalized = c.getType() != RS_TYPE_FLOAT_32;//c.getIsNormalized(); + mAttribs[userNum].stride = stride; + String8 tmp(RS_SHADER_ATTR); + tmp.append(elem->getFieldName(fieldI)); + mAttribs[userNum].name.setTo(tmp.string()); + + // Remember which allocation this attribute came from + mAttribAllocationIndex[userNum] = ct; + userNum ++; + } + } + + return true; +} + +void RsdMeshObj::renderPrimitiveRange(const Context *rsc, uint32_t primIndex, uint32_t start, uint32_t len) const { + if (len < 1 || primIndex >= mRSMesh->mHal.state.primitivesCount || mAttribCount == 0) { + LOGE("Invalid mesh or parameters"); + return; + } + + for (uint32_t ct=0; ct < mRSMesh->mHal.state.vertexBuffersCount; ct++) { + const Allocation *alloc = mRSMesh->mHal.state.vertexBuffers[ct].get(); + rsdAllocationSyncAll(rsc, alloc, RS_ALLOCATION_USAGE_SCRIPT); + } + + // update attributes with either buffer information or data ptr based on their current state + for (uint32_t ct=0; ct < mAttribCount; ct++) { + uint32_t allocIndex = mAttribAllocationIndex[ct]; + Allocation *alloc = mRSMesh->mHal.state.vertexBuffers[allocIndex].get(); + DrvAllocation *drvAlloc = (DrvAllocation *)alloc->mHal.drv; + + if (drvAlloc->bufferID) { + mAttribs[ct].buffer = drvAlloc->bufferID; + mAttribs[ct].ptr = NULL; + } else { + mAttribs[ct].buffer = 0; + mAttribs[ct].ptr = (const uint8_t*)drvAlloc->mallocPtr; + } + } + + RsdVertexArray va(mAttribs, mAttribCount); + va.setup(rsc); + + Mesh::Primitive_t *prim = mRSMesh->mHal.state.primitives[primIndex]; + const Allocation *idxAlloc = prim->mIndexBuffer.get(); + if (idxAlloc) { + DrvAllocation *drvAlloc = (DrvAllocation *)idxAlloc->mHal.drv; + rsdAllocationSyncAll(rsc, idxAlloc, RS_ALLOCATION_USAGE_SCRIPT); + + if (drvAlloc->bufferID) { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, drvAlloc->bufferID); + glDrawElements(mGLPrimitives[primIndex], len, GL_UNSIGNED_SHORT, (uint16_t *)(start * 2)); + } else { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glDrawElements(mGLPrimitives[primIndex], len, GL_UNSIGNED_SHORT, drvAlloc->mallocPtr); + } + } else { + glDrawArrays(mGLPrimitives[primIndex], start, len); + } + + rsdGLCheckError(rsc, "Mesh::renderPrimitiveRange"); +} + +void RsdMeshObj::updateGLPrimitives() { + mGLPrimitives = new uint32_t[mRSMesh->mHal.state.primitivesCount]; + for (uint32_t i = 0; i < mRSMesh->mHal.state.primitivesCount; i ++) { + switch (mRSMesh->mHal.state.primitives[i]->mPrimitive) { + case RS_PRIMITIVE_POINT: mGLPrimitives[i] = GL_POINTS; break; + case RS_PRIMITIVE_LINE: mGLPrimitives[i] = GL_LINES; break; + case RS_PRIMITIVE_LINE_STRIP: mGLPrimitives[i] = GL_LINE_STRIP; break; + case RS_PRIMITIVE_TRIANGLE: mGLPrimitives[i] = GL_TRIANGLES; break; + case RS_PRIMITIVE_TRIANGLE_STRIP: mGLPrimitives[i] = GL_TRIANGLE_STRIP; break; + case RS_PRIMITIVE_TRIANGLE_FAN: mGLPrimitives[i] = GL_TRIANGLE_FAN; break; + } + } +} diff --git a/libs/rs/driver/rsdMeshObj.h b/libs/rs/driver/rsdMeshObj.h new file mode 100644 index 0000000..8b1271b --- /dev/null +++ b/libs/rs/driver/rsdMeshObj.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2011 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. + */ + +#ifndef ANDROID_RSD_MESH_OBJ_H +#define ANDROID_RSD_MESH_OBJ_H + +// --------------------------------------------------------------------------- +namespace android { +namespace renderscript { + + class Context; + class Mesh; + class Element; + +} +} + +#include "driver/rsdVertexArray.h" + +// An element is a group of Components that occupies one cell in a structure. +class RsdMeshObj { +public: + RsdMeshObj(const android::renderscript::Context *, + const android::renderscript::Mesh *); + ~RsdMeshObj(); + + void renderPrimitiveRange(const android::renderscript::Context *, uint32_t primIndex, uint32_t start, uint32_t len) const; + + bool init(); + +protected: + const android::renderscript::Mesh *mRSMesh; + + uint32_t *mGLPrimitives; + void updateGLPrimitives(); + + bool isValidGLComponent(const android::renderscript::Element *elem, uint32_t fieldIdx); + // Attribues that allow us to map to GL + RsdVertexArray::Attrib *mAttribs; + // This allows us to figure out which allocation the attribute + // belongs to. In the event the allocation is uploaded to GL + // buffer, it lets us properly map it + uint32_t *mAttribAllocationIndex; + uint32_t mAttribCount; +}; + +#endif //ANDROID_RSD_MESH_OBJ_H + + + diff --git a/libs/rs/driver/rsdProgram.cpp b/libs/rs/driver/rsdProgram.cpp new file mode 100644 index 0000000..39b3805 --- /dev/null +++ b/libs/rs/driver/rsdProgram.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2011 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 "rsdCore.h" +#include "rsdAllocation.h" +#include "rsdProgramVertex.h" +#include "rsdShader.h" +#include "rsdShaderCache.h" + +#include "rsContext.h" +#include "rsProgramVertex.h" +#include "rsProgramFragment.h" + +#include <GLES/gl.h> +#include <GLES/glext.h> +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +using namespace android; +using namespace android::renderscript; + +bool rsdProgramVertexInit(const Context *rsc, const ProgramVertex *pv, + const char* shader, uint32_t shaderLen) { + RsdShader *drv = new RsdShader(pv, GL_VERTEX_SHADER, shader, shaderLen); + pv->mHal.drv = drv; + + return drv->createShader(); +} + +static void SyncProgramConstants(const Context *rsc, const Program *p) { + for (uint32_t ct=0; ct < p->mHal.state.texturesCount; ct++) { + const Allocation *a = p->mHal.state.textures[ct].get(); + DrvAllocation *drvAlloc = (DrvAllocation *)a->mHal.drv; + if (drvAlloc->uploadDeferred) { + rsdAllocationSyncAll(rsc, a, RS_ALLOCATION_USAGE_SCRIPT); + } + } +} + +void rsdProgramVertexSetActive(const Context *rsc, const ProgramVertex *pv) { + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + + SyncProgramConstants(rsc, pv); + dc->gl.shaderCache->setActiveVertex((RsdShader*)pv->mHal.drv); +} + +void rsdProgramVertexDestroy(const Context *rsc, const ProgramVertex *pv) { + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + + RsdShader *drv = NULL; + if(pv->mHal.drv) { + drv = (RsdShader*)pv->mHal.drv; + if (rsc->props.mLogShaders) { + LOGV("Destroying vertex shader with ID %u", drv->getShaderID()); + } + if (drv->getShaderID()) { + dc->gl.shaderCache->cleanupVertex(drv->getShaderID()); + } + delete drv; + } +} + +bool rsdProgramFragmentInit(const Context *rsc, const ProgramFragment *pf, + const char* shader, uint32_t shaderLen) { + RsdShader *drv = new RsdShader(pf, GL_FRAGMENT_SHADER, shader, shaderLen); + pf->mHal.drv = drv; + + return drv->createShader(); +} + +void rsdProgramFragmentSetActive(const Context *rsc, const ProgramFragment *pf) { + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + + SyncProgramConstants(rsc, pf); + dc->gl.shaderCache->setActiveFragment((RsdShader*)pf->mHal.drv); +} + +void rsdProgramFragmentDestroy(const Context *rsc, const ProgramFragment *pf) { + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + + RsdShader *drv = NULL; + if(pf->mHal.drv) { + drv = (RsdShader*)pf->mHal.drv; + if (rsc->props.mLogShaders) { + LOGV("Destroying fragment shader with ID %u", drv->getShaderID()); + } + if (drv->getShaderID()) { + dc->gl.shaderCache->cleanupFragment(drv->getShaderID()); + } + delete drv; + } +} + + diff --git a/libs/rs/driver/rsdProgramFragment.h b/libs/rs/driver/rsdProgramFragment.h new file mode 100644 index 0000000..366cb40 --- /dev/null +++ b/libs/rs/driver/rsdProgramFragment.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2011 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. + */ + +#ifndef RSD_PROGRAM_FRAGMENT_H +#define RSD_PROGRAM_FRAGMENT_H + +#include <rs_hal.h> + + +bool rsdProgramFragmentInit(const android::renderscript::Context *rsc, + const android::renderscript::ProgramFragment *, + const char* shader, uint32_t shaderLen); +void rsdProgramFragmentSetActive(const android::renderscript::Context *rsc, + const android::renderscript::ProgramFragment *); +void rsdProgramFragmentDestroy(const android::renderscript::Context *rsc, + const android::renderscript::ProgramFragment *); + + +#endif //RSD_PROGRAM_Fragment_H diff --git a/libs/rs/driver/rsdProgramRaster.cpp b/libs/rs/driver/rsdProgramRaster.cpp new file mode 100644 index 0000000..65995be --- /dev/null +++ b/libs/rs/driver/rsdProgramRaster.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2011 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 "rsdCore.h" +#include "rsdProgramStore.h" + +#include "rsContext.h" +#include "rsProgramStore.h" + +#include <GLES/gl.h> +#include <GLES/glext.h> + + +using namespace android; +using namespace android::renderscript; + +bool rsdProgramRasterInit(const Context *, const ProgramRaster *) { + return true; +} + +void rsdProgramRasterSetActive(const Context *, const ProgramRaster *pr) { + switch (pr->mHal.state.cull) { + case RS_CULL_BACK: + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + break; + case RS_CULL_FRONT: + glEnable(GL_CULL_FACE); + glCullFace(GL_FRONT); + break; + case RS_CULL_NONE: + glDisable(GL_CULL_FACE); + break; + } + +} + +void rsdProgramRasterDestroy(const Context *, const ProgramRaster *) { +} + + diff --git a/libs/rs/driver/rsdProgramRaster.h b/libs/rs/driver/rsdProgramRaster.h new file mode 100644 index 0000000..20adaad --- /dev/null +++ b/libs/rs/driver/rsdProgramRaster.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2011 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. + */ + +#ifndef RSD_PROGRAM_RASTER_H +#define RSD_PROGRAM_RASTER_H + +#include <rs_hal.h> + + +bool rsdProgramRasterInit(const android::renderscript::Context *rsc, + const android::renderscript::ProgramRaster *); +void rsdProgramRasterSetActive(const android::renderscript::Context *rsc, + const android::renderscript::ProgramRaster *); +void rsdProgramRasterDestroy(const android::renderscript::Context *rsc, + const android::renderscript::ProgramRaster *); + + +#endif diff --git a/libs/rs/driver/rsdProgramStore.cpp b/libs/rs/driver/rsdProgramStore.cpp new file mode 100644 index 0000000..e591453 --- /dev/null +++ b/libs/rs/driver/rsdProgramStore.cpp @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2011 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 "rsdCore.h" +#include "rsdProgramStore.h" + +#include "rsContext.h" +#include "rsProgramStore.h" + +#include <GLES/gl.h> +#include <GLES/glext.h> + + +using namespace android; +using namespace android::renderscript; + +struct DrvProgramStore { + GLenum blendSrc; + GLenum blendDst; + bool blendEnable; + + GLenum depthFunc; + bool depthTestEnable; +}; + +bool rsdProgramStoreInit(const Context *rsc, const ProgramStore *ps) { + DrvProgramStore *drv = (DrvProgramStore *)calloc(1, sizeof(DrvProgramStore)); + if (drv == NULL) { + return false; + } + + ps->mHal.drv = drv; + drv->depthTestEnable = true; + + switch (ps->mHal.state.depthFunc) { + case RS_DEPTH_FUNC_ALWAYS: + drv->depthTestEnable = false; + drv->depthFunc = GL_ALWAYS; + break; + case RS_DEPTH_FUNC_LESS: + drv->depthFunc = GL_LESS; + break; + case RS_DEPTH_FUNC_LEQUAL: + drv->depthFunc = GL_LEQUAL; + break; + case RS_DEPTH_FUNC_GREATER: + drv->depthFunc = GL_GREATER; + break; + case RS_DEPTH_FUNC_GEQUAL: + drv->depthFunc = GL_GEQUAL; + break; + case RS_DEPTH_FUNC_EQUAL: + drv->depthFunc = GL_EQUAL; + break; + case RS_DEPTH_FUNC_NOTEQUAL: + drv->depthFunc = GL_NOTEQUAL; + break; + default: + LOGE("Unknown depth function."); + goto error; + } + + + + drv->blendEnable = true; + if ((ps->mHal.state.blendSrc == RS_BLEND_SRC_ONE) && + (ps->mHal.state.blendDst == RS_BLEND_DST_ZERO)) { + drv->blendEnable = false; + } + + switch (ps->mHal.state.blendSrc) { + case RS_BLEND_SRC_ZERO: + drv->blendSrc = GL_ZERO; + break; + case RS_BLEND_SRC_ONE: + drv->blendSrc = GL_ONE; + break; + case RS_BLEND_SRC_DST_COLOR: + drv->blendSrc = GL_DST_COLOR; + break; + case RS_BLEND_SRC_ONE_MINUS_DST_COLOR: + drv->blendSrc = GL_ONE_MINUS_DST_COLOR; + break; + case RS_BLEND_SRC_SRC_ALPHA: + drv->blendSrc = GL_SRC_ALPHA; + break; + case RS_BLEND_SRC_ONE_MINUS_SRC_ALPHA: + drv->blendSrc = GL_ONE_MINUS_SRC_ALPHA; + break; + case RS_BLEND_SRC_DST_ALPHA: + drv->blendSrc = GL_DST_ALPHA; + break; + case RS_BLEND_SRC_ONE_MINUS_DST_ALPHA: + drv->blendSrc = GL_ONE_MINUS_DST_ALPHA; + break; + case RS_BLEND_SRC_SRC_ALPHA_SATURATE: + drv->blendSrc = GL_SRC_ALPHA_SATURATE; + break; + default: + LOGE("Unknown blend src mode."); + goto error; + } + + switch (ps->mHal.state.blendDst) { + case RS_BLEND_DST_ZERO: + drv->blendDst = GL_ZERO; + break; + case RS_BLEND_DST_ONE: + drv->blendDst = GL_ONE; + break; + case RS_BLEND_DST_SRC_COLOR: + drv->blendDst = GL_SRC_COLOR; + break; + case RS_BLEND_DST_ONE_MINUS_SRC_COLOR: + drv->blendDst = GL_ONE_MINUS_SRC_COLOR; + break; + case RS_BLEND_DST_SRC_ALPHA: + drv->blendDst = GL_SRC_ALPHA; + break; + case RS_BLEND_DST_ONE_MINUS_SRC_ALPHA: + drv->blendDst = GL_ONE_MINUS_SRC_ALPHA; + break; + case RS_BLEND_DST_DST_ALPHA: + drv->blendDst = GL_DST_ALPHA; + break; + case RS_BLEND_DST_ONE_MINUS_DST_ALPHA: + drv->blendDst = GL_ONE_MINUS_DST_ALPHA; + break; + default: + LOGE("Unknown blend dst mode."); + goto error; + } + + return true; + +error: + free(drv); + ps->mHal.drv = NULL; + return false; +} + +void rsdProgramStoreSetActive(const Context *rsc, const ProgramStore *ps) { + DrvProgramStore *drv = (DrvProgramStore *)ps->mHal.drv; + + glColorMask(ps->mHal.state.colorRWriteEnable, + ps->mHal.state.colorGWriteEnable, + ps->mHal.state.colorBWriteEnable, + ps->mHal.state.colorAWriteEnable); + + if (drv->blendEnable) { + glEnable(GL_BLEND); + glBlendFunc(drv->blendSrc, drv->blendDst); + } else { + glDisable(GL_BLEND); + } + + if (rsc->mUserSurfaceConfig.depthMin > 0) { + glDepthMask(ps->mHal.state.depthWriteEnable); + if (drv->depthTestEnable || ps->mHal.state.depthWriteEnable) { + glEnable(GL_DEPTH_TEST); + glDepthFunc(drv->depthFunc); + } else { + glDisable(GL_DEPTH_TEST); + } + } else { + glDepthMask(false); + glDisable(GL_DEPTH_TEST); + } + + /* + if (rsc->mUserSurfaceConfig.stencilMin > 0) { + } else { + glStencilMask(0); + glDisable(GL_STENCIL_TEST); + } + */ + + if (ps->mHal.state.ditherEnable) { + glEnable(GL_DITHER); + } else { + glDisable(GL_DITHER); + } +} + +void rsdProgramStoreDestroy(const Context *rsc, const ProgramStore *ps) { + free(ps->mHal.drv); + ps->mHal.drv = NULL; +} + + diff --git a/libs/rs/driver/rsdProgramStore.h b/libs/rs/driver/rsdProgramStore.h new file mode 100644 index 0000000..217a0ce --- /dev/null +++ b/libs/rs/driver/rsdProgramStore.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2011 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. + */ + +#ifndef RSD_PROGRAM_STORE_H +#define RSD_PROGRAM_STORE_H + +#include <rs_hal.h> + + +bool rsdProgramStoreInit(const android::renderscript::Context *rsc, + const android::renderscript::ProgramStore *ps); +void rsdProgramStoreSetActive(const android::renderscript::Context *rsc, + const android::renderscript::ProgramStore *ps); +void rsdProgramStoreDestroy(const android::renderscript::Context *rsc, + const android::renderscript::ProgramStore *ps); + + +#endif diff --git a/libs/rs/driver/rsdProgramVertex.h b/libs/rs/driver/rsdProgramVertex.h new file mode 100644 index 0000000..e998572 --- /dev/null +++ b/libs/rs/driver/rsdProgramVertex.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2011 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. + */ + +#ifndef RSD_PROGRAM_VERTEX_H +#define RSD_PROGRAM_VERTEX_H + +#include <rs_hal.h> + +bool rsdProgramVertexInit(const android::renderscript::Context *rsc, + const android::renderscript::ProgramVertex *, + const char* shader, uint32_t shaderLen); +void rsdProgramVertexSetActive(const android::renderscript::Context *rsc, + const android::renderscript::ProgramVertex *); +void rsdProgramVertexDestroy(const android::renderscript::Context *rsc, + const android::renderscript::ProgramVertex *); + + +#endif //RSD_PROGRAM_VERTEX_H diff --git a/libs/rs/driver/rsdRuntime.h b/libs/rs/driver/rsdRuntime.h new file mode 100644 index 0000000..840eced --- /dev/null +++ b/libs/rs/driver/rsdRuntime.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2011 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. + */ + +#ifndef RSD_RUNTIME_STUBS_H +#define RSD_RUNTIME_STUBS_H + +#include <rs_hal.h> +#include <bcc/bcc.h> + +#include "rsMutex.h" + +const RsdSymbolTable * rsdLookupSymbolMath(const char *sym); + +void* rsdLookupRuntimeStub(void* pContext, char const* name); + +#endif diff --git a/libs/rs/driver/rsdRuntimeMath.cpp b/libs/rs/driver/rsdRuntimeMath.cpp new file mode 100644 index 0000000..acb990d --- /dev/null +++ b/libs/rs/driver/rsdRuntimeMath.cpp @@ -0,0 +1,442 @@ +/* + * Copyright (C) 2011 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 "rsMatrix4x4.h" +#include "rsMatrix3x3.h" +#include "rsMatrix2x2.h" + +#include "rsdCore.h" +#include "rsdRuntime.h" + + +using namespace android; +using namespace android::renderscript; + + +static float SC_exp10(float v) { + return pow(10.f, v); +} + +static float SC_fract(float v, int *iptr) { + int i = (int)floor(v); + iptr[0] = i; + return fmin(v - i, 0x1.fffffep-1f); +} + +static float SC_log2(float v) { + return log10(v) / log10(2.f); +} + +static float SC_mad(float v1, float v2, float v3) { + return v1 * v2 + v3; +} + +#if 0 +static float SC_pown(float v, int p) { + return powf(v, (float)p); +} + +static float SC_powr(float v, float p) { + return powf(v, p); +} +#endif + +float SC_rootn(float v, int r) { + return pow(v, 1.f / r); +} + +float SC_rsqrt(float v) { + return 1.f / sqrtf(v); +} + +float SC_sincos(float v, float *cosptr) { + *cosptr = cosf(v); + return sinf(v); +} + +////////////////////////////////////////////////////////////////////////////// +// Integer +////////////////////////////////////////////////////////////////////////////// + + +static uint32_t SC_abs_i32(int32_t v) {return abs(v);} +static uint16_t SC_abs_i16(int16_t v) {return (uint16_t)abs(v);} +static uint8_t SC_abs_i8(int8_t v) {return (uint8_t)abs(v);} + +static uint32_t SC_clz_u32(uint32_t v) {return __builtin_clz(v);} +static uint16_t SC_clz_u16(uint16_t v) {return (uint16_t)__builtin_clz(v);} +static uint8_t SC_clz_u8(uint8_t v) {return (uint8_t)__builtin_clz(v);} +static int32_t SC_clz_i32(int32_t v) {return (int32_t)__builtin_clz((uint32_t)v);} +static int16_t SC_clz_i16(int16_t v) {return (int16_t)__builtin_clz(v);} +static int8_t SC_clz_i8(int8_t v) {return (int8_t)__builtin_clz(v);} + +static uint32_t SC_max_u32(uint32_t v, uint32_t v2) {return rsMax(v, v2);} +static uint16_t SC_max_u16(uint16_t v, uint16_t v2) {return rsMax(v, v2);} +static uint8_t SC_max_u8(uint8_t v, uint8_t v2) {return rsMax(v, v2);} +static int32_t SC_max_i32(int32_t v, int32_t v2) {return rsMax(v, v2);} +static int16_t SC_max_i16(int16_t v, int16_t v2) {return rsMax(v, v2);} +static int8_t SC_max_i8(int8_t v, int8_t v2) {return rsMax(v, v2);} + +static uint32_t SC_min_u32(uint32_t v, uint32_t v2) {return rsMin(v, v2);} +static uint16_t SC_min_u16(uint16_t v, uint16_t v2) {return rsMin(v, v2);} +static uint8_t SC_min_u8(uint8_t v, uint8_t v2) {return rsMin(v, v2);} +static int32_t SC_min_i32(int32_t v, int32_t v2) {return rsMin(v, v2);} +static int16_t SC_min_i16(int16_t v, int16_t v2) {return rsMin(v, v2);} +static int8_t SC_min_i8(int8_t v, int8_t v2) {return rsMin(v, v2);} + +////////////////////////////////////////////////////////////////////////////// +// Float util +////////////////////////////////////////////////////////////////////////////// + +static float SC_clamp_f32(float amount, float low, float high) { + return amount < low ? low : (amount > high ? high : amount); +} + +static float SC_degrees(float radians) { + return radians * (180.f / M_PI); +} + +static float SC_max_f32(float v, float v2) { + return rsMax(v, v2); +} + +static float SC_min_f32(float v, float v2) { + return rsMin(v, v2); +} + +static float SC_mix_f32(float start, float stop, float amount) { + //LOGE("lerpf %f %f %f", start, stop, amount); + return start + (stop - start) * amount; +} + +static float SC_radians(float degrees) { + return degrees * (M_PI / 180.f); +} + +static float SC_step_f32(float edge, float v) { + if (v < edge) return 0.f; + return 1.f; +} + +static float SC_sign_f32(float value) { + if (value > 0) return 1.f; + if (value < 0) return -1.f; + return value; +} + +static void SC_MatrixLoadIdentity_4x4(Matrix4x4 *m) { + m->loadIdentity(); +} +static void SC_MatrixLoadIdentity_3x3(Matrix3x3 *m) { + m->loadIdentity(); +} +static void SC_MatrixLoadIdentity_2x2(Matrix2x2 *m) { + m->loadIdentity(); +} + +static void SC_MatrixLoad_4x4_f(Matrix4x4 *m, const float *f) { + m->load(f); +} +static void SC_MatrixLoad_3x3_f(Matrix3x3 *m, const float *f) { + m->load(f); +} +static void SC_MatrixLoad_2x2_f(Matrix2x2 *m, const float *f) { + m->load(f); +} + +static void SC_MatrixLoad_4x4_4x4(Matrix4x4 *m, const Matrix4x4 *s) { + m->load(s); +} +static void SC_MatrixLoad_4x4_3x3(Matrix4x4 *m, const Matrix3x3 *s) { + m->load(s); +} +static void SC_MatrixLoad_4x4_2x2(Matrix4x4 *m, const Matrix2x2 *s) { + m->load(s); +} +static void SC_MatrixLoad_3x3_3x3(Matrix3x3 *m, const Matrix3x3 *s) { + m->load(s); +} +static void SC_MatrixLoad_2x2_2x2(Matrix2x2 *m, const Matrix2x2 *s) { + m->load(s); +} + +static void SC_MatrixLoadRotate(Matrix4x4 *m, float rot, float x, float y, float z) { + m->loadRotate(rot, x, y, z); +} +static void SC_MatrixLoadScale(Matrix4x4 *m, float x, float y, float z) { + m->loadScale(x, y, z); +} +static void SC_MatrixLoadTranslate(Matrix4x4 *m, float x, float y, float z) { + m->loadTranslate(x, y, z); +} +static void SC_MatrixRotate(Matrix4x4 *m, float rot, float x, float y, float z) { + m->rotate(rot, x, y, z); +} +static void SC_MatrixScale(Matrix4x4 *m, float x, float y, float z) { + m->scale(x, y, z); +} +static void SC_MatrixTranslate(Matrix4x4 *m, float x, float y, float z) { + m->translate(x, y, z); +} + +static void SC_MatrixLoadMultiply_4x4_4x4_4x4(Matrix4x4 *m, const Matrix4x4 *lhs, const Matrix4x4 *rhs) { + m->loadMultiply(lhs, rhs); +} +static void SC_MatrixLoadMultiply_3x3_3x3_3x3(Matrix3x3 *m, const Matrix3x3 *lhs, const Matrix3x3 *rhs) { + m->loadMultiply(lhs, rhs); +} +static void SC_MatrixLoadMultiply_2x2_2x2_2x2(Matrix2x2 *m, const Matrix2x2 *lhs, const Matrix2x2 *rhs) { + m->loadMultiply(lhs, rhs); +} + +static void SC_MatrixMultiply_4x4_4x4(Matrix4x4 *m, const Matrix4x4 *rhs) { + m->multiply(rhs); +} +static void SC_MatrixMultiply_3x3_3x3(Matrix3x3 *m, const Matrix3x3 *rhs) { + m->multiply(rhs); +} +static void SC_MatrixMultiply_2x2_2x2(Matrix2x2 *m, const Matrix2x2 *rhs) { + m->multiply(rhs); +} + +static void SC_MatrixLoadOrtho(Matrix4x4 *m, float l, float r, float b, float t, float n, float f) { + m->loadOrtho(l, r, b, t, n, f); +} +static void SC_MatrixLoadFrustum(Matrix4x4 *m, float l, float r, float b, float t, float n, float f) { + m->loadFrustum(l, r, b, t, n, f); +} +static void SC_MatrixLoadPerspective(Matrix4x4 *m, float fovy, float aspect, float near, float far) { + m->loadPerspective(fovy, aspect, near, far); +} + +static bool SC_MatrixInverse_4x4(Matrix4x4 *m) { + return m->inverse(); +} +static bool SC_MatrixInverseTranspose_4x4(Matrix4x4 *m) { + return m->inverseTranspose(); +} +static void SC_MatrixTranspose_4x4(Matrix4x4 *m) { + m->transpose(); +} +static void SC_MatrixTranspose_3x3(Matrix3x3 *m) { + m->transpose(); +} +static void SC_MatrixTranspose_2x2(Matrix2x2 *m) { + m->transpose(); +} + +static float SC_randf(float max) { + float r = (float)rand(); + r *= max; + r /= RAND_MAX; + return r; +} + +static float SC_randf2(float min, float max) { + float r = (float)rand(); + r /= RAND_MAX; + r = r * (max - min) + min; + return r; +} + +static int SC_randi(int max) { + return (int)SC_randf(max); +} + +static int SC_randi2(int min, int max) { + return (int)SC_randf2(min, max); +} + +static float SC_frac(float v) { + int i = (int)floor(v); + return fmin(v - i, 0x1.fffffep-1f); +} + + +////////////////////////////////////////////////////////////////////////////// +// Class implementation +////////////////////////////////////////////////////////////////////////////// + +// llvm name mangling ref +// <builtin-type> ::= v # void +// ::= b # bool +// ::= c # char +// ::= a # signed char +// ::= h # unsigned char +// ::= s # short +// ::= t # unsigned short +// ::= i # int +// ::= j # unsigned int +// ::= l # long +// ::= m # unsigned long +// ::= x # long long, __int64 +// ::= y # unsigned long long, __int64 +// ::= f # float +// ::= d # double + +static RsdSymbolTable gSyms[] = { + { "_Z4acosf", (void *)&acosf, true }, + { "_Z5acoshf", (void *)&acoshf, true }, + { "_Z4asinf", (void *)&asinf, true }, + { "_Z5asinhf", (void *)&asinhf, true }, + { "_Z4atanf", (void *)&atanf, true }, + { "_Z5atan2ff", (void *)&atan2f, true }, + { "_Z5atanhf", (void *)&atanhf, true }, + { "_Z4cbrtf", (void *)&cbrtf, true }, + { "_Z4ceilf", (void *)&ceilf, true }, + { "_Z8copysignff", (void *)©signf, true }, + { "_Z3cosf", (void *)&cosf, true }, + { "_Z4coshf", (void *)&coshf, true }, + { "_Z4erfcf", (void *)&erfcf, true }, + { "_Z3erff", (void *)&erff, true }, + { "_Z3expf", (void *)&expf, true }, + { "_Z4exp2f", (void *)&exp2f, true }, + { "_Z5exp10f", (void *)&SC_exp10, true }, + { "_Z5expm1f", (void *)&expm1f, true }, + { "_Z4fabsf", (void *)&fabsf, true }, + { "_Z4fdimff", (void *)&fdimf, true }, + { "_Z5floorf", (void *)&floorf, true }, + { "_Z3fmafff", (void *)&fmaf, true }, + { "_Z4fmaxff", (void *)&fmaxf, true }, + { "_Z4fminff", (void *)&fminf, true }, // float fmin(float, float) + { "_Z4fmodff", (void *)&fmodf, true }, + { "_Z5fractfPf", (void *)&SC_fract, true }, + { "_Z5frexpfPi", (void *)&frexpf, true }, + { "_Z5hypotff", (void *)&hypotf, true }, + { "_Z5ilogbf", (void *)&ilogbf, true }, + { "_Z5ldexpfi", (void *)&ldexpf, true }, + { "_Z6lgammaf", (void *)&lgammaf, true }, + { "_Z6lgammafPi", (void *)&lgammaf_r, true }, + { "_Z3logf", (void *)&logf, true }, + { "_Z4log2f", (void *)&SC_log2, true }, + { "_Z5log10f", (void *)&log10f, true }, + { "_Z5log1pf", (void *)&log1pf, true }, + { "_Z4logbf", (void *)&logbf, true }, + { "_Z3madfff", (void *)&SC_mad, true }, + { "_Z4modffPf", (void *)&modff, true }, + //{ "_Z3nanj", (void *)&SC_nan, true }, + { "_Z9nextafterff", (void *)&nextafterf, true }, + { "_Z3powff", (void *)&powf, true }, + { "_Z9remainderff", (void *)&remainderf, true }, + { "_Z6remquoffPi", (void *)&remquof, true }, + { "_Z4rintf", (void *)&rintf, true }, + { "_Z5rootnfi", (void *)&SC_rootn, true }, + { "_Z5roundf", (void *)&roundf, true }, + { "_Z5rsqrtf", (void *)&SC_rsqrt, true }, + { "_Z3sinf", (void *)&sinf, true }, + { "_Z6sincosfPf", (void *)&SC_sincos, true }, + { "_Z4sinhf", (void *)&sinhf, true }, + { "_Z4sqrtf", (void *)&sqrtf, true }, + { "_Z3tanf", (void *)&tanf, true }, + { "_Z4tanhf", (void *)&tanhf, true }, + { "_Z6tgammaf", (void *)&tgammaf, true }, + { "_Z5truncf", (void *)&truncf, true }, + + { "_Z3absi", (void *)&SC_abs_i32, true }, + { "_Z3abss", (void *)&SC_abs_i16, true }, + { "_Z3absc", (void *)&SC_abs_i8, true }, + { "_Z3clzj", (void *)&SC_clz_u32, true }, + { "_Z3clzt", (void *)&SC_clz_u16, true }, + { "_Z3clzh", (void *)&SC_clz_u8, true }, + { "_Z3clzi", (void *)&SC_clz_i32, true }, + { "_Z3clzs", (void *)&SC_clz_i16, true }, + { "_Z3clzc", (void *)&SC_clz_i8, true }, + { "_Z3maxjj", (void *)&SC_max_u32, true }, + { "_Z3maxtt", (void *)&SC_max_u16, true }, + { "_Z3maxhh", (void *)&SC_max_u8, true }, + { "_Z3maxii", (void *)&SC_max_i32, true }, + { "_Z3maxss", (void *)&SC_max_i16, true }, + { "_Z3maxcc", (void *)&SC_max_i8, true }, + { "_Z3minjj", (void *)&SC_min_u32, true }, + { "_Z3mintt", (void *)&SC_min_u16, true }, + { "_Z3minhh", (void *)&SC_min_u8, true }, + { "_Z3minii", (void *)&SC_min_i32, true }, + { "_Z3minss", (void *)&SC_min_i16, true }, + { "_Z3mincc", (void *)&SC_min_i8, true }, + + { "_Z5clampfff", (void *)&SC_clamp_f32, true }, + { "_Z7degreesf", (void *)&SC_degrees, true }, + { "_Z3maxff", (void *)&SC_max_f32, true }, + { "_Z3minff", (void *)&SC_min_f32, true }, + { "_Z3mixfff", (void *)&SC_mix_f32, true }, + { "_Z7radiansf", (void *)&SC_radians, true }, + { "_Z4stepff", (void *)&SC_step_f32, true }, + //{ "smoothstep", (void *)&, true }, + { "_Z4signf", (void *)&SC_sign_f32, true }, + + // matrix + { "_Z20rsMatrixLoadIdentityP12rs_matrix4x4", (void *)&SC_MatrixLoadIdentity_4x4, true }, + { "_Z20rsMatrixLoadIdentityP12rs_matrix3x3", (void *)&SC_MatrixLoadIdentity_3x3, true }, + { "_Z20rsMatrixLoadIdentityP12rs_matrix2x2", (void *)&SC_MatrixLoadIdentity_2x2, true }, + + { "_Z12rsMatrixLoadP12rs_matrix4x4PKf", (void *)&SC_MatrixLoad_4x4_f, true }, + { "_Z12rsMatrixLoadP12rs_matrix3x3PKf", (void *)&SC_MatrixLoad_3x3_f, true }, + { "_Z12rsMatrixLoadP12rs_matrix2x2PKf", (void *)&SC_MatrixLoad_2x2_f, true }, + + { "_Z12rsMatrixLoadP12rs_matrix4x4PKS_", (void *)&SC_MatrixLoad_4x4_4x4, true }, + { "_Z12rsMatrixLoadP12rs_matrix4x4PK12rs_matrix3x3", (void *)&SC_MatrixLoad_4x4_3x3, true }, + { "_Z12rsMatrixLoadP12rs_matrix4x4PK12rs_matrix2x2", (void *)&SC_MatrixLoad_4x4_2x2, true }, + { "_Z12rsMatrixLoadP12rs_matrix3x3PKS_", (void *)&SC_MatrixLoad_3x3_3x3, true }, + { "_Z12rsMatrixLoadP12rs_matrix2x2PKS_", (void *)&SC_MatrixLoad_2x2_2x2, true }, + + { "_Z18rsMatrixLoadRotateP12rs_matrix4x4ffff", (void *)&SC_MatrixLoadRotate, true }, + { "_Z17rsMatrixLoadScaleP12rs_matrix4x4fff", (void *)&SC_MatrixLoadScale, true }, + { "_Z21rsMatrixLoadTranslateP12rs_matrix4x4fff", (void *)&SC_MatrixLoadTranslate, true }, + { "_Z14rsMatrixRotateP12rs_matrix4x4ffff", (void *)&SC_MatrixRotate, true }, + { "_Z13rsMatrixScaleP12rs_matrix4x4fff", (void *)&SC_MatrixScale, true }, + { "_Z17rsMatrixTranslateP12rs_matrix4x4fff", (void *)&SC_MatrixTranslate, true }, + + { "_Z20rsMatrixLoadMultiplyP12rs_matrix4x4PKS_S2_", (void *)&SC_MatrixLoadMultiply_4x4_4x4_4x4, true }, + { "_Z16rsMatrixMultiplyP12rs_matrix4x4PKS_", (void *)&SC_MatrixMultiply_4x4_4x4, true }, + { "_Z20rsMatrixLoadMultiplyP12rs_matrix3x3PKS_S2_", (void *)&SC_MatrixLoadMultiply_3x3_3x3_3x3, true }, + { "_Z16rsMatrixMultiplyP12rs_matrix3x3PKS_", (void *)&SC_MatrixMultiply_3x3_3x3, true }, + { "_Z20rsMatrixLoadMultiplyP12rs_matrix2x2PKS_S2_", (void *)&SC_MatrixLoadMultiply_2x2_2x2_2x2, true }, + { "_Z16rsMatrixMultiplyP12rs_matrix2x2PKS_", (void *)&SC_MatrixMultiply_2x2_2x2, true }, + + { "_Z17rsMatrixLoadOrthoP12rs_matrix4x4ffffff", (void *)&SC_MatrixLoadOrtho, true }, + { "_Z19rsMatrixLoadFrustumP12rs_matrix4x4ffffff", (void *)&SC_MatrixLoadFrustum, true }, + { "_Z23rsMatrixLoadPerspectiveP12rs_matrix4x4ffff", (void *)&SC_MatrixLoadPerspective, true }, + + { "_Z15rsMatrixInverseP12rs_matrix4x4", (void *)&SC_MatrixInverse_4x4, true }, + { "_Z24rsMatrixInverseTransposeP12rs_matrix4x4", (void *)&SC_MatrixInverseTranspose_4x4, true }, + { "_Z17rsMatrixTransposeP12rs_matrix4x4", (void *)&SC_MatrixTranspose_4x4, true }, + { "_Z17rsMatrixTransposeP12rs_matrix4x4", (void *)&SC_MatrixTranspose_3x3, true }, + { "_Z17rsMatrixTransposeP12rs_matrix4x4", (void *)&SC_MatrixTranspose_2x2, true }, + + // RS Math + { "_Z6rsRandi", (void *)&SC_randi, true }, + { "_Z6rsRandii", (void *)&SC_randi2, true }, + { "_Z6rsRandf", (void *)&SC_randf, true }, + { "_Z6rsRandff", (void *)&SC_randf2, true }, + { "_Z6rsFracf", (void *)&SC_frac, true }, + + { NULL, NULL, false } +}; + +const RsdSymbolTable * rsdLookupSymbolMath(const char *sym) { + const RsdSymbolTable *syms = gSyms; + + while (syms->mPtr) { + if (!strcmp(syms->mName, sym)) { + return syms; + } + syms++; + } + return NULL; +} + diff --git a/libs/rs/driver/rsdRuntimeStubs.cpp b/libs/rs/driver/rsdRuntimeStubs.cpp new file mode 100644 index 0000000..9cbff95 --- /dev/null +++ b/libs/rs/driver/rsdRuntimeStubs.cpp @@ -0,0 +1,692 @@ +/* + * Copyright (C) 2011 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 "rsMatrix4x4.h" +#include "rsMatrix3x3.h" +#include "rsMatrix2x2.h" +#include "rsRuntime.h" + +#include "utils/Timers.h" +#include "rsdCore.h" + +#include "rsdRuntime.h" + +#include <time.h> + +using namespace android; +using namespace android::renderscript; + +#define GET_TLS() ScriptTLSStruct * tls = \ + (ScriptTLSStruct *)pthread_getspecific(rsdgThreadTLSKey); \ + Context * rsc = tls->mContext; \ + ScriptC * sc = (ScriptC *) tls->mScript + + + +////////////////////////////////////////////////////////////////////////////// +// Allocation +////////////////////////////////////////////////////////////////////////////// + +static uint32_t SC_allocGetDimX(Allocation *a) { + return a->mHal.state.dimensionX; +} + +static uint32_t SC_allocGetDimY(Allocation *a) { + return a->mHal.state.dimensionY; +} + +static uint32_t SC_allocGetDimZ(Allocation *a) { + return a->mHal.state.dimensionZ; +} + +static uint32_t SC_allocGetDimLOD(Allocation *a) { + return a->mHal.state.hasMipmaps; +} + +static uint32_t SC_allocGetDimFaces(Allocation *a) { + return a->mHal.state.hasFaces; +} + +static const void * SC_getElementAtX(Allocation *a, uint32_t x) { + const uint8_t *p = (const uint8_t *)a->getPtr(); + return &p[a->mHal.state.elementSizeBytes * x]; +} + +static const void * SC_getElementAtXY(Allocation *a, uint32_t x, uint32_t y) { + const uint8_t *p = (const uint8_t *)a->getPtr(); + return &p[a->mHal.state.elementSizeBytes * (x + y * a->mHal.state.dimensionX)]; +} + +static const void * SC_getElementAtXYZ(Allocation *a, uint32_t x, uint32_t y, uint32_t z) { + const uint8_t *p = (const uint8_t *)a->getPtr(); + return &p[a->mHal.state.elementSizeBytes * (x + y * a->mHal.state.dimensionX + + z * a->mHal.state.dimensionX * a->mHal.state.dimensionY)]; +} + +static void SC_AllocationSyncAll2(Allocation *a, RsAllocationUsageType source) { + GET_TLS(); + rsrAllocationSyncAll(rsc, sc, a, source); +} + +static void SC_AllocationSyncAll(Allocation *a) { + GET_TLS(); + rsrAllocationSyncAll(rsc, sc, a, RS_ALLOCATION_USAGE_SCRIPT); +} + +const Allocation * SC_getAllocation(const void *ptr) { + GET_TLS(); + return rsrGetAllocation(rsc, sc, ptr); +} + + +////////////////////////////////////////////////////////////////////////////// +// Context +////////////////////////////////////////////////////////////////////////////// + +static void SC_BindTexture(ProgramFragment *pf, uint32_t slot, Allocation *a) { + GET_TLS(); + rsrBindTexture(rsc, sc, pf, slot, a); +} + +static void SC_BindSampler(ProgramFragment *pf, uint32_t slot, Sampler *s) { + GET_TLS(); + rsrBindSampler(rsc, sc, pf, slot, s); +} + +static void SC_BindProgramStore(ProgramStore *ps) { + GET_TLS(); + rsrBindProgramStore(rsc, sc, ps); +} + +static void SC_BindProgramFragment(ProgramFragment *pf) { + GET_TLS(); + rsrBindProgramFragment(rsc, sc, pf); +} + +static void SC_BindProgramVertex(ProgramVertex *pv) { + GET_TLS(); + rsrBindProgramVertex(rsc, sc, pv); +} + +static void SC_BindProgramRaster(ProgramRaster *pr) { + GET_TLS(); + rsrBindProgramRaster(rsc, sc, pr); +} + +static void SC_BindFrameBufferObjectColorTarget(Allocation *a, uint32_t slot) { + GET_TLS(); + rsrBindFrameBufferObjectColorTarget(rsc, sc, a, slot); +} + +static void SC_BindFrameBufferObjectDepthTarget(Allocation *a) { + GET_TLS(); + rsrBindFrameBufferObjectDepthTarget(rsc, sc, a); +} + +static void SC_ClearFrameBufferObjectColorTarget(uint32_t slot) { + GET_TLS(); + rsrClearFrameBufferObjectColorTarget(rsc, sc, slot); +} + +static void SC_ClearFrameBufferObjectDepthTarget(Context *, Script *) { + GET_TLS(); + rsrClearFrameBufferObjectDepthTarget(rsc, sc); +} + +static void SC_ClearFrameBufferObjectTargets(Context *, Script *) { + GET_TLS(); + rsrClearFrameBufferObjectTargets(rsc, sc); +} + + +////////////////////////////////////////////////////////////////////////////// +// VP +////////////////////////////////////////////////////////////////////////////// + +static void SC_VpLoadProjectionMatrix(const rsc_Matrix *m) { + GET_TLS(); + rsrVpLoadProjectionMatrix(rsc, sc, m); +} + +static void SC_VpLoadModelMatrix(const rsc_Matrix *m) { + GET_TLS(); + rsrVpLoadModelMatrix(rsc, sc, m); +} + +static void SC_VpLoadTextureMatrix(const rsc_Matrix *m) { + GET_TLS(); + rsrVpLoadTextureMatrix(rsc, sc, m); +} + +static void SC_PfConstantColor(ProgramFragment *pf, float r, float g, float b, float a) { + GET_TLS(); + rsrPfConstantColor(rsc, sc, pf, r, g, b, a); +} + +static void SC_VpGetProjectionMatrix(rsc_Matrix *m) { + GET_TLS(); + rsrVpGetProjectionMatrix(rsc, sc, m); +} + + +////////////////////////////////////////////////////////////////////////////// +// Drawing +////////////////////////////////////////////////////////////////////////////// + +static void SC_DrawQuadTexCoords(float x1, float y1, float z1, float u1, float v1, + float x2, float y2, float z2, float u2, float v2, + float x3, float y3, float z3, float u3, float v3, + float x4, float y4, float z4, float u4, float v4) { + GET_TLS(); + rsrDrawQuadTexCoords(rsc, sc, + x1, y1, z1, u1, v1, + x2, y2, z2, u2, v2, + x3, y3, z3, u3, v3, + x4, y4, z4, u4, v4); +} + +static void SC_DrawQuad(float x1, float y1, float z1, + float x2, float y2, float z2, + float x3, float y3, float z3, + float x4, float y4, float z4) { + GET_TLS(); + rsrDrawQuad(rsc, sc, x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4); +} + +static void SC_DrawSpriteScreenspace(float x, float y, float z, float w, float h) { + GET_TLS(); + rsrDrawSpriteScreenspace(rsc, sc, x, y, z, w, h); +} + +static void SC_DrawRect(float x1, float y1, float x2, float y2, float z) { + GET_TLS(); + rsrDrawRect(rsc, sc, x1, y1, x2, y2, z); +} + +static void SC_DrawMesh(Mesh *m) { + GET_TLS(); + rsrDrawMesh(rsc, sc, m); +} + +static void SC_DrawMeshPrimitive(Mesh *m, uint32_t primIndex) { + GET_TLS(); + rsrDrawMeshPrimitive(rsc, sc, m, primIndex); +} + +static void SC_DrawMeshPrimitiveRange(Mesh *m, uint32_t primIndex, uint32_t start, uint32_t len) { + GET_TLS(); + rsrDrawMeshPrimitiveRange(rsc, sc, m, primIndex, start, len); +} + +static void SC_MeshComputeBoundingBox(Mesh *m, + float *minX, float *minY, float *minZ, + float *maxX, float *maxY, float *maxZ) { + GET_TLS(); + rsrMeshComputeBoundingBox(rsc, sc, m, minX, minY, minZ, maxX, maxY, maxZ); +} + + + +////////////////////////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////////////////////////// + + +static void SC_Color(float r, float g, float b, float a) { + GET_TLS(); + rsrColor(rsc, sc, r, g, b, a); +} + +static void SC_Finish() { + GET_TLS(); + rsrFinish(rsc, sc); +} + +static void SC_ClearColor(float r, float g, float b, float a) { + GET_TLS(); + rsrClearColor(rsc, sc, r, g, b, a); +} + +static void SC_ClearDepth(float v) { + GET_TLS(); + rsrClearDepth(rsc, sc, v); +} + +static uint32_t SC_GetWidth() { + GET_TLS(); + return rsrGetWidth(rsc, sc); +} + +static uint32_t SC_GetHeight() { + GET_TLS(); + return rsrGetHeight(rsc, sc); +} + +static void SC_DrawTextAlloc(Allocation *a, int x, int y) { + GET_TLS(); + rsrDrawTextAlloc(rsc, sc, a, x, y); +} + +static void SC_DrawText(const char *text, int x, int y) { + GET_TLS(); + rsrDrawText(rsc, sc, text, x, y); +} + +static void SC_MeasureTextAlloc(Allocation *a, + int32_t *left, int32_t *right, int32_t *top, int32_t *bottom) { + GET_TLS(); + rsrMeasureTextAlloc(rsc, sc, a, left, right, top, bottom); +} + +static void SC_MeasureText(const char *text, + int32_t *left, int32_t *right, int32_t *top, int32_t *bottom) { + GET_TLS(); + rsrMeasureText(rsc, sc, text, left, right, top, bottom); +} + +static void SC_BindFont(Font *f) { + GET_TLS(); + rsrBindFont(rsc, sc, f); +} + +static void SC_FontColor(float r, float g, float b, float a) { + GET_TLS(); + rsrFontColor(rsc, sc, r, g, b, a); +} + + + +////////////////////////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////////////////////////// + +static void SC_SetObject(ObjectBase **dst, ObjectBase * src) { + GET_TLS(); + rsrSetObject(rsc, sc, dst, src); +} + +static void SC_ClearObject(ObjectBase **dst) { + GET_TLS(); + rsrClearObject(rsc, sc, dst); +} + +static bool SC_IsObject(const ObjectBase *src) { + GET_TLS(); + return rsrIsObject(rsc, sc, src); +} + + + + +static const Allocation * SC_GetAllocation(const void *ptr) { + GET_TLS(); + return rsrGetAllocation(rsc, sc, ptr); +} + +static void SC_ForEach(Script *target, + Allocation *in, + Allocation *out, + const void *usr, + const RsScriptCall *call) { + GET_TLS(); + rsrForEach(rsc, sc, target, in, out, usr, 0, NULL); +} + +static void SC_ForEach2(Script *target, + Allocation *in, + Allocation *out, + const void *usr, + const RsScriptCall *call) { + GET_TLS(); + rsrForEach(rsc, sc, target, in, out, usr, 0, call); +} + + + +////////////////////////////////////////////////////////////////////////////// +// Time routines +////////////////////////////////////////////////////////////////////////////// + +static float SC_GetDt() { + GET_TLS(); + return rsrGetDt(rsc, sc); +} + +time_t SC_Time(time_t *timer) { + GET_TLS(); + return rsrTime(rsc, sc, timer); +} + +tm* SC_LocalTime(tm *local, time_t *timer) { + GET_TLS(); + return rsrLocalTime(rsc, sc, local, timer); +} + +int64_t SC_UptimeMillis() { + GET_TLS(); + return rsrUptimeMillis(rsc, sc); +} + +int64_t SC_UptimeNanos() { + GET_TLS(); + return rsrUptimeNanos(rsc, sc); +} + +////////////////////////////////////////////////////////////////////////////// +// Message routines +////////////////////////////////////////////////////////////////////////////// + +static uint32_t SC_ToClient2(int cmdID, void *data, int len) { + GET_TLS(); + return rsrToClient(rsc, sc, cmdID, data, len); +} + +static uint32_t SC_ToClient(int cmdID) { + GET_TLS(); + return rsrToClient(rsc, sc, cmdID, NULL, 0); +} + +static uint32_t SC_ToClientBlocking2(int cmdID, void *data, int len) { + GET_TLS(); + return rsrToClientBlocking(rsc, sc, cmdID, data, len); +} + +static uint32_t SC_ToClientBlocking(int cmdID) { + GET_TLS(); + return rsrToClientBlocking(rsc, sc, cmdID, NULL, 0); +} + +int SC_divsi3(int a, int b) { + return a / b; +} + +int SC_modsi3(int a, int b) { + return a % b; +} + +unsigned int SC_udivsi3(unsigned int a, unsigned int b) { + return a / b; +} + +unsigned int SC_umodsi3(unsigned int a, unsigned int b) { + return a % b; +} + +static void SC_debugF(const char *s, float f) { + LOGD("%s %f, 0x%08x", s, f, *((int *) (&f))); +} +static void SC_debugFv2(const char *s, float f1, float f2) { + LOGD("%s {%f, %f}", s, f1, f2); +} +static void SC_debugFv3(const char *s, float f1, float f2, float f3) { + LOGD("%s {%f, %f, %f}", s, f1, f2, f3); +} +static void SC_debugFv4(const char *s, float f1, float f2, float f3, float f4) { + LOGD("%s {%f, %f, %f, %f}", s, f1, f2, f3, f4); +} +static void SC_debugD(const char *s, double d) { + LOGD("%s %f, 0x%08llx", s, d, *((long long *) (&d))); +} +static void SC_debugFM4v4(const char *s, const float *f) { + LOGD("%s {%f, %f, %f, %f", s, f[0], f[4], f[8], f[12]); + LOGD("%s %f, %f, %f, %f", s, f[1], f[5], f[9], f[13]); + LOGD("%s %f, %f, %f, %f", s, f[2], f[6], f[10], f[14]); + LOGD("%s %f, %f, %f, %f}", s, f[3], f[7], f[11], f[15]); +} +static void SC_debugFM3v3(const char *s, const float *f) { + LOGD("%s {%f, %f, %f", s, f[0], f[3], f[6]); + LOGD("%s %f, %f, %f", s, f[1], f[4], f[7]); + LOGD("%s %f, %f, %f}",s, f[2], f[5], f[8]); +} +static void SC_debugFM2v2(const char *s, const float *f) { + LOGD("%s {%f, %f", s, f[0], f[2]); + LOGD("%s %f, %f}",s, f[1], f[3]); +} + +static void SC_debugI32(const char *s, int32_t i) { + LOGD("%s %i 0x%x", s, i, i); +} +static void SC_debugU32(const char *s, uint32_t i) { + LOGD("%s %u 0x%x", s, i, i); +} +static void SC_debugLL64(const char *s, long long ll) { + LOGD("%s %lld 0x%llx", s, ll, ll); +} +static void SC_debugULL64(const char *s, unsigned long long ll) { + LOGD("%s %llu 0x%llx", s, ll, ll); +} + +static void SC_debugP(const char *s, const void *p) { + LOGD("%s %p", s, p); +} + + +////////////////////////////////////////////////////////////////////////////// +// Stub implementation +////////////////////////////////////////////////////////////////////////////// + +// llvm name mangling ref +// <builtin-type> ::= v # void +// ::= b # bool +// ::= c # char +// ::= a # signed char +// ::= h # unsigned char +// ::= s # short +// ::= t # unsigned short +// ::= i # int +// ::= j # unsigned int +// ::= l # long +// ::= m # unsigned long +// ::= x # long long, __int64 +// ::= y # unsigned long long, __int64 +// ::= f # float +// ::= d # double + +static RsdSymbolTable gSyms[] = { + { "__divsi3", (void *)&SC_divsi3, true }, + { "__modsi3", (void *)&SC_modsi3, true }, + { "__udivsi3", (void *)&SC_udivsi3, true }, + { "__umodsi3", (void *)&SC_umodsi3, true }, + { "memset", (void *)&memset, true }, + { "memcpy", (void *)&memcpy, true }, + + // Refcounting + { "_Z11rsSetObjectP10rs_elementS_", (void *)&SC_SetObject, true }, + { "_Z13rsClearObjectP10rs_element", (void *)&SC_ClearObject, true }, + { "_Z10rsIsObject10rs_element", (void *)&SC_IsObject, true }, + + { "_Z11rsSetObjectP7rs_typeS_", (void *)&SC_SetObject, true }, + { "_Z13rsClearObjectP7rs_type", (void *)&SC_ClearObject, true }, + { "_Z10rsIsObject7rs_type", (void *)&SC_IsObject, true }, + + { "_Z11rsSetObjectP13rs_allocationS_", (void *)&SC_SetObject, true }, + { "_Z13rsClearObjectP13rs_allocation", (void *)&SC_ClearObject, true }, + { "_Z10rsIsObject13rs_allocation", (void *)&SC_IsObject, true }, + + { "_Z11rsSetObjectP10rs_samplerS_", (void *)&SC_SetObject, true }, + { "_Z13rsClearObjectP10rs_sampler", (void *)&SC_ClearObject, true }, + { "_Z10rsIsObject10rs_sampler", (void *)&SC_IsObject, true }, + + { "_Z11rsSetObjectP9rs_scriptS_", (void *)&SC_SetObject, true }, + { "_Z13rsClearObjectP9rs_script", (void *)&SC_ClearObject, true }, + { "_Z10rsIsObject9rs_script", (void *)&SC_IsObject, true }, + + { "_Z11rsSetObjectP7rs_meshS_", (void *)&SC_SetObject, true }, + { "_Z13rsClearObjectP7rs_mesh", (void *)&SC_ClearObject, true }, + { "_Z10rsIsObject7rs_mesh", (void *)&SC_IsObject, true }, + + { "_Z11rsSetObjectP19rs_program_fragmentS_", (void *)&SC_SetObject, true }, + { "_Z13rsClearObjectP19rs_program_fragment", (void *)&SC_ClearObject, true }, + { "_Z10rsIsObject19rs_program_fragment", (void *)&SC_IsObject, true }, + + { "_Z11rsSetObjectP17rs_program_vertexS_", (void *)&SC_SetObject, true }, + { "_Z13rsClearObjectP17rs_program_vertex", (void *)&SC_ClearObject, true }, + { "_Z10rsIsObject17rs_program_vertex", (void *)&SC_IsObject, true }, + + { "_Z11rsSetObjectP17rs_program_rasterS_", (void *)&SC_SetObject, true }, + { "_Z13rsClearObjectP17rs_program_raster", (void *)&SC_ClearObject, true }, + { "_Z10rsIsObject17rs_program_raster", (void *)&SC_IsObject, true }, + + { "_Z11rsSetObjectP16rs_program_storeS_", (void *)&SC_SetObject, true }, + { "_Z13rsClearObjectP16rs_program_store", (void *)&SC_ClearObject, true }, + { "_Z10rsIsObject16rs_program_store", (void *)&SC_IsObject, true }, + + { "_Z11rsSetObjectP7rs_fontS_", (void *)&SC_SetObject, true }, + { "_Z13rsClearObjectP7rs_font", (void *)&SC_ClearObject, true }, + { "_Z10rsIsObject7rs_font", (void *)&SC_IsObject, true }, + + // Allocation ops + { "_Z19rsAllocationGetDimX13rs_allocation", (void *)&SC_allocGetDimX, true }, + { "_Z19rsAllocationGetDimY13rs_allocation", (void *)&SC_allocGetDimY, true }, + { "_Z19rsAllocationGetDimZ13rs_allocation", (void *)&SC_allocGetDimZ, true }, + { "_Z21rsAllocationGetDimLOD13rs_allocation", (void *)&SC_allocGetDimLOD, true }, + { "_Z23rsAllocationGetDimFaces13rs_allocation", (void *)&SC_allocGetDimFaces, true }, + + { "_Z14rsGetElementAt13rs_allocationj", (void *)&SC_getElementAtX, true }, + { "_Z14rsGetElementAt13rs_allocationjj", (void *)&SC_getElementAtXY, true }, + { "_Z14rsGetElementAt13rs_allocationjjj", (void *)&SC_getElementAtXYZ, true }, + + { "_Z15rsGetAllocationPKv", (void *)&SC_getAllocation, true }, + + { "_Z21rsAllocationMarkDirty13rs_allocation", (void *)&SC_AllocationSyncAll, true }, + { "_Z20rsgAllocationSyncAll13rs_allocation", (void *)&SC_AllocationSyncAll, false }, + { "_Z20rsgAllocationSyncAll13rs_allocationj", (void *)&SC_AllocationSyncAll2, false }, + { "_Z15rsGetAllocationPKv", (void *)&SC_GetAllocation, true }, + + + // Messaging + + { "_Z14rsSendToClienti", (void *)&SC_ToClient, false }, + { "_Z14rsSendToClientiPKvj", (void *)&SC_ToClient2, false }, + { "_Z22rsSendToClientBlockingi", (void *)&SC_ToClientBlocking, false }, + { "_Z22rsSendToClientBlockingiPKvj", (void *)&SC_ToClientBlocking2, false }, + + { "_Z22rsgBindProgramFragment19rs_program_fragment", (void *)&SC_BindProgramFragment, false }, + { "_Z19rsgBindProgramStore16rs_program_store", (void *)&SC_BindProgramStore, false }, + { "_Z20rsgBindProgramVertex17rs_program_vertex", (void *)&SC_BindProgramVertex, false }, + { "_Z20rsgBindProgramRaster17rs_program_raster", (void *)&SC_BindProgramRaster, false }, + { "_Z14rsgBindSampler19rs_program_fragmentj10rs_sampler", (void *)&SC_BindSampler, false }, + { "_Z14rsgBindTexture19rs_program_fragmentj13rs_allocation", (void *)&SC_BindTexture, false }, + + { "_Z36rsgProgramVertexLoadProjectionMatrixPK12rs_matrix4x4", (void *)&SC_VpLoadProjectionMatrix, false }, + { "_Z31rsgProgramVertexLoadModelMatrixPK12rs_matrix4x4", (void *)&SC_VpLoadModelMatrix, false }, + { "_Z33rsgProgramVertexLoadTextureMatrixPK12rs_matrix4x4", (void *)&SC_VpLoadTextureMatrix, false }, + + { "_Z35rsgProgramVertexGetProjectionMatrixP12rs_matrix4x4", (void *)&SC_VpGetProjectionMatrix, false }, + + { "_Z31rsgProgramFragmentConstantColor19rs_program_fragmentffff", (void *)&SC_PfConstantColor, false }, + + { "_Z11rsgGetWidthv", (void *)&SC_GetWidth, false }, + { "_Z12rsgGetHeightv", (void *)&SC_GetHeight, false }, + + + { "_Z11rsgDrawRectfffff", (void *)&SC_DrawRect, false }, + { "_Z11rsgDrawQuadffffffffffff", (void *)&SC_DrawQuad, false }, + { "_Z20rsgDrawQuadTexCoordsffffffffffffffffffff", (void *)&SC_DrawQuadTexCoords, false }, + { "_Z24rsgDrawSpriteScreenspacefffff", (void *)&SC_DrawSpriteScreenspace, false }, + + { "_Z11rsgDrawMesh7rs_mesh", (void *)&SC_DrawMesh, false }, + { "_Z11rsgDrawMesh7rs_meshj", (void *)&SC_DrawMeshPrimitive, false }, + { "_Z11rsgDrawMesh7rs_meshjjj", (void *)&SC_DrawMeshPrimitiveRange, false }, + { "_Z25rsgMeshComputeBoundingBox7rs_meshPfS0_S0_S0_S0_S0_", (void *)&SC_MeshComputeBoundingBox, false }, + + { "_Z13rsgClearColorffff", (void *)&SC_ClearColor, false }, + { "_Z13rsgClearDepthf", (void *)&SC_ClearDepth, false }, + + { "_Z11rsgDrawTextPKcii", (void *)&SC_DrawText, false }, + { "_Z11rsgDrawText13rs_allocationii", (void *)&SC_DrawTextAlloc, false }, + { "_Z14rsgMeasureTextPKcPiS1_S1_S1_", (void *)&SC_MeasureText, false }, + { "_Z14rsgMeasureText13rs_allocationPiS0_S0_S0_", (void *)&SC_MeasureTextAlloc, false }, + + { "_Z11rsgBindFont7rs_font", (void *)&SC_BindFont, false }, + { "_Z12rsgFontColorffff", (void *)&SC_FontColor, false }, + + { "_Z18rsgBindColorTarget13rs_allocationj", (void *)&SC_BindFrameBufferObjectColorTarget, false }, + { "_Z18rsgBindDepthTarget13rs_allocation", (void *)&SC_BindFrameBufferObjectDepthTarget, false }, + { "_Z19rsgClearColorTargetj", (void *)&SC_ClearFrameBufferObjectColorTarget, false }, + { "_Z19rsgClearDepthTargetv", (void *)&SC_ClearFrameBufferObjectDepthTarget, false }, + { "_Z24rsgClearAllRenderTargetsv", (void *)&SC_ClearFrameBufferObjectTargets, false }, + + { "_Z9rsForEach9rs_script13rs_allocationS0_PKv", (void *)&SC_ForEach, false }, + { "_Z9rsForEach9rs_script13rs_allocationS0_PKvj", (void *)&SC_ForEach2, false }, + + // time + { "_Z6rsTimePi", (void *)&SC_Time, true }, + { "_Z11rsLocaltimeP5rs_tmPKi", (void *)&SC_LocalTime, true }, + { "_Z14rsUptimeMillisv", (void*)&SC_UptimeMillis, true }, + { "_Z13rsUptimeNanosv", (void*)&SC_UptimeNanos, true }, + { "_Z7rsGetDtv", (void*)&SC_GetDt, false }, + + // misc + { "_Z5colorffff", (void *)&SC_Color, false }, + { "_Z9rsgFinishv", (void *)&SC_Finish, false }, + + // Debug + { "_Z7rsDebugPKcf", (void *)&SC_debugF, true }, + { "_Z7rsDebugPKcff", (void *)&SC_debugFv2, true }, + { "_Z7rsDebugPKcfff", (void *)&SC_debugFv3, true }, + { "_Z7rsDebugPKcffff", (void *)&SC_debugFv4, true }, + { "_Z7rsDebugPKcd", (void *)&SC_debugD, true }, + { "_Z7rsDebugPKcPK12rs_matrix4x4", (void *)&SC_debugFM4v4, true }, + { "_Z7rsDebugPKcPK12rs_matrix3x3", (void *)&SC_debugFM3v3, true }, + { "_Z7rsDebugPKcPK12rs_matrix2x2", (void *)&SC_debugFM2v2, true }, + { "_Z7rsDebugPKci", (void *)&SC_debugI32, true }, + { "_Z7rsDebugPKcj", (void *)&SC_debugU32, true }, + // Both "long" and "unsigned long" need to be redirected to their + // 64-bit counterparts, since we have hacked Slang to use 64-bit + // for "long" on Arm (to be similar to Java). + { "_Z7rsDebugPKcl", (void *)&SC_debugLL64, true }, + { "_Z7rsDebugPKcm", (void *)&SC_debugULL64, true }, + { "_Z7rsDebugPKcx", (void *)&SC_debugLL64, true }, + { "_Z7rsDebugPKcy", (void *)&SC_debugULL64, true }, + { "_Z7rsDebugPKcPKv", (void *)&SC_debugP, true }, + + { NULL, NULL, false } +}; + + +void* rsdLookupRuntimeStub(void* pContext, char const* name) { + ScriptC *s = (ScriptC *)pContext; + if (!strcmp(name, "__isThreadable")) { + return (void*) s->mHal.info.isThreadable; + } else if (!strcmp(name, "__clearThreadable")) { + s->mHal.info.isThreadable = false; + return NULL; + } + + RsdSymbolTable *syms = gSyms; + const RsdSymbolTable *sym = rsdLookupSymbolMath(name); + + if (!sym) { + while (syms->mPtr) { + if (!strcmp(syms->mName, name)) { + sym = syms; + } + syms++; + } + } + + if (sym) { + s->mHal.info.isThreadable &= sym->threadable; + return sym->mPtr; + } + LOGE("ScriptC sym lookup failed for %s", name); + return NULL; +} + + diff --git a/libs/rs/driver/rsdSampler.cpp b/libs/rs/driver/rsdSampler.cpp new file mode 100644 index 0000000..af48c61 --- /dev/null +++ b/libs/rs/driver/rsdSampler.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2011 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 "rsdCore.h" +#include "rsdSampler.h" + +#include "rsContext.h" +#include "rsSampler.h" +#include "rsProgramVertex.h" +#include "rsProgramFragment.h" + +#include <GLES/gl.h> +#include <GLES/glext.h> + + +using namespace android; +using namespace android::renderscript; + +bool rsdSamplerInit(const android::renderscript::Context *, + const android::renderscript::Sampler *) { + return true; +} + +void rsdSamplerDestroy(const android::renderscript::Context *rsc, + const android::renderscript::Sampler *s) { +} diff --git a/libs/rs/driver/rsdSampler.h b/libs/rs/driver/rsdSampler.h new file mode 100644 index 0000000..3a64e9e --- /dev/null +++ b/libs/rs/driver/rsdSampler.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2011 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. + */ + +#ifndef RSD_SAMPLER_H +#define RSD_SAMPLER_H + +#include <rs_hal.h> + + +bool rsdSamplerInit(const android::renderscript::Context *rsc, + const android::renderscript::Sampler *); + +void rsdSamplerDestroy(const android::renderscript::Context *rsc, + const android::renderscript::Sampler *); + + +#endif // RSD_SAMPLER_H diff --git a/libs/rs/driver/rsdShader.cpp b/libs/rs/driver/rsdShader.cpp new file mode 100644 index 0000000..15cc417 --- /dev/null +++ b/libs/rs/driver/rsdShader.cpp @@ -0,0 +1,537 @@ +/* + * Copyright (C) 2011 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 <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +#include <rs_hal.h> +#include <rsContext.h> +#include <rsProgram.h> + +#include "rsdCore.h" +#include "rsdAllocation.h" +#include "rsdShader.h" +#include "rsdShaderCache.h" + +using namespace android; +using namespace android::renderscript; + +RsdShader::RsdShader(const Program *p, uint32_t type, + const char * shaderText, uint32_t shaderLength) { + + mUserShader.setTo(shaderText, shaderLength); + mRSProgram = p; + mType = type; + initMemberVars(); + initAttribAndUniformArray(); + init(); +} + +RsdShader::~RsdShader() { + if (mShaderID) { + glDeleteShader(mShaderID); + } + + delete[] mAttribNames; + delete[] mUniformNames; + delete[] mUniformArraySizes; +} + +void RsdShader::initMemberVars() { + mDirty = true; + mShaderID = 0; + mAttribCount = 0; + mUniformCount = 0; + + mAttribNames = NULL; + mUniformNames = NULL; + mUniformArraySizes = NULL; + + mIsValid = false; +} + +void RsdShader::init() { + uint32_t attribCount = 0; + uint32_t uniformCount = 0; + for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) { + initAddUserElement(mRSProgram->mHal.state.inputElements[ct].get(), mAttribNames, NULL, &attribCount, RS_SHADER_ATTR); + } + for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) { + initAddUserElement(mRSProgram->mHal.state.constantTypes[ct]->getElement(), mUniformNames, mUniformArraySizes, &uniformCount, RS_SHADER_UNI); + } + + mTextureUniformIndexStart = uniformCount; + char buf[256]; + for (uint32_t ct=0; ct < mRSProgram->mHal.state.texturesCount; ct++) { + snprintf(buf, sizeof(buf), "UNI_Tex%i", ct); + mUniformNames[uniformCount].setTo(buf); + mUniformArraySizes[uniformCount] = 1; + uniformCount++; + } +} + +String8 RsdShader::getGLSLInputString() const { + String8 s; + for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) { + const Element *e = mRSProgram->mHal.state.inputElements[ct].get(); + for (uint32_t field=0; field < e->getFieldCount(); field++) { + const Element *f = e->getField(field); + + // Cannot be complex + rsAssert(!f->getFieldCount()); + switch (f->getComponent().getVectorSize()) { + case 1: s.append("attribute float ATTRIB_"); break; + case 2: s.append("attribute vec2 ATTRIB_"); break; + case 3: s.append("attribute vec3 ATTRIB_"); break; + case 4: s.append("attribute vec4 ATTRIB_"); break; + default: + rsAssert(0); + } + + s.append(e->getFieldName(field)); + s.append(";\n"); + } + } + return s; +} + +void RsdShader::appendAttributes() { + for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) { + const Element *e = mRSProgram->mHal.state.inputElements[ct].get(); + for (uint32_t field=0; field < e->getFieldCount(); field++) { + const Element *f = e->getField(field); + const char *fn = e->getFieldName(field); + + if (fn[0] == '#') { + continue; + } + + // Cannot be complex + rsAssert(!f->getFieldCount()); + switch (f->getComponent().getVectorSize()) { + case 1: mShader.append("attribute float ATTRIB_"); break; + case 2: mShader.append("attribute vec2 ATTRIB_"); break; + case 3: mShader.append("attribute vec3 ATTRIB_"); break; + case 4: mShader.append("attribute vec4 ATTRIB_"); break; + default: + rsAssert(0); + } + + mShader.append(fn); + mShader.append(";\n"); + } + } +} + +void RsdShader::appendTextures() { + char buf[256]; + for (uint32_t ct=0; ct < mRSProgram->mHal.state.texturesCount; ct++) { + if (mRSProgram->mHal.state.textureTargets[ct] == RS_TEXTURE_2D) { + snprintf(buf, sizeof(buf), "uniform sampler2D UNI_Tex%i;\n", ct); + } else { + snprintf(buf, sizeof(buf), "uniform samplerCube UNI_Tex%i;\n", ct); + } + mShader.append(buf); + } +} + +bool RsdShader::createShader() { + + if (mType == GL_FRAGMENT_SHADER) { + mShader.append("precision mediump float;\n"); + } + appendUserConstants(); + appendAttributes(); + appendTextures(); + + mShader.append(mUserShader); + + return true; +} + +bool RsdShader::loadShader(const Context *rsc) { + mShaderID = glCreateShader(mType); + rsAssert(mShaderID); + + if (rsc->props.mLogShaders) { + LOGV("Loading shader type %x, ID %i", mType, mShaderID); + LOGV("%s", mShader.string()); + } + + if (mShaderID) { + const char * ss = mShader.string(); + glShaderSource(mShaderID, 1, &ss, NULL); + glCompileShader(mShaderID); + + GLint compiled = 0; + glGetShaderiv(mShaderID, GL_COMPILE_STATUS, &compiled); + if (!compiled) { + GLint infoLen = 0; + glGetShaderiv(mShaderID, GL_INFO_LOG_LENGTH, &infoLen); + if (infoLen) { + char* buf = (char*) malloc(infoLen); + if (buf) { + glGetShaderInfoLog(mShaderID, infoLen, NULL, buf); + LOGE("Could not compile shader \n%s\n", buf); + free(buf); + } + glDeleteShader(mShaderID); + mShaderID = 0; + rsc->setError(RS_ERROR_BAD_SHADER, "Error returned from GL driver loading shader text,"); + return false; + } + } + } + + if (rsc->props.mLogShaders) { + LOGV("--Shader load result %x ", glGetError()); + } + mIsValid = true; + return true; +} + +void RsdShader::appendUserConstants() { + for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) { + const Element *e = mRSProgram->mHal.state.constantTypes[ct]->getElement(); + for (uint32_t field=0; field < e->getFieldCount(); field++) { + const Element *f = e->getField(field); + const char *fn = e->getFieldName(field); + + if (fn[0] == '#') { + continue; + } + + // Cannot be complex + rsAssert(!f->getFieldCount()); + if (f->getType() == RS_TYPE_MATRIX_4X4) { + mShader.append("uniform mat4 UNI_"); + } else if (f->getType() == RS_TYPE_MATRIX_3X3) { + mShader.append("uniform mat3 UNI_"); + } else if (f->getType() == RS_TYPE_MATRIX_2X2) { + mShader.append("uniform mat2 UNI_"); + } else { + switch (f->getComponent().getVectorSize()) { + case 1: mShader.append("uniform float UNI_"); break; + case 2: mShader.append("uniform vec2 UNI_"); break; + case 3: mShader.append("uniform vec3 UNI_"); break; + case 4: mShader.append("uniform vec4 UNI_"); break; + default: + rsAssert(0); + } + } + + mShader.append(fn); + if (e->getFieldArraySize(field) > 1) { + mShader.appendFormat("[%d]", e->getFieldArraySize(field)); + } + mShader.append(";\n"); + } + } +} + +void RsdShader::logUniform(const Element *field, const float *fd, uint32_t arraySize ) { + RsDataType dataType = field->getType(); + uint32_t elementSize = field->getSizeBytes() / sizeof(float); + for (uint32_t i = 0; i < arraySize; i ++) { + if (arraySize > 1) { + LOGV("Array Element [%u]", i); + } + if (dataType == RS_TYPE_MATRIX_4X4) { + LOGV("Matrix4x4"); + LOGV("{%f, %f, %f, %f", fd[0], fd[4], fd[8], fd[12]); + LOGV(" %f, %f, %f, %f", fd[1], fd[5], fd[9], fd[13]); + LOGV(" %f, %f, %f, %f", fd[2], fd[6], fd[10], fd[14]); + LOGV(" %f, %f, %f, %f}", fd[3], fd[7], fd[11], fd[15]); + } else if (dataType == RS_TYPE_MATRIX_3X3) { + LOGV("Matrix3x3"); + LOGV("{%f, %f, %f", fd[0], fd[3], fd[6]); + LOGV(" %f, %f, %f", fd[1], fd[4], fd[7]); + LOGV(" %f, %f, %f}", fd[2], fd[5], fd[8]); + } else if (dataType == RS_TYPE_MATRIX_2X2) { + LOGV("Matrix2x2"); + LOGV("{%f, %f", fd[0], fd[2]); + LOGV(" %f, %f}", fd[1], fd[3]); + } else { + switch (field->getComponent().getVectorSize()) { + case 1: + LOGV("Uniform 1 = %f", fd[0]); + break; + case 2: + LOGV("Uniform 2 = %f %f", fd[0], fd[1]); + break; + case 3: + LOGV("Uniform 3 = %f %f %f", fd[0], fd[1], fd[2]); + break; + case 4: + LOGV("Uniform 4 = %f %f %f %f", fd[0], fd[1], fd[2], fd[3]); + break; + default: + rsAssert(0); + } + } + LOGE("Element size %u data=%p", elementSize, fd); + fd += elementSize; + LOGE("New data=%p", fd); + } +} + +void RsdShader::setUniform(const Context *rsc, const Element *field, const float *fd, + int32_t slot, uint32_t arraySize ) { + RsDataType dataType = field->getType(); + if (dataType == RS_TYPE_MATRIX_4X4) { + glUniformMatrix4fv(slot, arraySize, GL_FALSE, fd); + } else if (dataType == RS_TYPE_MATRIX_3X3) { + glUniformMatrix3fv(slot, arraySize, GL_FALSE, fd); + } else if (dataType == RS_TYPE_MATRIX_2X2) { + glUniformMatrix2fv(slot, arraySize, GL_FALSE, fd); + } else { + switch (field->getComponent().getVectorSize()) { + case 1: + glUniform1fv(slot, arraySize, fd); + break; + case 2: + glUniform2fv(slot, arraySize, fd); + break; + case 3: + glUniform3fv(slot, arraySize, fd); + break; + case 4: + glUniform4fv(slot, arraySize, fd); + break; + default: + rsAssert(0); + } + } +} + +void RsdShader::setupSampler(const Context *rsc, const Sampler *s, const Allocation *tex) { + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + + GLenum trans[] = { + GL_NEAREST, //RS_SAMPLER_NEAREST, + GL_LINEAR, //RS_SAMPLER_LINEAR, + GL_LINEAR_MIPMAP_LINEAR, //RS_SAMPLER_LINEAR_MIP_LINEAR, + GL_REPEAT, //RS_SAMPLER_WRAP, + GL_CLAMP_TO_EDGE, //RS_SAMPLER_CLAMP + GL_LINEAR_MIPMAP_NEAREST, //RS_SAMPLER_LINEAR_MIP_NEAREST + }; + + GLenum transNP[] = { + GL_NEAREST, //RS_SAMPLER_NEAREST, + GL_LINEAR, //RS_SAMPLER_LINEAR, + GL_LINEAR, //RS_SAMPLER_LINEAR_MIP_LINEAR, + GL_CLAMP_TO_EDGE, //RS_SAMPLER_WRAP, + GL_CLAMP_TO_EDGE, //RS_SAMPLER_CLAMP + GL_LINEAR, //RS_SAMPLER_LINEAR_MIP_NEAREST, + }; + + // This tells us the correct texture type + DrvAllocation *drvTex = (DrvAllocation *)tex->mHal.drv; + const GLenum target = drvTex->glTarget; + + if (!dc->gl.gl.OES_texture_npot && tex->getType()->getIsNp2()) { + if (tex->getHasGraphicsMipmaps() && + (dc->gl.gl.GL_NV_texture_npot_2D_mipmap || dc->gl.gl.GL_IMG_texture_npot)) { + if (dc->gl.gl.GL_NV_texture_npot_2D_mipmap) { + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, trans[s->mHal.state.minFilter]); + } else { + switch (trans[s->mHal.state.minFilter]) { + case GL_LINEAR_MIPMAP_LINEAR: + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); + break; + default: + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, trans[s->mHal.state.minFilter]); + break; + } + } + } else { + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, transNP[s->mHal.state.minFilter]); + } + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, transNP[s->mHal.state.magFilter]); + glTexParameteri(target, GL_TEXTURE_WRAP_S, transNP[s->mHal.state.wrapS]); + glTexParameteri(target, GL_TEXTURE_WRAP_T, transNP[s->mHal.state.wrapT]); + } else { + if (tex->getHasGraphicsMipmaps()) { + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, trans[s->mHal.state.minFilter]); + } else { + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, transNP[s->mHal.state.minFilter]); + } + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, trans[s->mHal.state.magFilter]); + glTexParameteri(target, GL_TEXTURE_WRAP_S, trans[s->mHal.state.wrapS]); + glTexParameteri(target, GL_TEXTURE_WRAP_T, trans[s->mHal.state.wrapT]); + } + + float anisoValue = rsMin(dc->gl.gl.EXT_texture_max_aniso, s->mHal.state.aniso); + if (dc->gl.gl.EXT_texture_max_aniso > 1.0f) { + glTexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisoValue); + } + + rsdGLCheckError(rsc, "Sampler::setup tex env"); +} + +void RsdShader::setupTextures(const Context *rsc, RsdShaderCache *sc) { + if (mRSProgram->mHal.state.texturesCount == 0) { + return; + } + + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + + uint32_t numTexturesToBind = mRSProgram->mHal.state.texturesCount; + uint32_t numTexturesAvailable = dc->gl.gl.maxFragmentTextureImageUnits; + if (numTexturesToBind >= numTexturesAvailable) { + LOGE("Attempting to bind %u textures on shader id %u, but only %u are available", + mRSProgram->mHal.state.texturesCount, (uint32_t)this, numTexturesAvailable); + rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind more textuers than available"); + numTexturesToBind = numTexturesAvailable; + } + + for (uint32_t ct=0; ct < numTexturesToBind; ct++) { + glActiveTexture(GL_TEXTURE0 + ct); + if (!mRSProgram->mHal.state.textures[ct].get()) { + LOGE("No texture bound for shader id %u, texture unit %u", (uint)this, ct); + rsc->setError(RS_ERROR_BAD_SHADER, "No texture bound"); + continue; + } + + DrvAllocation *drvTex = (DrvAllocation *)mRSProgram->mHal.state.textures[ct]->mHal.drv; + if (drvTex->glTarget != GL_TEXTURE_2D && drvTex->glTarget != GL_TEXTURE_CUBE_MAP) { + LOGE("Attempting to bind unknown texture to shader id %u, texture unit %u", (uint)this, ct); + rsc->setError(RS_ERROR_BAD_SHADER, "Non-texture allocation bound to a shader"); + } + glBindTexture(drvTex->glTarget, drvTex->textureID); + rsdGLCheckError(rsc, "ProgramFragment::setup tex bind"); + if (mRSProgram->mHal.state.samplers[ct].get()) { + setupSampler(rsc, mRSProgram->mHal.state.samplers[ct].get(), mRSProgram->mHal.state.textures[ct].get()); + } else { + glTexParameteri(drvTex->glTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(drvTex->glTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(drvTex->glTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(drvTex->glTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + rsdGLCheckError(rsc, "ProgramFragment::setup tex env"); + } + + glUniform1i(sc->fragUniformSlot(mTextureUniformIndexStart + ct), ct); + rsdGLCheckError(rsc, "ProgramFragment::setup uniforms"); + } + + glActiveTexture(GL_TEXTURE0); + mDirty = false; + rsdGLCheckError(rsc, "ProgramFragment::setup"); +} + +void RsdShader::setupUserConstants(const Context *rsc, RsdShaderCache *sc, bool isFragment) { + uint32_t uidx = 0; + for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) { + Allocation *alloc = mRSProgram->mHal.state.constants[ct].get(); + if (!alloc) { + LOGE("Attempting to set constants on shader id %u, but alloc at slot %u is not set", (uint32_t)this, ct); + rsc->setError(RS_ERROR_BAD_SHADER, "No constant allocation bound"); + continue; + } + + const uint8_t *data = static_cast<const uint8_t *>(alloc->getPtr()); + const Element *e = mRSProgram->mHal.state.constantTypes[ct]->getElement(); + for (uint32_t field=0; field < e->getFieldCount(); field++) { + const Element *f = e->getField(field); + const char *fieldName = e->getFieldName(field); + // If this field is padding, skip it + if (fieldName[0] == '#') { + continue; + } + + uint32_t offset = e->getFieldOffsetBytes(field); + const float *fd = reinterpret_cast<const float *>(&data[offset]); + + int32_t slot = -1; + uint32_t arraySize = 1; + if (!isFragment) { + slot = sc->vtxUniformSlot(uidx); + arraySize = sc->vtxUniformSize(uidx); + } else { + slot = sc->fragUniformSlot(uidx); + arraySize = sc->fragUniformSize(uidx); + } + if (rsc->props.mLogShadersUniforms) { + LOGV("Uniform slot=%i, offset=%i, constant=%i, field=%i, uidx=%i, name=%s", slot, offset, ct, field, uidx, fieldName); + } + uidx ++; + if (slot < 0) { + continue; + } + + if (rsc->props.mLogShadersUniforms) { + logUniform(f, fd, arraySize); + } + setUniform(rsc, f, fd, slot, arraySize); + } + } +} + +void RsdShader::setup(const android::renderscript::Context *rsc, RsdShaderCache *sc) { + + setupUserConstants(rsc, sc, mType == GL_FRAGMENT_SHADER); + setupTextures(rsc, sc); +} + +void RsdShader::initAttribAndUniformArray() { + mAttribCount = 0; + for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) { + const Element *elem = mRSProgram->mHal.state.inputElements[ct].get(); + for (uint32_t field=0; field < elem->getFieldCount(); field++) { + if (elem->getFieldName(field)[0] != '#') { + mAttribCount ++; + } + } + } + + mUniformCount = 0; + for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) { + const Element *elem = mRSProgram->mHal.state.constantTypes[ct]->getElement(); + + for (uint32_t field=0; field < elem->getFieldCount(); field++) { + if (elem->getFieldName(field)[0] != '#') { + mUniformCount ++; + } + } + } + mUniformCount += mRSProgram->mHal.state.texturesCount; + + if (mAttribCount) { + mAttribNames = new String8[mAttribCount]; + } + if (mUniformCount) { + mUniformNames = new String8[mUniformCount]; + mUniformArraySizes = new uint32_t[mUniformCount]; + } +} + +void RsdShader::initAddUserElement(const Element *e, String8 *names, uint32_t *arrayLengths, uint32_t *count, const char *prefix) { + rsAssert(e->getFieldCount()); + for (uint32_t ct=0; ct < e->getFieldCount(); ct++) { + const Element *ce = e->getField(ct); + if (ce->getFieldCount()) { + initAddUserElement(ce, names, arrayLengths, count, prefix); + } else if (e->getFieldName(ct)[0] != '#') { + String8 tmp(prefix); + tmp.append(e->getFieldName(ct)); + names[*count].setTo(tmp.string()); + if (arrayLengths) { + arrayLengths[*count] = e->getFieldArraySize(ct); + } + (*count)++; + } + } +} diff --git a/libs/rs/driver/rsdShader.h b/libs/rs/driver/rsdShader.h new file mode 100644 index 0000000..63c4231 --- /dev/null +++ b/libs/rs/driver/rsdShader.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2011 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. + */ + +#ifndef ANDROID_RSD_SHADER_H +#define ANDROID_RSD_SHADER_H + +#include <utils/String8.h> + +// --------------------------------------------------------------------------- +namespace android { +namespace renderscript { + +class Element; +class Context; +class Program; + +} +} + +class RsdShaderCache; + +#define RS_SHADER_ATTR "ATTRIB_" +#define RS_SHADER_UNI "UNI_" + +class RsdShader { +public: + + RsdShader(const android::renderscript::Program *p, uint32_t type, + const char * shaderText, uint32_t shaderLength); + virtual ~RsdShader(); + + bool createShader(); + + uint32_t getShaderID() const {return mShaderID;} + + uint32_t getAttribCount() const {return mAttribCount;} + uint32_t getUniformCount() const {return mUniformCount;} + const android::String8 & getAttribName(uint32_t i) const {return mAttribNames[i];} + const android::String8 & getUniformName(uint32_t i) const {return mUniformNames[i];} + uint32_t getUniformArraySize(uint32_t i) const {return mUniformArraySizes[i];} + + android::String8 getGLSLInputString() const; + + bool isValid() const {return mIsValid;} + void forceDirty() const {mDirty = true;} + + bool loadShader(const android::renderscript::Context *); + void setup(const android::renderscript::Context *, RsdShaderCache *sc); + +protected: + + const android::renderscript::Program *mRSProgram; + bool mIsValid; + + // Applies to vertex and fragment shaders only + void appendUserConstants(); + void setupUserConstants(const android::renderscript::Context *rsc, RsdShaderCache *sc, bool isFragment); + void initAddUserElement(const android::renderscript::Element *e, android::String8 *names, uint32_t *arrayLengths, uint32_t *count, const char *prefix); + void setupTextures(const android::renderscript::Context *rsc, RsdShaderCache *sc); + void setupSampler(const android::renderscript::Context *rsc, const android::renderscript::Sampler *s, const android::renderscript::Allocation *tex); + + void appendAttributes(); + void appendTextures(); + + void initAttribAndUniformArray(); + + mutable bool mDirty; + android::String8 mShader; + android::String8 mUserShader; + uint32_t mShaderID; + uint32_t mType; + + uint32_t mTextureCount; + uint32_t mAttribCount; + uint32_t mUniformCount; + android::String8 *mAttribNames; + android::String8 *mUniformNames; + uint32_t *mUniformArraySizes; + + int32_t mTextureUniformIndexStart; + + void logUniform(const android::renderscript::Element *field, const float *fd, uint32_t arraySize ); + void setUniform(const android::renderscript::Context *rsc, const android::renderscript::Element *field, const float *fd, int32_t slot, uint32_t arraySize ); + void initMemberVars(); + void init(); +}; + +#endif //ANDROID_RSD_SHADER_H + + + + diff --git a/libs/rs/driver/rsdShaderCache.cpp b/libs/rs/driver/rsdShaderCache.cpp new file mode 100644 index 0000000..d11490c --- /dev/null +++ b/libs/rs/driver/rsdShaderCache.cpp @@ -0,0 +1,283 @@ +/* + * Copyright (C) 2011 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 <rs_hal.h> +#include <rsContext.h> + +#include "rsdShader.h" +#include "rsdShaderCache.h" +#include "rsdGL.h" + +#include <GLES/gl.h> +#include <GLES2/gl2.h> + +using namespace android; +using namespace android::renderscript; + + +RsdShaderCache::RsdShaderCache() { + mEntries.setCapacity(16); + mVertexDirty = true; + mFragmentDirty = true; +} + +RsdShaderCache::~RsdShaderCache() { + cleanupAll(); +} + +void RsdShaderCache::updateUniformArrayData(const Context *rsc, RsdShader *prog, uint32_t linkedID, + UniformData *data, const char* logTag, + UniformQueryData **uniformList, uint32_t uniListSize) { + + for (uint32_t ct=0; ct < prog->getUniformCount(); ct++) { + if (data[ct].slot >= 0 && data[ct].arraySize > 1) { + //Iterate over the list of active GL uniforms and find highest array index + for (uint32_t ui = 0; ui < uniListSize; ui ++) { + if (prog->getUniformName(ct) == uniformList[ui]->name) { + data[ct].arraySize = (uint32_t)uniformList[ui]->arraySize; + break; + } + } + } + + if (rsc->props.mLogShaders) { + LOGV("%s U, %s = %d, arraySize = %d\n", logTag, + prog->getUniformName(ct).string(), data[ct].slot, data[ct].arraySize); + } + } +} + +void RsdShaderCache::populateUniformData(RsdShader *prog, uint32_t linkedID, UniformData *data) { + for (uint32_t ct=0; ct < prog->getUniformCount(); ct++) { + data[ct].slot = glGetUniformLocation(linkedID, prog->getUniformName(ct)); + data[ct].arraySize = prog->getUniformArraySize(ct); + } +} + +bool RsdShaderCache::hasArrayUniforms(RsdShader *vtx, RsdShader *frag) { + UniformData *data = mCurrent->vtxUniforms; + for (uint32_t ct=0; ct < vtx->getUniformCount(); ct++) { + if (data[ct].slot >= 0 && data[ct].arraySize > 1) { + return true; + } + } + data = mCurrent->fragUniforms; + for (uint32_t ct=0; ct < frag->getUniformCount(); ct++) { + if (data[ct].slot >= 0 && data[ct].arraySize > 1) { + return true; + } + } + return false; +} + +bool RsdShaderCache::setup(const Context *rsc) { + if (!mVertexDirty && !mFragmentDirty) { + return true; + } + + if (!link(rsc)) { + return false; + } + + if (mFragmentDirty) { + mFragment->setup(rsc, this); + mFragmentDirty = false; + } + if (mVertexDirty) { + mVertex->setup(rsc, this); + mVertexDirty = false; + } + + return true; +} + +bool RsdShaderCache::link(const Context *rsc) { + + RsdShader *vtx = mVertex; + RsdShader *frag = mFragment; + if (!vtx->getShaderID()) { + vtx->loadShader(rsc); + } + if (!frag->getShaderID()) { + frag->loadShader(rsc); + } + + // Don't try to cache if shaders failed to load + if (!vtx->getShaderID() || !frag->getShaderID()) { + return false; + } + //LOGV("rsdShaderCache lookup vtx %i, frag %i", vtx->getShaderID(), frag->getShaderID()); + uint32_t entryCount = mEntries.size(); + for (uint32_t ct = 0; ct < entryCount; ct ++) { + if ((mEntries[ct]->vtx == vtx->getShaderID()) && + (mEntries[ct]->frag == frag->getShaderID())) { + + //LOGV("SC using program %i", mEntries[ct]->program); + glUseProgram(mEntries[ct]->program); + mCurrent = mEntries[ct]; + //LOGV("RsdShaderCache hit, using %i", ct); + rsdGLCheckError(rsc, "RsdShaderCache::link (hit)"); + return true; + } + } + + //LOGV("RsdShaderCache miss"); + //LOGE("e0 %x", glGetError()); + ProgramEntry *e = new ProgramEntry(vtx->getAttribCount(), + vtx->getUniformCount(), + frag->getUniformCount()); + mEntries.push(e); + mCurrent = e; + e->vtx = vtx->getShaderID(); + e->frag = frag->getShaderID(); + e->program = glCreateProgram(); + if (e->program) { + GLuint pgm = e->program; + glAttachShader(pgm, vtx->getShaderID()); + //LOGE("e1 %x", glGetError()); + glAttachShader(pgm, frag->getShaderID()); + + glBindAttribLocation(pgm, 0, "ATTRIB_position"); + glBindAttribLocation(pgm, 1, "ATTRIB_color"); + glBindAttribLocation(pgm, 2, "ATTRIB_normal"); + glBindAttribLocation(pgm, 3, "ATTRIB_texture0"); + + //LOGE("e2 %x", glGetError()); + glLinkProgram(pgm); + //LOGE("e3 %x", glGetError()); + GLint linkStatus = GL_FALSE; + glGetProgramiv(pgm, GL_LINK_STATUS, &linkStatus); + if (linkStatus != GL_TRUE) { + GLint bufLength = 0; + glGetProgramiv(pgm, GL_INFO_LOG_LENGTH, &bufLength); + if (bufLength) { + char* buf = (char*) malloc(bufLength); + if (buf) { + glGetProgramInfoLog(pgm, bufLength, NULL, buf); + LOGE("Could not link program:\n%s\n", buf); + free(buf); + } + } + glDeleteProgram(pgm); + rsc->setError(RS_ERROR_FATAL_PROGRAM_LINK, "Error linking GL Programs"); + return false; + } + + for (uint32_t ct=0; ct < e->vtxAttrCount; ct++) { + e->vtxAttrs[ct].slot = glGetAttribLocation(pgm, vtx->getAttribName(ct)); + e->vtxAttrs[ct].name = vtx->getAttribName(ct).string(); + if (rsc->props.mLogShaders) { + LOGV("vtx A %i, %s = %d\n", ct, vtx->getAttribName(ct).string(), e->vtxAttrs[ct].slot); + } + } + + populateUniformData(vtx, pgm, e->vtxUniforms); + populateUniformData(frag, pgm, e->fragUniforms); + + // Only populate this list if we have arrays in our uniforms + UniformQueryData **uniformList = NULL; + GLint numUniforms = 0; + bool hasArrays = hasArrayUniforms(vtx, frag); + if (hasArrays) { + // Get the number of active uniforms and the length of the longest name + glGetProgramiv(pgm, GL_ACTIVE_UNIFORMS, &numUniforms); + GLint maxNameLength = 0; + glGetProgramiv(pgm, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxNameLength); + if (numUniforms > 0 && maxNameLength > 0) { + uniformList = new UniformQueryData*[numUniforms]; + // Iterate over all the uniforms and build the list we + // can later use to match our uniforms to + for (uint32_t ct = 0; ct < (uint32_t)numUniforms; ct++) { + uniformList[ct] = new UniformQueryData(maxNameLength); + glGetActiveUniform(pgm, ct, maxNameLength, &uniformList[ct]->writtenLength, + &uniformList[ct]->arraySize, &uniformList[ct]->type, + uniformList[ct]->name); + //LOGE("GL UNI idx=%u, arraySize=%u, name=%s", ct, + // uniformList[ct]->arraySize, uniformList[ct]->name); + } + } + } + + // We now know the highest index of all of the array uniforms + // and we need to update our cache to reflect that + // we may have declared [n], but only m < n elements are used + updateUniformArrayData(rsc, vtx, pgm, e->vtxUniforms, "vtx", + uniformList, (uint32_t)numUniforms); + updateUniformArrayData(rsc, frag, pgm, e->fragUniforms, "frag", + uniformList, (uint32_t)numUniforms); + + // Clean up the uniform data from GL + if (uniformList != NULL) { + for (uint32_t ct = 0; ct < (uint32_t)numUniforms; ct++) { + delete uniformList[ct]; + } + delete[] uniformList; + uniformList = NULL; + } + } + + //LOGV("SC made program %i", e->program); + glUseProgram(e->program); + rsdGLCheckError(rsc, "RsdShaderCache::link (miss)"); + + return true; +} + +int32_t RsdShaderCache::vtxAttribSlot(const String8 &attrName) const { + for (uint32_t ct=0; ct < mCurrent->vtxAttrCount; ct++) { + if (attrName == mCurrent->vtxAttrs[ct].name) { + return mCurrent->vtxAttrs[ct].slot; + } + } + return -1; +} + +void RsdShaderCache::cleanupVertex(uint32_t id) { + int32_t numEntries = (int32_t)mEntries.size(); + for (int32_t ct = 0; ct < numEntries; ct ++) { + if (mEntries[ct]->vtx == id) { + glDeleteProgram(mEntries[ct]->program); + + delete mEntries[ct]; + mEntries.removeAt(ct); + numEntries = (int32_t)mEntries.size(); + ct --; + } + } +} + +void RsdShaderCache::cleanupFragment(uint32_t id) { + int32_t numEntries = (int32_t)mEntries.size(); + for (int32_t ct = 0; ct < numEntries; ct ++) { + if (mEntries[ct]->frag == id) { + glDeleteProgram(mEntries[ct]->program); + + delete mEntries[ct]; + mEntries.removeAt(ct); + numEntries = (int32_t)mEntries.size(); + ct --; + } + } +} + +void RsdShaderCache::cleanupAll() { + for (uint32_t ct=0; ct < mEntries.size(); ct++) { + glDeleteProgram(mEntries[ct]->program); + free(mEntries[ct]); + } + mEntries.clear(); +} + diff --git a/libs/rs/driver/rsdShaderCache.h b/libs/rs/driver/rsdShaderCache.h new file mode 100644 index 0000000..17ee3e8 --- /dev/null +++ b/libs/rs/driver/rsdShaderCache.h @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2011 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. + */ + +#ifndef ANDROID_RSD_SHADER_CACHE_H +#define ANDROID_RSD_SHADER_CACHE_H + +namespace android { +namespace renderscript { + +class Context; + +} +} + +#include <utils/String8.h> +#include <utils/Vector.h> +class RsdShader; + +// --------------------------------------------------------------------------- + +// An element is a group of Components that occupies one cell in a structure. +class RsdShaderCache { +public: + RsdShaderCache(); + virtual ~RsdShaderCache(); + + void setActiveVertex(RsdShader *pv) { + mVertexDirty = true; + mVertex = pv; + } + + void setActiveFragment(RsdShader *pf) { + mFragmentDirty = true; + mFragment = pf; + } + + bool setup(const android::renderscript::Context *rsc); + + void cleanupVertex(uint32_t id); + void cleanupFragment(uint32_t id); + + void cleanupAll(); + + int32_t vtxAttribSlot(const android::String8 &attrName) const; + int32_t vtxUniformSlot(uint32_t a) const {return mCurrent->vtxUniforms[a].slot;} + uint32_t vtxUniformSize(uint32_t a) const {return mCurrent->vtxUniforms[a].arraySize;} + int32_t fragUniformSlot(uint32_t a) const {return mCurrent->fragUniforms[a].slot;} + uint32_t fragUniformSize(uint32_t a) const {return mCurrent->fragUniforms[a].arraySize;} + +protected: + bool link(const android::renderscript::Context *rsc); + bool mFragmentDirty; + bool mVertexDirty; + RsdShader *mVertex; + RsdShader *mFragment; + + struct UniformQueryData { + char *name; + uint32_t nameLength; + int32_t writtenLength; + int32_t arraySize; + uint32_t type; + UniformQueryData(uint32_t maxName) { + name = NULL; + nameLength = maxName; + if (nameLength > 0 ) { + name = new char[nameLength]; + } + } + ~UniformQueryData() { + if (name != NULL) { + delete[] name; + name = NULL; + } + } + }; + struct UniformData { + int32_t slot; + uint32_t arraySize; + }; + struct AttrData { + int32_t slot; + const char* name; + }; + struct ProgramEntry { + ProgramEntry(uint32_t numVtxAttr, uint32_t numVtxUnis, + uint32_t numFragUnis) : vtx(0), frag(0), program(0), vtxAttrCount(0), + vtxAttrs(0), vtxUniforms(0), fragUniforms(0) { + vtxAttrCount = numVtxAttr; + if (numVtxAttr) { + vtxAttrs = new AttrData[numVtxAttr]; + } + if (numVtxUnis) { + vtxUniforms = new UniformData[numVtxUnis]; + } + if (numFragUnis) { + fragUniforms = new UniformData[numFragUnis]; + } + } + ~ProgramEntry() { + if (vtxAttrs) { + delete[] vtxAttrs; + vtxAttrs = NULL; + } + if (vtxUniforms) { + delete[] vtxUniforms; + vtxUniforms = NULL; + } + if (fragUniforms) { + delete[] fragUniforms; + fragUniforms = NULL; + } + } + uint32_t vtx; + uint32_t frag; + uint32_t program; + uint32_t vtxAttrCount; + AttrData *vtxAttrs; + UniformData *vtxUniforms; + UniformData *fragUniforms; + }; + android::Vector<ProgramEntry*> mEntries; + ProgramEntry *mCurrent; + + bool hasArrayUniforms(RsdShader *vtx, RsdShader *frag); + void populateUniformData(RsdShader *prog, uint32_t linkedID, UniformData *data); + void updateUniformArrayData(const android::renderscript::Context *rsc, + RsdShader *prog, uint32_t linkedID, + UniformData *data, const char* logTag, + UniformQueryData **uniformList, uint32_t uniListSize); +}; + + +#endif //ANDROID_RSD_SHADER_CACHE_H + + + + diff --git a/libs/rs/driver/rsdVertexArray.cpp b/libs/rs/driver/rsdVertexArray.cpp new file mode 100644 index 0000000..62ec107 --- /dev/null +++ b/libs/rs/driver/rsdVertexArray.cpp @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2011 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 <rs_hal.h> +#include <rsContext.h> + +#include <GLES/gl.h> +#include <GLES2/gl2.h> + +#include "rsdGL.h" +#include "rsdCore.h" +#include "rsdVertexArray.h" +#include "rsdShaderCache.h" + +using namespace android; +using namespace android::renderscript; + +RsdVertexArray::RsdVertexArray(const Attrib *attribs, uint32_t numAttribs) { + mAttribs = attribs; + mCount = numAttribs; +} + +RsdVertexArray::~RsdVertexArray() { +} + +RsdVertexArray::Attrib::Attrib() { + clear(); +} + +void RsdVertexArray::Attrib::clear() { + buffer = 0; + offset = 0; + type = 0; + size = 0; + stride = 0; + ptr = NULL; + normalized = false; + name.setTo(""); +} + +void RsdVertexArray::Attrib::set(uint32_t type, uint32_t size, uint32_t stride, + bool normalized, uint32_t offset, + const char *name) { + clear(); + this->type = type; + this->size = size; + this->offset = offset; + this->normalized = normalized; + this->stride = stride; + this->name.setTo(name); +} + +void RsdVertexArray::logAttrib(uint32_t idx, uint32_t slot) const { + if (idx == 0) { + LOGV("Starting vertex attribute binding"); + } + LOGV("va %i: slot=%i name=%s buf=%i ptr=%p size=%i type=0x%x stride=0x%x norm=%i offset=0x%x", + idx, slot, + mAttribs[idx].name.string(), + mAttribs[idx].buffer, + mAttribs[idx].ptr, + mAttribs[idx].size, + mAttribs[idx].type, + mAttribs[idx].stride, + mAttribs[idx].normalized, + mAttribs[idx].offset); +} + +void RsdVertexArray::setup(const Context *rsc) const { + + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + RsdVertexArrayState *state = dc->gl.vertexArrayState; + RsdShaderCache *sc = dc->gl.shaderCache; + + rsdGLCheckError(rsc, "RsdVertexArray::setup start"); + uint32_t maxAttrs = state->mAttrsEnabledSize; + + for (uint32_t ct=1; ct < maxAttrs; ct++) { + if(state->mAttrsEnabled[ct]) { + glDisableVertexAttribArray(ct); + state->mAttrsEnabled[ct] = false; + } + } + + rsdGLCheckError(rsc, "RsdVertexArray::setup disabled"); + for (uint32_t ct=0; ct < mCount; ct++) { + int32_t slot = sc->vtxAttribSlot(mAttribs[ct].name); + if (rsc->props.mLogShadersAttr) { + logAttrib(ct, slot); + } + if (slot < 0 || slot >= (int32_t)maxAttrs) { + continue; + } + glEnableVertexAttribArray(slot); + state->mAttrsEnabled[slot] = true; + glBindBuffer(GL_ARRAY_BUFFER, mAttribs[ct].buffer); + glVertexAttribPointer(slot, + mAttribs[ct].size, + mAttribs[ct].type, + mAttribs[ct].normalized, + mAttribs[ct].stride, + mAttribs[ct].ptr + mAttribs[ct].offset); + } + rsdGLCheckError(rsc, "RsdVertexArray::setup done"); +} +//////////////////////////////////////////// +RsdVertexArrayState::RsdVertexArrayState() { + mAttrsEnabled = NULL; + mAttrsEnabledSize = 0; +} + +RsdVertexArrayState::~RsdVertexArrayState() { + if (mAttrsEnabled) { + delete[] mAttrsEnabled; + mAttrsEnabled = NULL; + } +} +void RsdVertexArrayState::init(uint32_t maxAttrs) { + mAttrsEnabledSize = maxAttrs; + mAttrsEnabled = new bool[mAttrsEnabledSize]; + for (uint32_t ct = 0; ct < mAttrsEnabledSize; ct++) { + mAttrsEnabled[ct] = false; + } +} + diff --git a/libs/rs/driver/rsdVertexArray.h b/libs/rs/driver/rsdVertexArray.h new file mode 100644 index 0000000..3e807a3 --- /dev/null +++ b/libs/rs/driver/rsdVertexArray.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2011 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. + */ + +#ifndef ANDROID_RSD_VERTEX_ARRAY_H +#define ANDROID_RSD_VERTEX_ARRAY_H + +namespace android { +namespace renderscript { + +class Context; + +} +} + +#include <utils/String8.h> + +// An element is a group of Components that occupies one cell in a structure. +class RsdVertexArray { +public: + class Attrib { + public: + uint32_t buffer; + const uint8_t * ptr; + uint32_t offset; + uint32_t type; + uint32_t size; + uint32_t stride; + bool normalized; + android::String8 name; + + Attrib(); + void clear(); + void set(uint32_t type, uint32_t size, uint32_t stride, bool normalized, uint32_t offset, const char *name); + }; + + RsdVertexArray(const Attrib *attribs, uint32_t numAttribs); + virtual ~RsdVertexArray(); + + void setup(const android::renderscript::Context *rsc) const; + void logAttrib(uint32_t idx, uint32_t slot) const; + +protected: + void clear(uint32_t index); + uint32_t mActiveBuffer; + const uint8_t * mActivePointer; + uint32_t mCount; + + const Attrib *mAttribs; +}; + + +class RsdVertexArrayState { +public: + RsdVertexArrayState(); + ~RsdVertexArrayState(); + void init(uint32_t maxAttrs); + + bool *mAttrsEnabled; + uint32_t mAttrsEnabledSize; +}; + + +#endif //ANDROID_RSD_VERTEX_ARRAY_H + + + |