Stride argument in OpenGL ES 2.0

I’m putting this information here, as it took me way more time than it should to understand how the stride argument works in glVertexAttribPointer.

This argument is extremely important if you want to pack data in the same order as they are accessed by the CPU/GPU.

When reading the manual, I thought that stride was the number of bytes the OpenGL implementation would skip after reading size elements from the provided array.

However, it tends to work like this. glVertexAttribPointer :

  • starts reading data from the provided address (or from the current GL_ARRAY_BUFFER if any is bound),
  • read size elements from the address,
  • passes the values to the corresponding GLSL attribute,
  • jump stride bytes from the address it started reading from,
  • repeats this procedure count times, where count is the third argument passed to glDrawArrays.

So, for example, let’s take a float array stored at memory’s address 0x20000, containing the following 15 elements :

GLfloat arr[] = { 
  /* 0x20000 */ -1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
  /* 0x20014 */ -1.0f, 0.0f, 1.0f, 0.0f, 0.0f,
  /* 0x20028 */  0.0f, 1.0f, 1.0f, 1.0f, 1.0f 
};

If you use glVertexAttribArray like this :

glVertexAttribArray(your_glsl_attrib_index, 3, GL_FLOAT, GL_FALSE, 20, arr);

And then use glDrawArrays, the OpenGL implementation will do something akin to this :

  • Copy the address arr (0x20000).
  • Start reading {-1.0f, 1.0f, 1.0f} from the copied address (referred as copy_arr here) and pass these values to the GLSL attribute identified by your_glsl_attrib_index.
  • Do something like copy_arr += stride. At this point, copy_arr == 0x20014.

Then, on the second iteration, it will read {-1.0f, 0.0f, 1.0f} from the new copy_arr address, redo copy_arr += stride and continue like this for each iteration.

Here’s a concise diagram resuming this.

Schema showing how the OpenGL Stride argument works

Workaround for Unable to load native library: libnative-activity.so

So, another bug I had to deal with NativeActivity and for which I have no clear solution but a workaround for.

The problem

I compiled a version of libnative-activity.so that depends on my own library, libmyy.so, in order to add more flexibility during the testing process.

However, when trying to load the app, the app crashed with the following error :

    05-23 22:59:00.650: E/AndroidRuntime(4758): Caused by: java.lang.IllegalArgumentException: Unable to load native library: /data/app-lib/my.pack.name-2/libnative-activity.so

The workaround

  • Create a java class that subclasses android.app.NativeActivity and load the libnative-activity.so library with System.loadLibrary, in a static initialiser.
  • Edit AndroidManifest.xml to use this library, and remember to set android:hasCode to true in the tag.

Example

Here the java class will be called NativeDebug

app/src/main/java/my/pack/name/NativeDebug.java

package my.pack.name;

import android.app.NativeActivity;

public class NativeDebug extends NativeActivity {
  static { System.loadLibrary("native-activity"); }
}

app/src/main/AndroidManifest.xml

<!-- The package name is generally set up by gradle. It is not very important here-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="my.pack.name">

  <!-- Actually this .apk Java has code ! Set hasCode to true. Else your NativeDebug
        class will not be inserted in the final apk and your app will crash failing to find it. -->
  <application
      android:allowBackup="false"
      android:fullBackupContent="false"
      android:icon="@mipmap/ic_launcher"
      android:label="AppName"
      android:hasCode="true">

    <!-- Our activity is the built-in NativeActivity framework class.
         This will take care of integrating with our NDK code. -->
    <activity android:name=".NativeDebug"
              android:configChanges="orientation|keyboardHidden">
      <!-- Tell NativeActivity the name of or .so -->
      <meta-data android:name="android.app.lib_name"
                 android:value="native-activity" />
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>
  </application>

</manifest>

Note that this AndroidManifest.xml is based on the one provided with the NDK sample named native-activity.

Then install the new app (./gradlew installDebug or Android Studio ▶ button) and try your application.
In my case, it worked ! The library was loaded, my library was loaded too in the process, and the native code in my library was executed !

I still do not understand why NativeActivity.java tries to load libraries with a native C++ method named loadNativeCode. However, I do understand that loadNativeCode returns 0 when trying to load my libnative-activity.so file and NativeActivity in return throws an exception, with no hint about the problem whatsoever. A slightly more useful exception message seems to have been added now, though…

In the case that System.loadLibrary fails to load the library, your app will still crash but with a nice and helpful error message that you can use to solve the problem, this time.