1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 #include "EglOsApi.h" 17 #include <string.h> 18 #include <X11/Xlib.h> 19 #include <GL/glx.h> 20 #include <utils/threads.h> 21 22 23 class ErrorHandler{ 24 public: 25 ErrorHandler(EGLNativeDisplayType dpy); 26 ~ErrorHandler(); 27 int getLastError(){ return s_lastErrorCode;}; 28 29 private: 30 static int s_lastErrorCode; 31 int (*m_oldErrorHandler) (Display *, XErrorEvent *); 32 static android::Mutex s_lock; 33 static int errorHandlerProc(EGLNativeDisplayType dpy,XErrorEvent* event); 34 35 }; 36 37 class SrfcInfo{ 38 public: 39 typedef enum{ 40 WINDOW = 0, 41 PBUFFER = 1, 42 PIXMAP 43 }SurfaceType; 44 SrfcInfo(GLXDrawable drawable,SurfaceType type):m_type(type), 45 m_srfc(drawable){}; 46 GLXDrawable srfc(){return m_srfc;}; 47 private: 48 SurfaceType m_type; 49 GLXDrawable m_srfc; 50 }; 51 52 int ErrorHandler::s_lastErrorCode = 0; 53 android::Mutex ErrorHandler::s_lock; 54 55 ErrorHandler::ErrorHandler(EGLNativeDisplayType dpy){ 56 android::Mutex::Autolock mutex(s_lock); 57 XSync(dpy,False); 58 s_lastErrorCode = 0; 59 m_oldErrorHandler = XSetErrorHandler(errorHandlerProc); 60 } 61 62 ErrorHandler::~ErrorHandler(){ 63 android::Mutex::Autolock mutex(s_lock); 64 XSetErrorHandler(m_oldErrorHandler); 65 s_lastErrorCode = 0; 66 } 67 68 int ErrorHandler::errorHandlerProc(EGLNativeDisplayType dpy,XErrorEvent* event){ 69 android::Mutex::Autolock mutex(s_lock); 70 s_lastErrorCode = event->error_code; 71 return 0; 72 } 73 74 #define IS_SUCCESS(a) \ 75 if(a != Success) return false; 76 77 namespace EglOS { 78 79 EGLNativeDisplayType getDefaultDisplay() {return XOpenDisplay(0);} 80 81 bool releaseDisplay(EGLNativeDisplayType dpy) { 82 return XCloseDisplay(dpy); 83 } 84 85 EglConfig* pixelFormatToConfig(EGLNativeDisplayType dpy,int renderableType,EGLNativePixelFormatType* frmt){ 86 87 int bSize,red,green,blue,alpha,depth,stencil; 88 int supportedSurfaces,visualType,visualId; 89 int caveat,transparentType,samples; 90 int tRed=0,tGreen=0,tBlue=0; 91 int pMaxWidth,pMaxHeight,pMaxPixels; 92 int tmp; 93 int configId,level,renderable; 94 int doubleBuffer; 95 96 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_TRANSPARENT_TYPE,&tmp)); 97 if(tmp == GLX_TRANSPARENT_INDEX) { 98 return NULL; // not supporting transparent index 99 } else if( tmp == GLX_NONE) { 100 transparentType = EGL_NONE; 101 } else { 102 transparentType = EGL_TRANSPARENT_RGB; 103 104 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_TRANSPARENT_RED_VALUE,&tRed)); 105 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_TRANSPARENT_GREEN_VALUE,&tGreen)); 106 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_TRANSPARENT_BLUE_VALUE,&tBlue)); 107 } 108 109 110 // 111 // filter out single buffer configurations 112 // 113 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_DOUBLEBUFFER,&doubleBuffer)); 114 if (!doubleBuffer) return NULL; 115 116 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_BUFFER_SIZE,&bSize)); 117 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_RED_SIZE,&red)); 118 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_GREEN_SIZE,&green)); 119 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_BLUE_SIZE,&blue)); 120 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_ALPHA_SIZE,&alpha)); 121 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_DEPTH_SIZE,&depth)); 122 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_STENCIL_SIZE,&stencil)); 123 124 125 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_X_RENDERABLE,&renderable)); 126 127 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_X_VISUAL_TYPE,&visualType)); 128 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_VISUAL_ID,&visualId)); 129 130 //supported surfaces types 131 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_DRAWABLE_TYPE,&tmp)); 132 supportedSurfaces = 0; 133 if(tmp & GLX_WINDOW_BIT && visualId != 0) { 134 supportedSurfaces |= EGL_WINDOW_BIT; 135 } else { 136 visualId = 0; 137 visualType = EGL_NONE; 138 } 139 if(tmp & GLX_PBUFFER_BIT) supportedSurfaces |= EGL_PBUFFER_BIT; 140 141 caveat = 0; 142 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_CONFIG_CAVEAT,&tmp)); 143 if (tmp == GLX_NONE) caveat = EGL_NONE; 144 else if(tmp == GLX_SLOW_CONFIG) caveat = EGL_SLOW_CONFIG; 145 else if(tmp == GLX_NON_CONFORMANT_CONFIG) caveat = EGL_NON_CONFORMANT_CONFIG; 146 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_MAX_PBUFFER_WIDTH,&pMaxWidth)); 147 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_MAX_PBUFFER_HEIGHT,&pMaxHeight)); 148 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_MAX_PBUFFER_HEIGHT,&pMaxPixels)); 149 150 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_LEVEL,&level)); 151 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_FBCONFIG_ID,&configId)); 152 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_SAMPLES,&samples)); 153 //Filter out configs that does not support RGBA 154 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_RENDER_TYPE,&tmp)); 155 if (!(tmp & GLX_RGBA_BIT)) { 156 return NULL; 157 } 158 159 return new EglConfig(red,green,blue,alpha,caveat,configId,depth,level,pMaxWidth,pMaxHeight, 160 pMaxPixels,renderable,renderableType,visualId,visualType,samples,stencil, 161 supportedSurfaces,transparentType,tRed,tGreen,tBlue,*frmt); 162 } 163 164 void queryConfigs(EGLNativeDisplayType dpy,int renderableType,ConfigsList& listOut) { 165 int n; 166 EGLNativePixelFormatType* frmtList = glXGetFBConfigs(dpy,0,&n); 167 for(int i =0 ;i < n ; i++) { 168 EglConfig* conf = pixelFormatToConfig(dpy,renderableType,&frmtList[i]); 169 if(conf) listOut.push_back(conf); 170 } 171 XFree(frmtList); 172 } 173 174 bool validNativeDisplay(EGLNativeInternalDisplayType dpy) { 175 return dpy != NULL; 176 } 177 178 bool validNativeWin(EGLNativeDisplayType dpy,EGLNativeWindowType win) { 179 Window root; 180 int tmp; 181 unsigned int utmp; 182 ErrorHandler handler(dpy); 183 if(!XGetGeometry(dpy,win,&root,&tmp,&tmp,&utmp,&utmp,&utmp,&utmp)) return false; 184 return handler.getLastError() == 0; 185 } 186 187 bool validNativeWin(EGLNativeDisplayType dpy,EGLNativeSurfaceType win) { 188 if (!win) return false; 189 return validNativeWin(dpy,win->srfc()); 190 } 191 192 bool validNativePixmap(EGLNativeDisplayType dpy,EGLNativeSurfaceType pix) { 193 Window root; 194 int tmp; 195 unsigned int utmp; 196 ErrorHandler handler(dpy); 197 if(!XGetGeometry(dpy,pix ? pix->srfc() : NULL,&root,&tmp,&tmp,&utmp,&utmp,&utmp,&utmp)) return false; 198 return handler.getLastError() == 0; 199 } 200 201 bool checkWindowPixelFormatMatch(EGLNativeDisplayType dpy,EGLNativeWindowType win,EglConfig* cfg,unsigned int* width,unsigned int* height) { 202 //TODO: to check what does ATI & NVIDIA enforce on win pixelformat 203 unsigned int depth,configDepth,border; 204 int r,g,b,x,y; 205 IS_SUCCESS(glXGetFBConfigAttrib(dpy,cfg->nativeConfig(),GLX_RED_SIZE,&r)); 206 IS_SUCCESS(glXGetFBConfigAttrib(dpy,cfg->nativeConfig(),GLX_GREEN_SIZE,&g)); 207 IS_SUCCESS(glXGetFBConfigAttrib(dpy,cfg->nativeConfig(),GLX_BLUE_SIZE,&b)); 208 configDepth = r + g + b; 209 Window root; 210 if(!XGetGeometry(dpy,win,&root,&x,&y,width,height,&border,&depth)) return false; 211 return depth >= configDepth; 212 } 213 214 bool checkPixmapPixelFormatMatch(EGLNativeDisplayType dpy,EGLNativePixmapType pix,EglConfig* cfg,unsigned int* width,unsigned int* height) { 215 unsigned int depth,configDepth,border; 216 int r,g,b,x,y; 217 IS_SUCCESS(glXGetFBConfigAttrib(dpy,cfg->nativeConfig(),GLX_RED_SIZE,&r)); 218 IS_SUCCESS(glXGetFBConfigAttrib(dpy,cfg->nativeConfig(),GLX_GREEN_SIZE,&g)); 219 IS_SUCCESS(glXGetFBConfigAttrib(dpy,cfg->nativeConfig(),GLX_BLUE_SIZE,&b)); 220 configDepth = r + g + b; 221 Window root; 222 if(!XGetGeometry(dpy,pix,&root,&x,&y,width,height,&border,&depth)) return false; 223 return depth >= configDepth; 224 } 225 226 EGLNativeSurfaceType createPbufferSurface(EGLNativeDisplayType dpy,EglConfig* cfg,EglPbufferSurface* srfc){ 227 EGLint width,height,largest; 228 srfc->getDim(&width,&height,&largest); 229 230 int attribs[] = { 231 GLX_PBUFFER_WIDTH ,width, 232 GLX_PBUFFER_HEIGHT ,height, 233 GLX_LARGEST_PBUFFER ,largest, 234 None 235 }; 236 GLXPbuffer pb = glXCreatePbuffer(dpy,cfg->nativeConfig(),attribs); 237 return pb ? new SrfcInfo(pb,SrfcInfo::PBUFFER) : NULL; 238 } 239 240 bool releasePbuffer(EGLNativeDisplayType dis,EGLNativeSurfaceType pb) { 241 if (!pb) return false; 242 glXDestroyPbuffer(dis,pb->srfc()); 243 244 return true; 245 } 246 247 EGLNativeContextType createContext(EGLNativeDisplayType dpy,EglConfig* cfg,EGLNativeContextType sharedContext) { 248 ErrorHandler handler(dpy); 249 EGLNativeContextType retVal = glXCreateNewContext(dpy,cfg->nativeConfig(),GLX_RGBA_TYPE,sharedContext,true); 250 return handler.getLastError() == 0 ? retVal : NULL; 251 } 252 253 bool destroyContext(EGLNativeDisplayType dpy,EGLNativeContextType ctx) { 254 glXDestroyContext(dpy,ctx); 255 return true; 256 } 257 258 bool makeCurrent(EGLNativeDisplayType dpy,EglSurface* read,EglSurface* draw,EGLNativeContextType ctx){ 259 260 ErrorHandler handler(dpy); 261 bool retval = false; 262 if (!ctx && !read && !draw) { 263 // unbind 264 retval = glXMakeContextCurrent(dpy, NULL, NULL, NULL); 265 } 266 else if (ctx && read && draw) { 267 retval = glXMakeContextCurrent(dpy,draw->native()->srfc(),read->native()->srfc(),ctx); 268 } 269 return (handler.getLastError() == 0) && retval; 270 } 271 272 void swapBuffers(EGLNativeDisplayType dpy,EGLNativeSurfaceType srfc){ 273 if (srfc) { 274 glXSwapBuffers(dpy,srfc->srfc()); 275 } 276 } 277 278 void waitNative() { 279 glXWaitX(); 280 } 281 282 void swapInterval(EGLNativeDisplayType dpy,EGLNativeSurfaceType win,int interval){ 283 const char* extensions = glXQueryExtensionsString(dpy,DefaultScreen(dpy)); 284 typedef void (*GLXSWAPINTERVALEXT)(Display*,GLXDrawable,int); 285 GLXSWAPINTERVALEXT glXSwapIntervalEXT = NULL; 286 287 if(strstr(extensions,"EXT_swap_control")) { 288 glXSwapIntervalEXT = (GLXSWAPINTERVALEXT)glXGetProcAddress((const GLubyte*)"glXSwapIntervalEXT"); 289 } 290 if(glXSwapIntervalEXT && win) { 291 glXSwapIntervalEXT(dpy,win->srfc(),interval); 292 } 293 } 294 295 EGLNativeSurfaceType createWindowSurface(EGLNativeWindowType wnd){ 296 return new SrfcInfo(wnd,SrfcInfo::WINDOW); 297 } 298 299 EGLNativeSurfaceType createPixmapSurface(EGLNativePixmapType pix){ 300 return new SrfcInfo(pix,SrfcInfo::PIXMAP); 301 } 302 303 void destroySurface(EGLNativeSurfaceType srfc){ 304 delete srfc; 305 }; 306 307 EGLNativeInternalDisplayType getInternalDisplay(EGLNativeDisplayType dpy){ 308 return dpy; 309 } 310 311 void deleteDisplay(EGLNativeInternalDisplayType idpy){ 312 } 313 314 }; 315