Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright 2010, The Android Open Source Project
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  *  * Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  *  * Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 #include "RenderingThread.h"
     26 
     27 #include "ANPNativeWindow_npapi.h"
     28 
     29 #include <android/native_window.h>
     30 
     31 extern ANPLogInterfaceV0           gLogI;
     32 extern ANPNativeWindowInterfaceV0  gNativeWindowI;
     33 
     34 RenderingThread::RenderingThread(NPP npp) : android::Thread() {
     35     m_npp = npp;
     36     m_width = -1;
     37     m_height = -1;
     38 
     39     m_ANW = NULL;
     40 #if (!USE_SOFTWARE_RENDERING)
     41     m_eglSurface = EGL_NO_SURFACE;
     42     m_eglContext = EGL_NO_CONTEXT;
     43     m_eglDisplay = EGL_NO_DISPLAY;
     44 #endif
     45 }
     46 
     47 android::status_t RenderingThread::readyToRun() {
     48     gLogI.log(kError_ANPLogType, "thread %p acquiring native window...", this);
     49     while (m_ANW == NULL) {
     50         m_ANW = gNativeWindowI.acquireNativeWindow(m_npp);
     51         if (!m_ANW)
     52             gLogI.log(kError_ANPLogType, "thread %p acquire native window FAILED!", this);
     53 
     54     }
     55     gLogI.log(kError_ANPLogType, "thread %p acquired native window successfully!", this);
     56 
     57 #if (!USE_SOFTWARE_RENDERING)
     58     m_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
     59 
     60     //initialize context
     61     EGLint numConfigs;
     62     static const EGLint configAttribs[] = {
     63         EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
     64         EGL_RED_SIZE, 8,
     65         EGL_GREEN_SIZE, 8,
     66         EGL_BLUE_SIZE, 8,
     67         EGL_ALPHA_SIZE, 8,
     68         EGL_NONE
     69     };
     70 
     71     eglChooseConfig(m_eglDisplay, configAttribs, &m_eglConfig, 1, &numConfigs);
     72     checkGlError("eglChooseConfig");
     73 
     74     static const EGLint contextAttribs[] = {
     75         EGL_CONTEXT_CLIENT_VERSION, 2,
     76         EGL_NONE
     77     };
     78 
     79     m_eglContext = eglCreateContext(m_eglDisplay, m_eglConfig, NULL, contextAttribs);
     80     checkGlError("eglCreateContext");
     81 #endif
     82 
     83     return android::NO_ERROR;
     84 }
     85 
     86 void RenderingThread::setDimensions(int width, int height) {
     87     android::Mutex::Autolock lock(m_sync);
     88     m_width = width;
     89     m_height = height;
     90 }
     91 
     92 void RenderingThread::getDimensions(int& width, int& height) {
     93     android::Mutex::Autolock lock(m_sync);
     94     width = m_width;
     95     height = m_height;
     96 }
     97 
     98 void RenderingThread::printGLString(const char *name, GLenum s) {
     99     const char *v = (const char *) glGetString(s);
    100     gLogI.log(kError_ANPLogType, "GL %s = %s\n", name, v);
    101 }
    102 
    103 void RenderingThread::checkGlError(const char* op) {
    104     for (GLint error = glGetError(); error; error
    105             = glGetError()) {
    106         gLogI.log(kError_ANPLogType, "after %s() glError (0x%x)\n", op, error);
    107     }
    108 }
    109 
    110 GLenum RenderingThread::getInternalFormat(SkBitmap::Config config)
    111 {
    112     switch(config) {
    113         case SkBitmap::kA8_Config:
    114             return GL_ALPHA;
    115         case SkBitmap::kARGB_4444_Config:
    116             return GL_RGBA;
    117         case SkBitmap::kARGB_8888_Config:
    118             return GL_RGBA;
    119         case SkBitmap::kRGB_565_Config:
    120             return GL_RGB;
    121         default:
    122             return -1;
    123     }
    124 }
    125 
    126 GLenum RenderingThread::getType(SkBitmap::Config config)
    127 {
    128     switch(config) {
    129         case SkBitmap::kA8_Config:
    130             return GL_UNSIGNED_BYTE;
    131         case SkBitmap::kARGB_4444_Config:
    132             return GL_UNSIGNED_SHORT_4_4_4_4;
    133         case SkBitmap::kARGB_8888_Config:
    134             return GL_UNSIGNED_BYTE;
    135         case SkBitmap::kIndex8_Config:
    136             return -1; // No type for compressed data.
    137         case SkBitmap::kRGB_565_Config:
    138             return GL_UNSIGNED_SHORT_5_6_5;
    139         default:
    140             return -1;
    141     }
    142 }
    143 
    144 void RenderingThread::setupNativeWindow(ANativeWindow* ANW, const SkBitmap& bitmap)
    145 {
    146     int result = ANativeWindow_setBuffersGeometry(ANW, bitmap.width(),
    147             bitmap.height(), WINDOW_FORMAT_RGBA_8888);
    148 
    149     if (android::NO_ERROR != result) {
    150         gLogI.log(kError_ANPLogType, "ERROR setBuffersGeometry() status is (%d)", result);
    151     }
    152 
    153 #if (!USE_SOFTWARE_RENDERING)
    154     if (m_eglSurface != EGL_NO_SURFACE) {
    155         gLogI.log(kDebug_ANPLogType, "destroying old surface");
    156         eglDestroySurface(m_eglDisplay, m_eglSurface);
    157     }
    158 
    159     m_eglSurface = eglCreateWindowSurface(m_eglDisplay, m_eglConfig, ANW, NULL);
    160     checkGlError("eglCreateWindowSurface");
    161 
    162     eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext);
    163 
    164     //optional: enable async mode
    165     //eglSwapInterval(m_eglDisplay, 0);
    166 #endif
    167 
    168     updateNativeWindow(ANW, bitmap);
    169 }
    170 
    171 void RenderingThread::updateNativeWindow(ANativeWindow* ANW,
    172                                          const SkBitmap& bitmap)
    173 {
    174 #if USE_SOFTWARE_RENDERING
    175     if (bitmap.height() == 0 || bitmap.width() == 0)
    176         return;
    177 
    178     //STEP 1: lock the ANW, getting a buffer
    179     ANativeWindow_Buffer buffer;
    180     if (ANativeWindow_lock(ANW, &buffer, NULL) < 0 ) // todo: use rect parameter for efficiency
    181         return;
    182 
    183     //STEP 2: draw into the buffer
    184     uint8_t* img = (uint8_t*)buffer.bits;
    185     int row, col;
    186     int bpp = 4; // Here we only deal with RGBA8888 format.
    187     bitmap.lockPixels();
    188     uint8_t* bitmapOrigin = static_cast<uint8_t*>(bitmap.getPixels());
    189     // Copy line by line to handle offsets and stride
    190     for (row = 0 ; row < bitmap.height(); row ++) {
    191         uint8_t* dst = &(img[(buffer.stride * (row + 0) + 0) * bpp]);
    192         uint8_t* src = &(bitmapOrigin[bitmap.width() * row * bpp]);
    193         memcpy(dst, src, bpp * bitmap.width());
    194     }
    195     bitmap.unlockPixels();
    196 
    197     //STEP 3: push the buffer to the queue
    198     ANativeWindow_unlockAndPost(ANW);
    199 
    200 #else
    201 
    202     //rotate the intensity of the green channel, other channels fixed
    203     static int i = 0;
    204     i = (i >= 245) ? 0 : i+10;
    205 
    206     glClearColor(0.6, (i*1.0/256), 0.6, 0.6);
    207     glClear(GL_COLOR_BUFFER_BIT);
    208 
    209     eglSwapBuffers(m_eglDisplay, m_eglSurface);
    210 #endif
    211 }
    212 
    213