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
RenderingThread(NPP npp)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
readyToRun()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
setDimensions(int width,int height)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
getDimensions(int & width,int & height)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
printGLString(const char * name,GLenum s)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
checkGlError(const char * op)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
getInternalFormat(SkBitmap::Config config)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
getType(SkBitmap::Config config)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
setupNativeWindow(ANativeWindow * ANW,const SkBitmap & bitmap)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
updateNativeWindow(ANativeWindow * ANW,const SkBitmap & bitmap)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