Home | History | Annotate | Download | only in EGL
      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