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