opengles.c revision 6674489666e2a5ca2f12a1c1015cd0bf3bd36494
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" */
18int  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 */
59extern int android_init_opengles_pipes(void);
60#endif
61
62static ADynamicLibrary*  rendererLib;
63
64/* Define the function pointers */
65#define DYNLINK_FUNC(name) \
66    static name##Fn name = NULL;
67DYNLINK_FUNCTIONS
68#undef DYNLINK_FUNC
69
70static int
71initOpenglesEmulationFuncs(ADynamicLibrary* rendererLib)
72{
73    void*  symbol;
74    char*  error;
75
76#define DYNLINK_FUNC(name) \
77    symbol = adynamicLibrary_findSymbol(rendererLib, #name, &error); \
78    if (symbol != NULL) { \
79        name = symbol; \
80    } else { \
81        derror("GLES emulation: Could not find required symbol (%s): %s", #name, error); \
82        free(error); \
83        return -1; \
84    }
85DYNLINK_FUNCTIONS
86#undef DYNLINK_FUNC
87
88    return 0;
89}
90
91int
92android_initOpenglesEmulation(void)
93{
94    char* error = NULL;
95
96    if (rendererLib != NULL)
97        return 0;
98
99    D("Initializing hardware OpenGLES emulation support");
100
101    rendererLib = adynamicLibrary_open(RENDERER_LIB_NAME, &error);
102    if (rendererLib == NULL) {
103        derror("Could not load OpenGLES emulation library: %s", error);
104        return -1;
105    }
106
107#ifndef CONFIG_STANDALONE_UI
108    android_init_opengles_pipes();
109#endif
110
111
112    /* Resolve the functions */
113    if (initOpenglesEmulationFuncs(rendererLib) < 0) {
114        derror("OpenGLES emulation library mismatch. Be sure to use the correct version!");
115        goto BAD_EXIT;
116    }
117
118    if (!initLibrary()) {
119        derror("OpenGLES initialization failed!");
120        goto BAD_EXIT;
121    }
122
123    if (android_gles_fast_pipes) {
124#ifdef _WIN32
125        /* XXX: NEED Win32 pipe implementation */
126        setStreamMode(STREAM_MODE_TCP);
127#else
128	    setStreamMode(STREAM_MODE_UNIX);
129#endif
130    } else {
131	    setStreamMode(STREAM_MODE_TCP);
132    }
133    return 0;
134
135BAD_EXIT:
136    derror("OpenGLES emulation library could not be initialized!");
137    adynamicLibrary_close(rendererLib);
138    rendererLib = NULL;
139    return -1;
140}
141
142int
143android_startOpenglesRenderer(int width, int height)
144{
145    if (!rendererLib) {
146        D("Can't start OpenGLES renderer without support libraries");
147        return -1;
148    }
149
150    if (!initOpenGLRenderer(width, height, ANDROID_OPENGLES_BASE_PORT)) {
151        D("Can't start OpenGLES renderer?");
152        return -1;
153    }
154    return 0;
155}
156
157void
158android_setPostCallback(OnPostFunc onPost, void* onPostContext)
159{
160    if (rendererLib) {
161        setPostCallback(onPost, onPostContext);
162    }
163}
164
165static void strncpy_safe(char* dst, const char* src, size_t n)
166{
167    strncpy(dst, src, n);
168    dst[n-1] = '\0';
169}
170
171static void extractBaseString(char* dst, const char* src, size_t dstSize)
172{
173    size_t len = strlen(src);
174    const char* begin = strchr(src, '(');
175    const char* end = strrchr(src, ')');
176
177    if (!begin || !end) {
178        strncpy_safe(dst, src, dstSize);
179        return;
180    }
181    begin += 1;
182
183    // "foo (bar)"
184    //       ^  ^
185    //       b  e
186    //     = 5  8
187    // substring with NUL-terminator is end-begin+1 bytes
188    if (end - begin + 1 > dstSize) {
189        end = begin + dstSize - 1;
190    }
191
192    strncpy_safe(dst, begin, end - begin + 1);
193}
194
195void
196android_getOpenglesHardwareStrings(char* vendor, size_t vendorBufSize,
197                                   char* renderer, size_t rendererBufSize,
198                                   char* version, size_t versionBufSize)
199{
200    const char *vendorSrc, *rendererSrc, *versionSrc;
201
202    getHardwareStrings(&vendorSrc, &rendererSrc, &versionSrc);
203    if (!vendorSrc) vendorSrc = "";
204    if (!rendererSrc) rendererSrc = "";
205    if (!versionSrc) versionSrc = "";
206
207    /* Special case for the default ES to GL translators: extract the strings
208     * of the underlying OpenGL implementation. */
209    if (strncmp(vendorSrc, "Google", 6) == 0 &&
210            strncmp(rendererSrc, "Android Emulator OpenGL ES Translator", 37) == 0) {
211        extractBaseString(vendor, vendorSrc, vendorBufSize);
212        extractBaseString(renderer, rendererSrc, rendererBufSize);
213        extractBaseString(version, versionSrc, versionBufSize);
214    } else {
215        strncpy_safe(vendor, vendorSrc, vendorBufSize);
216        strncpy_safe(renderer, rendererSrc, rendererBufSize);
217        strncpy_safe(version, versionSrc, versionBufSize);
218    }
219}
220
221void
222android_stopOpenglesRenderer(void)
223{
224    if (rendererLib) {
225        stopOpenGLRenderer();
226    }
227}
228
229int
230android_showOpenglesWindow(void* window, int x, int y, int width, int height, float rotation)
231{
232    if (rendererLib) {
233        int success = createOpenGLSubwindow((FBNativeWindowType)window, x, y, width, height, rotation);
234        return success ? 0 : -1;
235    } else {
236        return -1;
237    }
238}
239
240int
241android_hideOpenglesWindow(void)
242{
243    if (rendererLib) {
244        int success = destroyOpenGLSubwindow();
245        return success ? 0 : -1;
246    } else {
247        return -1;
248    }
249}
250
251void
252android_redrawOpenglesWindow(void)
253{
254    if (rendererLib) {
255        repaintOpenGLDisplay();
256    }
257}
258
259void
260android_gles_unix_path(char* buff, size_t buffsize, int port)
261{
262    const char* user = getenv("USER");
263    char *p = buff, *end = buff + buffsize;
264
265    /* The logic here must correspond to the one inside
266     * development/tools/emulator/opengl/shared/libOpenglCodecCommon/UnixStream.cpp */
267    p = bufprint(p, end, "/tmp/");
268    if (user && user[0]) {
269        p = bufprint(p, end, "android-%s/", user);
270    }
271    p = bufprint(p, end, "qemu-gles-%d", port);
272}
273
274#else // CONFIG_ANDROID_OPENGLES
275
276int android_initOpenglesEmulation(void)
277{
278    return -1;
279}
280
281int android_startOpenglesRenderer(int width, int height)
282{
283    return -1;
284}
285
286void android_getOpenglesHardwareStrings(char* vendor, size_t vendorBufSize,
287                                       char* renderer, size_t rendererBufSize,
288                                       char* version, size_t versionBufSize)
289{
290    assert(vendorBufSize > 0 && rendererBufSize > 0 && versionBufSize > 0);
291    assert(vendor != NULL && renderer != NULL && version != NULL);
292    vendor[0] = renderer[0] = version[0] = 0;
293}
294
295void android_stopOpenglesRenderer(void)
296{}
297
298int android_showOpenglesWindow(void* window, int x, int y, int width, int height, float rotation)
299{
300    return -1;
301}
302
303int android_hideOpenglesWindow(void)
304{
305    return -1;
306}
307
308void android_redrawOpenglesWindow(void)
309{}
310
311void android_gles_unix_path(char* buff, size_t buffsize, int port)
312{
313    buff[0] = '\0';
314}
315
316#endif // !CONFIG_ANDROID_OPENGLES
317