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 31extern ANPLogInterfaceV0 gLogI; 32extern ANPNativeWindowInterfaceV0 gNativeWindowI; 33 34RenderingThread::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 47android::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 86void RenderingThread::setDimensions(int width, int height) { 87 android::Mutex::Autolock lock(m_sync); 88 m_width = width; 89 m_height = height; 90} 91 92void RenderingThread::getDimensions(int& width, int& height) { 93 android::Mutex::Autolock lock(m_sync); 94 width = m_width; 95 height = m_height; 96} 97 98void 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 103void 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 110GLenum 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 126GLenum 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 144void 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 171void 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