// 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. #pragma version(1) #pragma rs java_package_name(com.android.perftest) #include "rs_graphics.rsh" #include "shader_def.rsh" #include "subtest_def.rsh" // Parameters for galaxy live wallpaper rs_allocation gTSpace; rs_allocation gTLight1; rs_allocation gTFlares; rs_mesh gParticlesMesh; rs_program_fragment gPFBackground; rs_program_fragment gPFStars; rs_program_vertex gPVStars; rs_program_vertex gPVBkProj; rs_program_store gPSLights; float gXOffset = 0.5f; #define ELLIPSE_RATIO 0.892f #define PI 3.1415f #define TWO_PI 6.283f #define ELLIPSE_TWIST 0.023333333f static float angle = 50.f; static int gOldWidth; static int gOldHeight; static int gWidth; static int gHeight; static float gSpeed[12000]; static int gGalaxyRadius = 300; static rs_allocation gParticlesBuffer; typedef struct __attribute__((packed, aligned(4))) Particle { uchar4 color; float3 position; } Particle_t; Particle_t *Particles; typedef struct VpConsts { rs_matrix4x4 Proj; rs_matrix4x4 MVP; } VpConsts_t; VpConsts_t *vpConstants; // End of parameters for galaxy live wallpaper rs_program_vertex gProgVertex; rs_program_fragment gProgFragmentColor; rs_program_fragment gProgFragmentTexture; rs_program_store gProgStoreBlendAlpha; rs_allocation gTexOpaque; rs_allocation gTexTorus; rs_allocation gTexGlobe; typedef struct ListAllocs_s { rs_allocation item; } ListAllocs; ListAllocs *gTexList100; ListAllocs *gSampleTextList100; ListAllocs *gListViewText; rs_mesh gSingleMesh; rs_font gFontSans; rs_sampler gLinearClamp; typedef struct UiTestData_s { int testId; int user1; int user2; int user3; } UiTestData; UiTestData *gData; static float gDt = 0; void init() { } static int gRenderSurfaceW; static int gRenderSurfaceH; static void bindProgramVertexOrtho() { // Default vertex shader rsgBindProgramVertex(gProgVertex); // Setup the projection matrix rs_matrix4x4 proj; rsMatrixLoadOrtho(&proj, 0, gRenderSurfaceW, gRenderSurfaceH, 0, -500, 500); rsgProgramVertexLoadProjectionMatrix(&proj); } /** * Methods to draw the galaxy live wall paper */ static float mapf(float minStart, float minStop, float maxStart, float maxStop, float value) { return maxStart + (maxStart - maxStop) * ((value - minStart) / (minStop - minStart)); } /** * Helper function to generate the stars. */ static float randomGauss() { float x1; float x2; float w = 2.f; while (w >= 1.0f) { x1 = rsRand(2.0f) - 1.0f; x2 = rsRand(2.0f) - 1.0f; w = x1 * x1 + x2 * x2; } w = sqrt(-2.0f * log(w) / w); return x1 * w; } /** * Generates the properties for a given star. */ static void createParticle(Particle_t *part, int idx, float scale) { float d = fabs(randomGauss()) * gGalaxyRadius * 0.5f + rsRand(64.0f); float id = d / gGalaxyRadius; float z = randomGauss() * 0.4f * (1.0f - id); if (d < gGalaxyRadius * 0.33f) { part->color.x = (uchar) (220 + id * 35); part->color.y = 220; part->color.z = 220; } else { part->color.x = 180; part->color.y = 180; part->color.z = (uchar) clamp(140.f + id * 115.f, 140.f, 255.f); } // Stash point size * 10 in Alpha part->color.w = (uchar) (rsRand(1.2f, 2.1f) * 60); if (d > gGalaxyRadius * 0.15f) { z *= 0.6f * (1.0f - id); } else { z *= 0.72f; } // Map to the projection coordinates (viewport.x = -1.0 -> 1.0) d = mapf(-4.0f, gGalaxyRadius + 4.0f, 0.0f, scale, d); part->position.x = rsRand(TWO_PI); part->position.y = d; gSpeed[idx] = rsRand(0.0015f, 0.0025f) * (0.5f + (scale / d)) * 0.8f; part->position.z = z / 5.0f; } /** * Initialize all the starts, called from Java */ void initParticles() { Particle_t *part = Particles; float scale = gGalaxyRadius / (gWidth * 0.5f); int count = rsAllocationGetDimX(gParticlesBuffer); for (int i = 0; i < count; i ++) { createParticle(part, i, scale); part++; } } static void drawSpace() { rsgBindProgramFragment(gPFBackground); rsgBindTexture(gPFBackground, 0, gTSpace); rsgDrawQuadTexCoords( 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, gWidth, 0.0f, 0.0f, 2.0f, 1.0f, gWidth, gHeight, 0.0f, 2.0f, 0.0f, 0.0f, gHeight, 0.0f, 0.0f, 0.0f); } static void drawLights() { rsgBindProgramVertex(gPVBkProj); rsgBindProgramFragment(gPFBackground); rsgBindTexture(gPFBackground, 0, gTLight1); float scale = 512.0f / gWidth; float x = -scale - scale * 0.05f; float y = -scale; scale *= 2.0f; rsgDrawQuad(x, y, 0.0f, x + scale * 1.1f, y, 0.0f, x + scale * 1.1f, y + scale, 0.0f, x, y + scale, 0.0f); } static void drawParticles(float offset) { float a = offset * angle; float absoluteAngle = fabs(a); rs_matrix4x4 matrix; rsMatrixLoadTranslate(&matrix, 0.0f, 0.0f, 10.0f - 6.0f * absoluteAngle / 50.0f); if (gHeight > gWidth) { rsMatrixScale(&matrix, 6.6f, 6.0f, 1.0f); } else { rsMatrixScale(&matrix, 12.6f, 12.0f, 1.0f); } rsMatrixRotate(&matrix, absoluteAngle, 1.0f, 0.0f, 0.0f); rsMatrixRotate(&matrix, a, 0.0f, 0.4f, 0.1f); rsMatrixLoad(&vpConstants->MVP, &vpConstants->Proj); rsMatrixMultiply(&vpConstants->MVP, &matrix); rsgAllocationSyncAll(rsGetAllocation(vpConstants)); rsgBindProgramVertex(gPVStars); rsgBindProgramFragment(gPFStars); rsgBindProgramStore(gPSLights); rsgBindTexture(gPFStars, 0, gTFlares); Particle_t *vtx = Particles; int count = rsAllocationGetDimX(gParticlesBuffer); for (int i = 0; i < count; i++) { vtx->position.x = vtx->position.x + gSpeed[i]; vtx++; } rsgDrawMesh(gParticlesMesh); } /* end of methods for drawing galaxy */ // Display sample images in a mesh with different texture static void displayIcons(int meshMode) { bindProgramVertexOrtho(); // Fragment shader with texture rsgBindProgramStore(gProgStoreBlendAlpha); rsgBindProgramFragment(gProgFragmentTexture); rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp); rsgBindTexture(gProgFragmentTexture, 0, gTexTorus); rsgDrawQuadTexCoords( 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, gRenderSurfaceH, 0.0f, 0.0f, 1.0f, gRenderSurfaceW, gRenderSurfaceH, 0.0f, 1.0f, 1.0f, gRenderSurfaceW, 0.0f, 0.0f, 1.0f, 0.0f); int meshCount = (int)pow(10.0f, (float)(meshMode + 1)); float wSize = gRenderSurfaceW/(float)meshCount; float hSize = gRenderSurfaceH/(float)meshCount; rs_matrix4x4 matrix; rsMatrixLoadScale(&matrix, wSize, hSize, 1.0); float yPos = 0; float yPad = hSize / 2; float xPad = wSize / 2; for (int y = 0; y < meshCount; y++) { yPos = y * hSize + yPad; float xPos = 0; for (int x = 0; x < meshCount; x++) { xPos = x * wSize + xPad; rs_matrix4x4 transMatrix; rsMatrixLoadTranslate(&transMatrix, xPos, yPos, 0); rsMatrixMultiply(&transMatrix, &matrix); rsgProgramVertexLoadModelMatrix(&transMatrix); int i = (x + y * meshCount) % 100; rsgBindTexture(gProgFragmentTexture, 0, gTexList100[i].item); rsgDrawMesh(gSingleMesh); } } } // Draw meshes in a single page with top left corner coordinates (xStart, yStart) static void drawMeshInPage(float xStart, float yStart, int wResolution, int hResolution) { // Draw wResolution * hResolution meshes in one page float wMargin = 100.0f; float hMargin = 100.0f; float xPad = 50.0f; float yPad = 20.0f; float size = 100.0f; // size of images // font info rs_font font = gFontSans; rsgBindFont(font); rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f); // Measure text size int left = 0, right = 0, top = 0, bottom = 0; rsgMeasureText(gSampleTextList100[0].item, &left, &right, &top, &bottom); float textHeight = (float)(top - bottom); rs_matrix4x4 matrix; rsMatrixLoadScale(&matrix, size, size, 1.0); for (int y = 0; y < hResolution; y++) { float yPos = yStart + hMargin + y * size + y * yPad; for (int x = 0; x < wResolution; x++) { float xPos = xStart + wMargin + x * size + x * xPad; rs_matrix4x4 transMatrix; rsMatrixLoadTranslate(&transMatrix, xPos + size/2, yPos + size/2, 0); rsMatrixMultiply(&transMatrix, &matrix); // scale the mesh rsgProgramVertexLoadModelMatrix(&transMatrix); int i = (y * wResolution + x) % 100; rsgBindTexture(gProgFragmentTexture, 0, gTexList100[i].item); rsgDrawMesh(gSingleMesh); rsgDrawText(gSampleTextList100[i].item, xPos, yPos + size + yPad/2 + textHeight); } } } // Display both images and text as shown in launcher and homepage // meshMode will decide how many pages we draw // meshMode = 0: draw 3 pages of meshes // meshMode = 1: draw 5 pages of meshes static void displayImageWithText(int wResolution, int hResolution, int meshMode) { bindProgramVertexOrtho(); // Fragment shader with texture rsgBindProgramStore(gProgStoreBlendAlpha); rsgBindProgramFragment(gProgFragmentTexture); rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp); drawMeshInPage(0, 0, wResolution, hResolution); drawMeshInPage(-1.0f*gRenderSurfaceW, 0, wResolution, hResolution); drawMeshInPage(1.0f*gRenderSurfaceW, 0, wResolution, hResolution); if (meshMode == 1) { // draw another two pages of meshes drawMeshInPage(-2.0f*gRenderSurfaceW, 0, wResolution, hResolution); drawMeshInPage(2.0f*gRenderSurfaceW, 0, wResolution, hResolution); } } // Display a list of text as the list view static void displayListView() { // set text color rsgFontColor(0.9f, 0.9f, 0.9f, 1.0f); rsgBindFont(gFontSans); // get the size of the list rs_allocation textAlloc; textAlloc = rsGetAllocation(gListViewText); int allocSize = rsAllocationGetDimX(textAlloc); int listItemHeight = 80; int yOffset = listItemHeight; // set the color for the list divider rsgBindProgramFragment(gProgFragmentColor); rsgProgramFragmentConstantColor(gProgFragmentColor, 1.0, 1.0, 1.0, 1); // draw the list with divider for (int i = 0; i < allocSize; i++) { if (yOffset - listItemHeight > gRenderSurfaceH) { break; } rsgDrawRect(0, yOffset - 1, gRenderSurfaceW, yOffset, 0); rsgDrawText(gListViewText[i].item, 20, yOffset - 10); yOffset += listItemHeight; } } static void drawGalaxy() { rsgClearColor(0.f, 0.f, 0.f, 1.f); gParticlesBuffer = rsGetAllocation(Particles); rsgBindProgramFragment(gPFBackground); gWidth = rsgGetWidth(); gHeight = rsgGetHeight(); if ((gWidth != gOldWidth) || (gHeight != gOldHeight)) { initParticles(); gOldWidth = gWidth; gOldHeight = gHeight; } float offset = mix(-1.0f, 1.0f, gXOffset); drawSpace(); drawParticles(offset); drawLights(); } // Display images and text with live wallpaper in the background static void displayLiveWallPaper(int wResolution, int hResolution) { bindProgramVertexOrtho(); drawGalaxy(); rsgBindProgramVertex(gProgVertex); rsgBindProgramStore(gProgStoreBlendAlpha); rsgBindProgramFragment(gProgFragmentTexture); rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp); drawMeshInPage(0, 0, wResolution, hResolution); drawMeshInPage(-1.0f*gRenderSurfaceW, 0, wResolution, hResolution); drawMeshInPage(1.0f*gRenderSurfaceW, 0, wResolution, hResolution); drawMeshInPage(-2.0f*gRenderSurfaceW, 0, wResolution, hResolution); drawMeshInPage(2.0f*gRenderSurfaceW, 0, wResolution, hResolution); } void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32_t y) { TestData *testData = (TestData*)usrData; gRenderSurfaceW = testData->renderSurfaceW; gRenderSurfaceH = testData->renderSurfaceH; gDt = testData->dt; gData = (UiTestData*)v_in; switch(gData->testId) { case 0: displayIcons(gData->user1); break; case 1: displayImageWithText(gData->user1, gData->user2, gData->user3); break; case 2: displayListView(); break; case 3: displayLiveWallPaper(gData->user1, gData->user2); break; default: rsDebug("Wrong test number", 0); break; } }