## 5 Experimental Results and Discussion
### AR Rendering
The classes _ObjLoader_ and _ObjParser_ of the developed 3D engine as well as the _mRenderer_ of the rendering thread generate the largest number of temporary objects and impose time restrictions on prototype's memory allocation per frame. When attempting to render and load a huge volume of vertices on low-memory devices, performance issues with excessive demands on CPU arise, like the memory leak that happened during the 20-25 s on the low-end device (Figure 10b). Furthermore, UV texture mapping has a significant memory instances count. Therefore, techniques compatible with OpenGL ES 2.0 such as  
Figure 10: Memory profiling for the low-end and the mid-range device during an AR session with the 3D Model “CHURCH”: **[a]** 40 s timeline upon pattern recognition with the memory allocation of the main memory types, including Graphics (yellow) and Native (dark blue); **[b]** graphics objects and classes with the most heap count. vertex-data re-ordering, organization on VBOs and texture compression are essential for the overall performance amelioration. The proposed optimizations applied to the developed 3D graphics engine are compared with standard rendering methods to determine their impact and efficacy. The techniques of (i) instancing and (ii) vertex-data organization are tested individually. In every comparative test, the OpenGL ES commands of each technique are organized in groups using markers and annotated with descriptive labels. For geometry instancing evaluation, two separate sessions with the 3D models \"POTTERY\" and \"CHURCH\" are created for frame rate of 60 FPS. In the first one, each mesh is drawn ten times with standard index rendering (_glDrawElements_) and the second one implements the developed technique that draws ten instances of each mesh in one call. A unique transformation matrix is applied to each of the ten meshes in both cases, in order to replicate a real AR usage scenario. Total rendering time as well as the FPS corresponding to the number of vertices being drawn at each frame are presented in Table 10 and Figure 11, respectively. The best results are obtained with instancing, as expected. A total of 16,610 vertices for the \"POTTERY\" and 427,120 vertices for the STATUE are rendered in a single draw call in less than 20 s and 36 s at the mid-range device and 29 s and 49 s at the low-end one. Regarding drawing performance, FPS drop is significant after the seventh instance for both devices when 11,627 and 298,984 vertices are being drawn for \"POTTERY\" and \"STATUE\", respectively. Both sessions render the same number of vertices and it can be concluded that the number of draw calls is the actual bottleneck. However, the \"STATUE\" has 26 \(\times\) more vertices and is 10\(\times\) larger in size than \"POTTERY\" but rendering during instancing is only 1.14x faster for the low-end and 2.2\(\times\) slower for the mid-range device. The increased rendering time can probably be attributed to the texture file of \"POTTERY\" which needs to be accessed and fetched from texture cache memory while GPU is running at the main thread. Evaluation of the geometry processing stage involves testing vertex fetching efficiency. The testing environment comprises the 3D models \"POTTERY\" and \"STATUE\", grouped in the same vertex buffer object with half float coordinates in the normalized model space. The previous testing session is replicated and executed three times for both devices. The ten meshes of each model are rendered with the standard _glDrawElements()_ rendering arrays and the developed VBO format using both index rendering and instancing. The average frame rate and the total rendering time of each combination are presented in Tables 11 and 12. Storing groups of 3D models in the same VBO provides significant performance stability for the low-level device and a 3.7\(\times\) speed gain for the textured model \"POTTERY\" and a 3.14\(\times\) for the model \"STATUE\" with per vertex color for the standard index rendering.