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     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