diff options
25 files changed, 1293 insertions, 117 deletions
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java index 4b8c58e..9ac1a00 100644 --- a/graphics/java/android/renderscript/Allocation.java +++ b/graphics/java/android/renderscript/Allocation.java @@ -99,6 +99,14 @@ public class Allocation extends BaseObj { */ public static final int USAGE_GRAPHICS_CONSTANTS = 0x0008; + /** + * @hide + * USAGE_GRAPHICS_RENDER_TARGET The allcation will be used as a + * target for offscreen rendering + * + */ + public static final int USAGE_GRAPHICS_RENDER_TARGET = 0x0010; + /** * Controls mipmap behavior when using the bitmap creation and @@ -137,7 +145,8 @@ public class Allocation extends BaseObj { if ((usage & ~(USAGE_SCRIPT | USAGE_GRAPHICS_TEXTURE | USAGE_GRAPHICS_VERTEX | - USAGE_GRAPHICS_CONSTANTS)) != 0) { + USAGE_GRAPHICS_CONSTANTS | + USAGE_GRAPHICS_RENDER_TARGET)) != 0) { throw new RSIllegalArgumentException("Unknown usage specified."); } mType = t; diff --git a/graphics/java/android/renderscript/Element.java b/graphics/java/android/renderscript/Element.java index fae22f0..0c1ad2a 100644 --- a/graphics/java/android/renderscript/Element.java +++ b/graphics/java/android/renderscript/Element.java @@ -124,7 +124,8 @@ public class Element extends BaseObj { PIXEL_A (8), PIXEL_LA (9), PIXEL_RGB (10), - PIXEL_RGBA (11); + PIXEL_RGBA (11), + PIXEL_DEPTH (12); int mID; DataKind(int id) { @@ -536,10 +537,12 @@ public class Element extends BaseObj { dk == DataKind.PIXEL_A || dk == DataKind.PIXEL_LA || dk == DataKind.PIXEL_RGB || - dk == DataKind.PIXEL_RGBA)) { + dk == DataKind.PIXEL_RGBA || + dk == DataKind.PIXEL_DEPTH)) { throw new RSIllegalArgumentException("Unsupported DataKind"); } if (!(dt == DataType.UNSIGNED_8 || + dt == DataType.UNSIGNED_16 || dt == DataType.UNSIGNED_5_6_5 || dt == DataType.UNSIGNED_4_4_4_4 || dt == DataType.UNSIGNED_5_5_5_1)) { @@ -554,16 +557,25 @@ public class Element extends BaseObj { if (dt == DataType.UNSIGNED_4_4_4_4 && dk != DataKind.PIXEL_RGBA) { throw new RSIllegalArgumentException("Bad kind and type combo"); } + if (dt == DataType.UNSIGNED_16 && + dk != DataKind.PIXEL_DEPTH) { + throw new RSIllegalArgumentException("Bad kind and type combo"); + } int size = 1; - if (dk == DataKind.PIXEL_LA) { + switch (dk) { + case PIXEL_LA: size = 2; - } - if (dk == DataKind.PIXEL_RGB) { + break; + case PIXEL_RGB: size = 3; - } - if (dk == DataKind.PIXEL_RGBA) { + break; + case PIXEL_RGBA: size = 4; + break; + case PIXEL_DEPTH: + size = 2; + break; } boolean norm = true; diff --git a/libs/rs/Android.mk b/libs/rs/Android.mk index 14152d8..9100693 100644 --- a/libs/rs/Android.mk +++ b/libs/rs/Android.mk @@ -90,6 +90,7 @@ LOCAL_SRC_FILES:= \ rsContext.cpp \ rsDevice.cpp \ rsElement.cpp \ + rsFBOCache.cpp \ rsFileA3D.cpp \ rsFont.cpp \ rsLocklessFifo.cpp \ diff --git a/libs/rs/RenderScriptDefines.h b/libs/rs/RenderScriptDefines.h index 4e1ac88..bb275b5 100644 --- a/libs/rs/RenderScriptDefines.h +++ b/libs/rs/RenderScriptDefines.h @@ -84,6 +84,7 @@ enum RsAllocationUsageType { RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE = 0x0002, RS_ALLOCATION_USAGE_GRAPHICS_VERTEX = 0x0004, RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS = 0x0008, + RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET = 0x0010, RS_ALLOCATION_USAGE_ALL = 0x000F }; @@ -147,6 +148,7 @@ enum RsDataKind { RS_KIND_PIXEL_LA, RS_KIND_PIXEL_RGB, RS_KIND_PIXEL_RGBA, + RS_KIND_PIXEL_DEPTH, }; enum RsSamplerParam { diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp index b8ddb0b..6b37e03 100644 --- a/libs/rs/rsAllocation.cpp +++ b/libs/rs/rsAllocation.cpp @@ -56,7 +56,8 @@ void Allocation::init(Context *rsc, const Type *type) { mTextureID = 0; mBufferID = 0; - mUploadDefered = false; + mRenderTargetID = 0; + mUploadDeferred = false; mUserBitmapCallback = NULL; mUserBitmapCallbackData = NULL; @@ -93,6 +94,10 @@ Allocation::~Allocation() { glDeleteTextures(1, &mTextureID); mTextureID = 0; } + if (mRenderTargetID) { + glDeleteRenderbuffers(1, &mRenderTargetID); + mRenderTargetID = 0; + } #endif //ANDROID_RS_SERIALIZE } @@ -112,9 +117,14 @@ bool Allocation::fixAllocation() { return false; } -void Allocation::deferedUploadToTexture(const Context *rsc) { +void Allocation::deferredUploadToTexture(const Context *rsc) { mHal.state.usageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE; - mUploadDefered = true; + mUploadDeferred = true; +} + +void Allocation::deferredAllocateRenderTarget(const Context *rsc) { + mHal.state.usageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET; + mUploadDeferred = true; } uint32_t Allocation::getGLTarget() const { @@ -155,8 +165,11 @@ void Allocation::syncAll(Context *rsc, RsAllocationUsageType src) { if (getIsBufferObject()) { uploadToBufferObject(rsc); } + if (getIsRenderTarget() && !getIsTexture()) { + allocateRenderTarget(rsc); + } - mUploadDefered = false; + mUploadDeferred = false; } void Allocation::uploadToTexture(const Context *rsc) { @@ -184,7 +197,7 @@ void Allocation::uploadToTexture(const Context *rsc) { // Force a crash to 1: restart the app, 2: make sure we get a bugreport. LOGE("Upload to texture failed to gen mTextureID"); rsc->dumpDebug(); - mUploadDefered = true; + mUploadDeferred = true; return; } isFirstUpload = true; @@ -200,6 +213,32 @@ void Allocation::uploadToTexture(const Context *rsc) { #endif //ANDROID_RS_SERIALIZE } +void Allocation::allocateRenderTarget(const Context *rsc) { +#ifndef ANDROID_RS_SERIALIZE + mHal.state.usageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET; + + GLenum format = mHal.state.type->getElement()->getComponent().getGLFormat(); + if (!format) { + return; + } + + if (!mRenderTargetID) { + glGenRenderbuffers(1, &mRenderTargetID); + + if (!mRenderTargetID) { + // This should generally not happen + LOGE("allocateRenderTarget failed to gen mRenderTargetID"); + rsc->dumpDebug(); + return; + } + glBindRenderbuffer(GL_RENDERBUFFER, mRenderTargetID); + glRenderbufferStorage(GL_RENDERBUFFER, format, + mHal.state.type->getDimX(), + mHal.state.type->getDimY()); + } +#endif //ANDROID_RS_SERIALIZE +} + #ifndef ANDROID_RS_SERIALIZE const static GLenum gFaceOrder[] = { GL_TEXTURE_CUBE_MAP_POSITIVE_X, @@ -271,9 +310,9 @@ void Allocation::upload2DTexture(bool isFirstUpload) { #endif //ANDROID_RS_SERIALIZE } -void Allocation::deferedUploadToBufferObject(const Context *rsc) { +void Allocation::deferredUploadToBufferObject(const Context *rsc) { mHal.state.usageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_VERTEX; - mUploadDefered = true; + mUploadDeferred = true; } void Allocation::uploadToBufferObject(const Context *rsc) { @@ -288,7 +327,7 @@ void Allocation::uploadToBufferObject(const Context *rsc) { } if (!mBufferID) { LOGE("Upload to buffer object failed"); - mUploadDefered = true; + mUploadDeferred = true; return; } GLenum target = (GLenum)getGLTarget(); @@ -300,7 +339,7 @@ void Allocation::uploadToBufferObject(const Context *rsc) { } void Allocation::uploadCheck(Context *rsc) { - if (mUploadDefered) { + if (mUploadDeferred) { syncAll(rsc, RS_ALLOCATION_USAGE_SCRIPT); } } @@ -329,7 +368,7 @@ void Allocation::data(Context *rsc, uint32_t xoff, uint32_t lod, memcpy(ptr, data, size); sendDirty(); - mUploadDefered = true; + mUploadDeferred = true; } void Allocation::data(Context *rsc, uint32_t xoff, uint32_t yoff, uint32_t lod, RsAllocationCubemapFace face, @@ -362,7 +401,7 @@ void Allocation::data(Context *rsc, uint32_t xoff, uint32_t yoff, uint32_t lod, dst += destW * eSize; } sendDirty(); - mUploadDefered = true; + mUploadDeferred = true; } else { update2DTexture(data, xoff, yoff, lod, face, w, h); } @@ -407,7 +446,7 @@ void Allocation::elementData(Context *rsc, uint32_t x, const void *data, memcpy(ptr, data, sizeBytes); sendDirty(); - mUploadDefered = true; + mUploadDeferred = true; } void Allocation::elementData(Context *rsc, uint32_t x, uint32_t y, @@ -450,7 +489,7 @@ void Allocation::elementData(Context *rsc, uint32_t x, uint32_t y, memcpy(ptr, data, sizeBytes); sendDirty(); - mUploadDefered = true; + mUploadDeferred = true; } void Allocation::addProgramToDirty(const Program *p) { @@ -617,12 +656,12 @@ namespace renderscript { void rsi_AllocationUploadToTexture(Context *rsc, RsAllocation va, bool genmip, uint32_t baseMipLevel) { Allocation *alloc = static_cast<Allocation *>(va); - alloc->deferedUploadToTexture(rsc); + alloc->deferredUploadToTexture(rsc); } void rsi_AllocationUploadToBufferObject(Context *rsc, RsAllocation va) { Allocation *alloc = static_cast<Allocation *>(va); - alloc->deferedUploadToBufferObject(rsc); + alloc->deferredUploadToBufferObject(rsc); } static void mip565(const Adapter2D &out, const Adapter2D &in) { @@ -792,7 +831,6 @@ RsAllocation rsaAllocationCreateTyped(RsContext con, RsType vtype, return alloc; } - RsAllocation rsaAllocationCreateFromBitmap(RsContext con, RsType vtype, RsAllocationMipmapControl mips, const void *data, uint32_t usages) { @@ -811,7 +849,7 @@ RsAllocation rsaAllocationCreateFromBitmap(RsContext con, RsType vtype, rsaAllocationGenerateScriptMips(rsc, texAlloc); } - texAlloc->deferedUploadToTexture(rsc); + texAlloc->deferredUploadToTexture(rsc); return texAlloc; } @@ -852,7 +890,7 @@ RsAllocation rsaAllocationCubeCreateFromBitmap(RsContext con, RsType vtype, rsaAllocationGenerateScriptMips(rsc, texAlloc); } - texAlloc->deferedUploadToTexture(rsc); + texAlloc->deferredUploadToTexture(rsc); return texAlloc; } diff --git a/libs/rs/rsAllocation.h b/libs/rs/rsAllocation.h index e63140c..d334841 100644 --- a/libs/rs/rsAllocation.h +++ b/libs/rs/rsAllocation.h @@ -71,13 +71,17 @@ public: void syncAll(Context *rsc, RsAllocationUsageType src); - void deferedUploadToTexture(const Context *rsc); + void deferredUploadToTexture(const Context *rsc); void uploadToTexture(const Context *rsc); uint32_t getTextureID() const {return mTextureID;} + void deferredAllocateRenderTarget(const Context *rsc); + void allocateRenderTarget(const Context *rsc); + uint32_t getRenderTargetID() const {return mRenderTargetID;} + uint32_t getGLTarget() const; - void deferedUploadToBufferObject(const Context *rsc); + void deferredUploadToBufferObject(const Context *rsc); void uploadToBufferObject(const Context *rsc); uint32_t getBufferObjectID() const {return mBufferID;} @@ -118,6 +122,9 @@ public: bool getIsTexture() const { return (mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE) != 0; } + bool getIsRenderTarget() const { + return (mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET) != 0; + } bool getIsBufferObject() const { return (mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_VERTEX) != 0; } @@ -161,7 +168,10 @@ protected: // is allowed. uint32_t mBufferID; - bool mUploadDefered; + // Is this a legal structure to be used as an FBO render target + uint32_t mRenderTargetID; + + bool mUploadDeferred; private: void init(Context *rsc, const Type *); diff --git a/libs/rs/rsComponent.cpp b/libs/rs/rsComponent.cpp index 4c4987a..e2ae043 100644 --- a/libs/rs/rsComponent.cpp +++ b/libs/rs/rsComponent.cpp @@ -18,6 +18,7 @@ #ifndef ANDROID_RS_SERIALIZE #include <GLES/gl.h> +#include <GLES2/gl2.h> #endif using namespace android; @@ -207,6 +208,7 @@ uint32_t Component::getGLFormat() const { 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; } #endif //ANDROID_RS_SERIALIZE diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp index c761c75..d727ba1 100644 --- a/libs/rs/rsContext.cpp +++ b/libs/rs/rsContext.cpp @@ -409,6 +409,7 @@ bool Context::setupCheck() { mFragment->setupGL2(this, &mStateFragment, &mShaderCache); mRaster->setupGL2(this, &mStateRaster); mVertex->setupGL2(this, &mStateVertex, &mShaderCache); + mFBOCache.setupGL2(this); return true; } diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h index 72574a6..eacfdf7 100644 --- a/libs/rs/rsContext.h +++ b/libs/rs/rsContext.h @@ -38,6 +38,7 @@ #include "rsProgramRaster.h" #include "rsProgramVertex.h" #include "rsShaderCache.h" +#include "rsFBOCache.h" #include "rsVertexArray.h" #include "rsgApiStructs.h" @@ -119,6 +120,7 @@ public: ScriptCState mScriptC; ShaderCache mShaderCache; + FBOCache mFBOCache; void swapBuffers(); void setRootScript(Script *); diff --git a/libs/rs/rsFBOCache.cpp b/libs/rs/rsFBOCache.cpp new file mode 100644 index 0000000..78aa8ce --- /dev/null +++ b/libs/rs/rsFBOCache.cpp @@ -0,0 +1,209 @@ +/* + * 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 "rsFBOCache.h" + +#include "rsContext.h" +#include "rsAllocation.h" + +#ifndef ANDROID_RS_SERIALIZE +#include <GLES/gl.h> +#include <GLES2/gl2.h> +#endif //ANDROID_RS_SERIALIZE + +using namespace android; +using namespace android::renderscript; + + +FBOCache::FBOCache() { + mFBOId = 0; + mDirty = false; + mMaxTargets = 1; + mColorTargets = new ObjectBaseRef<Allocation>[mMaxTargets]; +} + +FBOCache::~FBOCache() { + delete[] mColorTargets; +#ifndef ANDROID_RS_SERIALIZE + if(mFBOId != 0) { + glDeleteFramebuffers(1, &mFBOId); + } +#endif //ANDROID_RS_SERIALIZE +} + +void FBOCache::bindColorTarget(Context *rsc, Allocation *a, uint32_t slot) { + if (slot >= mMaxTargets) { + LOGE("Invalid render target index"); + return; + } + if (a != NULL) { + if (!a->getIsTexture()) { + LOGE("Invalid Color Target"); + return; + } + if (a->getIsTexture()) { + if (a->getTextureID() == 0) { + a->deferredUploadToTexture(rsc); + } + } else if (a->getRenderTargetID() == 0) { + a->deferredAllocateRenderTarget(rsc); + } + } + mColorTargets[slot].set(a); + mDirty = true; +} + +void FBOCache::bindDepthTarget(Context *rsc, Allocation *a) { + if (a != NULL) { + if (!a->getIsRenderTarget()) { + LOGE("Invalid Depth Target"); + return; + } + if (a->getIsTexture()) { + if (a->getTextureID() == 0) { + a->deferredUploadToTexture(rsc); + } + } else if (a->getRenderTargetID() == 0) { + a->deferredAllocateRenderTarget(rsc); + } + } + mDepthTarget.set(a); + mDirty = true; +} + +void FBOCache::resetAll(Context *) { + for (uint32_t i = 0; i < mMaxTargets; i ++) { + mColorTargets[i].set(NULL); + } + mDepthTarget.set(NULL); + mDirty = true; +} + +bool FBOCache::renderToFramebuffer() { + if (mDepthTarget.get() != NULL) { + return false; + } + + for (uint32_t i = 0; i < mMaxTargets; i ++) { + if (mColorTargets[i].get() != NULL) { + return false; + } + } + return true; +} + +void FBOCache::checkError(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 FBOCache::setDepthAttachment(Context *rsc) { +#ifndef ANDROID_RS_SERIALIZE + if (mDepthTarget.get() != NULL) { + mDepthTarget->uploadCheck(rsc); + if (mDepthTarget->getIsTexture()) { + uint32_t texID = mDepthTarget->getTextureID(); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_TEXTURE_2D, texID, 0); + } else { + uint32_t texID = mDepthTarget->getRenderTargetID(); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, texID); + } + } else { + // Reset last attachment + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_TEXTURE_2D, 0, 0); + } +#endif //ANDROID_RS_SERIALIZE +} + +void FBOCache::setColorAttachment(Context *rsc) { +#ifndef ANDROID_RS_SERIALIZE + // Now attach color targets + for (uint32_t i = 0; i < mMaxTargets; i ++) { + uint32_t texID = 0; + if (mColorTargets[i].get() != NULL) { + mColorTargets[i]->uploadCheck(rsc); + if (mColorTargets[i]->getIsTexture()) { + uint32_t texID = mColorTargets[i]->getTextureID(); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, + GL_TEXTURE_2D, texID, 0); + } else { + uint32_t texID = mDepthTarget->getRenderTargetID(); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, + GL_RENDERBUFFER, texID); + } + } 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); + } + } +#endif //ANDROID_RS_SERIALIZE +} + +void FBOCache::setupGL2(Context *rsc) { +#ifndef ANDROID_RS_SERIALIZE + if (!mDirty) { + return; + } + + bool framebuffer = renderToFramebuffer(); + + if (!framebuffer) { + if(mFBOId == 0) { + glGenFramebuffers(1, &mFBOId); + } + glBindFramebuffer(GL_FRAMEBUFFER, mFBOId); + + setDepthAttachment(rsc); + setColorAttachment(rsc); + + glViewport(0, 0, mColorTargets[0]->getType()->getDimX(), + mColorTargets[0]->getType()->getDimY()); + + checkError(rsc); + } else { + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glViewport(0, 0, rsc->getWidth(), rsc->getHeight()); + } +#endif //ANDROID_RS_SERIALIZE +} diff --git a/libs/rs/rsFBOCache.h b/libs/rs/rsFBOCache.h new file mode 100644 index 0000000..9a0a3b6 --- /dev/null +++ b/libs/rs/rsFBOCache.h @@ -0,0 +1,57 @@ +/* + * 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_FRAME_BUFFER_OBJECT_CACHE_H +#define ANDROID_FRAME_BUFFER_OBJECT_CACHE_H + +#include "rsObjectBase.h" + +// --------------------------------------------------------------------------- +namespace android { +namespace renderscript { + +class Allocation; + +class FBOCache { +public: + FBOCache(); + ~FBOCache(); + + void bindColorTarget(Context *rsc, Allocation *a, uint32_t slot); + void bindDepthTarget(Context *, Allocation *a); + void resetAll(Context *); + + void setupGL2(Context *); + +protected: + + bool mDirty; + uint32_t mMaxTargets; + void checkError(Context *); + void setColorAttachment(Context *rsc); + void setDepthAttachment(Context *rsc); + bool renderToFramebuffer(); + ObjectBaseRef<Allocation> *mColorTargets; + ObjectBaseRef<Allocation> mDepthTarget; + + uint32_t mFBOId; + +}; + +} // renderscript +} // android + +#endif //ANDROID_FRAME_BUFFER_OBJECT_CACHE_H diff --git a/libs/rs/rsFont.cpp b/libs/rs/rsFont.cpp index 01dbab8..595c89a 100644 --- a/libs/rs/rsFont.cpp +++ b/libs/rs/rsFont.cpp @@ -566,7 +566,7 @@ void FontState::initVertexArrayBuffers() { indexPtr[i6 + 5] = i4 + 3; } - indexAlloc->deferedUploadToBufferObject(mRSC); + indexAlloc->deferredUploadToBufferObject(mRSC); mIndexBuffer.set(indexAlloc); const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3); diff --git a/libs/rs/rsMesh.cpp b/libs/rs/rsMesh.cpp index 76fe62d..e29c800 100644 --- a/libs/rs/rsMesh.cpp +++ b/libs/rs/rsMesh.cpp @@ -282,13 +282,13 @@ void Mesh::renderPrimitiveRange(Context *rsc, uint32_t primIndex, uint32_t start void Mesh::uploadAll(Context *rsc) { for (uint32_t ct = 0; ct < mVertexBufferCount; ct ++) { if (mVertexBuffers[ct].get()) { - mVertexBuffers[ct]->deferedUploadToBufferObject(rsc); + mVertexBuffers[ct]->deferredUploadToBufferObject(rsc); } } for (uint32_t ct = 0; ct < mPrimitivesCount; ct ++) { if (mPrimitives[ct]->mIndexBuffer.get()) { - mPrimitives[ct]->mIndexBuffer->deferedUploadToBufferObject(rsc); + mPrimitives[ct]->mIndexBuffer->deferredUploadToBufferObject(rsc); } } } diff --git a/libs/rs/rsScriptC_LibGL.cpp b/libs/rs/rsScriptC_LibGL.cpp index 4047049..1ed0f31 100644 --- a/libs/rs/rsScriptC_LibGL.cpp +++ b/libs/rs/rsScriptC_LibGL.cpp @@ -86,6 +86,33 @@ static void SC_bindProgramRaster(RsProgramRaster pv) { rsi_ContextBindProgramRaster(rsc, pv); } +static void SC_bindFrameBufferObjectColorTarget(RsAllocation va, uint32_t slot) { + CHECK_OBJ(va); + GET_TLS(); + rsc->mFBOCache.bindColorTarget(rsc, static_cast<Allocation *>(va), slot); +} + +static void SC_bindFrameBufferObjectDepthTarget(RsAllocation va) { + CHECK_OBJ(va); + GET_TLS(); + rsc->mFBOCache.bindDepthTarget(rsc, static_cast<Allocation *>(va)); +} + +static void SC_clearFrameBufferObjectColorTarget(uint32_t slot) { + GET_TLS(); + rsc->mFBOCache.bindColorTarget(rsc, NULL, slot); +} + +static void SC_clearFrameBufferObjectDepthTarget() { + GET_TLS(); + rsc->mFBOCache.bindDepthTarget(rsc, NULL); +} + +static void SC_clearFrameBufferObjectTargets() { + GET_TLS(); + rsc->mFBOCache.resetAll(rsc); +} + ////////////////////////////////////////////////////////////////////////////// // VP ////////////////////////////////////////////////////////////////////////////// @@ -275,6 +302,10 @@ static void SC_color(float r, float g, float b, float a) { pf->setConstantColor(rsc, r, g, b, a); } +static void SC_finish() { + glFinish(); +} + static void SC_allocationSyncAll(RsAllocation va) { CHECK_OBJ(va); GET_TLS(); @@ -291,6 +322,7 @@ static void SC_allocationSyncAll2(RsAllocation va, RsAllocationUsageType source) static void SC_ClearColor(float r, float g, float b, float a) { GET_TLS(); + rsc->mFBOCache.setupGL2(rsc); rsc->setupProgramStore(); glClearColor(r, g, b, a); @@ -299,6 +331,7 @@ static void SC_ClearColor(float r, float g, float b, float a) { static void SC_ClearDepth(float v) { GET_TLS(); + rsc->mFBOCache.setupGL2(rsc); rsc->setupProgramStore(); glClearDepthf(v); @@ -444,8 +477,15 @@ static ScriptCState::SymbolTable_t gSyms[] = { { "_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 }, + // misc { "_Z5colorffff", (void *)&SC_color, false }, + { "_Z9rsgFinishv", (void *)&SC_finish, false }, { NULL, NULL, false } }; diff --git a/libs/rs/scriptc/rs_graphics.rsh b/libs/rs/scriptc/rs_graphics.rsh index 67ffc3d..d53bc95 100644 --- a/libs/rs/scriptc/rs_graphics.rsh +++ b/libs/rs/scriptc/rs_graphics.rsh @@ -1,6 +1,46 @@ #ifndef __RS_GRAPHICS_RSH__ #define __RS_GRAPHICS_RSH__ +/** + * Set the color target used for all subsequent rendering calls + * @param colorTarget + * @param slot + */ +extern void __attribute__((overloadable)) + rsgBindColorTarget(rs_allocation colorTarget, uint slot); + +/** + * Clear the previously set color target + * @param slot + */ +extern void __attribute__((overloadable)) + rsgClearColorTarget(uint slot); + +/** + * Set the depth target used for all subsequent rendering calls + * @param depthTarget + */ +extern void __attribute__((overloadable)) + rsgBindDepthTarget(rs_allocation depthTarget); + +/** + * Clear the previously set depth target + */ +extern void __attribute__((overloadable)) + rsgClearDepthTarget(void); + +/** + * Clear all color and depth targets and resume rendering into + * the framebuffer + */ +extern void __attribute__((overloadable)) + rsgClearAllRenderTargets(void); + +/** + * Force RenderScript to finish all rendering commands + */ +extern uint __attribute__((overloadable)) + rsgFinish(void); /** * Bind a new ProgramFragment to the rendering context. diff --git a/tests/RenderScriptTests/FBOTest/Android.mk b/tests/RenderScriptTests/FBOTest/Android.mk new file mode 100644 index 0000000..55525c4 --- /dev/null +++ b/tests/RenderScriptTests/FBOTest/Android.mk @@ -0,0 +1,30 @@ +# +# Copyright (C) 2008 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. +# + +ifneq ($(TARGET_SIMULATOR),true) + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src) + +LOCAL_PACKAGE_NAME := FBOTest + +include $(BUILD_PACKAGE) + +endif diff --git a/tests/RenderScriptTests/FBOTest/AndroidManifest.xml b/tests/RenderScriptTests/FBOTest/AndroidManifest.xml new file mode 100644 index 0000000..c2e0cc6 --- /dev/null +++ b/tests/RenderScriptTests/FBOTest/AndroidManifest.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.fbotest"> + <application android:label="_FBOTest"> + <activity android:name="FBOTest" + android:theme="@android:style/Theme.Black.NoTitleBar"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> +</manifest> diff --git a/tests/RenderScriptTests/FBOTest/res/drawable/robot.png b/tests/RenderScriptTests/FBOTest/res/drawable/robot.png Binary files differnew file mode 100644 index 0000000..f7353fd --- /dev/null +++ b/tests/RenderScriptTests/FBOTest/res/drawable/robot.png diff --git a/tests/RenderScriptTests/FBOTest/res/raw/robot.a3d b/tests/RenderScriptTests/FBOTest/res/raw/robot.a3d Binary files differnew file mode 100644 index 0000000..f48895c --- /dev/null +++ b/tests/RenderScriptTests/FBOTest/res/raw/robot.a3d diff --git a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOTest.java b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOTest.java new file mode 100644 index 0000000..79d6012 --- /dev/null +++ b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOTest.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2008 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. + */ + +package com.android.fbotest; + +import android.renderscript.RSSurfaceView; +import android.renderscript.RenderScript; + +import android.app.Activity; +import android.content.res.Configuration; +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.provider.Settings.System; +import android.util.Config; +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.MenuInflater; +import android.view.Window; +import android.widget.Button; +import android.widget.ListView; +import android.net.Uri; + +import java.lang.Runtime; + +public class FBOTest extends Activity { + + private FBOTestView mView; + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + + // Create our Preview view and set it as the content of our + // Activity + mView = new FBOTestView(this); + setContentView(mView); + } + + @Override + protected void onResume() { + // Ideally a game should implement onResume() and onPause() + // to take appropriate action when the activity looses focus + super.onResume(); + mView.resume(); + } + + @Override + protected void onPause() { + // Ideally a game should implement onResume() and onPause() + // to take appropriate action when the activity looses focus + super.onPause(); + mView.pause(); + } +} + diff --git a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOTestRS.java b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOTestRS.java new file mode 100644 index 0000000..9e30c4b5 --- /dev/null +++ b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOTestRS.java @@ -0,0 +1,205 @@ +/* + * 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. + */ + +package com.android.fbotest; + +import java.io.Writer; + +import android.content.res.Resources; +import android.renderscript.*; +import android.renderscript.Element.DataType; +import android.renderscript.Element.DataKind; +import android.renderscript.ProgramStore.DepthFunc; +import android.renderscript.Type.Builder; +import android.util.Log; + + +public class FBOTestRS { + + public FBOTestRS() { + } + + public void init(RenderScriptGL rs, Resources res) { + mRS = rs; + mRes = res; + initRS(); + } + + public void surfaceChanged() { + mRS.getWidth(); + mRS.getHeight(); + } + + private Resources mRes; + private RenderScriptGL mRS; + private Sampler mSampler; + private ProgramStore mPSBackground; + private ProgramFragment mPFBackground; + private ProgramVertex mPVBackground; + private ProgramVertexFixedFunction.Constants mPVA; + + private Allocation mGridImage; + private Allocation mOffscreen; + private Allocation mOffscreenDepth; + private Allocation mAllocPV; + + private Font mItalic; + private Allocation mTextAlloc; + + private ScriptField_MeshInfo mMeshes; + private ScriptC_fbotest mScript; + + + public void onActionDown(float x, float y) { + mScript.invoke_onActionDown(x, y); + } + + public void onActionScale(float scale) { + mScript.invoke_onActionScale(scale); + } + + public void onActionMove(float x, float y) { + mScript.invoke_onActionMove(x, y); + } + + private void initPFS() { + ProgramStore.Builder b = new ProgramStore.Builder(mRS); + + b.setDepthFunc(ProgramStore.DepthFunc.LESS); + b.setDitherEnabled(false); + b.setDepthMaskEnabled(true); + mPSBackground = b.create(); + + mScript.set_gPFSBackground(mPSBackground); + } + + private void initPF() { + Sampler.Builder bs = new Sampler.Builder(mRS); + bs.setMinification(Sampler.Value.LINEAR); + bs.setMagnification(Sampler.Value.LINEAR); + bs.setWrapS(Sampler.Value.CLAMP); + bs.setWrapT(Sampler.Value.CLAMP); + mSampler = bs.create(); + + ProgramFragmentFixedFunction.Builder b = new ProgramFragmentFixedFunction.Builder(mRS); + b.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE, + ProgramFragmentFixedFunction.Builder.Format.RGBA, 0); + mPFBackground = b.create(); + mPFBackground.bindSampler(mSampler, 0); + + mScript.set_gPFBackground(mPFBackground); + } + + private void initPV() { + ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS); + mPVBackground = pvb.create(); + + mPVA = new ProgramVertexFixedFunction.Constants(mRS); + ((ProgramVertexFixedFunction)mPVBackground).bindConstants(mPVA); + + mScript.set_gPVBackground(mPVBackground); + } + + private void loadImage() { + mGridImage = Allocation.createFromBitmapResource(mRS, mRes, R.drawable.robot, + Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE, + Allocation.USAGE_GRAPHICS_TEXTURE); + mScript.set_gTGrid(mGridImage); + } + + private void initTextAllocation(String fileName) { + String allocString = "Displaying file: " + fileName; + mTextAlloc = Allocation.createFromString(mRS, allocString, Allocation.USAGE_SCRIPT); + mScript.set_gTextAlloc(mTextAlloc); + } + + private void initMeshes(FileA3D model) { + int numEntries = model.getIndexEntryCount(); + int numMeshes = 0; + for (int i = 0; i < numEntries; i ++) { + FileA3D.IndexEntry entry = model.getIndexEntry(i); + if (entry != null && entry.getEntryType() == FileA3D.EntryType.MESH) { + numMeshes ++; + } + } + + if (numMeshes > 0) { + mMeshes = new ScriptField_MeshInfo(mRS, numMeshes); + + for (int i = 0; i < numEntries; i ++) { + FileA3D.IndexEntry entry = model.getIndexEntry(i); + if (entry != null && entry.getEntryType() == FileA3D.EntryType.MESH) { + Mesh mesh = entry.getMesh(); + mMeshes.set_mMesh(i, mesh, false); + mMeshes.set_mNumIndexSets(i, mesh.getPrimitiveCount(), false); + } + } + mMeshes.copyAll(); + } else { + throw new RSRuntimeException("No valid meshes in file"); + } + + mScript.bind_gMeshes(mMeshes); + mScript.invoke_updateMeshInfo(); + } + + public void loadA3DFile(String path) { + FileA3D model = FileA3D.createFromFile(mRS, path); + initMeshes(model); + initTextAllocation(path); + } + + private void initRS() { + + mScript = new ScriptC_fbotest(mRS, mRes, R.raw.fbotest); + + initPFS(); + initPF(); + initPV(); + + loadImage(); + + Type.Builder b = new Type.Builder(mRS, Element.RGBA_8888(mRS)); + b.setX(512).setY(512); + mOffscreen = Allocation.createTyped(mRS, + b.create(), + Allocation.USAGE_GRAPHICS_TEXTURE | + Allocation.USAGE_GRAPHICS_RENDER_TARGET); + mScript.set_gOffscreen(mOffscreen); + + b = new Type.Builder(mRS, + Element.createPixel(mRS, DataType.UNSIGNED_16, + DataKind.PIXEL_DEPTH)); + b.setX(512).setY(512); + mOffscreenDepth = Allocation.createTyped(mRS, + b.create(), + Allocation.USAGE_GRAPHICS_RENDER_TARGET); + mScript.set_gOffscreenDepth(mOffscreenDepth); + + FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.robot); + initMeshes(model); + + mItalic = Font.create(mRS, mRes, "serif", Font.Style.ITALIC, 8); + mScript.set_gItalic(mItalic); + + initTextAllocation("R.raw.robot"); + + mRS.bindRootScript(mScript); + } +} + + + diff --git a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOTestView.java b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOTestView.java new file mode 100644 index 0000000..c9598ee --- /dev/null +++ b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOTestView.java @@ -0,0 +1,144 @@ +/* + * 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. + */ + +package com.android.fbotest; + +import android.renderscript.RSSurfaceView; +import android.renderscript.RenderScriptGL; + +import android.content.Context; +import android.view.MotionEvent; +import android.view.SurfaceHolder; +import android.view.ScaleGestureDetector; +import android.util.Log; + +public class FBOTestView extends RSSurfaceView { + + private RenderScriptGL mRS; + private FBOTestRS mRender; + + private ScaleGestureDetector mScaleDetector; + + private static final int INVALID_POINTER_ID = -1; + private int mActivePointerId = INVALID_POINTER_ID; + + public FBOTestView(Context context) { + super(context); + ensureRenderScript(); + mScaleDetector = new ScaleGestureDetector(context, new ScaleListener()); + } + + private void ensureRenderScript() { + if (mRS == null) { + RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig(); + sc.setDepth(16, 24); + mRS = createRenderScriptGL(sc); + mRender = new FBOTestRS(); + mRender.init(mRS, getResources()); + } + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + ensureRenderScript(); + } + + @Override + public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { + super.surfaceChanged(holder, format, w, h); + mRender.surfaceChanged(); + } + + @Override + protected void onDetachedFromWindow() { + mRender = null; + if (mRS != null) { + mRS = null; + destroyRenderScriptGL(); + } + } + + public void loadA3DFile(String path) { + mRender.loadA3DFile(path); + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + mScaleDetector.onTouchEvent(ev); + + boolean ret = false; + float x = ev.getX(); + float y = ev.getY(); + + final int action = ev.getAction(); + + switch (action & MotionEvent.ACTION_MASK) { + case MotionEvent.ACTION_DOWN: { + mRender.onActionDown(x, y); + mActivePointerId = ev.getPointerId(0); + ret = true; + break; + } + case MotionEvent.ACTION_MOVE: { + if (!mScaleDetector.isInProgress()) { + mRender.onActionMove(x, y); + } + mRender.onActionDown(x, y); + ret = true; + break; + } + + case MotionEvent.ACTION_UP: { + mActivePointerId = INVALID_POINTER_ID; + break; + } + + case MotionEvent.ACTION_CANCEL: { + mActivePointerId = INVALID_POINTER_ID; + break; + } + + case MotionEvent.ACTION_POINTER_UP: { + final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) + >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; + final int pointerId = ev.getPointerId(pointerIndex); + if (pointerId == mActivePointerId) { + // This was our active pointer going up. Choose a new + // active pointer and adjust accordingly. + final int newPointerIndex = pointerIndex == 0 ? 1 : 0; + x = ev.getX(newPointerIndex); + y = ev.getY(newPointerIndex); + mRender.onActionDown(x, y); + mActivePointerId = ev.getPointerId(newPointerIndex); + } + break; + } + } + + return ret; + } + + private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { + @Override + public boolean onScale(ScaleGestureDetector detector) { + mRender.onActionScale(detector.getScaleFactor()); + return true; + } + } +} + + diff --git a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbotest.rs b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbotest.rs new file mode 100644 index 0000000..31dd3e9 --- /dev/null +++ b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbotest.rs @@ -0,0 +1,221 @@ +// 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. + +#pragma version(1) + +#pragma rs java_package_name(com.android.fbotest) + +#include "rs_graphics.rsh" + +rs_program_vertex gPVBackground; +rs_program_fragment gPFBackground; + +rs_allocation gTGrid; + +rs_program_store gPFSBackground; + +rs_font gItalic; +rs_allocation gTextAlloc; + +rs_allocation gOffscreen; +rs_allocation gOffscreenDepth; + +typedef struct MeshInfo { + rs_mesh mMesh; + int mNumIndexSets; + float3 bBoxMin; + float3 bBoxMax; +} MeshInfo_t; + +MeshInfo_t *gMeshes; + +static float3 gLookAt; + +static float gRotateX; +static float gRotateY; +static float gZoom; + +static float gLastX; +static float gLastY; + +void onActionDown(float x, float y) { + gLastX = x; + gLastY = y; +} + +void onActionScale(float scale) { + + gZoom *= 1.0f / scale; + gZoom = max(0.1f, min(gZoom, 500.0f)); +} + +void onActionMove(float x, float y) { + float dx = gLastX - x; + float dy = gLastY - y; + + if (fabs(dy) <= 2.0f) { + dy = 0.0f; + } + if (fabs(dx) <= 2.0f) { + dx = 0.0f; + } + + gRotateY -= dx; + if (gRotateY > 360) { + gRotateY -= 360; + } + if (gRotateY < 0) { + gRotateY += 360; + } + + gRotateX -= dy; + gRotateX = min(gRotateX, 80.0f); + gRotateX = max(gRotateX, -80.0f); + + gLastX = x; + gLastY = y; +} + +void init() { + gRotateX = 0.0f; + gRotateY = 0.0f; + gZoom = 50.0f; + gLookAt = 0.0f; +} + +void updateMeshInfo() { + rs_allocation allMeshes = rsGetAllocation(gMeshes); + int size = rsAllocationGetDimX(allMeshes); + gLookAt = 0.0f; + float minX, minY, minZ, maxX, maxY, maxZ; + for (int i = 0; i < size; i++) { + MeshInfo_t *info = (MeshInfo_t*)rsGetElementAt(allMeshes, i); + rsgMeshComputeBoundingBox(info->mMesh, + &minX, &minY, &minZ, + &maxX, &maxY, &maxZ); + info->bBoxMin = (minX, minY, minZ); + info->bBoxMax = (maxX, maxY, maxZ); + gLookAt += (info->bBoxMin + info->bBoxMax)*0.5f; + } + gLookAt = gLookAt / (float)size; +} + +static void renderAllMeshes() { + rs_allocation allMeshes = rsGetAllocation(gMeshes); + int size = rsAllocationGetDimX(allMeshes); + gLookAt = 0.0f; + float minX, minY, minZ, maxX, maxY, maxZ; + for (int i = 0; i < size; i++) { + MeshInfo_t *info = (MeshInfo_t*)rsGetElementAt(allMeshes, i); + rsgDrawMesh(info->mMesh); + } +} + +static void drawDescription() { + uint width = rsgGetWidth(); + uint height = rsgGetHeight(); + int left = 0, right = 0, top = 0, bottom = 0; + + rsgBindFont(gItalic); + + rsgMeasureText(gTextAlloc, &left, &right, &top, &bottom); + rsgDrawText(gTextAlloc, 2 -left, height - 2 + bottom); +} + +static void renderOffscreen(bool useDepth) { + + rsgBindColorTarget(gOffscreen, 0); + if (useDepth) { + rsgBindDepthTarget(gOffscreenDepth); + rsgClearDepth(1.0f); + } else { + rsgClearDepthTarget(); + } + rsgClearColor(0.8f, 0.8f, 0.8f, 1.0f); + + rsgBindProgramVertex(gPVBackground); + rs_matrix4x4 proj; + float aspect = (float)rsAllocationGetDimX(gOffscreen) / (float)rsAllocationGetDimY(gOffscreen); + rsMatrixLoadPerspective(&proj, 30.0f, aspect, 1.0f, 100.0f); + rsgProgramVertexLoadProjectionMatrix(&proj); + + rsgBindProgramFragment(gPFBackground); + rsgBindProgramStore(gPFSBackground); + rsgBindTexture(gPFBackground, 0, gTGrid); + + rs_matrix4x4 matrix; + rsMatrixLoadIdentity(&matrix); + // Position our models on the screen + rsMatrixTranslate(&matrix, gLookAt.x, gLookAt.y, gLookAt.z - gZoom); + rsMatrixRotate(&matrix, gRotateX, 1.0f, 0.0f, 0.0f); + rsMatrixRotate(&matrix, gRotateY, 0.0f, 1.0f, 0.0f); + rsgProgramVertexLoadModelMatrix(&matrix); + + renderAllMeshes(); + + // Render into the frambuffer + rsgClearAllRenderTargets(); +} + +static void drawOffscreenResult(int posX, int posY) { + // display the result + rs_matrix4x4 proj, matrix; + rsMatrixLoadOrtho(&proj, 0, rsgGetWidth(), rsgGetHeight(), 0, -500, 500); + rsgProgramVertexLoadProjectionMatrix(&proj); + rsMatrixLoadIdentity(&matrix); + rsgProgramVertexLoadModelMatrix(&matrix); + rsgBindTexture(gPFBackground, 0, gOffscreen); + float startX = posX, startY = posY; + float width = 256, height = 256; + rsgDrawQuadTexCoords(startX, startY, 0, 0, 1, + startX, startY + height, 0, 0, 0, + startX + width, startY + height, 0, 1, 0, + startX + width, startY, 0, 1, 1); +} + +int root(int launchID) { + + rsgClearColor(1.0f, 1.0f, 1.0f, 1.0f); + rsgClearDepth(1.0f); + + renderOffscreen(true); + drawOffscreenResult(0, 0); + + renderOffscreen(false); + drawOffscreenResult(0, 256); + + rsgBindProgramVertex(gPVBackground); + rs_matrix4x4 proj; + float aspect = (float)rsgGetWidth() / (float)rsgGetHeight(); + rsMatrixLoadPerspective(&proj, 30.0f, aspect, 1.0f, 100.0f); + rsgProgramVertexLoadProjectionMatrix(&proj); + + rsgBindProgramFragment(gPFBackground); + rsgBindProgramStore(gPFSBackground); + rsgBindTexture(gPFBackground, 0, gTGrid); + + rs_matrix4x4 matrix; + rsMatrixLoadIdentity(&matrix); + // Position our models on the screen + rsMatrixTranslate(&matrix, gLookAt.x, gLookAt.y, gLookAt.z - gZoom); + rsMatrixRotate(&matrix, gRotateX, 1.0f, 0.0f, 0.0f); + rsMatrixRotate(&matrix, gRotateY, 0.0f, 1.0f, 0.0f); + rsgProgramVertexLoadModelMatrix(&matrix); + + renderAllMeshes(); + + drawDescription(); + + return 0; +} diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java index 9757ec6..5443ef8 100644 --- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java +++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java @@ -22,6 +22,8 @@ import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.renderscript.*; +import android.renderscript.Element.DataKind; +import android.renderscript.Element.DataType; import android.renderscript.Allocation.MipmapControl; import android.renderscript.Program.TextureType; import android.renderscript.ProgramStore.DepthFunc; @@ -399,6 +401,23 @@ public class RsBenchRS { initProgramRaster(); initCustomShaders(); + Type.Builder b = new Type.Builder(mRS, Element.RGBA_8888(mRS)); + b.setX(1280).setY(720); + Allocation offscreen = Allocation.createTyped(mRS, + b.create(), + Allocation.USAGE_GRAPHICS_TEXTURE | + Allocation.USAGE_GRAPHICS_RENDER_TARGET); + mScript.set_gRenderBufferColor(offscreen); + + b = new Type.Builder(mRS, + Element.createPixel(mRS, DataType.UNSIGNED_16, + DataKind.PIXEL_DEPTH)); + b.setX(1280).setY(720); + offscreen = Allocation.createTyped(mRS, + b.create(), + Allocation.USAGE_GRAPHICS_RENDER_TARGET); + mScript.set_gRenderBufferDepth(offscreen); + mRS.bindRootScript(mScript); } } diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs index 3c92725..fd0f16f 100644 --- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs +++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs @@ -76,11 +76,17 @@ rs_program_vertex gProgVertexPixelLightMove; rs_program_fragment gProgFragmentPixelLight; rs_program_fragment gProgFragmentMultitex; +rs_allocation gRenderBufferColor; +rs_allocation gRenderBufferDepth; + float gDt = 0; void init() { } +static int gRenderSurfaceW; +static int gRenderSurfaceH; + static const char *sampleText = "This is a sample of small text for performace"; // Offsets for multiple layer of text static int textOffsets[] = { 0, 0, -5, -5, 5, 5, -8, -8, 8, 8}; @@ -91,6 +97,11 @@ static float textColors[] = {1.0f, 1.0f, 1.0f, 1.0f, 0.5f, 0.6f, 0.7f, 1.0f, }; +static void setupOffscreenTarget() { + rsgBindColorTarget(gRenderBufferColor, 0); + rsgBindDepthTarget(gRenderBufferDepth); +} + static void displayFontSamples(int fillNum) { rs_font fonts[5]; @@ -100,8 +111,8 @@ static void displayFontSamples(int fillNum) { rsSetObject(&fonts[3], gFontSerifBoldItalic); rsSetObject(&fonts[4], gFontSans); - uint width = rsgGetWidth(); - uint height = rsgGetHeight(); + uint width = gRenderSurfaceW; + uint height = gRenderSurfaceH; int left = 0, right = 0, top = 0, bottom = 0; rsgMeasureText(sampleText, &left, &right, &top, &bottom); @@ -136,7 +147,7 @@ static void bindProgramVertexOrtho() { rsgBindProgramVertex(gProgVertex); // Setup the projection matrix rs_matrix4x4 proj; - rsMatrixLoadOrtho(&proj, 0, rsgGetWidth(), rsgGetHeight(), 0, -500, 500); + rsMatrixLoadOrtho(&proj, 0, gRenderSurfaceW, gRenderSurfaceH, 0, -500, 500); rsgProgramVertexLoadProjectionMatrix(&proj); } @@ -158,7 +169,7 @@ static void displaySingletexFill(bool blend, int quadCount) { for (int i = 0; i < quadCount; i ++) { float startX = 10 * i, startY = 10 * i; - float width = rsgGetWidth() - startX, height = rsgGetHeight() - startY; + float width = gRenderSurfaceW - startX, height = gRenderSurfaceH - startY; rsgDrawQuadTexCoords(startX, startY, 0, 0, 0, startX, startY + height, 0, 0, 1, startX + width, startY + height, 0, 1, 1, @@ -216,7 +227,7 @@ static void displayMeshSamples(int meshNum) { bindProgramVertexOrtho(); rs_matrix4x4 matrix; - rsMatrixLoadTranslate(&matrix, rsgGetWidth()/2, rsgGetHeight()/2, 0); + rsMatrixLoadTranslate(&matrix, gRenderSurfaceW/2, gRenderSurfaceH/2, 0); rsgProgramVertexLoadModelMatrix(&matrix); // Fragment shader with texture @@ -344,7 +355,7 @@ static void displaySimpleGeoSamples(bool useTexture, int numMeshes) { rsgBindProgramRaster(gCullBack); // Setup the projection matrix with 30 degree field of view rs_matrix4x4 proj; - float aspect = (float)rsgGetWidth() / (float)rsgGetHeight(); + float aspect = (float)gRenderSurfaceW / (float)gRenderSurfaceH; rsMatrixLoadPerspective(&proj, 30.0f, aspect, 0.1f, 100.0f); rsgProgramVertexLoadProjectionMatrix(&proj); @@ -445,7 +456,7 @@ static void displayCustomShaderSamples(int numMeshes) { } // Setup the projection matrix - float aspect = (float)rsgGetWidth() / (float)rsgGetHeight(); + float aspect = (float)gRenderSurfaceW / (float)gRenderSurfaceH; rsMatrixLoadPerspective(&gVSConstants->proj, 30.0f, aspect, 0.1f, 100.0f); setupCustomShaderLights(); @@ -476,7 +487,7 @@ static void displayPixelLightSamples(int numMeshes, bool heavyVertex) { gVSConstPixel->time = rsUptimeMillis()*0.005; // Setup the projection matrix - float aspect = (float)rsgGetWidth() / (float)rsgGetHeight(); + float aspect = (float)gRenderSurfaceW / (float)gRenderSurfaceH; rsMatrixLoadPerspective(&gVSConstPixel->proj, 30.0f, aspect, 0.1f, 100.0f); setupCustomShaderLights(); @@ -520,7 +531,7 @@ static void displayMultitextureSample(bool blend, int quadCount) { for (int i = 0; i < quadCount; i ++) { float startX = 10 * i, startY = 10 * i; - float width = rsgGetWidth() - startX, height = rsgGetHeight() - startY; + float width = gRenderSurfaceW - startX, height = gRenderSurfaceH - startY; rsgDrawQuadTexCoords(startX, startY, 0, 0, 0, startX, startY + height, 0, 0, 1, startX + width, startY + height, 0, 1, 1, @@ -535,7 +546,7 @@ static void displayAnisoSample() { gAnisoTime += gDt; rsgBindProgramVertex(gProgVertex); - float aspect = (float)rsgGetWidth() / (float)rsgGetHeight(); + float aspect = (float)gRenderSurfaceW / (float)gRenderSurfaceH; rs_matrix4x4 proj; rsMatrixLoadPerspective(&proj, 30.0f, aspect, 0.1f, 100.0f); rsgProgramVertexLoadProjectionMatrix(&proj); @@ -592,10 +603,6 @@ static bool checkInit() { static int countdown = 5; - if (countdown == 0) { - gDt = 0; - countdown --; - } // Perform all the uploads so we only measure rendered time if(countdown > 1) { displayFontSamples(5); @@ -612,19 +619,13 @@ static bool checkInit() { countdown --; rsgClearColor(0.2f, 0.2f, 0.2f, 0.0f); - // Now use text metrics to center the text - uint width = rsgGetWidth(); - uint height = rsgGetHeight(); - int left = 0, right = 0, top = 0, bottom = 0; - rsgFontColor(0.9f, 0.9f, 0.95f, 1.0f); rsgBindFont(gFontSerifBoldItalic); - - const char* text = "Initializing"; - rsgMeasureText(text, &left, &right, &top, &bottom); - int centeredPosX = width / 2 - (right - left) / 2; - int centeredPosY = height / 2 - (top - bottom) / 2; - rsgDrawText(text, centeredPosX, centeredPosY); + if (countdown == 1) { + rsgDrawText("Rendering", 50, 50); + } else { + rsgDrawText("Initializing", 50, 50); + } return false; } @@ -632,70 +633,40 @@ static bool checkInit() { return true; } -static int frameCount = 0; -static int totalFramesRendered = 0; static int benchMode = 0; -#define testTime 5.0f -static float curTestTime = testTime; - static const char *testNames[] = { - "Finished text fill 1", - "Finished text fill 2", - "Finished text fill 3", - "Finished text fill 4", - "Finished text fill 5", - "Finished 25.6k geo flat color", - "Finished 51.2k geo flat color", - "Finished 204.8k geo raster load flat color", - "Finished 25.6k geo texture", - "Finished 51.2k geo texture", - "Finished 204.8k geo raster load texture", - "Finished full screen mesh 10 by 10", - "Finished full screen mesh 100 by 100", - "Finished full screen mesh W / 4 by H / 4", - "Finished 25.6k geo heavy vertex", - "Finished 51.2k geo heavy vertex", - "Finished 204.8k geo raster load heavy vertex", - "Finished singletexture 5x fill", - "Finished 3tex multitexture 5x fill", - "Finished blend singletexture 5x fill", - "Finished blend 3tex multitexture 5x fill", - "Finished 25.6k geo heavy fragment", - "Finished 51.2k geo heavy fragment", - "Finished 204.8k geo raster load heavy fragment", - "Finished 25.6k geo heavy fragment, heavy vertex", - "Finished 51.2k geo heavy fragment, heavy vertex", - "Finished 204.8k geo raster load heavy fragment, heavy vertex", + "Finished text fill 1,", + "Finished text fill 2,", + "Finished text fill 3,", + "Finished text fill 4,", + "Finished text fill 5,", + "Finished 25.6k geo flat color,", + "Finished 51.2k geo flat color,", + "Finished 204.8k geo raster load flat color,", + "Finished 25.6k geo texture,", + "Finished 51.2k geo texture,", + "Finished 204.8k geo raster load texture,", + "Finished full screen mesh 10 by 10,", + "Finished full screen mesh 100 by 100,", + "Finished full screen mesh W / 4 by H / 4,", + "Finished 25.6k geo heavy vertex,", + "Finished 51.2k geo heavy vertex,", + "Finished 204.8k geo raster load heavy vertex,", + "Finished singletexture 5x fill,", + "Finished 3tex multitexture 5x fill,", + "Finished blend singletexture 5x fill,", + "Finished blend 3tex multitexture 5x fill,", + "Finished 25.6k geo heavy fragment,", + "Finished 51.2k geo heavy fragment,", + "Finished 204.8k geo raster load heavy fragment,", + "Finished 25.6k geo heavy fragment heavy vertex,", + "Finished 51.2k geo heavy fragment heavy vertex,", + "Finished 204.8k geo raster load heavy fragment heavy vertex,", }; -int root(int launchID) { - - gDt = rsGetDt(); - - rsgClearColor(0.2f, 0.2f, 0.2f, 0.0f); - rsgClearDepth(1.0f); - - if(!checkInit()) { - return 1; - } - - curTestTime -= gDt; - if(curTestTime < 0.0f) { - float fps = (float)(frameCount) / (testTime - curTestTime); - rsDebug(testNames[benchMode], fps); - benchMode ++; - curTestTime = testTime; - totalFramesRendered += frameCount; - frameCount = 0; - gTorusRotation = 0; - - if (benchMode > gMaxModes) { - benchMode = 0; - } - } - - switch (benchMode) { +static void runTest(int index) { + switch (index) { case 0: displayFontSamples(1); break; @@ -777,10 +748,87 @@ int root(int launchID) { case 26: displayPixelLightSamples(8, true); break; + } +} + +static void drawOffscreenResult(int posX, int posY, int width, int height) { + bindProgramVertexOrtho(); + rs_matrix4x4 matrix; + rsMatrixLoadIdentity(&matrix); + rsgProgramVertexLoadModelMatrix(&matrix); + + rsgBindProgramFragment(gProgFragmentTexture); + + rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp); + rsgBindTexture(gProgFragmentTexture, 0, gRenderBufferColor); + + float startX = posX, startY = posY; + rsgDrawQuadTexCoords(startX, startY, 0, 0, 1, + startX, startY + height, 0, 0, 0, + startX + width, startY + height, 0, 1, 0, + startX + width, startY, 0, 1, 1); +} + +int root(int launchID) { + + gRenderSurfaceW = rsgGetWidth(); + gRenderSurfaceH = rsgGetHeight(); + rsgClearColor(0.2f, 0.2f, 0.2f, 1.0f); + rsgClearDepth(1.0f); + if(!checkInit()) { + return 1; + } + + rsgFinish(); + int64_t start = rsUptimeMillis(); + rsGetDt(); + + int drawPos = 0; + int frameCount = 100; + for(int i = 0; i < frameCount; i ++) { + setupOffscreenTarget(); + gRenderSurfaceW = rsAllocationGetDimX(gRenderBufferColor); + gRenderSurfaceH = rsAllocationGetDimY(gRenderBufferColor); + rsgClearColor(0.1f, 0.1f, 0.1f, 1.0f); + rsgClearDepth(1.0f); + + runTest(benchMode); + rsgClearAllRenderTargets(); + gRenderSurfaceW = rsgGetWidth(); + gRenderSurfaceH = rsgGetHeight(); + int size = 8; + drawOffscreenResult((drawPos+=size)%gRenderSurfaceW, (gRenderSurfaceH * 3) / 4, size, size); + gDt = rsGetDt(); } - frameCount ++; + rsgFinish(); + + int64_t end = rsUptimeMillis(); + float fps = (float)(frameCount) / ((float)(end - start)*0.001f); + rsDebug(testNames[benchMode], fps); + + drawOffscreenResult(0, 0, + gRenderSurfaceW / 2, + gRenderSurfaceH / 2); + + const char* text = testNames[benchMode]; + int left = 0, right = 0, top = 0, bottom = 0; + uint width = rsgGetWidth(); + uint height = rsgGetHeight(); + rsgFontColor(0.9f, 0.9f, 0.95f, 1.0f); + rsgBindFont(gFontSerifBoldItalic); + rsgMeasureText(text, &left, &right, &top, &bottom); + rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f); + rsgDrawText(text, 2 -left, height - 2 + bottom); + + benchMode ++; + + gTorusRotation = 0; + + if (benchMode > gMaxModes) { + benchMode = 0; + } return 1; } |