Integrate from //sandbox/mathias/donut/...@145728

SurfaceFlinger rework for new EGL driver model support.
diff --git a/opengl/tests/copybits/copybits.cpp b/opengl/tests/copybits/copybits.cpp
new file mode 100644
index 0000000..ff17cc9
--- /dev/null
+++ b/opengl/tests/copybits/copybits.cpp
@@ -0,0 +1,752 @@
+// Test software OpenGL hardware accelleration using copybits.
+
+#define LOG_TAG "copybits_test"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include <ui/PixelFormat.h>
+
+#include <cutils/log.h>
+#include <cutils/native_handle.h>
+
+#include <utils/Atomic.h>
+
+#include <private/ui/SharedState.h>
+
+#include <hardware/gralloc.h>
+#include <hardware/hardware.h>
+
+#define EGL_EGLEXT_PROTOTYPES
+#define GL_GLEXT_PROTOTYPES
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+extern "C" EGLNativeWindowType android_createDisplaySurface(void);
+
+using namespace android;
+
+EGLDisplay eglDisplay;
+EGLSurface eglSurface;
+EGLContext eglContext;
+GLuint texture;
+
+hw_module_t const* gralloc_module;
+alloc_device_t  *sAllocDev;
+
+#define FIXED_ONE 0x10000
+
+int init_gl_surface();
+void free_gl_surface();
+void init_scene();
+
+int create_physical_texture();
+int readTimer();
+
+// ===========================================================================
+// Buffer and implementation of android_native_buffer_t
+// ===========================================================================
+
+class NativeBuffer;
+
+class Buffer :  public android_native_buffer_t,
+                public LightRefBase<Buffer>
+{
+public:
+
+    // creates w * h buffer
+    Buffer(uint32_t w, uint32_t h, PixelFormat format, int usage);
+
+    // return status
+    status_t initCheck() const;
+
+
+    uint32_t getWidth() const           { return mWidth; }
+    uint32_t getHeight() const          { return mHeight; }
+    uint32_t getStride() const          { return mStride; }
+    uint32_t getUsage() const           { return mUsage; }
+    PixelFormat getPixelFormat() const  { return mFormat; }
+    buffer_handle_t getHandle() const   { return mBufferHandle; }
+
+    android_native_buffer_t* getNativeBuffer() const;
+
+    void setPixel(int x, int y, int r, int g, int b, int a);
+
+private:
+    friend class LightRefBase<Buffer>;
+    Buffer(const Buffer& rhs);
+    ~Buffer();
+    Buffer& operator = (const Buffer& rhs);
+    const Buffer& operator = (const Buffer& rhs) const;
+
+    status_t initSize(uint32_t w, uint32_t h);
+
+    static void incRef(android_native_base_t* buffer);
+    static void decRef(android_native_base_t* buffer);
+    static int getHandlePriv(android_native_buffer_t const * buffer,
+            buffer_handle_t* handle);
+
+    buffer_handle_t         mBufferHandle;
+    ssize_t                 mInitCheck;
+
+    uint32_t                mWidth;
+    uint32_t                mHeight;
+    uint32_t                mStride;
+    uint32_t                mVStride;
+    PixelFormat             mFormat;
+    void*                   mData;
+    uint32_t                mUsage;
+};
+
+Buffer::Buffer(uint32_t w, uint32_t h, PixelFormat format, int usage)
+    : mBufferHandle(0), mInitCheck(NO_INIT),
+    mWidth(0), mHeight(0), mStride(0), mVStride(0), mFormat(format), mData(0),
+    mUsage(usage)
+{
+    common.magic = ANDROID_NATIVE_BUFFER_MAGIC;
+    common.version = sizeof(android_native_buffer_t);
+    common.incRef = incRef;
+    common.decRef = decRef;
+    android_native_buffer_t::getHandle = getHandlePriv;
+    if (w>0 && h>0) {
+        mInitCheck = initSize(w, h);
+    }
+}
+
+Buffer::~Buffer()
+{
+    if (mBufferHandle) {
+
+        gralloc_module_t* mod = (gralloc_module_t*)sAllocDev->common.module;
+        mod->unmap(mod, mBufferHandle);
+
+        sAllocDev->free(sAllocDev, mBufferHandle);
+    }
+}
+
+void Buffer::incRef(android_native_base_t* buffer) {
+    Buffer* self = static_cast<Buffer*>(
+            reinterpret_cast<android_native_buffer_t *>(buffer));
+    self->incStrong(self);
+}
+
+void Buffer::decRef(android_native_base_t* buffer) {
+    Buffer* self = static_cast<Buffer*>(
+            reinterpret_cast<android_native_buffer_t *>(buffer));
+    self->decStrong(self);
+}
+
+int Buffer::getHandlePriv(android_native_buffer_t const * buffer,
+        buffer_handle_t* handle) {
+    Buffer const * self = static_cast<Buffer const *>(buffer);
+    *handle = self->getHandle();
+    return 0;
+}
+
+status_t Buffer::initCheck() const {
+    return mInitCheck;
+}
+
+android_native_buffer_t* Buffer::getNativeBuffer() const
+{
+    Buffer* that = const_cast<Buffer*>(this);
+    that->android_native_buffer_t::width = mWidth;
+    that->android_native_buffer_t::height = mHeight;
+    that->android_native_buffer_t::stride = mStride;
+    that->android_native_buffer_t::format = mFormat;
+    that->android_native_buffer_t::usage = mUsage;
+    that->android_native_buffer_t::bits = mData;
+    return static_cast<android_native_buffer_t*>(that);
+}
+
+status_t Buffer::initSize(uint32_t w, uint32_t h)
+{
+    status_t err = NO_ERROR;
+
+    int32_t stride;
+    err = sAllocDev->alloc(sAllocDev, w, h, mFormat, mUsage, &mBufferHandle, &stride);
+
+    if (err == NO_ERROR) {
+        void* addr = 0;
+        gralloc_module_t* mod = (gralloc_module_t*)sAllocDev->common.module;
+        err = mod->map(mod, mBufferHandle, &addr);
+        if (err == NO_ERROR) {
+            mData = addr;
+            mWidth  = w;
+            mHeight = h;
+            mStride = stride;
+            mVStride = 0;
+        }
+    }
+
+    return err;
+}
+
+void Buffer::setPixel(int x, int y, int r, int g, int b, int a) {
+    if (x < 0 || (unsigned int) x >= mWidth
+            || y < 0 || (unsigned int) y >= mHeight) {
+        // clipped
+        return;
+    }
+    int index = mStride * y + x;
+    switch (mFormat) {
+    case HAL_PIXEL_FORMAT_RGB_565: {
+            unsigned short val = (unsigned short) (
+                    ((0x1f & (r >> 3)) << 11)
+                    | ((0x3f & (g >> 2)) << 5)
+                    | (0x1f & (b >> 3)));
+            ((unsigned short*) mData)[index]= val;
+        }
+        break;
+    case HAL_PIXEL_FORMAT_RGBA_8888: { // ABGR
+        unsigned int val = (unsigned int)
+            (((a & 0xff) << 24)
+                    | ((b & 0xff) << 16)
+                    | ((g & 0xff) << 8)
+                    | (r & 0xff));
+            ((unsigned int*) mData)[index] = val;
+        }
+        break;
+    default:
+        // Unsupported pixel format
+        break;
+    }
+}
+
+
+static void gluLookAt(float eyeX, float eyeY, float eyeZ,
+        float centerX, float centerY, float centerZ, float upX, float upY,
+        float upZ)
+{
+    // See the OpenGL GLUT documentation for gluLookAt for a description
+    // of the algorithm. We implement it in a straightforward way:
+
+    float fx = centerX - eyeX;
+    float fy = centerY - eyeY;
+    float fz = centerZ - eyeZ;
+
+    // Normalize f
+    float rlf = 1.0f / sqrtf(fx*fx + fy*fy + fz*fz);
+    fx *= rlf;
+    fy *= rlf;
+    fz *= rlf;
+
+    // Normalize up
+    float rlup = 1.0f / sqrtf(upX*upX + upY*upY + upZ*upZ);
+    upX *= rlup;
+    upY *= rlup;
+    upZ *= rlup;
+
+    // compute s = f x up (x means "cross product")
+
+    float sx = fy * upZ - fz * upY;
+    float sy = fz * upX - fx * upZ;
+    float sz = fx * upY - fy * upX;
+
+    // compute u = s x f
+    float ux = sy * fz - sz * fy;
+    float uy = sz * fx - sx * fz;
+    float uz = sx * fy - sy * fx;
+
+    float m[16] ;
+    m[0] = sx;
+    m[1] = ux;
+    m[2] = -fx;
+    m[3] = 0.0f;
+
+    m[4] = sy;
+    m[5] = uy;
+    m[6] = -fy;
+    m[7] = 0.0f;
+
+    m[8] = sz;
+    m[9] = uz;
+    m[10] = -fz;
+    m[11] = 0.0f;
+
+    m[12] = 0.0f;
+    m[13] = 0.0f;
+    m[14] = 0.0f;
+    m[15] = 1.0f;
+
+    glMultMatrixf(m);
+    glTranslatef(-eyeX, -eyeY, -eyeZ);
+}
+
+int init_gralloc() {
+    int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &gralloc_module);
+    LOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID);
+
+    if (err == 0) {
+        gralloc_open(gralloc_module, &sAllocDev);
+    }
+    return err;
+}
+
+int init_gl_surface(void)
+{
+    EGLint numConfigs = 1;
+    EGLConfig myConfig = {0};
+    EGLint attrib[] =
+    {
+            EGL_DEPTH_SIZE,     16,
+            EGL_NONE
+    };
+
+    printf("init_gl_surface\n");
+    if ( (eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY)) == EGL_NO_DISPLAY )
+    {
+        printf("eglGetDisplay failed\n");
+        return 0;
+    }
+
+    if ( eglInitialize(eglDisplay, NULL, NULL) != EGL_TRUE )
+    {
+        printf("eglInitialize failed\n");
+        return 0;
+    }
+
+    if ( eglChooseConfig(eglDisplay, attrib, &myConfig, 1, &numConfigs) != EGL_TRUE )
+    {
+        printf("eglChooseConfig failed\n");
+        return 0;
+    }
+
+    if ( (eglSurface = eglCreateWindowSurface(eglDisplay, myConfig,
+            android_createDisplaySurface(), 0)) == EGL_NO_SURFACE )
+    {
+        printf("eglCreateWindowSurface failed\n");
+        return 0;
+    }
+
+    if ( (eglContext = eglCreateContext(eglDisplay, myConfig, 0, 0)) == EGL_NO_CONTEXT )
+    {
+        printf("eglCreateContext failed\n");
+        return 0;
+    }
+
+    if ( eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext) != EGL_TRUE )
+    {
+        printf("eglMakeCurrent failed\n");
+        return 0;
+    }
+
+    return 1;
+}
+
+void free_gl_surface(void)
+{
+    if (eglDisplay != EGL_NO_DISPLAY)
+    {
+        eglMakeCurrent( EGL_NO_DISPLAY, EGL_NO_SURFACE,
+                EGL_NO_SURFACE, EGL_NO_CONTEXT );
+        eglDestroyContext( eglDisplay, eglContext );
+        eglDestroySurface( eglDisplay, eglSurface );
+        eglTerminate( eglDisplay );
+        eglDisplay = EGL_NO_DISPLAY;
+    }
+}
+
+void init_scene(void)
+{
+    glDisable(GL_DITHER);
+    glEnable(GL_CULL_FACE);
+    float ratio = 320.0f /  480.0f;
+    glViewport(0, 0, 320, 480);
+
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    glFrustumf(-ratio, ratio, -1, 1, 1, 10);
+
+    glMatrixMode(GL_MODELVIEW);
+
+    glLoadIdentity();
+    gluLookAt(
+            0, 0, 3,  // eye
+            0, 0, 0,  // center
+            0, 1, 0); // up
+
+    glEnable(GL_TEXTURE_2D);
+}
+
+// #define USE_ALPHA_COLOR
+
+#define USE_GL_REPLACE
+// #define USE_GL_MODULATE
+
+// #define USE_BLEND
+
+#define USE_565
+// #define USE_8888
+
+// #define USE_NEAREST
+#define USE_LINEAR
+
+#define USE_SCALE
+
+void setSmoothGradient(Buffer* bufferObject) {
+    int pixels = bufferObject->getHeight() * bufferObject->getWidth();
+    int step = 0;
+    for (unsigned int y = 0; y < bufferObject->getHeight(); y++) {
+        for(unsigned int x = 0; x < bufferObject->getWidth() ; x++) {
+            int grey = step * 255 / pixels;
+            bufferObject->setPixel(x, y, grey, grey, grey, 255);
+            ++step;
+        }
+    }
+}
+
+void setSmoothAlphaGradient(Buffer* bufferObject) {
+    int pixels = bufferObject->getHeight() * bufferObject->getWidth();
+    int step = 0;
+    for (unsigned int y = 0; y < bufferObject->getHeight(); y++) {
+        for(unsigned int x = 0; x < bufferObject->getWidth() ; x++) {
+            int grey = step * 255 / pixels;
+            bufferObject->setPixel(x, y, 255, 255, 255, grey);
+            ++step;
+        }
+    }
+}
+
+void setOrientedCheckerboard(Buffer* bufferObject) {
+    bufferObject->setPixel(0, 0, 0, 0, 0, 255);
+    for(unsigned int x = 1; x < bufferObject->getWidth() ; x++) {
+        bufferObject->setPixel(x, 0, 0, 255, 0, 255);
+    }
+    for (unsigned int y = 1; y < bufferObject->getHeight(); y++) {
+        for(unsigned int x = 0; x < bufferObject->getWidth() ; x++) {
+            if ((x ^ y ) & 1) {
+                bufferObject->setPixel(x, y, 255, 255, 255, 255);
+            } else {
+                bufferObject->setPixel(x, y, 255, 0, 0, 255);
+            }
+        }
+    }
+}
+
+int create_physical_texture(unsigned int w, unsigned int h)
+{
+
+#ifdef USE_565
+    PixelFormat format = HAL_PIXEL_FORMAT_RGB_565;
+#else
+    PixelFormat format = HAL_PIXEL_FORMAT_RGBA_8888;
+#endif
+    int usage = GRALLOC_USAGE_SW_READ_OFTEN |
+        GRALLOC_USAGE_SW_WRITE_OFTEN |
+        GRALLOC_USAGE_HW_TEXTURE |
+        GRALLOC_USAGE_HW_2D; /* This is the key to allocating the texture in pmem. */
+    int32_t stride;
+    buffer_handle_t handle;
+
+    // Allocate the hardware buffer
+    Buffer* bufferObject = new Buffer(w, h, format, usage);
+
+    android_native_buffer_t* buffer = bufferObject->getNativeBuffer();
+
+    buffer->common.incRef(&buffer->common);
+
+    // create the new EGLImageKHR
+    EGLint attrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_NONE };
+    EGLDisplay dpy = eglGetCurrentDisplay();
+    EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+            (EGLClientBuffer)buffer, attrs);
+    if (image == EGL_NO_IMAGE_KHR) {
+        printf("Could not create an image %d\n", eglGetError());
+        return -1;
+    }
+
+    if (buffer->bits == NULL) {
+        printf("No bits allocated for image.\n");
+        return -2;
+    }
+
+    setOrientedCheckerboard(bufferObject);
+    // setSmoothGradient(bufferObject);
+    // setSmoothAlphaGradient(bufferObject);
+
+    glGenTextures(1, &texture);
+    glBindTexture(GL_TEXTURE_2D, texture);
+    glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
+#ifdef USE_LINEAR
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+#elif defined(USE_NEAREST)
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+#endif
+
+#ifdef USE_GL_REPLACE
+    glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+#elif defined(USE_GL_MODULATE)
+    glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+#endif
+
+#ifdef USE_ALPHA_COLOR
+    glColor4f(1.0f, 1.0f, 1.0f, 0.4f);
+#else
+    glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+#endif
+
+#ifdef USE_BLEND
+    glEnable(GL_BLEND);
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+#endif
+    return 0;
+}
+
+static const int SCALE_COUNT = 12;
+
+int scale(int base, int factor) {
+    static const float kTable[SCALE_COUNT] = {
+            0.1f, 0.25f, 0.5f, 0.75f, 1.0f,
+            1.5f, 2.0f, 2.5f, 3.0f, 3.5f, 4.0f, 5.0f
+    };
+    return base * kTable[factor];
+}
+
+class Timer {
+    struct timeval  first;
+    double elapsedSeconds;
+
+public:
+    Timer() {}
+    void start() {
+        gettimeofday(&first, NULL);
+    }
+
+    void stop() {
+        struct timeval  second,
+                        elapsed;
+        gettimeofday(&second, NULL);
+
+        if (first.tv_usec > second.tv_usec) {
+           second.tv_usec += 1000000;
+           second.tv_sec--;
+        }
+
+        elapsedSeconds = (second.tv_sec  - first.tv_sec) +
+            (second.tv_usec - first.tv_usec) / 1000000.0;
+    }
+
+    double getElapsedSeconds() {
+        return elapsedSeconds;
+    }
+
+    double getElapsedMs() {
+        return elapsedSeconds* 1000.0f;
+    }
+};
+
+int testTime()
+{
+    static const int WIDTH = 320;
+    static const int HEIGHT = 480;
+    static const int SCALE = 8;
+
+    if (create_physical_texture(WIDTH, HEIGHT) != 0) {
+        return -1;
+    }
+    // Need to do a dummy eglSwapBuffers first. Don't know why.
+    glClearColor(0.4, 1.0, 0.4, 0.4);
+    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+    eglSwapBuffers(eglDisplay, eglSurface);
+
+    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+
+#if defined(USE_SCALE)
+    static const int scaleOffset = 0;
+#else
+    static const int scaleOffset = 1;
+#endif
+    printf("ms\n");
+    for(int j = 0; j < SCALE; j++) {
+        int w = WIDTH >> (j + scaleOffset);
+        int h = HEIGHT >> j;
+        int cropRect[4] = {0,h,w,-h}; // Left bottom width height. Width and Height can be neg to flip.
+        glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, cropRect);
+        Timer timer;
+        timer.start();
+
+        int copyCount = 1000;
+        for (int i = 0; i < copyCount; i++) {
+            glDrawTexiOES(0, 0, 0, w, h);
+        }
+
+        timer.stop();
+        printf("%g\n", timer.getElapsedMs() / copyCount);
+    }
+
+    eglSwapBuffers(eglDisplay, eglSurface);
+    return 0;
+}
+
+int testStretch()
+{
+    static const int WIDTH = 8;
+    static const int HEIGHT = 8;
+
+    if (create_physical_texture(WIDTH, HEIGHT) != 0) {
+        return -1;
+    }
+    // Need to do a dummy eglSwapBuffers first. Don't know why.
+    glClearColor(0.4, 1.0, 0.4, 0.4);
+    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+    eglSwapBuffers(eglDisplay, eglSurface);
+
+    int cropRect[4] = {0,HEIGHT,WIDTH,-HEIGHT}; // Left bottom width height. Width and Height can be neg to flip.
+    glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, cropRect);
+
+    for(int frame = 0; frame < 2; frame++) {
+        glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+        int baseX = 10;
+        for (int x = 0; x < SCALE_COUNT; x++) {
+            int baseY = 10;
+            int width = scale(WIDTH, x);
+            for (int y = 0; y < SCALE_COUNT; y++) {
+                int height = scale(HEIGHT, y);
+                glDrawTexxOES(baseX << 16, baseY << 16, 0, width << 16, height << 16);
+                baseY += height + 10;
+            }
+            baseX += width + 10;
+        }
+
+        eglSwapBuffers(eglDisplay, eglSurface);
+    }
+    return 0;
+}
+
+int testRot90()
+{
+    static const int WIDTH = 8;
+    static const int HEIGHT = 8;
+
+    if (create_physical_texture(WIDTH, HEIGHT) != 0) {
+        return -1;
+    }
+
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    glOrthof(0, 320, 480, 0, 0, 1);
+
+    glMatrixMode(GL_MODELVIEW);
+
+    glLoadIdentity();
+
+    // Need to do a dummy eglSwapBuffers first. Don't know why.
+    glClearColor(0.4, 0.4, 0.4, 0.4);
+    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+    eglSwapBuffers(eglDisplay, eglSurface);
+
+    glEnable(GL_TEXTURE_2D);
+    glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glColor4x(0x10000, 0x10000, 0x10000, 0x10000);
+    glDisable(GL_BLEND);
+    glShadeModel(GL_FLAT);
+    glDisable(GL_DITHER);
+    glDisable(GL_CULL_FACE);
+
+    for(int frame = 0; frame < 2; frame++) {
+        glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+        int baseX = 10;
+        for (int x = 0; x < SCALE_COUNT; x++) {
+            int baseY = 10;
+            int width = scale(WIDTH, x);
+            for (int y = 0; y < SCALE_COUNT; y++) {
+                int height = scale(HEIGHT, y);
+
+                // Code copied from SurfaceFlinger LayerBase.cpp
+
+                const GLfixed texCoords[4][2] = {
+                        { 0,        0 },
+                        { 0,        0x10000 },
+                        { 0x10000,  0x10000 },
+                        { 0x10000,  0 }
+                };
+
+                GLfixed fx = baseX << 16;
+                GLfixed fy = baseY << 16;
+                GLfixed fw = width << 16;
+                GLfixed fh = height << 16;
+
+                /*
+                 * Vertex pattern:
+                 *    (2)--(3)
+                 *     |\   |
+                 *     | \  |
+                 *     |  \ |
+                 *     |   \|
+                 *    (1)--(0)
+                 *
+                 */
+
+                const GLfixed vertices[4][2] = {
+                        {fx + fw, fy},
+                        {fx,      fy},
+                        {fx,      fy + fh},
+                        {fx + fw, fy + fh}
+                };
+
+                static const bool rotate90 = true;
+
+                glMatrixMode(GL_TEXTURE);
+                glLoadIdentity();
+
+                glEnableClientState(GL_VERTEX_ARRAY);
+                glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+                glVertexPointer(2, GL_FIXED, 0, vertices);
+                glTexCoordPointer(2, GL_FIXED, 0, texCoords);
+
+                LOGW("testRot90 %d, %d %d, %d", baseX, baseY, width, height);
+                glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+                baseY += height + 10;
+            }
+            baseX += width + 10;
+        }
+
+        eglSwapBuffers(eglDisplay, eglSurface);
+    }
+    return 0;
+}
+
+int main(int argc, char **argv)
+{
+
+    int q;
+    int start, end;
+
+    if (init_gralloc()) {
+        printf("gralloc initialization failed - exiting\n");
+        return 0;
+    }
+
+    printf("Initializing EGL...\n");
+
+    if(!init_gl_surface())
+    {
+        printf("GL initialisation failed - exiting\n");
+        return 0;
+    }
+
+    init_scene();
+
+    printf("Start test...\n");
+    // testTime();
+    // testStretch();
+    testRot90();
+    free_gl_surface();
+
+    return 0;
+}