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 "emugl/common/mutex.h"
     18 
     19 #include <string.h>
     20 #include <X11/Xlib.h>
     21 #include <GL/glx.h>
     22 
     23 
     24 class ErrorHandler{
     25 public:
     26 ErrorHandler(EGLNativeDisplayType dpy);
     27 ~ErrorHandler();
     28 int getLastError(){ return s_lastErrorCode;};
     29 
     30 private:
     31 static int s_lastErrorCode;
     32 int (*m_oldErrorHandler) (Display *, XErrorEvent *);
     33 static emugl::Mutex s_lock;
     34 static int errorHandlerProc(EGLNativeDisplayType dpy,XErrorEvent* event);
     35 
     36 };
     37 
     38 class SrfcInfo{
     39 public:
     40     typedef enum{
     41                  WINDOW  = 0,
     42                  PBUFFER = 1,
     43                  PIXMAP
     44                 }SurfaceType;
     45     SrfcInfo(GLXDrawable drawable,SurfaceType type):m_type(type),
     46                                                     m_srfc(drawable){};
     47     GLXDrawable srfc(){return m_srfc;};
     48 private:
     49     SurfaceType m_type;
     50     GLXDrawable  m_srfc;
     51 };
     52 
     53 int ErrorHandler::s_lastErrorCode = 0;
     54 emugl::Mutex ErrorHandler::s_lock;
     55 
     56 ErrorHandler::ErrorHandler(EGLNativeDisplayType dpy){
     57    emugl::Mutex::AutoLock mutex(s_lock);
     58    XSync(dpy,False);
     59    s_lastErrorCode = 0;
     60    m_oldErrorHandler = XSetErrorHandler(errorHandlerProc);
     61 }
     62 
     63 ErrorHandler::~ErrorHandler(){
     64    emugl::Mutex::AutoLock mutex(s_lock);
     65    XSetErrorHandler(m_oldErrorHandler);
     66    s_lastErrorCode = 0;
     67 }
     68 
     69 int ErrorHandler::errorHandlerProc(EGLNativeDisplayType dpy,XErrorEvent* event){
     70     s_lastErrorCode = event->error_code;
     71     return 0;
     72 }
     73 
     74 #define IS_SUCCESS(a) \
     75         if(a != Success) return 0;
     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() : 0,&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, 0, 0, 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