Merge "Adding tests for element/mesh getters. Fixing bugs found by tests." into graphics-dev
diff --git a/graphics/java/android/renderscript/Element.java b/graphics/java/android/renderscript/Element.java
index 97ff307..11566c7 100644
--- a/graphics/java/android/renderscript/Element.java
+++ b/graphics/java/android/renderscript/Element.java
@@ -54,11 +54,36 @@
     int[] mArraySizes;
     int[] mOffsetInBytes;
 
+    int[] mVisibleElementMap;
+
     DataType mType;
     DataKind mKind;
     boolean mNormalized;
     int mVectorSize;
 
+    private void updateVisibleSubElements() {
+        if (mElements == null) {
+            return;
+        }
+
+        int noPaddingFieldCount = 0;
+        int fieldCount = mElementNames.length;
+        // Find out how many elements are not padding
+        for (int ct = 0; ct < fieldCount; ct ++) {
+            if (mElementNames[ct].charAt(0) != '#') {
+                noPaddingFieldCount ++;
+            }
+        }
+        mVisibleElementMap = new int[noPaddingFieldCount];
+
+        // Make a map that points us at non-padding elements
+        for (int ct = 0, ctNoPadding = 0; ct < fieldCount; ct ++) {
+            if (mElementNames[ct].charAt(0) != '#') {
+                mVisibleElementMap[ctNoPadding ++] = ct;
+            }
+        }
+    }
+
     /**
     * @hide
     * @return element size in bytes
@@ -83,6 +108,11 @@
      * RS_* objects.  32 bit opaque handles.
      */
     public enum DataType {
+        /**
+        * @hide
+        * new enum
+        */
+        NONE (0, 0),
         //FLOAT_16 (1, 2),
         FLOAT_32 (2, 4),
         FLOAT_64 (3, 8),
@@ -169,10 +199,10 @@
     * @return number of sub-elements in this element
     */
     public int getSubElementCount() {
-        if (mElements == null) {
+        if (mVisibleElementMap == null) {
             return 0;
         }
-        return mElements.length;
+        return mVisibleElementMap.length;
     }
 
     /**
@@ -181,13 +211,13 @@
     * @return sub-element in this element at given index
     */
     public Element getSubElement(int index) {
-        if (mElements == null) {
+        if (mVisibleElementMap == null) {
             throw new RSIllegalArgumentException("Element contains no sub-elements");
         }
-        if (index < 0 || index >= mElements.length) {
+        if (index < 0 || index >= mVisibleElementMap.length) {
             throw new RSIllegalArgumentException("Illegal sub-element index");
         }
-        return mElements[index];
+        return mElements[mVisibleElementMap[index]];
     }
 
     /**
@@ -196,13 +226,13 @@
     * @return sub-element in this element at given index
     */
     public String getSubElementName(int index) {
-        if (mElements == null) {
+        if (mVisibleElementMap == null) {
             throw new RSIllegalArgumentException("Element contains no sub-elements");
         }
-        if (index < 0 || index >= mElements.length) {
+        if (index < 0 || index >= mVisibleElementMap.length) {
             throw new RSIllegalArgumentException("Illegal sub-element index");
         }
-        return mElementNames[index];
+        return mElementNames[mVisibleElementMap[index]];
     }
 
     /**
@@ -211,13 +241,13 @@
     * @return array size of sub-element in this element at given index
     */
     public int getSubElementArraySize(int index) {
-        if (mElements == null) {
+        if (mVisibleElementMap == null) {
             throw new RSIllegalArgumentException("Element contains no sub-elements");
         }
-        if (index < 0 || index >= mElements.length) {
+        if (index < 0 || index >= mVisibleElementMap.length) {
             throw new RSIllegalArgumentException("Illegal sub-element index");
         }
-        return mArraySizes[index];
+        return mArraySizes[mVisibleElementMap[index]];
     }
 
     /**
@@ -226,13 +256,13 @@
     * @return offset in bytes of sub-element in this element at given index
     */
     public int getSubElementOffsetBytes(int index) {
-        if (mElements == null) {
+        if (mVisibleElementMap == null) {
             throw new RSIllegalArgumentException("Element contains no sub-elements");
         }
-        if (index < 0 || index >= mElements.length) {
+        if (index < 0 || index >= mVisibleElementMap.length) {
             throw new RSIllegalArgumentException("Illegal sub-element index");
         }
-        return mOffsetInBytes[index];
+        return mOffsetInBytes[mVisibleElementMap[index]];
     }
 
     /**
@@ -702,11 +732,14 @@
         mElements = e;
         mElementNames = n;
         mArraySizes = as;
+        mType = DataType.NONE;
+        mKind = DataKind.USER;
         mOffsetInBytes = new int[mElements.length];
         for (int ct = 0; ct < mElements.length; ct++ ) {
             mOffsetInBytes[ct] = mSize;
             mSize += mElements[ct].mSize * mArraySizes[ct];
         }
+        updateVisibleSubElements();
     }
 
     Element(int id, RenderScript rs, DataType dt, DataKind dk, boolean norm, int size) {
@@ -771,7 +804,7 @@
                 mSize += mElements[i].mSize * mArraySizes[i];
             }
         }
-
+        updateVisibleSubElements();
     }
 
     /**
diff --git a/libs/rs/rsElement.cpp b/libs/rs/rsElement.cpp
index 1e022cf..24c8738 100644
--- a/libs/rs/rsElement.cpp
+++ b/libs/rs/rsElement.cpp
@@ -27,6 +27,7 @@
     mFields = NULL;
     mFieldCount = 0;
     mHasReference = false;
+    memset(&mHal, 0, sizeof(mHal));
 }
 
 Element::~Element() {
@@ -176,16 +177,23 @@
         return;
     }
 
-    mHal.state.fields = new const Element*[mFieldCount];
-    mHal.state.fieldArraySizes = new uint32_t[mFieldCount];
-    mHal.state.fieldNames = new const char*[mFieldCount];
-    mHal.state.fieldNameLengths = new uint32_t[mFieldCount];
-    mHal.state.fieldOffsetBytes = new uint32_t[mFieldCount];
-    mHal.state.fieldsCount = mFieldCount;
+    uint32_t noPaddingFieldCount = 0;
+    for (uint32_t ct = 0; ct < mFieldCount; ct ++) {
+        if (mFields[ct].name.string()[0] != '#') {
+            noPaddingFieldCount ++;
+        }
+    }
+
+    mHal.state.fields = new const Element*[noPaddingFieldCount];
+    mHal.state.fieldArraySizes = new uint32_t[noPaddingFieldCount];
+    mHal.state.fieldNames = new const char*[noPaddingFieldCount];
+    mHal.state.fieldNameLengths = new uint32_t[noPaddingFieldCount];
+    mHal.state.fieldOffsetBytes = new uint32_t[noPaddingFieldCount];
+    mHal.state.fieldsCount = noPaddingFieldCount;
 
     size_t bits = 0;
     size_t bitsUnpadded = 0;
-    for (size_t ct=0; ct < mFieldCount; ct++) {
+    for (size_t ct = 0, ctNoPadding = 0; ct < mFieldCount; ct++) {
         mFields[ct].offsetBits = bits;
         mFields[ct].offsetBitsUnpadded = bitsUnpadded;
         bits += mFields[ct].e->getSizeBits() * mFields[ct].arraySize;
@@ -195,11 +203,17 @@
             mHasReference = true;
         }
 
-        mHal.state.fields[ct] = mFields[ct].e.get();
-        mHal.state.fieldArraySizes[ct] = mFields[ct].arraySize;
-        mHal.state.fieldNames[ct] = mFields[ct].name.string();
-        mHal.state.fieldNameLengths[ct] = mFields[ct].name.length() + 1; // to include 0
-        mHal.state.fieldOffsetBytes[ct] = mFields[ct].offsetBits >> 3;
+        if (mFields[ct].name.string()[0] == '#') {
+            continue;
+        }
+
+        mHal.state.fields[ctNoPadding] = mFields[ct].e.get();
+        mHal.state.fieldArraySizes[ctNoPadding] = mFields[ct].arraySize;
+        mHal.state.fieldNames[ctNoPadding] = mFields[ct].name.string();
+        mHal.state.fieldNameLengths[ctNoPadding] = mFields[ct].name.length() + 1; // to include 0
+        mHal.state.fieldOffsetBytes[ctNoPadding] = mFields[ct].offsetBits >> 3;
+
+        ctNoPadding ++;
     }
 
     mHal.state.elementSizeBytes = getSizeBytes();
diff --git a/libs/rs/scriptc/rs_types.rsh b/libs/rs/scriptc/rs_types.rsh
index c9bb4dc..e1c8650 100644
--- a/libs/rs/scriptc/rs_types.rsh
+++ b/libs/rs/scriptc/rs_types.rsh
@@ -435,8 +435,8 @@
  */
 typedef enum {
     RS_TYPE_NONE,
-    RS_TYPE_FLOAT_16,
-    RS_TYPE_FLOAT_32,
+    //RS_TYPE_FLOAT_16,
+    RS_TYPE_FLOAT_32 = 2,
     RS_TYPE_FLOAT_64,
     RS_TYPE_SIGNED_8,
     RS_TYPE_SIGNED_16,
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
index 4466e59..b3486ab 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
@@ -64,6 +64,8 @@
 
         unitTests = new ArrayList<UnitTest>();
 
+        unitTests.add(new UT_mesh(this, mRes, mCtx));
+        unitTests.add(new UT_element(this, mRes, mCtx));
         unitTests.add(new UT_sampler(this, mRes, mCtx));
         unitTests.add(new UT_program_store(this, mRes, mCtx));
         unitTests.add(new UT_program_raster(this, mRes, mCtx));
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_element.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_element.java
new file mode 100644
index 0000000..942f634
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_element.java
@@ -0,0 +1,133 @@
+/*
+ * 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.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.renderscript.Element.*;
+import android.renderscript.Element.DataKind.*;
+import android.renderscript.Element.DataType.*;
+
+public class UT_element extends UnitTest {
+    private Resources mRes;
+
+    Element simpleElem;
+    Element complexElem;
+
+    final String subElemNames[] = {
+        "subElem0",
+        "subElem1",
+        "subElem2",
+        "arrayElem0",
+        "arrayElem1",
+        "subElem3",
+        "subElem4",
+        "subElem5",
+        "subElem6",
+        "subElem_7",
+    };
+
+    final int subElemArraySizes[] = {
+        1,
+        1,
+        1,
+        2,
+        5,
+        1,
+        1,
+        1,
+        1,
+        1,
+    };
+
+    final int subElemOffsets[] = {
+        0,
+        4,
+        8,
+        12,
+        20,
+        40,
+        44,
+        48,
+        64,
+        80,
+    };
+
+    protected UT_element(RSTestCore rstc, Resources res, Context ctx) {
+        super(rstc, "Element", ctx);
+        mRes = res;
+    }
+
+    private void initializeGlobals(RenderScript RS, ScriptC_element s) {
+        simpleElem = Element.F32_3(RS);
+        complexElem = ScriptField_ComplexStruct.createElement(RS);
+        s.set_simpleElem(simpleElem);
+        s.set_complexElem(complexElem);
+
+        ScriptField_ComplexStruct data = new ScriptField_ComplexStruct(RS, 1);
+        s.bind_complexStruct(data);
+    }
+
+    private void testScriptSide(RenderScript pRS) {
+        ScriptC_element s = new ScriptC_element(pRS, mRes, R.raw.element);
+        pRS.setMessageHandler(mRsMessage);
+        initializeGlobals(pRS, s);
+        s.invoke_element_test();
+        pRS.finish();
+        waitForMessage();
+    }
+
+    private void testJavaSide(RenderScript RS) {
+
+        int subElemCount = simpleElem.getSubElementCount();
+        _RS_ASSERT("subElemCount == 0", subElemCount == 0);
+        _RS_ASSERT("simpleElem.getDataKind() == USER",
+                   simpleElem.getDataKind() == DataKind.USER);
+        _RS_ASSERT("simpleElem.getDataType() == FLOAT_32",
+                   simpleElem.getDataType() == DataType.FLOAT_32);
+
+        subElemCount = complexElem.getSubElementCount();
+        _RS_ASSERT("subElemCount == 10", subElemCount == 10);
+        _RS_ASSERT("complexElem.getDataKind() == USER",
+                   complexElem.getDataKind() == DataKind.USER);
+        _RS_ASSERT("complexElemsimpleElem.getDataType() == NONE",
+                   complexElem.getDataType() == DataType.NONE);
+        _RS_ASSERT("complexElem.getSizeBytes() == ScriptField_ComplexStruct.Item.sizeof",
+                   complexElem.getSizeBytes() == ScriptField_ComplexStruct.Item.sizeof);
+
+        for (int i = 0; i < subElemCount; i ++) {
+            _RS_ASSERT("complexElem.getSubElement(i) != null",
+                       complexElem.getSubElement(i) != null);
+            _RS_ASSERT("complexElem.getSubElementName(i).equals(subElemNames[i])",
+                       complexElem.getSubElementName(i).equals(subElemNames[i]));
+            _RS_ASSERT("complexElem.getSubElementArraySize(i) == subElemArraySizes[i]",
+                       complexElem.getSubElementArraySize(i) == subElemArraySizes[i]);
+            _RS_ASSERT("complexElem.getSubElementOffsetBytes(i) == subElemOffsets[i]",
+                       complexElem.getSubElementOffsetBytes(i) == subElemOffsets[i]);
+        }
+
+        updateUI();
+    }
+
+    public void run() {
+        RenderScript pRS = RenderScript.create(mCtx);
+        testScriptSide(pRS);
+        testJavaSide(pRS);
+        pRS.destroy();
+    }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_mesh.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_mesh.java
new file mode 100644
index 0000000..2ea9f17
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_mesh.java
@@ -0,0 +1,75 @@
+/*
+ * 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.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.renderscript.Mesh.*;
+
+public class UT_mesh extends UnitTest {
+    private Resources mRes;
+
+    Mesh mesh;
+
+    protected UT_mesh(RSTestCore rstc, Resources res, Context ctx) {
+        super(rstc, "Mesh", ctx);
+        mRes = res;
+    }
+
+    private void initializeGlobals(RenderScript RS, ScriptC_mesh s) {
+        Allocation vAlloc0 = Allocation.createSized(RS, Element.F32(RS), 10);
+        Allocation vAlloc1 = Allocation.createSized(RS, Element.F32_2(RS), 10);
+
+        Allocation iAlloc0 = Allocation.createSized(RS, Element.I16(RS), 10);
+        Allocation iAlloc2 = Allocation.createSized(RS, Element.I16(RS), 10);
+
+        Mesh.AllocationBuilder mBuilder = new Mesh.AllocationBuilder(RS);
+        mBuilder.addVertexAllocation(vAlloc0);
+        mBuilder.addVertexAllocation(vAlloc1);
+
+        mBuilder.addIndexSetAllocation(iAlloc0, Primitive.POINT);
+        mBuilder.addIndexSetType(Primitive.LINE);
+        mBuilder.addIndexSetAllocation(iAlloc2, Primitive.TRIANGLE);
+
+        s.set_mesh(mBuilder.create());
+        s.set_vertexAlloc0(vAlloc0);
+        s.set_vertexAlloc1(vAlloc1);
+        s.set_indexAlloc0(iAlloc0);
+        s.set_indexAlloc2(iAlloc2);
+    }
+
+    private void testScriptSide(RenderScript pRS) {
+        ScriptC_mesh s = new ScriptC_mesh(pRS, mRes, R.raw.mesh);
+        pRS.setMessageHandler(mRsMessage);
+        initializeGlobals(pRS, s);
+        s.invoke_mesh_test();
+        pRS.finish();
+        waitForMessage();
+    }
+
+    private void testJavaSide(RenderScript RS) {
+        updateUI();
+    }
+
+    public void run() {
+        RenderScript pRS = RenderScript.create(mCtx);
+        testScriptSide(pRS);
+        testJavaSide(pRS);
+        pRS.destroy();
+    }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/element.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/element.rs
new file mode 100644
index 0000000..c0bd36e
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/element.rs
@@ -0,0 +1,141 @@
+#include "shared.rsh"
+#include "rs_graphics.rsh"
+
+rs_element simpleElem;
+rs_element complexElem;
+typedef struct ComplexStruct {
+    float subElem0;
+    float subElem1;
+    int subElem2;
+    float arrayElem0[2];
+    int arrayElem1[5];
+    char subElem3;
+    float subElem4;
+    float2 subElem5;
+    float3 subElem6;
+    float4 subElem_7;
+} ComplexStruct_t;
+
+ComplexStruct_t *complexStruct;
+
+static const char *subElemNames[] = {
+    "subElem0",
+    "subElem1",
+    "subElem2",
+    "arrayElem0",
+    "arrayElem1",
+    "subElem3",
+    "subElem4",
+    "subElem5",
+    "subElem6",
+    "subElem_7",
+};
+
+static uint32_t subElemNamesSizes[] = {
+    8,
+    8,
+    8,
+    10,
+    10,
+    8,
+    8,
+    8,
+    8,
+    9,
+};
+
+static uint32_t subElemArraySizes[] = {
+    1,
+    1,
+    1,
+    2,
+    5,
+    1,
+    1,
+    1,
+    1,
+    1,
+};
+
+static void resetStruct() {
+    uint8_t *bytePtr = (uint8_t*)complexStruct;
+    uint32_t sizeOfStruct = sizeof(*complexStruct);
+    for(uint32_t i = 0; i < sizeOfStruct; i ++) {
+        bytePtr[i] = 0;
+    }
+}
+
+static bool equals(const char *name0, const char * name1, uint32_t len) {
+    for (uint32_t i = 0; i < len; i ++) {
+        if (name0[i] != name1[i]) {
+            return false;
+        }
+    }
+    return true;
+}
+
+static bool test_element_getters() {
+    bool failed = false;
+
+    uint32_t subElemOffsets[10];
+    uint32_t index = 0;
+    subElemOffsets[index++] = (uint32_t)&complexStruct->subElem0   - (uint32_t)complexStruct;
+    subElemOffsets[index++] = (uint32_t)&complexStruct->subElem1   - (uint32_t)complexStruct;
+    subElemOffsets[index++] = (uint32_t)&complexStruct->subElem2   - (uint32_t)complexStruct;
+    subElemOffsets[index++] = (uint32_t)&complexStruct->arrayElem0 - (uint32_t)complexStruct;
+    subElemOffsets[index++] = (uint32_t)&complexStruct->arrayElem1 - (uint32_t)complexStruct;
+    subElemOffsets[index++] = (uint32_t)&complexStruct->subElem3   - (uint32_t)complexStruct;
+    subElemOffsets[index++] = (uint32_t)&complexStruct->subElem4   - (uint32_t)complexStruct;
+    subElemOffsets[index++] = (uint32_t)&complexStruct->subElem5   - (uint32_t)complexStruct;
+    subElemOffsets[index++] = (uint32_t)&complexStruct->subElem6   - (uint32_t)complexStruct;
+    subElemOffsets[index++] = (uint32_t)&complexStruct->subElem_7  - (uint32_t)complexStruct;
+
+    uint32_t subElemCount = rsElementGetSubElementCount(simpleElem);
+    _RS_ASSERT(subElemCount == 0);
+    _RS_ASSERT(rsElementGetDataKind(simpleElem) == RS_KIND_USER);
+    _RS_ASSERT(rsElementGetDataType(simpleElem) == RS_TYPE_FLOAT_32);
+
+    subElemCount = rsElementGetSubElementCount(complexElem);
+    _RS_ASSERT(subElemCount == 10);
+    _RS_ASSERT(rsElementGetDataKind(complexElem) == RS_KIND_USER);
+    _RS_ASSERT(rsElementGetDataType(complexElem) == RS_TYPE_NONE);
+    _RS_ASSERT(rsElementGetSizeBytes(complexElem) == sizeof(*complexStruct));
+
+    char buffer[64];
+    for (uint32_t i = 0; i < subElemCount; i ++) {
+        rs_element subElem = rsElementGetSubElement(complexElem, i);
+        _RS_ASSERT(rsIsObject(subElem));
+
+        _RS_ASSERT(rsElementGetSubElementNameLength(complexElem, i) == subElemNamesSizes[i] + 1);
+
+        uint32_t written = rsElementGetSubElementName(complexElem, i, buffer, 64);
+        rsDebug(subElemNames[i], subElemNames[i]);
+        _RS_ASSERT(written == subElemNamesSizes[i]);
+        _RS_ASSERT(equals(buffer, subElemNames[i], written));
+
+        _RS_ASSERT(rsElementGetSubElementArraySize(complexElem, i) == subElemArraySizes[i]);
+        _RS_ASSERT(rsElementGetSubElementOffsetBytes(complexElem, i) == subElemOffsets[i]);
+    }
+
+    if (failed) {
+        rsDebug("test_element_getters FAILED", 0);
+    }
+    else {
+        rsDebug("test_element_getters PASSED", 0);
+    }
+
+    return failed;
+}
+
+void element_test() {
+    bool failed = false;
+    failed |= test_element_getters();
+
+    if (failed) {
+        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+    }
+    else {
+        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+    }
+}
+
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/mesh.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/mesh.rs
new file mode 100644
index 0000000..4d2b255
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/mesh.rs
@@ -0,0 +1,58 @@
+#include "shared.rsh"
+#include "rs_graphics.rsh"
+
+rs_mesh mesh;
+rs_allocation vertexAlloc0;
+rs_allocation vertexAlloc1;
+
+rs_allocation indexAlloc0;
+rs_allocation indexAlloc2;
+
+static bool test_mesh_getters() {
+    bool failed = false;
+
+    _RS_ASSERT(rsMeshGetVertexAllocationCount(mesh) == 2);
+    _RS_ASSERT(rsMeshGetPrimitiveCount(mesh) == 3);
+
+    rs_allocation meshV0 = rsMeshGetVertexAllocation(mesh, 0);
+    rs_allocation meshV1 = rsMeshGetVertexAllocation(mesh, 1);
+    rs_allocation meshV2 = rsMeshGetVertexAllocation(mesh, 2);
+    _RS_ASSERT(meshV0.p == vertexAlloc0.p);
+    _RS_ASSERT(meshV1.p == vertexAlloc1.p);
+    _RS_ASSERT(!rsIsObject(meshV2));
+
+    rs_allocation meshI0 = rsMeshGetIndexAllocation(mesh, 0);
+    rs_allocation meshI1 = rsMeshGetIndexAllocation(mesh, 1);
+    rs_allocation meshI2 = rsMeshGetIndexAllocation(mesh, 2);
+    rs_allocation meshI3 = rsMeshGetIndexAllocation(mesh, 3);
+    _RS_ASSERT(meshI0.p == indexAlloc0.p);
+    _RS_ASSERT(!rsIsObject(meshI1));
+    _RS_ASSERT(meshI2.p == indexAlloc2.p);
+    _RS_ASSERT(!rsIsObject(meshI3));
+
+    rs_primitive p0 = rsMeshGetPrimitive(mesh, 0);
+    rs_primitive p1 = rsMeshGetPrimitive(mesh, 1);
+    rs_primitive p2 = rsMeshGetPrimitive(mesh, 2);
+
+    if (failed) {
+        rsDebug("test_mesh_getters FAILED", 0);
+    }
+    else {
+        rsDebug("test_mesh_getters PASSED", 0);
+    }
+
+    return failed;
+}
+
+void mesh_test() {
+    bool failed = false;
+    failed |= test_mesh_getters();
+
+    if (failed) {
+        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+    }
+    else {
+        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+    }
+}
+