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();
getLastError()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;
SrfcInfo(GLXDrawable drawable,SurfaceType type)44 SrfcInfo(GLXDrawable drawable,SurfaceType type):m_type(type),
45 m_srfc(drawable){};
srfc()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
ErrorHandler(EGLNativeDisplayType dpy)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
~ErrorHandler()62 ErrorHandler::~ErrorHandler(){
63 android::Mutex::Autolock mutex(s_lock);
64 XSetErrorHandler(m_oldErrorHandler);
65 s_lastErrorCode = 0;
66 }
67
errorHandlerProc(EGLNativeDisplayType dpy,XErrorEvent * event)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
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
validNativeWin(EGLNativeDisplayType dpy,EGLNativeWindowType win)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
validNativeWin(EGLNativeDisplayType dpy,EGLNativeSurfaceType win)183 bool validNativeWin(EGLNativeDisplayType dpy,EGLNativeSurfaceType win) {
184 if (!win) return false;
185 return validNativeWin(dpy,win->srfc());
186 }
187
validNativePixmap(EGLNativeDisplayType dpy,EGLNativeSurfaceType pix)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
checkWindowPixelFormatMatch(EGLNativeDisplayType dpy,EGLNativeWindowType win,EglConfig * cfg,unsigned int * width,unsigned int * height)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
checkPixmapPixelFormatMatch(EGLNativeDisplayType dpy,EGLNativePixmapType pix,EglConfig * cfg,unsigned int * width,unsigned int * height)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
createPbufferSurface(EGLNativeDisplayType dpy,EglConfig * cfg,EglPbufferSurface * srfc)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
releasePbuffer(EGLNativeDisplayType dis,EGLNativeSurfaceType pb)236 bool releasePbuffer(EGLNativeDisplayType dis,EGLNativeSurfaceType pb) {
237 if (!pb) return false;
238 glXDestroyPbuffer(dis,pb->srfc());
239
240 return true;
241 }
242
createContext(EGLNativeDisplayType dpy,EglConfig * cfg,EGLNativeContextType sharedContext)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
destroyContext(EGLNativeDisplayType dpy,EGLNativeContextType ctx)249 bool destroyContext(EGLNativeDisplayType dpy,EGLNativeContextType ctx) {
250 glXDestroyContext(dpy,ctx);
251 return true;
252 }
253
makeCurrent(EGLNativeDisplayType dpy,EglSurface * read,EglSurface * draw,EGLNativeContextType ctx)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
swapBuffers(EGLNativeDisplayType dpy,EGLNativeSurfaceType srfc)268 void swapBuffers(EGLNativeDisplayType dpy,EGLNativeSurfaceType srfc){
269 if (srfc) {
270 glXSwapBuffers(dpy,srfc->srfc());
271 }
272 }
273
waitNative()274 void waitNative() {
275 glXWaitX();
276 }
277
swapInterval(EGLNativeDisplayType dpy,EGLNativeSurfaceType win,int interval)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
createWindowSurface(EGLNativeWindowType wnd)291 EGLNativeSurfaceType createWindowSurface(EGLNativeWindowType wnd){
292 return new SrfcInfo(wnd,SrfcInfo::WINDOW);
293 }
294
createPixmapSurface(EGLNativePixmapType pix)295 EGLNativeSurfaceType createPixmapSurface(EGLNativePixmapType pix){
296 return new SrfcInfo(pix,SrfcInfo::PIXMAP);
297 }
298
destroySurface(EGLNativeSurfaceType srfc)299 void destroySurface(EGLNativeSurfaceType srfc){
300 delete srfc;
301 };
302
getInternalDisplay(EGLNativeDisplayType dpy)303 EGLNativeInternalDisplayType getInternalDisplay(EGLNativeDisplayType dpy){
304 return dpy;
305 }
306
deleteDisplay(EGLNativeInternalDisplayType idpy)307 void deleteDisplay(EGLNativeInternalDisplayType idpy){
308 }
309
310 };
311