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 validNativeWin(EGLNativeDisplayType dpy,EGLNativeWindowType win) { 175 Window root; 176 int tmp; 177 unsigned int utmp; 178 ErrorHandler handler(dpy); 179 if(!XGetGeometry(dpy,win,&root,&tmp,&tmp,&utmp,&utmp,&utmp,&utmp)) return false; 180 return handler.getLastError() == 0; 181 } 182 183 bool validNativeWin(EGLNativeDisplayType dpy,EGLNativeSurfaceType win) { 184 if (!win) return false; 185 return validNativeWin(dpy,win->srfc()); 186 } 187 188 bool validNativePixmap(EGLNativeDisplayType dpy,EGLNativeSurfaceType pix) { 189 Window root; 190 int tmp; 191 unsigned int utmp; 192 ErrorHandler handler(dpy); 193 if(!XGetGeometry(dpy,pix ? pix->srfc() : NULL,&root,&tmp,&tmp,&utmp,&utmp,&utmp,&utmp)) return false; 194 return handler.getLastError() == 0; 195 } 196 197 bool checkWindowPixelFormatMatch(EGLNativeDisplayType dpy,EGLNativeWindowType win,EglConfig* cfg,unsigned int* width,unsigned int* height) { 198 //TODO: to check what does ATI & NVIDIA enforce on win pixelformat 199 unsigned int depth,configDepth,border; 200 int r,g,b,x,y; 201 IS_SUCCESS(glXGetFBConfigAttrib(dpy,cfg->nativeConfig(),GLX_RED_SIZE,&r)); 202 IS_SUCCESS(glXGetFBConfigAttrib(dpy,cfg->nativeConfig(),GLX_GREEN_SIZE,&g)); 203 IS_SUCCESS(glXGetFBConfigAttrib(dpy,cfg->nativeConfig(),GLX_BLUE_SIZE,&b)); 204 configDepth = r + g + b; 205 Window root; 206 if(!XGetGeometry(dpy,win,&root,&x,&y,width,height,&border,&depth)) return false; 207 return depth >= configDepth; 208 } 209 210 bool checkPixmapPixelFormatMatch(EGLNativeDisplayType dpy,EGLNativePixmapType pix,EglConfig* cfg,unsigned int* width,unsigned int* height) { 211 unsigned int depth,configDepth,border; 212 int r,g,b,x,y; 213 IS_SUCCESS(glXGetFBConfigAttrib(dpy,cfg->nativeConfig(),GLX_RED_SIZE,&r)); 214 IS_SUCCESS(glXGetFBConfigAttrib(dpy,cfg->nativeConfig(),GLX_GREEN_SIZE,&g)); 215 IS_SUCCESS(glXGetFBConfigAttrib(dpy,cfg->nativeConfig(),GLX_BLUE_SIZE,&b)); 216 configDepth = r + g + b; 217 Window root; 218 if(!XGetGeometry(dpy,pix,&root,&x,&y,width,height,&border,&depth)) return false; 219 return depth >= configDepth; 220 } 221 222 EGLNativeSurfaceType createPbufferSurface(EGLNativeDisplayType dpy,EglConfig* cfg,EglPbufferSurface* srfc){ 223 EGLint width,height,largest; 224 srfc->getDim(&width,&height,&largest); 225 226 int attribs[] = { 227 GLX_PBUFFER_WIDTH ,width, 228 GLX_PBUFFER_HEIGHT ,height, 229 GLX_LARGEST_PBUFFER ,largest, 230 None 231 }; 232 GLXPbuffer pb = glXCreatePbuffer(dpy,cfg->nativeConfig(),attribs); 233 return pb ? new SrfcInfo(pb,SrfcInfo::PBUFFER) : NULL; 234 } 235 236 bool releasePbuffer(EGLNativeDisplayType dis,EGLNativeSurfaceType pb) { 237 if (!pb) return false; 238 glXDestroyPbuffer(dis,pb->srfc()); 239 240 return true; 241 } 242 243 EGLNativeContextType createContext(EGLNativeDisplayType dpy,EglConfig* cfg,EGLNativeContextType sharedContext) { 244 ErrorHandler handler(dpy); 245 EGLNativeContextType retVal = glXCreateNewContext(dpy,cfg->nativeConfig(),GLX_RGBA_TYPE,sharedContext,true); 246 return handler.getLastError() == 0 ? retVal : NULL; 247 } 248 249 bool destroyContext(EGLNativeDisplayType dpy,EGLNativeContextType ctx) { 250 glXDestroyContext(dpy,ctx); 251 return true; 252 } 253 254 bool makeCurrent(EGLNativeDisplayType dpy,EglSurface* read,EglSurface* draw,EGLNativeContextType ctx){ 255 256 ErrorHandler handler(dpy); 257 bool retval = false; 258 if (!ctx && !read && !draw) { 259 // unbind 260 retval = glXMakeContextCurrent(dpy, NULL, NULL, NULL); 261 } 262 else if (ctx && read && draw) { 263 retval = glXMakeContextCurrent(dpy,draw->native()->srfc(),read->native()->srfc(),ctx); 264 } 265 return (handler.getLastError() == 0) && retval; 266 } 267 268 void swapBuffers(EGLNativeDisplayType dpy,EGLNativeSurfaceType srfc){ 269 if (srfc) { 270 glXSwapBuffers(dpy,srfc->srfc()); 271 } 272 } 273 274 void waitNative() { 275 glXWaitX(); 276 } 277 278 void swapInterval(EGLNativeDisplayType dpy,EGLNativeSurfaceType win,int interval){ 279 const char* extensions = glXQueryExtensionsString(dpy,DefaultScreen(dpy)); 280 typedef void (*GLXSWAPINTERVALEXT)(Display*,GLXDrawable,int); 281 GLXSWAPINTERVALEXT glXSwapIntervalEXT = NULL; 282 283 if(strstr(extensions,"EXT_swap_control")) { 284 glXSwapIntervalEXT = (GLXSWAPINTERVALEXT)glXGetProcAddress((const GLubyte*)"glXSwapIntervalEXT"); 285 } 286 if(glXSwapIntervalEXT && win) { 287 glXSwapIntervalEXT(dpy,win->srfc(),interval); 288 } 289 } 290 291 EGLNativeSurfaceType createWindowSurface(EGLNativeWindowType wnd){ 292 return new SrfcInfo(wnd,SrfcInfo::WINDOW); 293 } 294 295 EGLNativeSurfaceType createPixmapSurface(EGLNativePixmapType pix){ 296 return new SrfcInfo(pix,SrfcInfo::PIXMAP); 297 } 298 299 void destroySurface(EGLNativeSurfaceType srfc){ 300 delete srfc; 301 }; 302 303 EGLNativeInternalDisplayType getInternalDisplay(EGLNativeDisplayType dpy){ 304 return dpy; 305 } 306 307 void deleteDisplay(EGLNativeInternalDisplayType idpy){ 308 } 309 310 }; 311