Home | History | Annotate | Download | only in perftest
      1 // Copyright (C) 2009 The Android Open Source Project
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //      http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 #pragma version(1)
     16 
     17 #pragma rs java_package_name(com.android.perftest)
     18 
     19 #include "rs_graphics.rsh"
     20 #include "shader_def.rsh"
     21 #include "subtest_def.rsh"
     22 
     23 /* Message sent from script to renderscript */
     24 const int RS_MSG_TEST_DONE = 100;
     25 const int RS_MSG_RESULTS_READY = 101;
     26 
     27 const int gMaxModes = 31;
     28 int gMaxLoops;
     29 
     30 // Parameters for galaxy live wallpaper
     31 rs_allocation gTSpace;
     32 rs_allocation gTLight1;
     33 rs_allocation gTFlares;
     34 rs_mesh gParticlesMesh;
     35 
     36 rs_program_fragment gPFBackground;
     37 rs_program_fragment gPFStars;
     38 rs_program_vertex gPVStars;
     39 rs_program_vertex gPVBkProj;
     40 rs_program_store gPSLights;
     41 
     42 float gXOffset = 0.5f;
     43 
     44 #define ELLIPSE_RATIO 0.892f
     45 #define PI 3.1415f
     46 #define TWO_PI 6.283f
     47 #define ELLIPSE_TWIST 0.023333333f
     48 
     49 static float angle = 50.f;
     50 static int gOldWidth;
     51 static int gOldHeight;
     52 static int gWidth;
     53 static int gHeight;
     54 static float gSpeed[12000];
     55 static int gGalaxyRadius = 300;
     56 static rs_allocation gParticlesBuffer;
     57 
     58 typedef struct __attribute__((packed, aligned(4))) Particle {
     59     uchar4 color;
     60     float3 position;
     61 } Particle_t;
     62 Particle_t *Particles;
     63 
     64 typedef struct VpConsts {
     65     rs_matrix4x4 Proj;
     66     rs_matrix4x4 MVP;
     67 } VpConsts_t;
     68 VpConsts_t *vpConstants;
     69 // End of parameters for galaxy live wallpaper
     70 
     71 // Allocation to send test names back to java
     72 char *gStringBuffer = 0;
     73 // Allocation to write the results into
     74 static float gResultBuffer[gMaxModes];
     75 
     76 rs_program_vertex gProgVertex;
     77 rs_program_fragment gProgFragmentColor;
     78 rs_program_fragment gProgFragmentTexture;
     79 
     80 rs_program_store gProgStoreBlendNoneDepth;
     81 rs_program_store gProgStoreBlendNone;
     82 rs_program_store gProgStoreBlendAlpha;
     83 rs_program_store gProgStoreBlendAdd;
     84 
     85 rs_allocation gTexOpaque;
     86 rs_allocation gTexTorus;
     87 rs_allocation gTexTransparent;
     88 rs_allocation gTexChecker;
     89 rs_allocation gTexGlobe;
     90 
     91 typedef struct ListAllocs_s {
     92     rs_allocation item;
     93 } ListAllocs;
     94 
     95 ListAllocs *gTexList100;
     96 ListAllocs *gSampleTextList100;
     97 ListAllocs *gListViewText;
     98 
     99 rs_mesh g10by10Mesh;
    100 rs_mesh g100by100Mesh;
    101 rs_mesh gWbyHMesh;
    102 rs_mesh gSingleMesh;
    103 
    104 rs_font gFontSans;
    105 rs_font gFontSerif;
    106 
    107 int gDisplayMode;
    108 
    109 rs_sampler gLinearClamp;
    110 rs_sampler gLinearWrap;
    111 rs_sampler gMipLinearWrap;
    112 rs_sampler gNearestClamp;
    113 
    114 rs_program_raster gCullBack;
    115 rs_program_raster gCullFront;
    116 rs_program_raster gCullNone;
    117 
    118 // Export these out to easily set the inputs to shader
    119 VertexShaderInputs *gVSInputs;
    120 
    121 rs_program_fragment gProgFragmentMultitex;
    122 
    123 rs_allocation gRenderBufferColor;
    124 rs_allocation gRenderBufferDepth;
    125 
    126 static float gDt = 0;
    127 
    128 void init() {
    129 }
    130 
    131 static int gRenderSurfaceW;
    132 static int gRenderSurfaceH;
    133 
    134 /**
    135   * Methods to draw the galaxy live wall paper
    136   */
    137 static float mapf(float minStart, float minStop, float maxStart, float maxStop, float value) {
    138     return maxStart + (maxStart - maxStop) * ((value - minStart) / (minStop - minStart));
    139 }
    140 
    141 /**
    142  * Helper function to generate the stars.
    143  */
    144 static float randomGauss() {
    145     float x1;
    146     float x2;
    147     float w = 2.f;
    148 
    149     while (w >= 1.0f) {
    150         x1 = rsRand(2.0f) - 1.0f;
    151         x2 = rsRand(2.0f) - 1.0f;
    152         w = x1 * x1 + x2 * x2;
    153     }
    154 
    155     w = sqrt(-2.0f * log(w) / w);
    156     return x1 * w;
    157 }
    158 
    159 /**
    160  * Generates the properties for a given star.
    161  */
    162 static void createParticle(Particle_t *part, int idx, float scale) {
    163     float d = fabs(randomGauss()) * gGalaxyRadius * 0.5f + rsRand(64.0f);
    164     float id = d / gGalaxyRadius;
    165     float z = randomGauss() * 0.4f * (1.0f - id);
    166     float p = -d * ELLIPSE_TWIST;
    167 
    168     if (d < gGalaxyRadius * 0.33f) {
    169         part->color.x = (uchar) (220 + id * 35);
    170         part->color.y = 220;
    171         part->color.z = 220;
    172     } else {
    173         part->color.x = 180;
    174         part->color.y = 180;
    175         part->color.z = (uchar) clamp(140.f + id * 115.f, 140.f, 255.f);
    176     }
    177     // Stash point size * 10 in Alpha
    178     part->color.w = (uchar) (rsRand(1.2f, 2.1f) * 60);
    179 
    180     if (d > gGalaxyRadius * 0.15f) {
    181         z *= 0.6f * (1.0f - id);
    182     } else {
    183         z *= 0.72f;
    184     }
    185 
    186     // Map to the projection coordinates (viewport.x = -1.0 -> 1.0)
    187     d = mapf(-4.0f, gGalaxyRadius + 4.0f, 0.0f, scale, d);
    188 
    189     part->position.x = rsRand(TWO_PI);
    190     part->position.y = d;
    191     gSpeed[idx] = rsRand(0.0015f, 0.0025f) * (0.5f + (scale / d)) * 0.8f;
    192 
    193     part->position.z = z / 5.0f;
    194 }
    195 
    196 /**
    197  * Initialize all the starts, called from Java
    198  */
    199 void initParticles() {
    200     Particle_t *part = Particles;
    201     float scale = gGalaxyRadius / (gWidth * 0.5f);
    202     int count = rsAllocationGetDimX(gParticlesBuffer);
    203     for (int i = 0; i < count; i ++) {
    204         createParticle(part, i, scale);
    205         part++;
    206     }
    207 }
    208 
    209 static void drawSpace() {
    210     rsgBindProgramFragment(gPFBackground);
    211     rsgBindTexture(gPFBackground, 0, gTSpace);
    212     rsgDrawQuadTexCoords(
    213             0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
    214             gWidth, 0.0f, 0.0f, 2.0f, 1.0f,
    215             gWidth, gHeight, 0.0f, 2.0f, 0.0f,
    216             0.0f, gHeight, 0.0f, 0.0f, 0.0f);
    217 }
    218 
    219 static void drawLights() {
    220     rsgBindProgramVertex(gPVBkProj);
    221     rsgBindProgramFragment(gPFBackground);
    222     rsgBindTexture(gPFBackground, 0, gTLight1);
    223 
    224     float scale = 512.0f / gWidth;
    225     float x = -scale - scale * 0.05f;
    226     float y = -scale;
    227 
    228     scale *= 2.0f;
    229 
    230     rsgDrawQuad(x, y, 0.0f,
    231              x + scale * 1.1f, y, 0.0f,
    232              x + scale * 1.1f, y + scale, 0.0f,
    233              x, y + scale, 0.0f);
    234 }
    235 
    236 static void drawParticles(float offset) {
    237     float a = offset * angle;
    238     float absoluteAngle = fabs(a);
    239 
    240     rs_matrix4x4 matrix;
    241     rsMatrixLoadTranslate(&matrix, 0.0f, 0.0f, 10.0f - 6.0f * absoluteAngle / 50.0f);
    242     if (gHeight > gWidth) {
    243         rsMatrixScale(&matrix, 6.6f, 6.0f, 1.0f);
    244     } else {
    245         rsMatrixScale(&matrix, 12.6f, 12.0f, 1.0f);
    246     }
    247     rsMatrixRotate(&matrix, absoluteAngle, 1.0f, 0.0f, 0.0f);
    248     rsMatrixRotate(&matrix, a, 0.0f, 0.4f, 0.1f);
    249     rsMatrixLoad(&vpConstants->MVP, &vpConstants->Proj);
    250     rsMatrixMultiply(&vpConstants->MVP, &matrix);
    251     rsgAllocationSyncAll(rsGetAllocation(vpConstants));
    252 
    253     rsgBindProgramVertex(gPVStars);
    254     rsgBindProgramFragment(gPFStars);
    255     rsgBindProgramStore(gPSLights);
    256     rsgBindTexture(gPFStars, 0, gTFlares);
    257 
    258     Particle_t *vtx = Particles;
    259     int count = rsAllocationGetDimX(gParticlesBuffer);
    260     for (int i = 0; i < count; i++) {
    261         vtx->position.x = vtx->position.x + gSpeed[i];
    262         vtx++;
    263     }
    264 
    265     rsgDrawMesh(gParticlesMesh);
    266 }
    267 /* end of methods for drawing galaxy */
    268 
    269 static void setupOffscreenTarget() {
    270     rsgBindColorTarget(gRenderBufferColor, 0);
    271     rsgBindDepthTarget(gRenderBufferDepth);
    272 }
    273 
    274 rs_script gFontScript;
    275 rs_script gTorusScript;
    276 rs_allocation gDummyAlloc;
    277 
    278 static void displayFontSamples(int fillNum) {
    279     TestData testData;
    280     testData.renderSurfaceW = gRenderSurfaceW;
    281     testData.renderSurfaceH = gRenderSurfaceH;
    282     testData.user = fillNum;
    283     rsForEach(gFontScript, gDummyAlloc, gDummyAlloc, &testData, sizeof(testData));
    284 }
    285 
    286 static void bindProgramVertexOrtho() {
    287     // Default vertex shader
    288     rsgBindProgramVertex(gProgVertex);
    289     // Setup the projection matrix
    290     rs_matrix4x4 proj;
    291     rsMatrixLoadOrtho(&proj, 0, gRenderSurfaceW, gRenderSurfaceH, 0, -500, 500);
    292     rsgProgramVertexLoadProjectionMatrix(&proj);
    293 }
    294 
    295 static void displaySingletexFill(bool blend, int quadCount) {
    296     bindProgramVertexOrtho();
    297     rs_matrix4x4 matrix;
    298     rsMatrixLoadIdentity(&matrix);
    299     rsgProgramVertexLoadModelMatrix(&matrix);
    300 
    301     // Fragment shader with texture
    302     if (!blend) {
    303         rsgBindProgramStore(gProgStoreBlendNone);
    304     } else {
    305         rsgBindProgramStore(gProgStoreBlendAlpha);
    306     }
    307     rsgBindProgramFragment(gProgFragmentTexture);
    308     rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp);
    309     rsgBindTexture(gProgFragmentTexture, 0, gTexOpaque);
    310 
    311     for (int i = 0; i < quadCount; i ++) {
    312         float startX = 5 * i, startY = 5 * i;
    313         float width = gRenderSurfaceW - startX, height = gRenderSurfaceH - startY;
    314         rsgDrawQuadTexCoords(startX, startY, 0, 0, 0,
    315                              startX, startY + height, 0, 0, 1,
    316                              startX + width, startY + height, 0, 1, 1,
    317                              startX + width, startY, 0, 1, 0);
    318     }
    319 }
    320 
    321 static void displayMeshSamples(int meshNum) {
    322 
    323     bindProgramVertexOrtho();
    324     rs_matrix4x4 matrix;
    325     rsMatrixLoadTranslate(&matrix, gRenderSurfaceW/2, gRenderSurfaceH/2, 0);
    326     rsgProgramVertexLoadModelMatrix(&matrix);
    327 
    328     // Fragment shader with texture
    329     rsgBindProgramStore(gProgStoreBlendNone);
    330     rsgBindProgramFragment(gProgFragmentTexture);
    331     rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp);
    332 
    333     rsgBindTexture(gProgFragmentTexture, 0, gTexOpaque);
    334 
    335     if (meshNum == 0) {
    336         rsgDrawMesh(g10by10Mesh);
    337     } else if (meshNum == 1) {
    338         rsgDrawMesh(g100by100Mesh);
    339     } else if (meshNum == 2) {
    340         rsgDrawMesh(gWbyHMesh);
    341     }
    342 }
    343 
    344 // Display sample images in a mesh with different texture
    345 static void displayIcons(int meshMode) {
    346     bindProgramVertexOrtho();
    347 
    348     // Fragment shader with texture
    349     rsgBindProgramStore(gProgStoreBlendAlpha);
    350     rsgBindProgramFragment(gProgFragmentTexture);
    351     rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp);
    352     rsgBindTexture(gProgFragmentTexture, 0, gTexTorus);
    353     rsgDrawQuadTexCoords(
    354             0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
    355             0.0f, gRenderSurfaceH, 0.0f, 0.0f, 1.0f,
    356             gRenderSurfaceW, gRenderSurfaceH, 0.0f, 1.0f, 1.0f,
    357             gRenderSurfaceW, 0.0f, 0.0f, 1.0f, 0.0f);
    358 
    359     int meshCount = (int)pow(10.0f, (float)(meshMode + 1));
    360 
    361     float wSize = gRenderSurfaceW/(float)meshCount;
    362     float hSize = gRenderSurfaceH/(float)meshCount;
    363     rs_matrix4x4 matrix;
    364     rsMatrixLoadScale(&matrix, wSize, hSize, 1.0);
    365 
    366     float yPos = 0;
    367     float yPad = hSize / 2;
    368     float xPad = wSize / 2;
    369     for (int y = 0; y < meshCount; y++) {
    370         yPos = y * hSize + yPad;
    371         float xPos = 0;
    372         for (int x = 0; x < meshCount; x++) {
    373             xPos = x * wSize + xPad;
    374             rs_matrix4x4 transMatrix;
    375             rsMatrixLoadTranslate(&transMatrix, xPos, yPos, 0);
    376             rsMatrixMultiply(&transMatrix, &matrix);
    377             rsgProgramVertexLoadModelMatrix(&transMatrix);
    378             int i = (x + y * meshCount) % 100;
    379             rsgBindTexture(gProgFragmentTexture, 0, gTexList100[i].item);
    380             rsgDrawMesh(gSingleMesh);
    381         }
    382     }
    383 }
    384 
    385 // Draw meshes in a single page with top left corner coordinates (xStart, yStart)
    386 static void drawMeshInPage(float xStart, float yStart, int wResolution, int hResolution) {
    387     // Draw wResolution * hResolution meshes in one page
    388     float wMargin = 100.0f;
    389     float hMargin = 100.0f;
    390     float xPad = 50.0f;
    391     float yPad = 20.0f;
    392     float size = 100.0f;  // size of images
    393 
    394     // font info
    395     rs_font font = gFontSans;
    396     rsgBindFont(font);
    397     rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
    398 
    399     // Measure text size
    400     int left = 0, right = 0, top = 0, bottom = 0;
    401     rsgMeasureText(gSampleTextList100[0].item, &left, &right, &top, &bottom);
    402     float textHeight = (float)(top - bottom);
    403     float textWidth = (float)(right - left);
    404 
    405     rs_matrix4x4 matrix;
    406     rsMatrixLoadScale(&matrix, size, size, 1.0);
    407 
    408     for (int y = 0; y < hResolution; y++) {
    409         float yPos = yStart + hMargin + y * size + y * yPad;
    410         for (int x = 0; x < wResolution; x++) {
    411             float xPos = xStart + wMargin + x * size + x * xPad;
    412 
    413             rs_matrix4x4 transMatrix;
    414             rsMatrixLoadTranslate(&transMatrix, xPos + size/2, yPos + size/2, 0);
    415             rsMatrixMultiply(&transMatrix, &matrix);  // scale the mesh
    416             rsgProgramVertexLoadModelMatrix(&transMatrix);
    417 
    418             int i = (y * wResolution + x) % 100;
    419             rsgBindTexture(gProgFragmentTexture, 0, gTexList100[i].item);
    420             rsgDrawMesh(gSingleMesh);
    421             rsgDrawText(gSampleTextList100[i].item, xPos, yPos + size + yPad/2 + textHeight);
    422         }
    423     }
    424 }
    425 
    426 // Display both images and text as shown in launcher and homepage
    427 // meshMode will decide how many pages we draw
    428 // meshMode = 0: draw 3 pages of meshes
    429 // meshMode = 1: draw 5 pages of meshes
    430 static void displayImageWithText(int wResolution, int hResolution, int meshMode) {
    431     bindProgramVertexOrtho();
    432 
    433     // Fragment shader with texture
    434     rsgBindProgramStore(gProgStoreBlendAlpha);
    435     rsgBindProgramFragment(gProgFragmentTexture);
    436     rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp);
    437 
    438     drawMeshInPage(0, 0, wResolution, hResolution);
    439     drawMeshInPage(-1.0f*gRenderSurfaceW, 0, wResolution, hResolution);
    440     drawMeshInPage(1.0f*gRenderSurfaceW, 0, wResolution, hResolution);
    441     if (meshMode == 1) {
    442         // draw another two pages of meshes
    443         drawMeshInPage(-2.0f*gRenderSurfaceW, 0, wResolution, hResolution);
    444         drawMeshInPage(2.0f*gRenderSurfaceW, 0, wResolution, hResolution);
    445     }
    446 }
    447 
    448 // Display a list of text as the list view
    449 static void displayListView() {
    450     // set text color
    451     rsgFontColor(0.9f, 0.9f, 0.9f, 1.0f);
    452     rsgBindFont(gFontSans);
    453 
    454     // get the size of the list
    455     rs_allocation textAlloc;
    456     textAlloc = rsGetAllocation(gListViewText);
    457     int allocSize = rsAllocationGetDimX(textAlloc);
    458 
    459     int listItemHeight = 80;
    460     int yOffset = listItemHeight;
    461 
    462     // set the color for the list divider
    463     rsgBindProgramFragment(gProgFragmentColor);
    464     rsgProgramFragmentConstantColor(gProgFragmentColor, 1.0, 1.0, 1.0, 1);
    465 
    466     // draw the list with divider
    467     for (int i = 0; i < allocSize; i++) {
    468         if (yOffset - listItemHeight > gRenderSurfaceH) {
    469             break;
    470         }
    471         rsgDrawRect(0, yOffset - 1, gRenderSurfaceW, yOffset, 0);
    472         rsgDrawText(gListViewText[i].item, 20, yOffset - 10);
    473         yOffset += listItemHeight;
    474     }
    475 }
    476 
    477 static void drawGalaxy() {
    478     rsgClearColor(0.f, 0.f, 0.f, 1.f);
    479     gParticlesBuffer = rsGetAllocation(Particles);
    480     rsgBindProgramFragment(gPFBackground);
    481 
    482     gWidth = rsgGetWidth();
    483     gHeight = rsgGetHeight();
    484     if ((gWidth != gOldWidth) || (gHeight != gOldHeight)) {
    485         initParticles();
    486         gOldWidth = gWidth;
    487         gOldHeight = gHeight;
    488     }
    489 
    490     float offset = mix(-1.0f, 1.0f, gXOffset);
    491     drawSpace();
    492     drawParticles(offset);
    493     drawLights();
    494 }
    495 
    496 // Display images and text with live wallpaper in the background
    497 static void displayLiveWallPaper(int wResolution, int hResolution) {
    498     bindProgramVertexOrtho();
    499 
    500     drawGalaxy();
    501 
    502     rsgBindProgramVertex(gProgVertex);
    503     rsgBindProgramStore(gProgStoreBlendAlpha);
    504     rsgBindProgramFragment(gProgFragmentTexture);
    505     rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp);
    506 
    507     drawMeshInPage(0, 0, wResolution, hResolution);
    508     drawMeshInPage(-1.0f*gRenderSurfaceW, 0, wResolution, hResolution);
    509     drawMeshInPage(1.0f*gRenderSurfaceW, 0, wResolution, hResolution);
    510     drawMeshInPage(-2.0f*gRenderSurfaceW, 0, wResolution, hResolution);
    511     drawMeshInPage(2.0f*gRenderSurfaceW, 0, wResolution, hResolution);
    512 }
    513 
    514 // Quick hack to get some geometry numbers
    515 static void displaySimpleGeoSamples(bool useTexture, int numMeshes) {
    516     TestData testData;
    517     testData.renderSurfaceW = gRenderSurfaceW;
    518     testData.renderSurfaceH = gRenderSurfaceH;
    519     testData.dt = gDt;
    520     testData.user = 0;
    521     testData.user1 = useTexture ? 1 : 0;
    522     testData.user2 = numMeshes;
    523     rsForEach(gTorusScript, gDummyAlloc, gDummyAlloc, &testData, sizeof(testData));
    524 }
    525 
    526 static void displayCustomShaderSamples(int numMeshes) {
    527     TestData testData;
    528     testData.renderSurfaceW = gRenderSurfaceW;
    529     testData.renderSurfaceH = gRenderSurfaceH;
    530     testData.dt = gDt;
    531     testData.user = 1;
    532     testData.user1 = numMeshes;
    533     rsForEach(gTorusScript, gDummyAlloc, gDummyAlloc, &testData, sizeof(testData));
    534 }
    535 
    536 static void displayPixelLightSamples(int numMeshes, bool heavyVertex) {
    537     TestData testData;
    538     testData.renderSurfaceW = gRenderSurfaceW;
    539     testData.renderSurfaceH = gRenderSurfaceH;
    540     testData.dt = gDt;
    541     testData.user = 2;
    542     testData.user1 = numMeshes;
    543     testData.user2 = heavyVertex ? 1 : 0;
    544     rsForEach(gTorusScript, gDummyAlloc, gDummyAlloc, &testData, sizeof(testData));
    545 }
    546 
    547 static void displayMultitextureSample(bool blend, int quadCount) {
    548     bindProgramVertexOrtho();
    549     rs_matrix4x4 matrix;
    550     rsMatrixLoadIdentity(&matrix);
    551     rsgProgramVertexLoadModelMatrix(&matrix);
    552 
    553     // Fragment shader with texture
    554     if (!blend) {
    555         rsgBindProgramStore(gProgStoreBlendNone);
    556     } else {
    557         rsgBindProgramStore(gProgStoreBlendAlpha);
    558     }
    559     rsgBindProgramFragment(gProgFragmentMultitex);
    560     rsgBindSampler(gProgFragmentMultitex, 0, gLinearClamp);
    561     rsgBindSampler(gProgFragmentMultitex, 1, gLinearWrap);
    562     rsgBindSampler(gProgFragmentMultitex, 2, gLinearClamp);
    563     rsgBindTexture(gProgFragmentMultitex, 0, gTexChecker);
    564     rsgBindTexture(gProgFragmentMultitex, 1, gTexTorus);
    565     rsgBindTexture(gProgFragmentMultitex, 2, gTexTransparent);
    566 
    567     for (int i = 0; i < quadCount; i ++) {
    568         float startX = 10 * i, startY = 10 * i;
    569         float width = gRenderSurfaceW - startX, height = gRenderSurfaceH - startY;
    570         rsgDrawQuadTexCoords(startX, startY, 0, 0, 0,
    571                              startX, startY + height, 0, 0, 1,
    572                              startX + width, startY + height, 0, 1, 1,
    573                              startX + width, startY, 0, 1, 0);
    574     }
    575 }
    576 
    577 static bool checkInit() {
    578 
    579     static int countdown = 5;
    580 
    581     // Perform all the uploads so we only measure rendered time
    582     if(countdown > 1) {
    583         displayFontSamples(5);
    584         displaySingletexFill(true, 3);
    585         displayMeshSamples(0);
    586         displayMeshSamples(1);
    587         displayMeshSamples(2);
    588         displayMultitextureSample(true, 5);
    589         displayPixelLightSamples(1, false);
    590         displayPixelLightSamples(1, true);
    591         countdown --;
    592         rsgClearColor(0.2f, 0.2f, 0.2f, 0.0f);
    593 
    594         rsgFontColor(0.9f, 0.9f, 0.95f, 1.0f);
    595         rsgBindFont(gFontSerif);
    596         if (countdown == 1) {
    597             rsgDrawText("Rendering", 50, 50);
    598         } else {
    599             rsgDrawText("Initializing", 50, 50);
    600         }
    601 
    602         return false;
    603     }
    604 
    605     return true;
    606 }
    607 
    608 static int benchMode = 0;
    609 static int runningLoops = 0;
    610 static bool sendMsgFlag = false;
    611 
    612 static const char *testNames[] = {
    613     "Fill screen with text 1 time",
    614     "Fill screen with text 3 times",
    615     "Fill screen with text 5 times",
    616     "Geo test 25.6k flat color",
    617     "Geo test 51.2k flat color",
    618     "Geo test 204.8k small tries flat color",
    619     "Geo test 25.6k single texture",
    620     "Geo test 51.2k single texture",
    621     "Geo test 204.8k small tries single texture",
    622     "Full screen mesh 10 by 10",
    623     "Full screen mesh 100 by 100",
    624     "Full screen mesh W / 4 by H / 4",
    625     "Geo test 25.6k geo heavy vertex",
    626     "Geo test 51.2k geo heavy vertex",
    627     "Geo test 204.8k geo raster load heavy vertex",
    628     "Fill screen 10x singletexture",
    629     "Fill screen 10x 3tex multitexture",
    630     "Fill screen 10x blended singletexture",
    631     "Fill screen 10x blended 3tex multitexture",
    632     "Geo test 25.6k heavy fragment",
    633     "Geo test 51.2k heavy fragment",
    634     "Geo test 204.8k small tries heavy fragment",
    635     "Geo test 25.6k heavy fragment heavy vertex",
    636     "Geo test 51.2k heavy fragment heavy vertex",
    637     "Geo test 204.8k small tries heavy fragment heavy vertex",
    638     "UI test with icon display 10 by 10",
    639     "UI test with icon display 100 by 100",
    640     "UI test with image and text display 3 pages",
    641     "UI test with image and text display 5 pages",
    642     "UI test with list view",
    643     "UI test with live wallpaper",
    644 };
    645 
    646 static bool gIsDebugMode = false;
    647 void setDebugMode(int testNumber) {
    648     gIsDebugMode = true;
    649     benchMode = testNumber;
    650     rsgClearAllRenderTargets();
    651 }
    652 
    653 void setBenchmarkMode() {
    654     gIsDebugMode = false;
    655     benchMode = 0;
    656     runningLoops = 0;
    657 }
    658 
    659 
    660 void getTestName(int testIndex) {
    661     int bufferLen = rsAllocationGetDimX(rsGetAllocation(gStringBuffer));
    662     if (testIndex >= gMaxModes) {
    663         return;
    664     }
    665     uint charIndex = 0;
    666     while (testNames[testIndex][charIndex] != '\0' && charIndex < bufferLen) {
    667         gStringBuffer[charIndex] = testNames[testIndex][charIndex];
    668         charIndex ++;
    669     }
    670     gStringBuffer[charIndex] = '\0';
    671 }
    672 
    673 static void runTest(int index) {
    674     switch (index) {
    675     case 0:
    676         displayFontSamples(1);
    677         break;
    678     case 1:
    679         displayFontSamples(3);
    680         break;
    681     case 2:
    682         displayFontSamples(5);
    683         break;
    684     case 3:
    685         displaySimpleGeoSamples(false, 1);
    686         break;
    687     case 4:
    688         displaySimpleGeoSamples(false, 2);
    689         break;
    690     case 5:
    691         displaySimpleGeoSamples(false, 8);
    692         break;
    693     case 6:
    694         displaySimpleGeoSamples(true, 1);
    695         break;
    696     case 7:
    697         displaySimpleGeoSamples(true, 2);
    698         break;
    699     case 8:
    700         displaySimpleGeoSamples(true, 8);
    701         break;
    702     case 9:
    703         displayMeshSamples(0);
    704         break;
    705     case 10:
    706         displayMeshSamples(1);
    707         break;
    708     case 11:
    709         displayMeshSamples(2);
    710         break;
    711     case 12:
    712         displayCustomShaderSamples(1);
    713         break;
    714     case 13:
    715         displayCustomShaderSamples(2);
    716         break;
    717     case 14:
    718         displayCustomShaderSamples(10);
    719         break;
    720     case 15:
    721         displaySingletexFill(false, 10);
    722         break;
    723     case 16:
    724         displayMultitextureSample(false, 10);
    725         break;
    726     case 17:
    727         displaySingletexFill(true, 10);
    728         break;
    729     case 18:
    730         displayMultitextureSample(true, 10);
    731         break;
    732     case 19:
    733         displayPixelLightSamples(1, false);
    734         break;
    735     case 20:
    736         displayPixelLightSamples(2, false);
    737         break;
    738     case 21:
    739         displayPixelLightSamples(8, false);
    740         break;
    741     case 22:
    742         displayPixelLightSamples(1, true);
    743         break;
    744     case 23:
    745         displayPixelLightSamples(2, true);
    746         break;
    747     case 24:
    748         displayPixelLightSamples(8, true);
    749         break;
    750     case 25:
    751         displayIcons(0);
    752         break;
    753     case 26:
    754         displayIcons(1);
    755         break;
    756     case 27:
    757         displayImageWithText(7, 5, 0);
    758         break;
    759     case 28:
    760         displayImageWithText(7, 5, 1);
    761         break;
    762     case 29:
    763         displayListView();
    764         break;
    765     case 30:
    766         displayLiveWallPaper(7, 5);
    767         break;
    768     }
    769 }
    770 
    771 static void drawOffscreenResult(int posX, int posY, int width, int height) {
    772     bindProgramVertexOrtho();
    773 
    774     rs_matrix4x4 matrix;
    775     rsMatrixLoadIdentity(&matrix);
    776     rsgProgramVertexLoadModelMatrix(&matrix);
    777 
    778     rsgBindProgramFragment(gProgFragmentTexture);
    779 
    780     rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp);
    781     rsgBindTexture(gProgFragmentTexture, 0, gRenderBufferColor);
    782 
    783     float startX = posX, startY = posY;
    784     rsgDrawQuadTexCoords(startX, startY, 0, 0, 1,
    785                          startX, startY + height, 0, 0, 0,
    786                          startX + width, startY + height, 0, 1, 0,
    787                          startX + width, startY, 0, 1, 1);
    788 }
    789 
    790 static void benchmark() {
    791 
    792     gDt = 1.0f / 60.0f;
    793 
    794     rsgFinish();
    795     int64_t start = rsUptimeMillis();
    796 
    797     int drawPos = 0;
    798     int frameCount = 100;
    799     for(int i = 0; i < frameCount; i ++) {
    800         setupOffscreenTarget();
    801         gRenderSurfaceW = rsAllocationGetDimX(gRenderBufferColor);
    802         gRenderSurfaceH = rsAllocationGetDimY(gRenderBufferColor);
    803         rsgClearColor(0.1f, 0.1f, 0.1f, 1.0f);
    804         rsgClearDepth(1.0f);
    805 
    806         runTest(benchMode);
    807         rsgClearAllRenderTargets();
    808         gRenderSurfaceW = rsgGetWidth();
    809         gRenderSurfaceH = rsgGetHeight();
    810         int size = 8;
    811         // draw each frame at (8, 3/4 gRenderSurfaceH) with size
    812         drawOffscreenResult((drawPos+=size)%gRenderSurfaceW, (gRenderSurfaceH * 3) / 4, size, size);
    813     }
    814 
    815     rsgFinish();
    816 
    817     int64_t end = rsUptimeMillis();
    818     float fps = (float)(frameCount) / ((float)(end - start)*0.001f);
    819     rsDebug(testNames[benchMode], fps);
    820     gResultBuffer[benchMode] = fps;
    821     drawOffscreenResult(0, 0,
    822                         gRenderSurfaceW / 2,
    823                         gRenderSurfaceH / 2);
    824     const char* text = testNames[benchMode];
    825     int left = 0, right = 0, top = 0, bottom = 0;
    826     uint width = rsgGetWidth();
    827     uint height = rsgGetHeight();
    828     rsgFontColor(0.9f, 0.9f, 0.95f, 1.0f);
    829     rsgBindFont(gFontSerif);
    830     rsgMeasureText(text, &left, &right, &top, &bottom);
    831     rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
    832     rsgDrawText(text, 2 -left, height - 2 + bottom);
    833 
    834     benchMode ++;
    835 
    836     if (benchMode == gMaxModes) {
    837         rsSendToClientBlocking(RS_MSG_RESULTS_READY, gResultBuffer, gMaxModes*sizeof(float));
    838         benchMode = 0;
    839         runningLoops++;
    840         if ((gMaxLoops > 0) && (runningLoops > gMaxLoops) && !sendMsgFlag) {
    841             //Notifiy the test to stop and get results
    842             rsDebug("gMaxLoops and runningLoops: ", gMaxLoops, runningLoops);
    843             rsSendToClientBlocking(RS_MSG_TEST_DONE);
    844             sendMsgFlag = true;
    845         }
    846     }
    847 
    848 }
    849 
    850 static void debug() {
    851     gDt = rsGetDt();
    852 
    853     rsgFinish();
    854     runTest(benchMode);
    855 }
    856 
    857 int root(void) {
    858     gRenderSurfaceW = rsgGetWidth();
    859     gRenderSurfaceH = rsgGetHeight();
    860     rsgClearColor(0.2f, 0.2f, 0.2f, 1.0f);
    861     rsgClearDepth(1.0f);
    862     if(!checkInit()) {
    863         return 1;
    864     }
    865 
    866     if (gIsDebugMode) {
    867         debug();
    868     } else {
    869         benchmark();
    870     }
    871 
    872     return 1;
    873 }
    874