From 67f2e442a31b8395e3c1951f8e91139ec7f2be99 Mon Sep 17 00:00:00 2001 From: Alex Sakhartchouk Date: Thu, 18 Nov 2010 15:22:43 -0800 Subject: [PATCH] Support for cubemaps. Change-Id: Iaf6087f614451a8e233b3e5bc49c834ab0ad08ee --- .../java/android/renderscript/Allocation.java | 68 ++++++++- .../java/android/renderscript/Program.java | 55 ++++++- .../android/renderscript/ProgramFragment.java | 14 +- .../android/renderscript/ProgramVertex.java | 14 +- .../android/renderscript/RenderScript.java | 4 + .../jni/android_renderscript_RenderScript.cpp | 22 +++ libs/rs/RenderScript.h | 8 +- .../Samples/res/drawable/cubemap_test.png | Bin 0 -> 2898 bytes libs/rs/java/Samples/res/raw/shadercubef.glsl | 8 + libs/rs/java/Samples/res/raw/shadercubev.glsl | 10 ++ .../com/android/samples/RsRenderStatesRS.java | 29 +++- .../src/com/android/samples/rsrenderstates.rs | 44 +++++- libs/rs/rsAdapter.cpp | 11 ++ libs/rs/rsAllocation.cpp | 143 ++++++++++++++++-- libs/rs/rsAllocation.h | 5 +- libs/rs/rsFont.cpp | 4 +- libs/rs/rsProgram.cpp | 17 ++- libs/rs/rsProgram.h | 2 +- libs/rs/rsProgramFragment.cpp | 27 ++-- libs/rs/rsProgramVertex.cpp | 6 +- libs/rs/rsSampler.cpp | 25 +-- 21 files changed, 444 insertions(+), 72 deletions(-) create mode 100644 libs/rs/java/Samples/res/drawable/cubemap_test.png create mode 100644 libs/rs/java/Samples/res/raw/shadercubef.glsl create mode 100644 libs/rs/java/Samples/res/raw/shadercubev.glsl diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java index 0de53f2db942f..bad1208e6483c 100644 --- a/graphics/java/android/renderscript/Allocation.java +++ b/graphics/java/android/renderscript/Allocation.java @@ -34,6 +34,18 @@ public class Allocation extends BaseObj { Type mType; Bitmap mBitmap; + public enum CubemapLayout { + VERTICAL_FACE_LIST (0), + HORIZONTAL_FACE_LIST (1), + VERTICAL_CROSS (2), + HORIZONTAL_CROSS (3); + + int mID; + CubemapLayout(int id) { + mID = id; + } + } + Allocation(int id, RenderScript rs, Type t) { super(id, rs); mType = t; @@ -355,18 +367,21 @@ public class Allocation extends BaseObj { throw new RSInvalidStateException("Bad bitmap type: " + bc); } - static private Type typeFromBitmap(RenderScript rs, Bitmap b) { + static private Type typeFromBitmap(RenderScript rs, Bitmap b, boolean mip) { Element e = elementFromBitmap(rs, b); Type.Builder tb = new Type.Builder(rs, e); tb.add(Dimension.X, b.getWidth()); tb.add(Dimension.Y, b.getHeight()); + if (mip) { + tb.add(Dimension.LOD, 1); + } return tb.create(); } - static public Allocation createFromBitmap(RenderScript rs, Bitmap b, Element dstFmt, boolean genMips) { - + static public Allocation createFromBitmap(RenderScript rs, Bitmap b, + Element dstFmt, boolean genMips) { rs.validate(); - Type t = typeFromBitmap(rs, b); + Type t = typeFromBitmap(rs, b, genMips); int id = rs.nAllocationCreateFromBitmap(dstFmt.getID(), genMips, b); if(id == 0) { @@ -375,10 +390,49 @@ public class Allocation extends BaseObj { return new Allocation(id, rs, t); } + static public Allocation createCubemapFromBitmap(RenderScript rs, Bitmap b, + Element dstFmt, + boolean genMips, + CubemapLayout layout) { + rs.validate(); + int height = b.getHeight(); + int width = b.getWidth(); + + if (layout != CubemapLayout.VERTICAL_FACE_LIST) { + throw new RSIllegalArgumentException("Only vertical face list supported"); + } + if (height % 6 != 0) { + throw new RSIllegalArgumentException("Cubemap height must be multiple of 6"); + } + if (height / 6 != width) { + throw new RSIllegalArgumentException("Only square cobe map faces supported"); + } + boolean isPow2 = (width & (width - 1)) == 0; + if (!isPow2) { + throw new RSIllegalArgumentException("Only power of 2 cube faces supported"); + } + + Element e = elementFromBitmap(rs, b); + Type.Builder tb = new Type.Builder(rs, e); + tb.add(Dimension.X, width); + tb.add(Dimension.Y, width); + tb.add(Dimension.FACE, 1); + if (genMips) { + tb.add(Dimension.LOD, 1); + } + Type t = tb.create(); + + int id = rs.nAllocationCubeCreateFromBitmap(dstFmt.getID(), genMips, b); + if(id == 0) { + throw new RSRuntimeException("Load failed for bitmap " + b + " element " + e); + } + return new Allocation(id, rs, t); + } + static public Allocation createBitmapRef(RenderScript rs, Bitmap b) { rs.validate(); - Type t = typeFromBitmap(rs, b); + Type t = typeFromBitmap(rs, b, false); int id = rs.nAllocationCreateBitmapRef(t.getID(), b); if(id == 0) { @@ -404,7 +458,9 @@ public class Allocation extends BaseObj { if (aId == 0) { throw new RSRuntimeException("Load failed."); } - return new Allocation(aId, rs, null); + Allocation alloc = new Allocation(aId, rs, null); + alloc.updateFromNative(); + return alloc; } finally { if (is != null) { try { diff --git a/graphics/java/android/renderscript/Program.java b/graphics/java/android/renderscript/Program.java index 83c3601a484b0..22f3fc5d6113e 100644 --- a/graphics/java/android/renderscript/Program.java +++ b/graphics/java/android/renderscript/Program.java @@ -36,9 +36,32 @@ public class Program extends BaseObj { public static final int MAX_CONSTANT = 8; public static final int MAX_TEXTURE = 8; + public enum TextureType { + TEXTURE_2D (0), + TEXTURE_CUBE (1); + + int mID; + TextureType(int id) { + mID = id; + } + } + + enum ProgramParam { + INPUT (0), + OUTPUT (1), + CONSTANT (2), + TEXTURE_TYPE (3); + + int mID; + ProgramParam(int id) { + mID = id; + } + }; + Element mInputs[]; Element mOutputs[]; Type mConstants[]; + TextureType mTextures[]; int mTextureCount; String mShader; @@ -54,27 +77,34 @@ public class Program extends BaseObj { a.getType().getID() != mConstants[slot].getID()) { throw new IllegalArgumentException("Allocation type does not match slot type."); } - mRS.nProgramBindConstants(getID(), slot, a.getID()); + int id = a != null ? a.getID() : 0; + mRS.nProgramBindConstants(getID(), slot, id); } public void bindTexture(Allocation va, int slot) throws IllegalArgumentException { mRS.validate(); - if((slot < 0) || (slot >= mTextureCount)) { + if ((slot < 0) || (slot >= mTextureCount)) { throw new IllegalArgumentException("Slot ID out of range."); } + if (va != null && va.getType().getFaces() && + mTextures[slot] != TextureType.TEXTURE_CUBE) { + throw new IllegalArgumentException("Cannot bind cubemap to 2d texture slot"); + } - mRS.nProgramBindTexture(getID(), slot, va.getID()); + int id = va != null ? va.getID() : 0; + mRS.nProgramBindTexture(getID(), slot, id); } public void bindSampler(Sampler vs, int slot) throws IllegalArgumentException { mRS.validate(); - if((slot < 0) || (slot >= mTextureCount)) { + if ((slot < 0) || (slot >= mTextureCount)) { throw new IllegalArgumentException("Slot ID out of range."); } - mRS.nProgramBindSampler(getID(), slot, vs.getID()); + int id = vs != null ? vs.getID() : 0; + mRS.nProgramBindSampler(getID(), slot, id); } @@ -84,6 +114,7 @@ public class Program extends BaseObj { Element mOutputs[]; Type mConstants[]; Type mTextures[]; + TextureType mTextureTypes[]; int mInputCount; int mOutputCount; int mConstantCount; @@ -100,6 +131,7 @@ public class Program extends BaseObj { mOutputCount = 0; mConstantCount = 0; mTextureCount = 0; + mTextureTypes = new TextureType[MAX_TEXTURE]; } public BaseProgramBuilder setShader(String s) { @@ -192,6 +224,17 @@ public class Program extends BaseObj { throw new IllegalArgumentException("Max texture count exceeded."); } mTextureCount = count; + for (int i = 0; i < mTextureCount; i ++) { + mTextureTypes[i] = TextureType.TEXTURE_2D; + } + return this; + } + + public BaseProgramBuilder addTexture(TextureType texType) throws IllegalArgumentException { + if(mTextureCount >= MAX_TEXTURE) { + throw new IllegalArgumentException("Max texture count exceeded."); + } + mTextureTypes[mTextureCount ++] = texType; return this; } @@ -203,6 +246,8 @@ public class Program extends BaseObj { p.mConstants = new Type[mConstantCount]; System.arraycopy(mConstants, 0, p.mConstants, 0, mConstantCount); p.mTextureCount = mTextureCount; + p.mTextures = new TextureType[mTextureCount]; + System.arraycopy(mTextureTypes, 0, p.mTextures, 0, mTextureCount); } } diff --git a/graphics/java/android/renderscript/ProgramFragment.java b/graphics/java/android/renderscript/ProgramFragment.java index d30e4831e9bbc..faaf980bc01e1 100644 --- a/graphics/java/android/renderscript/ProgramFragment.java +++ b/graphics/java/android/renderscript/ProgramFragment.java @@ -37,23 +37,25 @@ public class ProgramFragment extends Program { public ProgramFragment create() { mRS.validate(); - int[] tmp = new int[(mInputCount + mOutputCount + mConstantCount + 1) * 2]; + int[] tmp = new int[(mInputCount + mOutputCount + mConstantCount + mTextureCount) * 2]; int idx = 0; for (int i=0; i < mInputCount; i++) { - tmp[idx++] = 0; + tmp[idx++] = ProgramParam.INPUT.mID; tmp[idx++] = mInputs[i].getID(); } for (int i=0; i < mOutputCount; i++) { - tmp[idx++] = 1; + tmp[idx++] = ProgramParam.OUTPUT.mID; tmp[idx++] = mOutputs[i].getID(); } for (int i=0; i < mConstantCount; i++) { - tmp[idx++] = 2; + tmp[idx++] = ProgramParam.CONSTANT.mID; tmp[idx++] = mConstants[i].getID(); } - tmp[idx++] = 3; - tmp[idx++] = mTextureCount; + for (int i=0; i < mTextureCount; i++) { + tmp[idx++] = ProgramParam.TEXTURE_TYPE.mID; + tmp[idx++] = mTextureTypes[i].mID; + } int id = mRS.nProgramFragmentCreate(mShader, tmp); ProgramFragment pf = new ProgramFragment(id, mRS); diff --git a/graphics/java/android/renderscript/ProgramVertex.java b/graphics/java/android/renderscript/ProgramVertex.java index 13f017a25d935..998e05e92471a 100644 --- a/graphics/java/android/renderscript/ProgramVertex.java +++ b/graphics/java/android/renderscript/ProgramVertex.java @@ -46,23 +46,25 @@ public class ProgramVertex extends Program { public ProgramVertex create() { mRS.validate(); - int[] tmp = new int[(mInputCount + mOutputCount + mConstantCount +1) * 2]; + int[] tmp = new int[(mInputCount + mOutputCount + mConstantCount + mTextureCount) * 2]; int idx = 0; for (int i=0; i < mInputCount; i++) { - tmp[idx++] = 0; + tmp[idx++] = ProgramParam.INPUT.mID; tmp[idx++] = mInputs[i].getID(); } for (int i=0; i < mOutputCount; i++) { - tmp[idx++] = 1; + tmp[idx++] = ProgramParam.OUTPUT.mID; tmp[idx++] = mOutputs[i].getID(); } for (int i=0; i < mConstantCount; i++) { - tmp[idx++] = 2; + tmp[idx++] = ProgramParam.CONSTANT.mID; tmp[idx++] = mConstants[i].getID(); } - tmp[idx++] = 3; - tmp[idx++] = mTextureCount; + for (int i=0; i < mTextureCount; i++) { + tmp[idx++] = ProgramParam.TEXTURE_TYPE.mID; + tmp[idx++] = mTextureTypes[i].mID; + } int id = mRS.nProgramVertexCreate(mShader, tmp); ProgramVertex pv = new ProgramVertex(id, mRS); diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java index dcf86e3792518..0660441c810da 100644 --- a/graphics/java/android/renderscript/RenderScript.java +++ b/graphics/java/android/renderscript/RenderScript.java @@ -204,6 +204,10 @@ public class RenderScript { synchronized int nAllocationCreateFromBitmap(int dstFmt, boolean genMips, Bitmap bmp) { return rsnAllocationCreateFromBitmap(mContext, dstFmt, genMips, bmp); } + native int rsnAllocationCubeCreateFromBitmap(int con, int dstFmt, boolean genMips, Bitmap bmp); + synchronized int nAllocationCubeCreateFromBitmap(int dstFmt, boolean genMips, Bitmap bmp) { + return rsnAllocationCubeCreateFromBitmap(mContext, dstFmt, genMips, bmp); + } native int rsnAllocationCreateBitmapRef(int con, int type, Bitmap bmp); synchronized int nAllocationCreateBitmapRef(int type, Bitmap bmp) { return rsnAllocationCreateBitmapRef(mContext, type, bmp); diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp index 1cc43863d6945..6a1a319ea80c1 100644 --- a/graphics/jni/android_renderscript_RenderScript.cpp +++ b/graphics/jni/android_renderscript_RenderScript.cpp @@ -455,6 +455,27 @@ nAllocationCreateFromBitmap(JNIEnv *_env, jobject _this, RsContext con, jint dst return 0; } +static int +nAllocationCubeCreateFromBitmap(JNIEnv *_env, jobject _this, RsContext con, jint dstFmt, jboolean genMips, jobject jbitmap) +{ + SkBitmap const * nativeBitmap = + (SkBitmap const *)_env->GetIntField(jbitmap, gNativeBitmapID); + const SkBitmap& bitmap(*nativeBitmap); + SkBitmap::Config config = bitmap.getConfig(); + + RsElement e = SkBitmapToPredefined(config); + if (e) { + bitmap.lockPixels(); + const int w = bitmap.width(); + const int h = bitmap.height(); + const void* ptr = bitmap.getPixels(); + jint id = (jint)rsaAllocationCubeCreateFromBitmap(con, w, h, (RsElement)dstFmt, e, genMips, ptr); + bitmap.unlockPixels(); + return id; + } + return 0; +} + static void nAllocationUpdateFromBitmap(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jobject jbitmap) { @@ -1301,6 +1322,7 @@ static JNINativeMethod methods[] = { {"rsnAllocationCreateTyped", "(II)I", (void*)nAllocationCreateTyped }, {"rsnAllocationUpdateFromBitmap", "(IILandroid/graphics/Bitmap;)V", (void*)nAllocationUpdateFromBitmap }, {"rsnAllocationCreateFromBitmap", "(IIZLandroid/graphics/Bitmap;)I", (void*)nAllocationCreateFromBitmap }, +{"rsnAllocationCubeCreateFromBitmap","(IIZLandroid/graphics/Bitmap;)I", (void*)nAllocationCubeCreateFromBitmap }, {"rsnAllocationCreateBitmapRef", "(IILandroid/graphics/Bitmap;)I", (void*)nAllocationCreateBitmapRef }, {"rsnAllocationCreateFromAssetStream","(IIZI)I", (void*)nAllocationCreateFromAssetStream }, {"rsnAllocationUploadToTexture", "(IIZI)V", (void*)nAllocationUploadToTexture }, diff --git a/libs/rs/RenderScript.h b/libs/rs/RenderScript.h index 20e289d3c35fc..0ed129ff96ca6 100644 --- a/libs/rs/RenderScript.h +++ b/libs/rs/RenderScript.h @@ -160,6 +160,11 @@ enum RsSamplerValue { RS_SAMPLER_CLAMP }; +enum RsTextureTarget { + RS_TEXTURE_2D, + RS_TEXTURE_CUBE +}; + enum RsDimension { RS_DIMENSION_X, RS_DIMENSION_Y, @@ -218,7 +223,7 @@ enum RsProgramParam { RS_PROGRAM_PARAM_INPUT, RS_PROGRAM_PARAM_OUTPUT, RS_PROGRAM_PARAM_CONSTANT, - RS_PROGRAM_PARAM_TEXTURE_COUNT, + RS_PROGRAM_PARAM_TEXTURE_TYPE, }; enum RsPrimitive { @@ -322,6 +327,7 @@ RsType rsaTypeCreate(RsContext, RsElement, uint32_t dimCount, const RsDimension *dims, const uint32_t *vals); RsAllocation rsaAllocationCreateTyped(RsContext rsc, RsType vtype); RsAllocation rsaAllocationCreateFromBitmap(RsContext con, uint32_t w, uint32_t h, RsElement _dst, RsElement _src, bool genMips, const void *data); +RsAllocation rsaAllocationCubeCreateFromBitmap(RsContext con, uint32_t w, uint32_t h, RsElement _dst, RsElement _src, bool genMips, const void *data); #ifndef NO_RS_FUNCS #include "rsgApiFuncDecl.h" diff --git a/libs/rs/java/Samples/res/drawable/cubemap_test.png b/libs/rs/java/Samples/res/drawable/cubemap_test.png new file mode 100644 index 0000000000000000000000000000000000000000..75ad0a421775f5ce560cc05e58b4c94add56009d GIT binary patch literal 2898 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 nxF7o{7vjJCjpG{`0GF4#M6Ip@4t 360.0f) { + gTorusRotation -= 360.0f; + } + + // Position our model on the screen + // Position our model on the screen + rsMatrixLoadTranslate(&gVSConstants->model, 0.0f, 0.0f, -10.0f); + rsMatrixRotate(&gVSConstants->model, gTorusRotation, 1.0f, 0.0f, 0.0f); + rsMatrixRotate(&gVSConstants->model, gTorusRotation, 0.0f, 0.0f, 1.0f); + // Setup the projectioni matrix + float aspect = (float)rsgGetWidth() / (float)rsgGetHeight(); + rsMatrixLoadPerspective(&gVSConstants->proj, 30.0f, aspect, 0.1f, 100.0f); + rsAllocationMarkDirty(rsGetAllocation(gFSConstants)); + + rsgBindProgramVertex(gProgVertexCube); + + // Fragment shader with texture + rsgBindProgramStore(gProgStoreBlendNoneDepth); + rsgBindProgramFragment(gProgFragmentCube); + rsgBindSampler(gProgFragmentCube, 0, gLinearClamp); + rsgBindTexture(gProgFragmentCube, 0, gTexCube); + + // Use back face culling + rsgBindProgramRaster(gCullBack); + rsgDrawMesh(gTorusMesh); + + rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f); + rsgBindFont(gFontMono); + rsgDrawText("Cubemap shader sample", 10, rsgGetHeight() - 10); +} + void displayMultitextureSample() { bindProgramVertexOrtho(); rs_matrix4x4 matrix; @@ -632,6 +671,9 @@ int root(int launchID) { case 9: displayCustomShaderSamples2(); break; + case 10: + displayCubemapShaderSample(); + break; } return 10; diff --git a/libs/rs/rsAdapter.cpp b/libs/rs/rsAdapter.cpp index 2a705a1d50c04..8d363fde19e14 100644 --- a/libs/rs/rsAdapter.cpp +++ b/libs/rs/rsAdapter.cpp @@ -143,8 +143,19 @@ void * Adapter2D::getElement(uint32_t x, uint32_t y) const { rsAssert(mAllocation.get()); rsAssert(mAllocation->getPtr()); rsAssert(mAllocation->getType()); + if (mFace != 0 && !mAllocation->getType()->getDimFaces()) { + LOGE("Adapter wants cubemap face, but allocation has none"); + return NULL; + } + uint8_t * ptr = static_cast(mAllocation->getPtr()); ptr += mAllocation->getType()->getLODOffset(mLOD, x, y); + + if (mFace != 0) { + uint32_t totalSizeBytes = mAllocation->getType()->getSizeBytes(); + uint32_t faceOffset = totalSizeBytes / 6; + ptr += faceOffset * mFace; + } return ptr; } diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp index 23135e2103366..4ade7140d3507 100644 --- a/libs/rs/rsAllocation.cpp +++ b/libs/rs/rsAllocation.cpp @@ -123,8 +123,22 @@ void Allocation::deferedUploadToTexture(const Context *rsc, bool genMipmap, uint mTextureGenMipmap = !mType->getDimLOD() && genMipmap; } +uint32_t Allocation::getGLTarget() const { + if (mIsTexture) { + if (mType->getDimFaces()) { + return GL_TEXTURE_CUBE_MAP; + } else { + return GL_TEXTURE_2D; + } + } + if (mIsVertexBuffer) { + return GL_ARRAY_BUFFER; + } + return 0; +} + + void Allocation::uploadToTexture(const Context *rsc) { - //rsAssert(!mTextureId); mIsTexture = true; if (!rsc->checkDriver()) { @@ -155,9 +169,30 @@ void Allocation::uploadToTexture(const Context *rsc) { } isFirstUpload = true; } - glBindTexture(GL_TEXTURE_2D, mTextureID); + + GLenum target = (GLenum)getGLTarget(); + glBindTexture(target, mTextureID); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + if (target == GL_TEXTURE_2D) { + upload2DTexture(isFirstUpload); + } else if (target == GL_TEXTURE_CUBE_MAP) { + uploadCubeTexture(isFirstUpload); + } + + if (mTextureGenMipmap) { +#ifndef ANDROID_RS_BUILD_FOR_HOST + glGenerateMipmap(target); +#endif //ANDROID_RS_BUILD_FOR_HOST + } + + rsc->checkError("Allocation::uploadToTexture"); +} + +void Allocation::upload2DTexture(bool isFirstUpload) { + GLenum type = mType->getElement()->getComponent().getGLType(); + GLenum format = mType->getElement()->getComponent().getGLFormat(); + Adapter2D adapt(getContext(), this); for (uint32_t lod = 0; (lod + mTextureLOD) < mType->getLODCount(); lod++) { adapt.setLOD(lod+mTextureLOD); @@ -169,17 +204,45 @@ void Allocation::uploadToTexture(const Context *rsc) { 0, format, type, ptr); } else { glTexSubImage2D(GL_TEXTURE_2D, lod, 0, 0, - adapt.getDimX(), adapt.getDimY(), - format, type, ptr); + adapt.getDimX(), adapt.getDimY(), + format, type, ptr); } } - if (mTextureGenMipmap) { -#ifndef ANDROID_RS_BUILD_FOR_HOST - glGenerateMipmap(GL_TEXTURE_2D); -#endif //ANDROID_RS_BUILD_FOR_HOST - } +} - rsc->checkError("Allocation::uploadToTexture"); +void Allocation::uploadCubeTexture(bool isFirstUpload) { + GLenum type = mType->getElement()->getComponent().getGLType(); + GLenum format = mType->getElement()->getComponent().getGLFormat(); + + GLenum faceOrder[] = { + 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 + }; + + Adapter2D adapt(getContext(), this); + for (uint32_t face = 0; face < 6; face ++) { + adapt.setFace(face); + + for (uint32_t lod = 0; (lod + mTextureLOD) < mType->getLODCount(); lod++) { + adapt.setLOD(lod+mTextureLOD); + + uint16_t * ptr = static_cast(adapt.getElement(0,0)); + + if (isFirstUpload) { + glTexImage2D(faceOrder[face], lod, format, + adapt.getDimX(), adapt.getDimY(), + 0, format, type, ptr); + } else { + glTexSubImage2D(faceOrder[face], lod, 0, 0, + adapt.getDimX(), adapt.getDimY(), + format, type, ptr); + } + } + } } void Allocation::deferedUploadToBufferObject(const Context *rsc) { @@ -205,10 +268,10 @@ void Allocation::uploadToBufferObject(const Context *rsc) { mUploadDefered = true; return; } - - glBindBuffer(GL_ARRAY_BUFFER, mBufferID); - glBufferData(GL_ARRAY_BUFFER, mType->getSizeBytes(), getPtr(), GL_DYNAMIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); + GLenum target = (GLenum)getGLTarget(); + glBindBuffer(target, mBufferID); + glBufferData(target, mType->getSizeBytes(), getPtr(), GL_DYNAMIC_DRAW); + glBindBuffer(target, 0); rsc->checkError("Allocation::uploadToBufferObject"); } @@ -816,3 +879,55 @@ RsAllocation rsaAllocationCreateFromBitmap(RsContext con, uint32_t w, uint32_t h return texAlloc; } + +RsAllocation rsaAllocationCubeCreateFromBitmap(RsContext con, uint32_t w, uint32_t h, RsElement _dst, RsElement _src, bool genMips, const void *data) { + Context *rsc = static_cast(con); + const Element *src = static_cast(_src); + const Element *dst = static_cast(_dst); + + // Cubemap allocation's faces should be Width by Width each. + // Source data should have 6 * Width by Width pixels + // Error checking is done in the java layer + RsDimension dims[] = {RS_DIMENSION_X, RS_DIMENSION_Y, RS_DIMENSION_LOD, RS_DIMENSION_FACE}; + uint32_t dimValues[] = {w, w, genMips, true}; + RsType type = rsaTypeCreate(rsc, _dst, 4, dims, dimValues); + + RsAllocation vTexAlloc = rsaAllocationCreateTyped(rsc, type); + Allocation *texAlloc = static_cast(vTexAlloc); + if (texAlloc == NULL) { + LOGE("Memory allocation failure"); + return NULL; + } + + uint8_t *sourcePtr = (uint8_t*)data; + ElementConverter_t cvt = pickConverter(dst, src); + if (cvt) { + for (uint32_t face = 0; face < 6; face ++) { + Adapter2D faceAdapter(rsc, texAlloc); + faceAdapter.setFace(face); + + cvt(faceAdapter.getElement(0, 0), sourcePtr, w * w); + + // Move the data pointer to the next cube face + sourcePtr += w * w * src->getSizeBytes(); + + if (genMips) { + Adapter2D adapt(rsc, texAlloc); + Adapter2D adapt2(rsc, texAlloc); + adapt.setFace(face); + adapt2.setFace(face); + for (uint32_t lod=0; lod < (texAlloc->getType()->getLODCount() -1); lod++) { + adapt.setLOD(lod); + adapt2.setLOD(lod + 1); + mip(adapt2, adapt); + } + } + } + } else { + rsc->setError(RS_ERROR_BAD_VALUE, "Unsupported bitmap format"); + delete texAlloc; + return NULL; + } + + return texAlloc; +} diff --git a/libs/rs/rsAllocation.h b/libs/rs/rsAllocation.h index f9a0fc9765d1a..5b432f2cf2797 100644 --- a/libs/rs/rsAllocation.h +++ b/libs/rs/rsAllocation.h @@ -48,6 +48,8 @@ public: void uploadToTexture(const Context *rsc); uint32_t getTextureID() const {return mTextureID;} + uint32_t getGLTarget() const; + void deferedUploadToBufferObject(const Context *rsc); void uploadToBufferObject(const Context *rsc); uint32_t getBufferObjectID() const {return mBufferID;} @@ -134,7 +136,8 @@ protected: private: void init(Context *rsc, const Type *); - + void upload2DTexture(bool isFirstUpload); + void uploadCubeTexture(bool isFirstUpload); }; } diff --git a/libs/rs/rsFont.cpp b/libs/rs/rsFont.cpp index e4d77b2b785e0..107022d5724d0 100644 --- a/libs/rs/rsFont.cpp +++ b/libs/rs/rsFont.cpp @@ -498,8 +498,8 @@ void FontState::initRenderState() { uint32_t tmp[4]; tmp[0] = RS_PROGRAM_PARAM_CONSTANT; tmp[1] = (uint32_t)inputType; - tmp[2] = RS_PROGRAM_PARAM_TEXTURE_COUNT; - tmp[3] = 1; + tmp[2] = RS_PROGRAM_PARAM_TEXTURE_TYPE; + tmp[3] = RS_TEXTURE_2D; mFontShaderFConstant.set(new Allocation(mRSC, inputType)); ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(), diff --git a/libs/rs/rsProgram.cpp b/libs/rs/rsProgram.cpp index 1c44e71051add..39b85e39ed3f7 100644 --- a/libs/rs/rsProgram.cpp +++ b/libs/rs/rsProgram.cpp @@ -48,13 +48,14 @@ Program::Program(Context *rsc, const char * shaderText, uint32_t shaderLength, if (params[ct] == RS_PROGRAM_PARAM_CONSTANT) { mConstantCount++; } - if (params[ct] == RS_PROGRAM_PARAM_TEXTURE_COUNT) { - mTextureCount = params[ct+1]; + if (params[ct] == RS_PROGRAM_PARAM_TEXTURE_TYPE) { + mTextureCount++; } } mTextures = new ObjectBaseRef[mTextureCount]; mSamplers = new ObjectBaseRef[mTextureCount]; + mTextureTargets = new RsTextureTarget[mTextureCount]; mInputElements = new ObjectBaseRef[mInputCount]; mOutputElements = new ObjectBaseRef[mOutputCount]; mConstantTypes = new ObjectBaseRef[mConstantCount]; @@ -63,6 +64,7 @@ Program::Program(Context *rsc, const char * shaderText, uint32_t shaderLength, uint32_t input = 0; uint32_t output = 0; uint32_t constant = 0; + uint32_t texture = 0; for (uint32_t ct=0; ct < paramLength; ct+=2) { if (params[ct] == RS_PROGRAM_PARAM_INPUT) { mInputElements[input++].set(reinterpret_cast(params[ct+1])); @@ -73,6 +75,9 @@ Program::Program(Context *rsc, const char * shaderText, uint32_t shaderLength, if (params[ct] == RS_PROGRAM_PARAM_CONSTANT) { mConstantTypes[constant++].set(reinterpret_cast(params[ct+1])); } + if (params[ct] == RS_PROGRAM_PARAM_TEXTURE_TYPE) { + mTextureTargets[texture++] = (RsTextureTarget)params[ct+1]; + } } mIsInternal = false; uint32_t internalTokenLen = strlen(RS_SHADER_INTERNAL); @@ -106,6 +111,7 @@ Program::~Program() { } delete[] mTextures; delete[] mSamplers; + delete[] mTextureTargets; delete[] mInputElements; delete[] mOutputElements; delete[] mConstantTypes; @@ -127,6 +133,7 @@ void Program::initMemberVars() { mTextures = NULL; mSamplers = NULL; + mTextureTargets = NULL; mInputElements = NULL; mOutputElements = NULL; mConstantTypes = NULL; @@ -176,6 +183,12 @@ void Program::bindTexture(Context *rsc, uint32_t slot, Allocation *a) { return; } + if (a && a->getType()->getDimFaces() && mTextureTargets[slot] != RS_TEXTURE_CUBE) { + LOGE("Attempt to bind cubemap to slot %u but 2d texture needed", slot); + rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind cubemap to 2d texture slot"); + return; + } + //LOGE("bindtex %i %p", slot, a); mTextures[slot].set(a); mDirty = true; diff --git a/libs/rs/rsProgram.h b/libs/rs/rsProgram.h index b682b977e1acf..c48464dadecc0 100644 --- a/libs/rs/rsProgram.h +++ b/libs/rs/rsProgram.h @@ -105,7 +105,7 @@ protected: // Constants are strictly accessed by programetic loads. ObjectBaseRef *mTextures; ObjectBaseRef *mSamplers; - + RsTextureTarget *mTextureTargets; bool loadShader(Context *, uint32_t type); }; diff --git a/libs/rs/rsProgramFragment.cpp b/libs/rs/rsProgramFragment.cpp index 407522ba11d36..ffa7d269fd782 100644 --- a/libs/rs/rsProgramFragment.cpp +++ b/libs/rs/rsProgramFragment.cpp @@ -99,15 +99,20 @@ void ProgramFragment::setupGL2(Context *rsc, ProgramFragmentState *state, Shader } mTextures[ct]->uploadCheck(rsc); - glBindTexture(GL_TEXTURE_2D, mTextures[ct]->getTextureID()); + GLenum target = (GLenum)mTextures[ct]->getGLTarget(); + if (target != GL_TEXTURE_2D && target != 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(target, mTextures[ct]->getTextureID()); rsc->checkError("ProgramFragment::setupGL2 tex bind"); if (mSamplers[ct].get()) { mSamplers[ct]->setupGL(rsc, mTextures[ct].get()); } else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); rsc->checkError("ProgramFragment::setupGL2 tex env"); } @@ -130,7 +135,11 @@ void ProgramFragment::createShader() { appendUserConstants(); char buf[256]; for (uint32_t ct=0; ct < mTextureCount; ct++) { - sprintf(buf, "uniform sampler2D UNI_Tex%i;\n", ct); + if (mTextureTargets[ct] == RS_TEXTURE_2D) { + sprintf(buf, "uniform sampler2D UNI_Tex%i;\n", ct); + } else { + sprintf(buf, "uniform samplerCube UNI_Tex%i;\n", ct); + } mShader.append(buf); } mShader.append(mUserShader); @@ -191,15 +200,13 @@ void ProgramFragmentState::init(Context *rsc) { Type *inputType = Type::getType(rsc, constInput, 1, 0, 0, false, false); - uint32_t tmp[4]; + uint32_t tmp[2]; tmp[0] = RS_PROGRAM_PARAM_CONSTANT; tmp[1] = (uint32_t)inputType; - tmp[2] = RS_PROGRAM_PARAM_TEXTURE_COUNT; - tmp[3] = 0; Allocation *constAlloc = new Allocation(rsc, inputType); ProgramFragment *pf = new ProgramFragment(rsc, shaderString.string(), - shaderString.length(), tmp, 4); + shaderString.length(), tmp, 2); pf->bindAllocation(rsc, constAlloc, 0); pf->setConstantColor(rsc, 1.0f, 1.0f, 1.0f, 1.0f); diff --git a/libs/rs/rsProgramVertex.cpp b/libs/rs/rsProgramVertex.cpp index e165967b70fee..3fd2981be0baa 100644 --- a/libs/rs/rsProgramVertex.cpp +++ b/libs/rs/rsProgramVertex.cpp @@ -253,16 +253,14 @@ void ProgramVertexState::init(Context *rsc) { shaderString.append(" varTex0 = ATTRIB_texture0;\n"); shaderString.append("}\n"); - uint32_t tmp[6]; + uint32_t tmp[4]; tmp[0] = RS_PROGRAM_PARAM_CONSTANT; tmp[1] = (uint32_t)inputType; tmp[2] = RS_PROGRAM_PARAM_INPUT; tmp[3] = (uint32_t)attrElem; - tmp[4] = RS_PROGRAM_PARAM_TEXTURE_COUNT; - tmp[5] = 0; ProgramVertex *pv = new ProgramVertex(rsc, shaderString.string(), - shaderString.length(), tmp, 6); + shaderString.length(), tmp, 4); Allocation *alloc = new Allocation(rsc, inputType); pv->bindAllocation(rsc, alloc, 0); diff --git a/libs/rs/rsSampler.cpp b/libs/rs/rsSampler.cpp index 1d0d27080cbf2..54282a8dd8cbe 100644 --- a/libs/rs/rsSampler.cpp +++ b/libs/rs/rsSampler.cpp @@ -71,29 +71,32 @@ void Sampler::setupGL(const Context *rsc, const Allocation *tex) { GL_CLAMP_TO_EDGE, //RS_SAMPLER_CLAMP }; + // This tells us the correct texture type + GLenum target = (GLenum)tex->getGLTarget(); + if (!rsc->ext_OES_texture_npot() && tex->getType()->getIsNp2()) { if (tex->getHasGraphicsMipmaps() && rsc->ext_GL_NV_texture_npot_2D_mipmap()) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, trans[mMinFilter]); + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, trans[mMinFilter]); } else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, transNP[mMinFilter]); + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, transNP[mMinFilter]); } - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, transNP[mMagFilter]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, transNP[mWrapS]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, transNP[mWrapT]); + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, transNP[mMagFilter]); + glTexParameteri(target, GL_TEXTURE_WRAP_S, transNP[mWrapS]); + glTexParameteri(target, GL_TEXTURE_WRAP_T, transNP[mWrapT]); } else { if (tex->getHasGraphicsMipmaps()) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, trans[mMinFilter]); + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, trans[mMinFilter]); } else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, transNP[mMinFilter]); + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, transNP[mMinFilter]); } - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, trans[mMagFilter]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, trans[mWrapS]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, trans[mWrapT]); + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, trans[mMagFilter]); + glTexParameteri(target, GL_TEXTURE_WRAP_S, trans[mWrapS]); + glTexParameteri(target, GL_TEXTURE_WRAP_T, trans[mWrapT]); } float anisoValue = rsMin(rsc->ext_texture_max_aniso(), mAniso); if (rsc->ext_texture_max_aniso() > 1.0f) { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisoValue); + glTexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisoValue); } rsc->checkError("Sampler::setupGL2 tex env");