OpenGL* ES 3.0 Instanced Rendering

This Android OpenGL ES 3.0 Sample was written by Cristiano Ferreira - Software Engineer at Intel Corporation.

By batch-rendering multiple versions of the same mesh, instanced rendering can help developers using OpenGL* ES 3.0 and later dramatically improve performance and resource efficiency. The sample code introduced here demonstrates a simple technique for using this capability.

Instanced rendering allows for the reuse of geometry information, to render multiple instances of the same mesh with a single API call. Developers can use uniforms to apply unique attributes to specific instances, which provides for variation using visual properties such as texture. By reducing overhead—and therefore resource requirements—to render large numbers of elements, instanced rendering offers the potential to improve visual experiences, especially on hardware-constrained mobile devices.

Instancing was first introduced in OpenGL 3.1 as an arb extension (ARB_draw_instanced). This capability has now been added to the mobile space, with its inclusion as a core feature in OpenGL ES 3.0.

Downloading and installing the sample

The code sample is available for download from GitHub.  To build and deploy the application to your Android device, choose either of the approaches described below.

Approach 1: Use BUILDANDROID.BAT

  1. Navigate to InstancingAndroid\Utilities
  2. Run buildandroid.bat

Approach 2: Build from the command line

  1. Navigate to InstancingAndroid\InstancingAndroid
  2. Run the following:

android update project –p .

ndk-build

ant debug

ant installd

Details of the implementation

This sample implements instancing by means of a uniform buffer that contains transform matrices for the model instances. The implementation operates as follows:

  1. The first step is filling the buffer with our transform data.
  2. When rendering, we simply call glDrawElementsInstanced instead of glDrawElements and pass in the number of instances as a parameter.
    • Submitting the geometry information only once, glDrawElementsInstanced uses those same resources repeatedly to draw the desired number of instances.
    • Each instance is assigned a unique identifier, as a value of gl_InstanceID that ranges from 0 up to ((num instances)-1). That value is used as an index to the uniform buffer to extract the current instances transform matrix and other properties.

While instancing does not require significant added work on the developer’s part, it can significantly increase rendering efficiency and performance.

Performance comparison: instanced versus non-instanced rendering

Instanced rendering is traditionally used for very large numbers of instances, on relatively simple (low poly) meshes. As shown in this sample, however, this capability can also be used effectively for fairly complex structures. The following chart compares the performance using an instanced draw call versus the non-instanced approach with multiple draw calls. As the number of instances increases, instanced rendering demonstrates a clear performance benefit, measured in terms of higher frame rates.

Conclusion

The instancing technique shown in this sample gives developers a simple means of substantially increasing performance in their OpenGL ES 3.0 applications. Instanced rendering lowers the resource requirements to provide rich, dynamic backgrounds, allowing developers to replace more limited billboarding techniques. That helps bring visual experiences that approach desktop-quality 3D graphics on mobile devices.

Additional Resources

OpenGL ES: The Standard for Embedded Accelerated 3D Graphics is Khronos Group’s official OpenGL ES page; it describes the standard and provides links to specifications, header files, and reference materials.

Android Developer Guide for OpenGL ES provides background and guidance for use of the OpenGL ES API with Android, including management of compatibility between the two.

OpenGL® ES 3.0 and Beyond: How To Deliver Desktop Graphics on Mobile Platforms describes capabilities of both OpenGL ES 3.0 and 3.1, including how they are supported on Intel’s Bay Trail platform.

Intel® Open Source Technology Center Intel Graphics for Linux* provides downloads, documentation, and community resources related to graphics for Linux on Intel® platforms.

 
06-02-2014
06-02-2014
Graphics Tech Samples
 
 
 
http://software.intel.com/sites/default/files/managed/0c/1e/instancing1.png
By batch-rendering multiple versions of the same mesh, instanced rendering can help developers using OpenGL* ES 3.0 and later dramatically improve performance and resource efficiency.
For more complete information about compiler optimizations, see our Optimization Notice.

2 comments

Top
Neil R.'s picture

Is there any reason why this example uses a large array of uniforms rather than instanced attributes? These are available on GLES 3.0 as well. At least on Mesa with Intel hardware if you use instanced attributes it generates a much more efficient shader because the per-instance matrix can be pushed directly into the registers. If a large uniform buffer is used then the shader ends up with a memory fetch request to get the matrix because the compiler has no way of knowing upfront that each shader instance is only going to access a very small part of the buffer. Presumably this would fix the problem mentioned in the comment by Rishi as well because it looks like the compiler is running out of space for the uniforms there. There would be much less of a limitation on the number of instances if a VBO is used to store the matrices instead.

Rishi R.'s picture

Hi,

    I would like to run this example on my Samsung galaxy S5(Open GL ES 3.0) and Nexus player(OpenGLES 3.1). On Galaxy S5, I am getting following errors. Can you please let me know if I should do something before trying to run this on S5? 

 

I/CPUT    (12540): Load Scene
I/CPUT    (12540): ReadFileContents(instanceV2.scene) : dir [instanceV2.scene], file [instanceV2.scene]
I/CPUT    (12540): Failed to read file instanceV2.scene
I/CPUT    (12540): Failed to load scene
I/CPUT    (12540): Failed to Load Scene, try loading asset set individually
I/CPUT    (12540): ReadFileContents(instanceV2/Asset/instanceV2.set) : dir [instanceV2/Asset], file [instanceV2.set]
I/CPUT    (12540): ReadFileContents(instanceV2/Material/concreteMultiMaterial.mtl) : dir [instanceV2/Material], file [concreteMultiMaterial.mtl]
I/CPUT    (12540): ReadFileContents(instanceV2/Material/concreteMaterialInstanced.mtl) : dir [instanceV2/Material], file [concreteMaterialInstanced.mtl]
I/CPUT    (12540): creating shader: instanceV2/Shader/supportShaderInstanced.glsl
I/CPUT    (12540): ReadFileContents(instanceV2/Shader/supportShaderInstanced.glsl) : dir [instanceV2/Shader], file [supportShaderInstanced.glsl]
I/CPUT    (12540): Created Shader: 7
I/CPUT    (12540): creating shader: instanceV2/Shader/supportShaderInstanced.glsl
I/CPUT    (12540): ReadFileContents(instanceV2/Shader/supportShaderInstanced.glsl) : dir [instanceV2/Shader], file [supportShaderInstanced.glsl]
I/CPUT    (12540): Created Shader: 8
I/CPUT    (12540): ReadFileContents(System/Shader/Default.rs) : dir [System/Shader], file [Default.rs]
I/CPUT    (12540): ERROR:[jni/../../CPUT/CPUT/CPUTMaterialEffectOGL.cpp:LoadMaterialEffect:342]
I/CPUT    (12540): Failed to link shader program:
I/CPUT    (12540): --From Vertex Shader:
I/CPUT    (12540): Error: uniform variables in vertex shader do not fit in 256 vectors.
I/CPUT    (12540): --From Fragment Shader:
I/CPUT    (12540): Error: uniform variables in vertex shader do not fit in 256 vectors.
I/CPUT    (12540):
I/CPUT    (12540): Exit BindConstantBuffers
I/CPUT    (12540): ReadFileContents(instanceV2/Material/concreteMaterialNonInstanced.mtl) : dir [instanceV2/Material], file [concreteMaterialNonInstanced.mtl]
I/CPUT    (12540): creating shader: instanceV2/Shader/supportShaderNonInstanced.glsl
I/CPUT    (12540): ReadFileContents(instanceV2/Shader/supportShaderNonInstanced.glsl) : dir [instanceV2/Shader], file [supportShaderNonInstanced.glsl]
I/CPUT    (12540): Created Shader: 10
I/CPUT    (12540): creating shader: instanceV2/Shader/supportShaderNonInstanced.glsl
I/CPUT    (12540): ReadFileContents(instanceV2/Shader/supportShaderNonInstanced.glsl) : dir [instanceV2/Shader], file [supportShaderNonInstanced.glsl]
I/CPUT    (12540): Created Shader: 11
I/CPUT    (12540): ReadFileContents(instanceV2/Texture/concreteSupportDM.dds) : dir [instanceV2/Texture], file [concreteSupportDM.dds]
W/CPUT    (12540): OpenGL error 00000501, at jni/../../CPUT/CPUT/CPUTTextureOGL.cpp:211 - for glCompressedTexImage2D( GL_TEXTURE_2D, mip, internalFormat, mipWidth, mipHeight, 0, pixelDataSize, (pData + sizeof(DDSHeader)) + offset )
F/libc    (12540): Fatal signal 6 (SIGABRT) at 0x000030fc (code=-6), thread 12557 (tel.cput.sample)
I/DEBUG   (  373): pid: 12540, tid: 12557, name: tel.cput.sample  >>> com.intel.cput.sample <<<
I/DEBUG   (  373):     #05  pc 00039269  /data/app-lib/com.intel.cput.sample-3/libcput_sample.so (CheckOpenGLError(char const*, char const*, int)+36)
I/DEBUG   (  373):     #06  pc 0003ebb3  /data/app-lib/com.intel.cput.sample-3/libcput_sample.so (CPUTTextureOGL::CreateNativeTexture(std::string const&, int*, bool)+462)
I/DEBUG   (  373):     #07  pc 0003ee1b  /data/app-lib/com.intel.cput.sample-3/libcput_sample.so (CPUTTextureOGL::CreateTexture(std::string const&, std::string const&, bool)+26)
I/DEBUG   (  373):     #08  pc 0002d117  /data/app-lib/com.intel.cput.sample-3/libcput_sample.so (CPUTAssetLibrary::GetTexture(std::string const&, bool, bool)+226)
I/DEBUG   (  373):     #09  pc 00036777  /data/app-lib/com.intel.cput.sample-3/libcput_sample.so (CPUTMaterialEffectOGL::BindTextures(CPUTShaderParameters&, CPUTModel const*, int)+394)
I/DEBUG   (  373):     #10  pc 00036ebf  /data/app-lib/com.intel.cput.sample-3/libcput_sample.so (CPUTMaterialEffectOGL::LoadMaterialEffect(std::string const&, CPUTModel const*, int, char const**, int, std::string*, float4*, int*, int*)+890)
I/DEBUG   (  373):     #11  pc 0003547f  /data/app-lib/com.intel.cput.sample-3/libcput_sample.so (CPUTMaterialEffect::CreateMaterialEffect(std::string const&, CPUTModel const*, int, char const**, int, std::string*, float4*, int*, int*)+66)
I/DEBUG   (  373):     #12  pc 0002d361  /data/app-lib/com.intel.cput.sample-3/libcput_sample.so (CPUTAssetLibrary::GetMaterialEffect(std::string const&, bool, CPUTModel const*, int, char const**)+264)
I/DEBUG   (  373):     #13  pc 000351c9  /data/app-lib/com.intel.cput.sample-3/libcput_sample.so (CPUTMaterial::LoadMaterial(std::string const&, CPUTModel const*, int, char const**, int, std::string*, int, std::string*, float4*, int*, int*)+896)
I/DEBUG   (  373):     #14  pc 000352a5  /data/app-lib/com.intel.cput.sample-3/libcput_sample.so (CPUTMaterial::CreateMaterial(std::string const&, CPUTModel const*, int, char const**, int, std::string*, int, std::string*, float4*, int*, int*)+104)
I/DEBUG   (  373):     #15  pc 0002d4d5  /data/app-lib/com.intel.cput.sample-3/libcput_sample.so (CPUTAssetLibrary::GetMaterial(std::string const&, bool, CPUTModel const*, int, char const**, int, std::string*, std::string*, float4*, int*, int*, int)+316)
I/DEBUG   (  373):     #16  pc 00038dcb  /data/app-lib/com.intel.cput.sample-3/libcput_sample.so (CPUTModelOGL::LoadModel(CPUTConfigBlock*, int*, CPUTModel*, int, std::string*)+1042)
I/DEBUG   (  373):     #17  pc 0002ebb1  /data/app-lib/com.intel.cput.sample-3/libcput_sample.so (CPUTAssetSetOGL::LoadAssetSet(std::string, int, std::string*)+504)
I/DEBUG   (  373):     #18  pc 0002efdb  /data/app-lib/com.intel.cput.sample-3/libcput_sample.so (CPUTAssetSetOGL::CreateAssetSet(std::string const&, std::string const&, int, std::string*)+250)
I/DEBUG   (  373):     #19  pc 0002d5b5  /data/app-lib/com.intel.cput.sample-3/libcput_sample.so (CPUTAssetLibrary::GetAssetSet(std::string const&, bool, int, std::string*)+168)

 

Add a Comment

Have a technical question? Visit our forums. Have site or software product issues? Contact support.