diff options
21 files changed, 444 insertions, 72 deletions
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java index 0de53f2..bad1208 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 83c3601..22f3fc5 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 d30e483..faaf980 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 13f017a..998e05e 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 dcf86e3..0660441 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 1cc4386..6a1a319 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 20e289d..0ed129f 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 Binary files differnew file mode 100644 index 0000000..75ad0a4 --- /dev/null +++ b/libs/rs/java/Samples/res/drawable/cubemap_test.png diff --git a/libs/rs/java/Samples/res/raw/shadercubef.glsl b/libs/rs/java/Samples/res/raw/shadercubef.glsl new file mode 100644 index 0000000..15696a4 --- /dev/null +++ b/libs/rs/java/Samples/res/raw/shadercubef.glsl @@ -0,0 +1,8 @@ + +varying vec3 worldNormal; + +void main() { + lowp vec4 col = textureCube(UNI_Tex0, worldNormal); + gl_FragColor = col; +} + diff --git a/libs/rs/java/Samples/res/raw/shadercubev.glsl b/libs/rs/java/Samples/res/raw/shadercubev.glsl new file mode 100644 index 0000000..70f5cd6 --- /dev/null +++ b/libs/rs/java/Samples/res/raw/shadercubev.glsl @@ -0,0 +1,10 @@ +varying vec3 worldNormal; + +// This is where actual shader code begins +void main() { + vec4 worldPos = UNI_model * ATTRIB_position; + gl_Position = UNI_proj * worldPos; + + mat3 model3 = mat3(UNI_model[0].xyz, UNI_model[1].xyz, UNI_model[2].xyz); + worldNormal = model3 * ATTRIB_normal; +} diff --git a/libs/rs/java/Samples/src/com/android/samples/RsRenderStatesRS.java b/libs/rs/java/Samples/src/com/android/samples/RsRenderStatesRS.java index f0b69d1..766601b 100644 --- a/libs/rs/java/Samples/src/com/android/samples/RsRenderStatesRS.java +++ b/libs/rs/java/Samples/src/com/android/samples/RsRenderStatesRS.java @@ -22,6 +22,8 @@ import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.renderscript.*; +import android.renderscript.Allocation.CubemapLayout; +import android.renderscript.Program.TextureType; import android.renderscript.ProgramStore.DepthFunc; import android.renderscript.Sampler.Value; import android.util.Log; @@ -80,6 +82,9 @@ public class RsRenderStatesRS { private ProgramVertex mProgVertexCustom2; private ProgramFragment mProgFragmentCustom2; + private ProgramVertex mProgVertexCube; + private ProgramFragment mProgFragmentCube; + private ProgramRaster mCullBack; private ProgramRaster mCullFront; private ProgramRaster mCullNone; @@ -88,6 +93,7 @@ public class RsRenderStatesRS { private Allocation mTexOpaque; private Allocation mTexTransparent; private Allocation mTexChecker; + private Allocation mTexCube; private Mesh mMbyNMesh; private Mesh mTorus; @@ -240,6 +246,19 @@ public class RsRenderStatesRS { mProgFragmentCustom2 = pfbCustom.create(); mProgFragmentCustom2.bindConstants(mFSConst2.getAllocation(), 0); + // Cubemap test shaders + pvbCustom = new ProgramVertex.ShaderBuilder(mRS); + pvbCustom.setShader(mRes, R.raw.shadercubev); + pvbCustom.addInput(ScriptField_VertexShaderInputs_s.createElement(mRS)); + pvbCustom.addConstant(mVSConst.getAllocation().getType()); + mProgVertexCube = pvbCustom.create(); + mProgVertexCube.bindConstants(mVSConst.getAllocation(), 0); + + pfbCustom = new ProgramFragment.ShaderBuilder(mRS); + pfbCustom.setShader(mRes, R.raw.shadercubef); + pfbCustom.addTexture(Program.TextureType.TEXTURE_CUBE); + mProgFragmentCube = pfbCustom.create(); + pfbCustom = new ProgramFragment.ShaderBuilder(mRS); pfbCustom.setShader(mRes, R.raw.multitexf); pfbCustom.setTextureCount(3); @@ -247,10 +266,11 @@ public class RsRenderStatesRS { mScript.set_gProgVertexCustom(mProgVertexCustom); mScript.set_gProgFragmentCustom(mProgFragmentCustom); - mScript.set_gProgFragmentMultitex(mProgFragmentMultitex); - mScript.set_gProgVertexCustom2(mProgVertexCustom2); mScript.set_gProgFragmentCustom2(mProgFragmentCustom2); + mScript.set_gProgVertexCube(mProgVertexCube); + mScript.set_gProgFragmentCube(mProgFragmentCube); + mScript.set_gProgFragmentMultitex(mProgFragmentMultitex); } private Allocation loadTextureRGB(int id) { @@ -272,11 +292,16 @@ public class RsRenderStatesRS { mTexOpaque = loadTextureRGB(R.drawable.data); mTexTransparent = loadTextureARGB(R.drawable.leaf); mTexChecker = loadTextureRGB(R.drawable.checker); + Bitmap b = BitmapFactory.decodeResource(mRes, R.drawable.cubemap_test); + mTexCube = Allocation.createCubemapFromBitmap(mRS, b, Element.RGB_565(mRS), false, + Allocation.CubemapLayout.VERTICAL_FACE_LIST); + mTexCube.uploadToTexture(0); mScript.set_gTexTorus(mTexTorus); mScript.set_gTexOpaque(mTexOpaque); mScript.set_gTexTransparent(mTexTransparent); mScript.set_gTexChecker(mTexChecker); + mScript.set_gTexCube(mTexCube); } private void initFonts() { diff --git a/libs/rs/java/Samples/src/com/android/samples/rsrenderstates.rs b/libs/rs/java/Samples/src/com/android/samples/rsrenderstates.rs index f26633d..39b0834 100644 --- a/libs/rs/java/Samples/src/com/android/samples/rsrenderstates.rs +++ b/libs/rs/java/Samples/src/com/android/samples/rsrenderstates.rs @@ -19,7 +19,7 @@ #include "rs_graphics.rsh" #include "shader_def.rsh" -const int gMaxModes = 10; +const int gMaxModes = 11; rs_program_vertex gProgVertex; rs_program_fragment gProgFragmentColor; @@ -34,6 +34,7 @@ rs_allocation gTexOpaque; rs_allocation gTexTorus; rs_allocation gTexTransparent; rs_allocation gTexChecker; +rs_allocation gTexCube; rs_mesh gMbyNMesh; rs_mesh gTorusMesh; @@ -71,6 +72,8 @@ rs_program_vertex gProgVertexCustom; rs_program_fragment gProgFragmentCustom; rs_program_vertex gProgVertexCustom2; rs_program_fragment gProgFragmentCustom2; +rs_program_vertex gProgVertexCube; +rs_program_fragment gProgFragmentCube; rs_program_fragment gProgFragmentMultitex; float gDt = 0; @@ -506,6 +509,42 @@ void displayCustomShaderSamples2() { rsgDrawText("Custom shader sample with array uniforms", 10, rsgGetHeight() - 10); } +void displayCubemapShaderSample() { + // Update vertex shader constants + // Load model matrix + // Aplly a rotation to our mesh + gTorusRotation += 50.0f * gDt; + if (gTorusRotation > 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 2a705a1..8d363fd 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<uint8_t *>(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 23135e2..4ade714 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<uint16_t *>(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<Context *>(con); + const Element *src = static_cast<const Element *>(_src); + const Element *dst = static_cast<const Element *>(_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<Allocation *>(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 f9a0fc9..5b432f2 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 e4d77b2..107022d 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 1c44e71..39b85e3 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<Allocation>[mTextureCount]; mSamplers = new ObjectBaseRef<Sampler>[mTextureCount]; + mTextureTargets = new RsTextureTarget[mTextureCount]; mInputElements = new ObjectBaseRef<Element>[mInputCount]; mOutputElements = new ObjectBaseRef<Element>[mOutputCount]; mConstantTypes = new ObjectBaseRef<Type>[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<Element *>(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<Type *>(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 b682b97..c48464d 100644 --- a/libs/rs/rsProgram.h +++ b/libs/rs/rsProgram.h @@ -105,7 +105,7 @@ protected: // Constants are strictly accessed by programetic loads. ObjectBaseRef<Allocation> *mTextures; ObjectBaseRef<Sampler> *mSamplers; - + RsTextureTarget *mTextureTargets; bool loadShader(Context *, uint32_t type); }; diff --git a/libs/rs/rsProgramFragment.cpp b/libs/rs/rsProgramFragment.cpp index 407522b..ffa7d26 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 e165967..3fd2981 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 1d0d270..54282a8 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"); |