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 s_lastErrorCode = event->error_code; 70 return 0; 71 } 72 73 #define IS_SUCCESS(a) \ 74 if(a != Success) return false; 75 76 namespace EglOS { 77 78 EGLNativeDisplayType getDefaultDisplay() {return XOpenDisplay(0);} 79 80 bool releaseDisplay(EGLNativeDisplayType dpy) { 81 return XCloseDisplay(dpy); 82 } 83 84 EglConfig* pixelFormatToConfig(EGLNativeDisplayType dpy,int renderableType,EGLNativePixelFormatType* frmt){ 85 86 int bSize,red,green,blue,alpha,depth,stencil; 87 int supportedSurfaces,visualType,visualId; 88 int caveat,transparentType,samples; 89 int tRed=0,tGreen=0,tBlue=0; 90 int pMaxWidth,pMaxHeight,pMaxPixels; 91 int tmp; 92 int configId,level,renderable; 93 int doubleBuffer; 94 95 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_TRANSPARENT_TYPE,&tmp)); 96 if(tmp == GLX_TRANSPARENT_INDEX) { 97 return NULL; // not supporting transparent index 98 } else if( tmp == GLX_NONE) { 99 transparentType = EGL_NONE; 100 } else { 101 transparentType = EGL_TRANSPARENT_RGB; 102 103 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_TRANSPARENT_RED_VALUE,&tRed)); 104 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_TRANSPARENT_GREEN_VALUE,&tGreen)); 105 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_TRANSPARENT_BLUE_VALUE,&tBlue)); 106 } 107 108 109 // 110 // filter out single buffer configurations 111 // 112 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_DOUBLEBUFFER,&doubleBuffer)); 113 if (!doubleBuffer) return NULL; 114 115 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_BUFFER_SIZE,&bSize)); 116 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_RED_SIZE,&red)); 117 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_GREEN_SIZE,&green)); 118 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_BLUE_SIZE,&blue)); 119 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_ALPHA_SIZE,&alpha)); 120 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_DEPTH_SIZE,&depth)); 121 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_STENCIL_SIZE,&stencil)); 122 123 124 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_X_RENDERABLE,&renderable)); 125 126 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_X_VISUAL_TYPE,&visualType)); 127 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_VISUAL_ID,&visualId)); 128 129 //supported surfaces types 130 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_DRAWABLE_TYPE,&tmp)); 131 supportedSurfaces = 0; 132 if(tmp & GLX_WINDOW_BIT && visualId != 0) { 133 supportedSurfaces |= EGL_WINDOW_BIT; 134 } else { 135 visualId = 0; 136 visualType = EGL_NONE; 137 } 138 if(tmp & GLX_PBUFFER_BIT) supportedSurfaces |= EGL_PBUFFER_BIT; 139 140 caveat = 0; 141 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_CONFIG_CAVEAT,&tmp)); 142 if (tmp == GLX_NONE) caveat = EGL_NONE; 143 else if(tmp == GLX_SLOW_CONFIG) caveat = EGL_SLOW_CONFIG; 144 else if(tmp == GLX_NON_CONFORMANT_CONFIG) caveat = EGL_NON_CONFORMANT_CONFIG; 145 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_MAX_PBUFFER_WIDTH,&pMaxWidth)); 146 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_MAX_PBUFFER_HEIGHT,&pMaxHeight)); 147 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_MAX_PBUFFER_HEIGHT,&pMaxPixels)); 148 149 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_LEVEL,&level)); 150 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_FBCONFIG_ID,&configId)); 151 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_SAMPLES,&samples)); 152 //Filter out configs that does not support RGBA 153 IS_SUCCESS(glXGetFBConfigAttrib(dpy,*frmt,GLX_RENDER_TYPE,&tmp)); 154 if (!(tmp & GLX_RGBA_BIT)) { 155 return NULL; 156 } 157 158 return new EglConfig(red,green,blue,alpha,caveat,configId,depth,level,pMaxWidth,pMaxHeight, 159 pMaxPixels,renderable,renderableType,visualId,visualType,samples,stencil, 160 supportedSurfaces,transparentType,tRed,tGreen,tBlue,*frmt); 161 } 162 163 void queryConfigs(EGLNativeDisplayType dpy,int renderableType,ConfigsList& listOut) { 164 int n; 165 EGLNativePixelFormatType* frmtList = glXGetFBConfigs(dpy,0,&n); 166 for(int i =0 ;i < n ; i++) { 167 EglConfig* conf = pixelFormatToConfig(dpy,renderableType,&frmtList[i]); 168 if(conf) listOut.push_back(conf); 169 } 170 XFree(frmtList); 171 } 172 173 bool validNativeDisplay(EGLNativeInternalDisplayType dpy) { 174 return dpy != NULL; 175 } 176 177 bool validNativeWin(EGLNativeDisplayType dpy,EGLNativeWindowType win) { 178 Window root; 179 int tmp; 180 unsigned int utmp; 181 ErrorHandler handler(dpy); 182 if(!XGetGeometry(dpy,win,&root,&tmp,&tmp,&utmp,&utmp,&utmp,&utmp)) return false; 183 return handler.getLastError() == 0; 184 } 185 186 bool validNativeWin(EGLNativeDisplayType dpy,EGLNativeSurfaceType win) { 187 if (!win) return false; 188 return validNativeWin(dpy,win->srfc()); 189 } 190 191 bool validNativePixmap(EGLNativeDisplayType dpy,EGLNativeSurfaceType pix) { 192 Window root; 193 int tmp; 194 unsigned int utmp; 195 ErrorHandler handler(dpy); 196 if(!XGetGeometry(dpy,pix ? pix->srfc() : NULL,&root,&tmp,&tmp,&utmp,&utmp,&utmp,&utmp)) return false; 197 return handler.getLastError() == 0; 198 } 199 200 bool checkWindowPixelFormatMatch(EGLNativeDisplayType dpy,EGLNativeWindowType win,EglConfig* cfg,unsigned int* width,unsigned int* height) { 201 //TODO: to check what does ATI & NVIDIA enforce on win pixelformat 202 unsigned int depth,configDepth,border; 203 int r,g,b,x,y; 204 IS_SUCCESS(glXGetFBConfigAttrib(dpy,cfg->nativeConfig(),GLX_RED_SIZE,&r)); 205 IS_SUCCESS(glXGetFBConfigAttrib(dpy,cfg->nativeConfig(),GLX_GREEN_SIZE,&g)); 206 IS_SUCCESS(glXGetFBConfigAttrib(dpy,cfg->nativeConfig(),GLX_BLUE_SIZE,&b)); 207 configDepth = r + g + b; 208 Window root; 209 if(!XGetGeometry(dpy,win,&root,&x,&y,width,height,&border,&depth)) return false; 210 return depth >= configDepth; 211 } 212 213 bool checkPixmapPixelFormatMatch(EGLNativeDisplayType dpy,EGLNativePixmapType pix,EglConfig* cfg,unsigned int* width,unsigned int* height) { 214 unsigned int depth,configDepth,border; 215 int r,g,b,x,y; 216 IS_SUCCESS(glXGetFBConfigAttrib(dpy,cfg->nativeConfig(),GLX_RED_SIZE,&r)); 217 IS_SUCCESS(glXGetFBConfigAttrib(dpy,cfg->nativeConfig(),GLX_GREEN_SIZE,&g)); 218 IS_SUCCESS(glXGetFBConfigAttrib(dpy,cfg->nativeConfig(),GLX_BLUE_SIZE,&b)); 219 configDepth = r + g + b; 220 Window root; 221 if(!XGetGeometry(dpy,pix,&root,&x,&y,width,height,&border,&depth)) return false; 222 return depth >= configDepth; 223 } 224 225 EGLNativeSurfaceType createPbufferSurface(EGLNativeDisplayType dpy,EglConfig* cfg,EglPbufferSurface* srfc){ 226 EGLint width,height,largest; 227 srfc->getDim(&width,&height,&largest); 228 229 int attribs[] = { 230 GLX_PBUFFER_WIDTH ,width, 231 GLX_PBUFFER_HEIGHT ,height, 232 GLX_LARGEST_PBUFFER ,largest, 233 None 234 }; 235 GLXPbuffer pb = glXCreatePbuffer(dpy,cfg->nativeConfig(),attribs); 236 return pb ? new SrfcInfo(pb,SrfcInfo::PBUFFER) : NULL; 237 } 238 239 bool releasePbuffer(EGLNativeDisplayType dis,EGLNativeSurfaceType pb) { 240 if (!pb) return false; 241 glXDestroyPbuffer(dis,pb->srfc()); 242 243 return true; 244 } 245 246 EGLNativeContextType createContext(EGLNativeDisplayType dpy,EglConfig* cfg,EGLNativeContextType sharedContext) { 247 ErrorHandler handler(dpy); 248 EGLNativeContextType retVal = glXCreateNewContext(dpy,cfg->nativeConfig(),GLX_RGBA_TYPE,sharedContext,true); 249 return handler.getLastError() == 0 ? retVal : NULL; 250 } 251 252 bool destroyContext(EGLNativeDisplayType dpy,EGLNativeContextType ctx) { 253 glXDestroyContext(dpy,ctx); 254 return true; 255 } 256 257 bool makeCurrent(EGLNativeDisplayType dpy,EglSurface* read,EglSurface* draw,EGLNativeContextType ctx){ 258 259 ErrorHandler handler(dpy); 260 bool retval = false; 261 if (!ctx && !read && !draw) { 262 // unbind 263 retval = glXMakeContextCurrent(dpy, NULL, NULL, NULL); 264 } 265 else if (ctx && read && draw) { 266 retval = glXMakeContextCurrent(dpy,draw->native()->srfc(),read->native()->srfc(),ctx); 267 } 268 return (handler.getLastError() == 0) && retval; 269 } 270 271 void swapBuffers(EGLNativeDisplayType dpy,EGLNativeSurfaceType srfc){ 272 if (srfc) { 273 glXSwapBuffers(dpy,srfc->srfc()); 274 } 275 } 276 277 void waitNative() { 278 glXWaitX(); 279 } 280 281 void swapInterval(EGLNativeDisplayType dpy,EGLNativeSurfaceType win,int interval){ 282 const char* extensions = glXQueryExtensionsString(dpy,DefaultScreen(dpy)); 283 typedef void (*GLXSWAPINTERVALEXT)(Display*,GLXDrawable,int); 284 GLXSWAPINTERVALEXT glXSwapIntervalEXT = NULL; 285 286 if(strstr(extensions,"EXT_swap_control")) { 287 glXSwapIntervalEXT = (GLXSWAPINTERVALEXT)glXGetProcAddress((const GLubyte*)"glXSwapIntervalEXT"); 288 } 289 if(glXSwapIntervalEXT && win) { 290 glXSwapIntervalEXT(dpy,win->srfc(),interval); 291 } 292 } 293 294 EGLNativeSurfaceType createWindowSurface(EGLNativeWindowType wnd){ 295 return new SrfcInfo(wnd,SrfcInfo::WINDOW); 296 } 297 298 EGLNativeSurfaceType createPixmapSurface(EGLNativePixmapType pix){ 299 return new SrfcInfo(pix,SrfcInfo::PIXMAP); 300 } 301 302 void destroySurface(EGLNativeSurfaceType srfc){ 303 delete srfc; 304 }; 305 306 EGLNativeInternalDisplayType getInternalDisplay(EGLNativeDisplayType dpy){ 307 return dpy; 308 } 309 310 void deleteDisplay(EGLNativeInternalDisplayType idpy){ 311 } 312 313 }; 314