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();
getLastError()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;
SrfcInfo(GLXDrawable drawable,SurfaceType type)45     SrfcInfo(GLXDrawable drawable,SurfaceType type):m_type(type),
46                                                     m_srfc(drawable){};
srfc()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 
ErrorHandler(EGLNativeDisplayType dpy)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 
~ErrorHandler()63 ErrorHandler::~ErrorHandler(){
64    emugl::Mutex::AutoLock mutex(s_lock);
65    XSetErrorHandler(m_oldErrorHandler);
66    s_lastErrorCode = 0;
67 }
68 
errorHandlerProc(EGLNativeDisplayType dpy,XErrorEvent * event)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 
getDefaultDisplay()79 EGLNativeDisplayType getDefaultDisplay() {return XOpenDisplay(0);}
80 
releaseDisplay(EGLNativeDisplayType dpy)81 bool releaseDisplay(EGLNativeDisplayType dpy) {
82     return XCloseDisplay(dpy);
83 }
84 
pixelFormatToConfig(EGLNativeDisplayType dpy,int renderableType,EGLNativePixelFormatType * frmt)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 
queryConfigs(EGLNativeDisplayType dpy,int renderableType,ConfigsList & listOut)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 
validNativeDisplay(EGLNativeInternalDisplayType dpy)174 bool validNativeDisplay(EGLNativeInternalDisplayType dpy) {
175     return dpy != NULL;
176 }
177 
validNativeWin(EGLNativeDisplayType dpy,EGLNativeWindowType win)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 
validNativeWin(EGLNativeDisplayType dpy,EGLNativeSurfaceType win)187 bool validNativeWin(EGLNativeDisplayType dpy,EGLNativeSurfaceType win) {
188     if (!win) return false;
189     return validNativeWin(dpy,win->srfc());
190 }
191 
validNativePixmap(EGLNativeDisplayType dpy,EGLNativeSurfaceType pix)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 
checkWindowPixelFormatMatch(EGLNativeDisplayType dpy,EGLNativeWindowType win,EglConfig * cfg,unsigned int * width,unsigned int * height)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 
checkPixmapPixelFormatMatch(EGLNativeDisplayType dpy,EGLNativePixmapType pix,EglConfig * cfg,unsigned int * width,unsigned int * height)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 
createPbufferSurface(EGLNativeDisplayType dpy,EglConfig * cfg,EglPbufferSurface * srfc)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 
releasePbuffer(EGLNativeDisplayType dis,EGLNativeSurfaceType pb)240 bool releasePbuffer(EGLNativeDisplayType dis,EGLNativeSurfaceType pb) {
241     if (!pb) return false;
242     glXDestroyPbuffer(dis,pb->srfc());
243 
244     return true;
245 }
246 
createContext(EGLNativeDisplayType dpy,EglConfig * cfg,EGLNativeContextType sharedContext)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 
destroyContext(EGLNativeDisplayType dpy,EGLNativeContextType ctx)253 bool destroyContext(EGLNativeDisplayType dpy,EGLNativeContextType ctx) {
254     glXDestroyContext(dpy,ctx);
255     return true;
256 }
257 
makeCurrent(EGLNativeDisplayType dpy,EglSurface * read,EglSurface * draw,EGLNativeContextType ctx)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 
swapBuffers(EGLNativeDisplayType dpy,EGLNativeSurfaceType srfc)272 void swapBuffers(EGLNativeDisplayType dpy,EGLNativeSurfaceType srfc){
273     if (srfc) {
274         glXSwapBuffers(dpy,srfc->srfc());
275     }
276 }
277 
waitNative()278 void waitNative() {
279     glXWaitX();
280 }
281 
swapInterval(EGLNativeDisplayType dpy,EGLNativeSurfaceType win,int interval)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 
createWindowSurface(EGLNativeWindowType wnd)295 EGLNativeSurfaceType createWindowSurface(EGLNativeWindowType wnd){
296     return new SrfcInfo(wnd,SrfcInfo::WINDOW);
297 }
298 
createPixmapSurface(EGLNativePixmapType pix)299 EGLNativeSurfaceType createPixmapSurface(EGLNativePixmapType pix){
300     return new SrfcInfo(pix,SrfcInfo::PIXMAP);
301 }
302 
destroySurface(EGLNativeSurfaceType srfc)303 void destroySurface(EGLNativeSurfaceType srfc){
304     delete srfc;
305 };
306 
getInternalDisplay(EGLNativeDisplayType dpy)307 EGLNativeInternalDisplayType getInternalDisplay(EGLNativeDisplayType dpy){
308     return dpy;
309 }
310 
deleteDisplay(EGLNativeInternalDisplayType idpy)311 void deleteDisplay(EGLNativeInternalDisplayType idpy){
312 }
313 
314 };
315