1 /* Copyright (C) 2011 The Android Open Source Project
2 **
3 ** This software is licensed under the terms of the GNU General Public
4 ** License version 2, as published by the Free Software Foundation, and
5 ** may be copied, distributed, and modified under those terms.
6 **
7 ** This program is distributed in the hope that it will be useful,
8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 ** GNU General Public License for more details.
11 */
12
13 #include "config-host.h"
14 #include "android/opengles.h"
15 #include <assert.h>
16
17 /* Declared in "android/globals.h" */
18 int android_gles_fast_pipes = 1;
19
20 #if CONFIG_ANDROID_OPENGLES
21
22 #include "android/globals.h"
23 #include <android/utils/debug.h>
24 #include <android/utils/path.h>
25 #include <android/utils/bufprint.h>
26 #include <android/utils/dll.h>
27
28 #define RENDER_API_NO_PROTOTYPES 1
29 #include <libOpenglRender/render_api.h>
30
31 #include <stdio.h>
32 #include <stdlib.h>
33
34 #define D(...) VERBOSE_PRINT(init,__VA_ARGS__)
35 #define DD(...) VERBOSE_PRINT(gles,__VA_ARGS__)
36
37 /* Name of the GLES rendering library we're going to use */
38 #if HOST_LONG_BITS == 32
39 #define RENDERER_LIB_NAME "libOpenglRender"
40 #elif HOST_LONG_BITS == 64
41 #define RENDERER_LIB_NAME "lib64OpenglRender"
42 #else
43 #error Unknown HOST_LONG_BITS
44 #endif
45
46 #define DYNLINK_FUNCTIONS \
47 DYNLINK_FUNC(initLibrary) \
48 DYNLINK_FUNC(setStreamMode) \
49 DYNLINK_FUNC(initOpenGLRenderer) \
50 DYNLINK_FUNC(setPostCallback) \
51 DYNLINK_FUNC(getHardwareStrings) \
52 DYNLINK_FUNC(createOpenGLSubwindow) \
53 DYNLINK_FUNC(destroyOpenGLSubwindow) \
54 DYNLINK_FUNC(repaintOpenGLDisplay) \
55 DYNLINK_FUNC(stopOpenGLRenderer)
56
57 #ifndef CONFIG_STANDALONE_UI
58 /* Defined in android/hw-pipe-net.c */
59 extern int android_init_opengles_pipes(void);
60 #endif
61
62 static ADynamicLibrary* rendererLib;
63 static int rendererStarted;
64 static char rendererAddress[256];
65
66 /* Define the function pointers */
67 #define DYNLINK_FUNC(name) \
68 static name##Fn name = NULL;
69 DYNLINK_FUNCTIONS
70 #undef DYNLINK_FUNC
71
72 static int
initOpenglesEmulationFuncs(ADynamicLibrary * rendererLib)73 initOpenglesEmulationFuncs(ADynamicLibrary* rendererLib)
74 {
75 void* symbol;
76 char* error;
77
78 #define DYNLINK_FUNC(name) \
79 symbol = adynamicLibrary_findSymbol(rendererLib, #name, &error); \
80 if (symbol != NULL) { \
81 name = symbol; \
82 } else { \
83 derror("GLES emulation: Could not find required symbol (%s): %s", #name, error); \
84 free(error); \
85 return -1; \
86 }
87 DYNLINK_FUNCTIONS
88 #undef DYNLINK_FUNC
89
90 return 0;
91 }
92
93 int
android_initOpenglesEmulation(void)94 android_initOpenglesEmulation(void)
95 {
96 char* error = NULL;
97
98 if (rendererLib != NULL)
99 return 0;
100
101 D("Initializing hardware OpenGLES emulation support");
102
103 rendererLib = adynamicLibrary_open(RENDERER_LIB_NAME, &error);
104 if (rendererLib == NULL) {
105 derror("Could not load OpenGLES emulation library: %s", error);
106 return -1;
107 }
108
109 #ifndef CONFIG_STANDALONE_UI
110 android_init_opengles_pipes();
111 #endif
112
113
114 /* Resolve the functions */
115 if (initOpenglesEmulationFuncs(rendererLib) < 0) {
116 derror("OpenGLES emulation library mismatch. Be sure to use the correct version!");
117 goto BAD_EXIT;
118 }
119
120 if (!initLibrary()) {
121 derror("OpenGLES initialization failed!");
122 goto BAD_EXIT;
123 }
124
125 if (android_gles_fast_pipes) {
126 #ifdef _WIN32
127 /* XXX: NEED Win32 pipe implementation */
128 setStreamMode(STREAM_MODE_TCP);
129 #else
130 setStreamMode(STREAM_MODE_UNIX);
131 #endif
132 } else {
133 setStreamMode(STREAM_MODE_TCP);
134 }
135 return 0;
136
137 BAD_EXIT:
138 derror("OpenGLES emulation library could not be initialized!");
139 adynamicLibrary_close(rendererLib);
140 rendererLib = NULL;
141 return -1;
142 }
143
144 int
android_startOpenglesRenderer(int width,int height)145 android_startOpenglesRenderer(int width, int height)
146 {
147 if (!rendererLib) {
148 D("Can't start OpenGLES renderer without support libraries");
149 return -1;
150 }
151
152 if (rendererStarted) {
153 return 0;
154 }
155
156 if (!initOpenGLRenderer(width, height, rendererAddress, sizeof(rendererAddress))) {
157 D("Can't start OpenGLES renderer?");
158 return -1;
159 }
160
161 rendererStarted = 1;
162 return 0;
163 }
164
165 void
android_setPostCallback(OnPostFunc onPost,void * onPostContext)166 android_setPostCallback(OnPostFunc onPost, void* onPostContext)
167 {
168 if (rendererLib) {
169 setPostCallback(onPost, onPostContext);
170 }
171 }
172
strncpy_safe(char * dst,const char * src,size_t n)173 static void strncpy_safe(char* dst, const char* src, size_t n)
174 {
175 strncpy(dst, src, n);
176 dst[n-1] = '\0';
177 }
178
extractBaseString(char * dst,const char * src,size_t dstSize)179 static void extractBaseString(char* dst, const char* src, size_t dstSize)
180 {
181 const char* begin = strchr(src, '(');
182 const char* end = strrchr(src, ')');
183
184 if (!begin || !end) {
185 strncpy_safe(dst, src, dstSize);
186 return;
187 }
188 begin += 1;
189
190 // "foo (bar)"
191 // ^ ^
192 // b e
193 // = 5 8
194 // substring with NUL-terminator is end-begin+1 bytes
195 if (end - begin + 1 > dstSize) {
196 end = begin + dstSize - 1;
197 }
198
199 strncpy_safe(dst, begin, end - begin + 1);
200 }
201
202 void
android_getOpenglesHardwareStrings(char * vendor,size_t vendorBufSize,char * renderer,size_t rendererBufSize,char * version,size_t versionBufSize)203 android_getOpenglesHardwareStrings(char* vendor, size_t vendorBufSize,
204 char* renderer, size_t rendererBufSize,
205 char* version, size_t versionBufSize)
206 {
207 const char *vendorSrc, *rendererSrc, *versionSrc;
208
209 assert(vendorBufSize > 0 && rendererBufSize > 0 && versionBufSize > 0);
210 assert(vendor != NULL && renderer != NULL && version != NULL);
211
212 if (!rendererStarted) {
213 D("Can't get OpenGL ES hardware strings when renderer not started");
214 vendor[0] = renderer[0] = version[0] = '\0';
215 return;
216 }
217
218 getHardwareStrings(&vendorSrc, &rendererSrc, &versionSrc);
219 if (!vendorSrc) vendorSrc = "";
220 if (!rendererSrc) rendererSrc = "";
221 if (!versionSrc) versionSrc = "";
222
223 /* Special case for the default ES to GL translators: extract the strings
224 * of the underlying OpenGL implementation. */
225 if (strncmp(vendorSrc, "Google", 6) == 0 &&
226 strncmp(rendererSrc, "Android Emulator OpenGL ES Translator", 37) == 0) {
227 extractBaseString(vendor, vendorSrc, vendorBufSize);
228 extractBaseString(renderer, rendererSrc, rendererBufSize);
229 extractBaseString(version, versionSrc, versionBufSize);
230 } else {
231 strncpy_safe(vendor, vendorSrc, vendorBufSize);
232 strncpy_safe(renderer, rendererSrc, rendererBufSize);
233 strncpy_safe(version, versionSrc, versionBufSize);
234 }
235 }
236
237 void
android_stopOpenglesRenderer(void)238 android_stopOpenglesRenderer(void)
239 {
240 if (rendererStarted) {
241 stopOpenGLRenderer();
242 rendererStarted = 0;
243 }
244 }
245
246 int
android_showOpenglesWindow(void * window,int x,int y,int width,int height,float rotation)247 android_showOpenglesWindow(void* window, int x, int y, int width, int height, float rotation)
248 {
249 if (rendererStarted) {
250 int success = createOpenGLSubwindow((FBNativeWindowType)window, x, y, width, height, rotation);
251 return success ? 0 : -1;
252 } else {
253 return -1;
254 }
255 }
256
257 int
android_hideOpenglesWindow(void)258 android_hideOpenglesWindow(void)
259 {
260 if (rendererStarted) {
261 int success = destroyOpenGLSubwindow();
262 return success ? 0 : -1;
263 } else {
264 return -1;
265 }
266 }
267
268 void
android_redrawOpenglesWindow(void)269 android_redrawOpenglesWindow(void)
270 {
271 if (rendererStarted) {
272 repaintOpenGLDisplay();
273 }
274 }
275
276 void
android_gles_server_path(char * buff,size_t buffsize)277 android_gles_server_path(char* buff, size_t buffsize)
278 {
279 strncpy_safe(buff, rendererAddress, buffsize);
280 }
281
282 #else // CONFIG_ANDROID_OPENGLES
283
android_initOpenglesEmulation(void)284 int android_initOpenglesEmulation(void)
285 {
286 return -1;
287 }
288
android_startOpenglesRenderer(int width,int height)289 int android_startOpenglesRenderer(int width, int height)
290 {
291 return -1;
292 }
293
294 void
android_setPostCallback(OnPostFunc onPost,void * onPostContext)295 android_setPostCallback(OnPostFunc onPost, void* onPostContext)
296 {
297 }
298
android_getOpenglesHardwareStrings(char * vendor,size_t vendorBufSize,char * renderer,size_t rendererBufSize,char * version,size_t versionBufSize)299 void android_getOpenglesHardwareStrings(char* vendor, size_t vendorBufSize,
300 char* renderer, size_t rendererBufSize,
301 char* version, size_t versionBufSize)
302 {
303 assert(vendorBufSize > 0 && rendererBufSize > 0 && versionBufSize > 0);
304 assert(vendor != NULL && renderer != NULL && version != NULL);
305 vendor[0] = renderer[0] = version[0] = 0;
306 }
307
android_stopOpenglesRenderer(void)308 void android_stopOpenglesRenderer(void)
309 {}
310
android_showOpenglesWindow(void * window,int x,int y,int width,int height,float rotation)311 int android_showOpenglesWindow(void* window, int x, int y, int width, int height, float rotation)
312 {
313 return -1;
314 }
315
android_hideOpenglesWindow(void)316 int android_hideOpenglesWindow(void)
317 {
318 return -1;
319 }
320
android_redrawOpenglesWindow(void)321 void android_redrawOpenglesWindow(void)
322 {}
323
android_gles_server_path(char * buff,size_t buffsize)324 void android_gles_server_path(char* buff, size_t buffsize)
325 {
326 buff[0] = '\0';
327 }
328
329 #endif // !CONFIG_ANDROID_OPENGLES
330