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