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