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 extern ANPLogInterfaceV0           gLogI;
     30 extern ANPNativeWindowInterfaceV0  gNativeWindowI;
     31 
     32 RenderingThread::RenderingThread(NPP npp) : android::Thread() {
     33     m_npp = npp;
     34     m_width = -1;
     35     m_height = -1;
     36 
     37     m_ANW = NULL;
     38 #if (!USE_SOFTWARE_RENDERING)
     39     m_eglSurface = EGL_NO_SURFACE;
     40     m_eglContext = EGL_NO_CONTEXT;
     41     m_eglDisplay = EGL_NO_DISPLAY;
     42 #endif
     43 }
     44 
     45 android::status_t RenderingThread::readyToRun() {
     46     gLogI.log(kError_ANPLogType, "thread %p acquiring native window...", this);
     47     while (m_ANW == NULL) {
     48         m_ANW = gNativeWindowI.acquireNativeWindow(m_npp);
     49         if (!m_ANW)
     50             gLogI.log(kError_ANPLogType, "thread %p acquire native window FAILED!", this);
     51 
     52     }
     53     gLogI.log(kError_ANPLogType, "thread %p acquired native window successfully!", this);
     54 
     55 #if (!USE_SOFTWARE_RENDERING)
     56     m_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
     57 
     58     //initialize context
     59     EGLint numConfigs;
     60     static const EGLint configAttribs[] = {
     61         EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
     62         EGL_RED_SIZE, 8,
     63         EGL_GREEN_SIZE, 8,
     64         EGL_BLUE_SIZE, 8,
     65         EGL_ALPHA_SIZE, 8,
     66         EGL_NONE
     67     };
     68 
     69     eglChooseConfig(m_eglDisplay, configAttribs, &m_eglConfig, 1, &numConfigs);
     70     checkGlError("eglChooseConfig");
     71 
     72     static const EGLint contextAttribs[] = {
     73         EGL_CONTEXT_CLIENT_VERSION, 2,
     74         EGL_NONE
     75     };
     76 
     77     m_eglContext = eglCreateContext(m_eglDisplay, m_eglConfig, NULL, contextAttribs);
     78     checkGlError("eglCreateContext");
     79 #endif
     80 
     81     return android::NO_ERROR;
     82 }
     83 
     84 void RenderingThread::setDimensions(int width, int height) {
     85     android::Mutex::Autolock lock(m_sync);
     86     m_width = width;
     87     m_height = height;
     88 }
     89 
     90 void RenderingThread::getDimensions(int& width, int& height) {
     91     android::Mutex::Autolock lock(m_sync);
     92     width = m_width;
     93     height = m_height;
     94 }
     95 
     96 void RenderingThread::printGLString(const char *name, GLenum s) {
     97     const char *v = (const char *) glGetString(s);
     98     gLogI.log(kError_ANPLogType, "GL %s = %s\n", name, v);
     99 }
    100 
    101 void RenderingThread::checkGlError(const char* op) {
    102     for (GLint error = glGetError(); error; error
    103             = glGetError()) {
    104         gLogI.log(kError_ANPLogType, "after %s() glError (0x%x)\n", op, error);
    105     }
    106 }
    107 
    108 GLenum RenderingThread::getInternalFormat(SkBitmap::Config config)
    109 {
    110     switch(config) {
    111         case SkBitmap::kA8_Config:
    112             return GL_ALPHA;
    113         case SkBitmap::kARGB_4444_Config:
    114             return GL_RGBA;
    115         case SkBitmap::kARGB_8888_Config:
    116             return GL_RGBA;
    117         case SkBitmap::kRGB_565_Config:
    118             return GL_RGB;
    119         default:
    120             return -1;
    121     }
    122 }
    123 
    124 GLenum RenderingThread::getType(SkBitmap::Config config)
    125 {
    126     switch(config) {
    127         case SkBitmap::kA8_Config:
    128             return GL_UNSIGNED_BYTE;
    129         case SkBitmap::kARGB_4444_Config:
    130             return GL_UNSIGNED_SHORT_4_4_4_4;
    131         case SkBitmap::kARGB_8888_Config:
    132             return GL_UNSIGNED_BYTE;
    133         case SkBitmap::kIndex8_Config:
    134             return -1; // No type for compressed data.
    135         case SkBitmap::kRGB_565_Config:
    136             return GL_UNSIGNED_SHORT_5_6_5;
    137         default:
    138             return -1;
    139     }
    140 }
    141 
    142 void RenderingThread::setupNativeWindow(ANativeWindow* ANW, const SkBitmap& bitmap)
    143 {
    144     int result = ANativeWindow_setBuffersGeometry(ANW, bitmap.width(),
    145             bitmap.height(), WINDOW_FORMAT_RGBA_8888);
    146 
    147     if (android::NO_ERROR != result) {
    148         gLogI.log(kError_ANPLogType, "ERROR setBuffersGeometry() status is (%d)", result);
    149     }
    150 
    151 #if (!USE_SOFTWARE_RENDERING)
    152     if (m_eglSurface != EGL_NO_SURFACE) {
    153         gLogI.log(kDebug_ANPLogType, "destroying old surface");
    154         eglDestroySurface(m_eglDisplay, m_eglSurface);
    155     }
    156 
    157     m_eglSurface = eglCreateWindowSurface(m_eglDisplay, m_eglConfig, ANW, NULL);
    158     checkGlError("eglCreateWindowSurface");
    159 
    160     eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext);
    161 
    162     //optional: enable async mode
    163     //eglSwapInterval(m_eglDisplay, 0);
    164 #endif
    165 
    166     updateNativeWindow(ANW, bitmap);
    167 }
    168 
    169 void RenderingThread::updateNativeWindow(ANativeWindow* ANW,
    170                                          const SkBitmap& bitmap)
    171 {
    172 #if USE_SOFTWARE_RENDERING
    173     if (bitmap.height() == 0 || bitmap.width() == 0)
    174         return;
    175 
    176     //STEP 1: lock the ANW, getting a buffer
    177     ANativeWindow_Buffer buffer;
    178     if (ANativeWindow_lock(ANW, &buffer, NULL) < 0 ) // todo: use rect parameter for efficiency
    179         return;
    180 
    181     //STEP 2: draw into the buffer
    182     uint8_t* img = (uint8_t*)buffer.bits;
    183     int row, col;
    184     int bpp = 4; // Here we only deal with RGBA8888 format.
    185     bitmap.lockPixels();
    186     uint8_t* bitmapOrigin = static_cast<uint8_t*>(bitmap.getPixels());
    187     // Copy line by line to handle offsets and stride
    188     for (row = 0 ; row < bitmap.height(); row ++) {
    189         uint8_t* dst = &(img[(buffer.stride * (row + 0) + 0) * bpp]);
    190         uint8_t* src = &(bitmapOrigin[bitmap.width() * row * bpp]);
    191         memcpy(dst, src, bpp * bitmap.width());
    192     }
    193     bitmap.unlockPixels();
    194 
    195     //STEP 3: push the buffer to the queue
    196     ANativeWindow_unlockAndPost(ANW);
    197 
    198 #else
    199 
    200     //rotate the intensity of the green channel, other channels fixed
    201     static int i = 0;
    202     i = (i >= 245) ? 0 : i+10;
    203 
    204     glClearColor(0.6, (i*1.0/256), 0.6, 0.6);
    205     glClear(GL_COLOR_BUFFER_BIT);
    206 
    207     eglSwapBuffers(m_eglDisplay, m_eglSurface);
    208 #endif
    209 }
    210 
    211