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