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;
63static int               rendererStarted;
64static char              rendererAddress[256];
65
66/* Define the function pointers */
67#define DYNLINK_FUNC(name) \
68    static name##Fn name = NULL;
69DYNLINK_FUNCTIONS
70#undef DYNLINK_FUNC
71
72static int
73initOpenglesEmulationFuncs(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    }
87DYNLINK_FUNCTIONS
88#undef DYNLINK_FUNC
89
90    return 0;
91}
92
93int
94android_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
137BAD_EXIT:
138    derror("OpenGLES emulation library could not be initialized!");
139    adynamicLibrary_close(rendererLib);
140    rendererLib = NULL;
141    return -1;
142}
143
144int
145android_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
165void
166android_setPostCallback(OnPostFunc onPost, void* onPostContext)
167{
168    if (rendererLib) {
169        setPostCallback(onPost, onPostContext);
170    }
171}
172
173static void strncpy_safe(char* dst, const char* src, size_t n)
174{
175    strncpy(dst, src, n);
176    dst[n-1] = '\0';
177}
178
179static 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
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
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
237void
238android_stopOpenglesRenderer(void)
239{
240    if (rendererStarted) {
241        stopOpenGLRenderer();
242        rendererStarted = 0;
243    }
244}
245
246int
247android_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
257int
258android_hideOpenglesWindow(void)
259{
260    if (rendererStarted) {
261        int success = destroyOpenGLSubwindow();
262        return success ? 0 : -1;
263    } else {
264        return -1;
265    }
266}
267
268void
269android_redrawOpenglesWindow(void)
270{
271    if (rendererStarted) {
272        repaintOpenGLDisplay();
273    }
274}
275
276void
277android_gles_server_path(char* buff, size_t buffsize)
278{
279    strncpy_safe(buff, rendererAddress, buffsize);
280}
281
282#else // CONFIG_ANDROID_OPENGLES
283
284int android_initOpenglesEmulation(void)
285{
286    return -1;
287}
288
289int android_startOpenglesRenderer(int width, int height)
290{
291    return -1;
292}
293
294void
295android_setPostCallback(OnPostFunc onPost, void* onPostContext)
296{
297}
298
299void 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
308void android_stopOpenglesRenderer(void)
309{}
310
311int android_showOpenglesWindow(void* window, int x, int y, int width, int height, float rotation)
312{
313    return -1;
314}
315
316int android_hideOpenglesWindow(void)
317{
318    return -1;
319}
320
321void android_redrawOpenglesWindow(void)
322{}
323
324void android_gles_server_path(char* buff, size_t buffsize)
325{
326    buff[0] = '\0';
327}
328
329#endif // !CONFIG_ANDROID_OPENGLES
330