blob: 74057503c788757667e9749d48353301f294be7a [file] [log] [blame]
David 'Digit' Turnercb88e792011-08-26 01:35:14 +02001/* 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"
Andrew Hsiehafb01182012-05-04 11:55:11 +080015#include <assert.h>
Jesse Hall183e9272012-04-26 15:13:27 -070016
17/* Declared in "android/globals.h" */
18int android_gles_fast_pipes = 1;
19
20#if CONFIG_ANDROID_OPENGLES
21
David Turner7b56a4a2011-09-12 18:21:58 +020022#include "android/globals.h"
David 'Digit' Turnercb88e792011-08-26 01:35:14 +020023#include <android/utils/debug.h>
24#include <android/utils/path.h>
25#include <android/utils/bufprint.h>
26#include <android/utils/dll.h>
Jesse Hall183e9272012-04-26 15:13:27 -070027
28#define RENDER_API_NO_PROTOTYPES 1
Jesse Hall6699b682012-04-18 10:28:46 -070029#include <libOpenglRender/render_api.h>
Jesse Hall183e9272012-04-26 15:13:27 -070030
David 'Digit' Turnercb88e792011-08-26 01:35:14 +020031#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 */
Andrew Hsiehc7389bd2012-03-13 02:13:40 -070038#if HOST_LONG_BITS == 32
David 'Digit' Turnercb88e792011-08-26 01:35:14 +020039#define RENDERER_LIB_NAME "libOpenglRender"
Andrew Hsiehc7389bd2012-03-13 02:13:40 -070040#elif HOST_LONG_BITS == 64
41#define RENDERER_LIB_NAME "lib64OpenglRender"
42#else
43#error Unknown HOST_LONG_BITS
44#endif
David 'Digit' Turnercb88e792011-08-26 01:35:14 +020045
David 'Digit' Turnercb88e792011-08-26 01:35:14 +020046#define DYNLINK_FUNCTIONS \
Jesse Hall6699b682012-04-18 10:28:46 -070047 DYNLINK_FUNC(initLibrary) \
48 DYNLINK_FUNC(setStreamMode) \
49 DYNLINK_FUNC(initOpenGLRenderer) \
Jesse Hallba5c1f62012-05-08 15:44:35 -070050 DYNLINK_FUNC(setPostCallback) \
Jesse Hall733fffa2012-04-26 11:07:32 -070051 DYNLINK_FUNC(getHardwareStrings) \
Jesse Hall6699b682012-04-18 10:28:46 -070052 DYNLINK_FUNC(createOpenGLSubwindow) \
53 DYNLINK_FUNC(destroyOpenGLSubwindow) \
54 DYNLINK_FUNC(repaintOpenGLDisplay) \
55 DYNLINK_FUNC(stopOpenGLRenderer)
David 'Digit' Turnercb88e792011-08-26 01:35:14 +020056
57#ifndef CONFIG_STANDALONE_UI
58/* Defined in android/hw-pipe-net.c */
59extern int android_init_opengles_pipes(void);
60#endif
61
62static ADynamicLibrary* rendererLib;
Jesse Hall23a322d2012-05-08 12:00:20 -070063static int rendererStarted;
David 'Digit' Turnercb88e792011-08-26 01:35:14 +020064
Jesse Hall6699b682012-04-18 10:28:46 -070065/* Define the function pointers */
66#define DYNLINK_FUNC(name) \
67 static name##Fn name = NULL;
David 'Digit' Turnercb88e792011-08-26 01:35:14 +020068DYNLINK_FUNCTIONS
David 'Digit' Turnercb88e792011-08-26 01:35:14 +020069#undef DYNLINK_FUNC
70
71static int
72initOpenglesEmulationFuncs(ADynamicLibrary* rendererLib)
73{
74 void* symbol;
75 char* error;
Jesse Hall6699b682012-04-18 10:28:46 -070076
77#define DYNLINK_FUNC(name) \
78 symbol = adynamicLibrary_findSymbol(rendererLib, #name, &error); \
David 'Digit' Turnercb88e792011-08-26 01:35:14 +020079 if (symbol != NULL) { \
Jesse Hall6699b682012-04-18 10:28:46 -070080 name = symbol; \
David 'Digit' Turnercb88e792011-08-26 01:35:14 +020081 } else { \
82 derror("GLES emulation: Could not find required symbol (%s): %s", #name, error); \
83 free(error); \
84 return -1; \
85 }
86DYNLINK_FUNCTIONS
87#undef DYNLINK_FUNC
Jesse Hall6699b682012-04-18 10:28:46 -070088
David 'Digit' Turnercb88e792011-08-26 01:35:14 +020089 return 0;
90}
91
92int
93android_initOpenglesEmulation(void)
94{
95 char* error = NULL;
96
97 if (rendererLib != NULL)
98 return 0;
99
100 D("Initializing hardware OpenGLES emulation support");
101
102 rendererLib = adynamicLibrary_open(RENDERER_LIB_NAME, &error);
103 if (rendererLib == NULL) {
104 derror("Could not load OpenGLES emulation library: %s", error);
105 return -1;
106 }
107
108#ifndef CONFIG_STANDALONE_UI
109 android_init_opengles_pipes();
110#endif
111
112
113 /* Resolve the functions */
114 if (initOpenglesEmulationFuncs(rendererLib) < 0) {
115 derror("OpenGLES emulation library mismatch. Be sure to use the correct version!");
116 goto BAD_EXIT;
117 }
118
119 if (!initLibrary()) {
120 derror("OpenGLES initialization failed!");
121 goto BAD_EXIT;
122 }
123
David Turner7b56a4a2011-09-12 18:21:58 +0200124 if (android_gles_fast_pipes) {
125#ifdef _WIN32
126 /* XXX: NEED Win32 pipe implementation */
127 setStreamMode(STREAM_MODE_TCP);
128#else
Jesse Hall6699b682012-04-18 10:28:46 -0700129 setStreamMode(STREAM_MODE_UNIX);
David Turner7b56a4a2011-09-12 18:21:58 +0200130#endif
131 } else {
Jesse Hall6699b682012-04-18 10:28:46 -0700132 setStreamMode(STREAM_MODE_TCP);
David Turner7b56a4a2011-09-12 18:21:58 +0200133 }
David 'Digit' Turnercb88e792011-08-26 01:35:14 +0200134 return 0;
135
136BAD_EXIT:
137 derror("OpenGLES emulation library could not be initialized!");
138 adynamicLibrary_close(rendererLib);
139 rendererLib = NULL;
140 return -1;
141}
142
143int
Jesse Hallba5c1f62012-05-08 15:44:35 -0700144android_startOpenglesRenderer(int width, int height)
David 'Digit' Turnercb88e792011-08-26 01:35:14 +0200145{
146 if (!rendererLib) {
147 D("Can't start OpenGLES renderer without support libraries");
148 return -1;
149 }
150
Jesse Hall23a322d2012-05-08 12:00:20 -0700151 if (rendererStarted) {
152 return 0;
153 }
154
Jesse Hallba5c1f62012-05-08 15:44:35 -0700155 if (!initOpenGLRenderer(width, height, ANDROID_OPENGLES_BASE_PORT)) {
David 'Digit' Turnercb88e792011-08-26 01:35:14 +0200156 D("Can't start OpenGLES renderer?");
157 return -1;
158 }
Jesse Hall23a322d2012-05-08 12:00:20 -0700159
160 rendererStarted = 1;
David 'Digit' Turnercb88e792011-08-26 01:35:14 +0200161 return 0;
162}
163
Jesse Hallba5c1f62012-05-08 15:44:35 -0700164void
165android_setPostCallback(OnPostFunc onPost, void* onPostContext)
166{
167 if (rendererLib) {
168 setPostCallback(onPost, onPostContext);
169 }
170}
171
Jesse Hall733fffa2012-04-26 11:07:32 -0700172static void strncpy_safe(char* dst, const char* src, size_t n)
173{
174 strncpy(dst, src, n);
175 dst[n-1] = '\0';
176}
177
178static void extractBaseString(char* dst, const char* src, size_t dstSize)
179{
180 size_t len = strlen(src);
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
202void
203android_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
Jesse Hall23a322d2012-05-08 12:00:20 -0700209 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';
215 return;
216 }
217
Jesse Hall733fffa2012-04-26 11:07:32 -0700218 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
David 'Digit' Turnercb88e792011-08-26 01:35:14 +0200237void
238android_stopOpenglesRenderer(void)
239{
Jesse Hall23a322d2012-05-08 12:00:20 -0700240 if (rendererStarted) {
David 'Digit' Turnercb88e792011-08-26 01:35:14 +0200241 stopOpenGLRenderer();
Jesse Hall23a322d2012-05-08 12:00:20 -0700242 rendererStarted = 0;
David 'Digit' Turnercb88e792011-08-26 01:35:14 +0200243 }
244}
245
246int
247android_showOpenglesWindow(void* window, int x, int y, int width, int height, float rotation)
248{
Jesse Hall23a322d2012-05-08 12:00:20 -0700249 if (rendererStarted) {
Jesse Hall6699b682012-04-18 10:28:46 -0700250 int success = createOpenGLSubwindow((FBNativeWindowType)window, x, y, width, height, rotation);
251 return success ? 0 : -1;
David 'Digit' Turnercb88e792011-08-26 01:35:14 +0200252 } else {
253 return -1;
254 }
255}
256
257int
258android_hideOpenglesWindow(void)
259{
Jesse Hall23a322d2012-05-08 12:00:20 -0700260 if (rendererStarted) {
Jesse Hall6699b682012-04-18 10:28:46 -0700261 int success = destroyOpenGLSubwindow();
262 return success ? 0 : -1;
David 'Digit' Turnercb88e792011-08-26 01:35:14 +0200263 } else {
264 return -1;
265 }
266}
267
268void
269android_redrawOpenglesWindow(void)
270{
Jesse Hall23a322d2012-05-08 12:00:20 -0700271 if (rendererStarted) {
David 'Digit' Turnercb88e792011-08-26 01:35:14 +0200272 repaintOpenGLDisplay();
273 }
274}
David Turner7b56a4a2011-09-12 18:21:58 +0200275
276void
277android_gles_unix_path(char* buff, size_t buffsize, int port)
278{
279 const char* user = getenv("USER");
280 char *p = buff, *end = buff + buffsize;
281
282 /* The logic here must correspond to the one inside
283 * development/tools/emulator/opengl/shared/libOpenglCodecCommon/UnixStream.cpp */
284 p = bufprint(p, end, "/tmp/");
285 if (user && user[0]) {
286 p = bufprint(p, end, "android-%s/", user);
287 }
288 p = bufprint(p, end, "qemu-gles-%d", port);
289}
Jesse Hall183e9272012-04-26 15:13:27 -0700290
291#else // CONFIG_ANDROID_OPENGLES
292
293int android_initOpenglesEmulation(void)
294{
295 return -1;
296}
297
Vladimir Chtchetkine66744892012-05-11 05:47:46 -0700298int android_startOpenglesRenderer(int width, int height)
Jesse Hall183e9272012-04-26 15:13:27 -0700299{
300 return -1;
301}
302
Vladimir Chtchetkine2c4c30e2012-05-11 06:56:43 -0700303void
304android_setPostCallback(OnPostFunc onPost, void* onPostContext)
305{
306}
307
Andrew Hsiehafb01182012-05-04 11:55:11 +0800308void android_getOpenglesHardwareStrings(char* vendor, size_t vendorBufSize,
309 char* renderer, size_t rendererBufSize,
310 char* version, size_t versionBufSize)
311{
312 assert(vendorBufSize > 0 && rendererBufSize > 0 && versionBufSize > 0);
313 assert(vendor != NULL && renderer != NULL && version != NULL);
314 vendor[0] = renderer[0] = version[0] = 0;
315}
316
Jesse Hall183e9272012-04-26 15:13:27 -0700317void android_stopOpenglesRenderer(void)
318{}
319
320int android_showOpenglesWindow(void* window, int x, int y, int width, int height, float rotation)
321{
322 return -1;
323}
324
325int android_hideOpenglesWindow(void)
326{
327 return -1;
328}
329
330void android_redrawOpenglesWindow(void)
331{}
332
333void android_gles_unix_path(char* buff, size_t buffsize, int port)
334{
335 buff[0] = '\0';
336}
337
338#endif // !CONFIG_ANDROID_OPENGLES