1 // Copyright 2016 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 // Display.cpp: Implements the egl::Display class, representing the abstract
16 // display on which graphics are drawn. Implements EGLDisplay.
17 // [EGL 1.4] section 2.1.2 page 3.
18
19 #include "Display.h"
20
21 #include "main.h"
22 #include "libEGL/Surface.hpp"
23 #include "libEGL/Context.hpp"
24 #include "common/Image.hpp"
25 #include "common/debug.h"
26 #include "Common/MutexLock.hpp"
27
28 #ifdef __ANDROID__
29 #include <system/window.h>
30 #include <sys/ioctl.h>
31 #include <linux/fb.h>
32 #include <fcntl.h>
33 #elif defined(__linux__)
34 #include "Main/libX11.hpp"
35 #elif defined(__APPLE__)
36 #include "OSXUtils.hpp"
37 #endif
38
39 #include <algorithm>
40 #include <vector>
41 #include <map>
42
43 namespace egl
44 {
45
46 class DisplayImplementation : public Display
47 {
48 public:
DisplayImplementation(EGLDisplay dpy,void * nativeDisplay)49 DisplayImplementation(EGLDisplay dpy, void *nativeDisplay) : Display(dpy, nativeDisplay) {}
~DisplayImplementation()50 ~DisplayImplementation() override {}
51
getSharedImage(EGLImageKHR name)52 Image *getSharedImage(EGLImageKHR name) override
53 {
54 return Display::getSharedImage(name);
55 }
56 };
57
get(EGLDisplay dpy)58 Display *Display::get(EGLDisplay dpy)
59 {
60 if(dpy != PRIMARY_DISPLAY && dpy != HEADLESS_DISPLAY) // We only support the default display
61 {
62 return nullptr;
63 }
64
65 static void *nativeDisplay = nullptr;
66
67 #if defined(__linux__) && !defined(__ANDROID__)
68 // Even if the application provides a native display handle, we open (and close) our own connection
69 if(!nativeDisplay && dpy != HEADLESS_DISPLAY && libX11 && libX11->XOpenDisplay)
70 {
71 nativeDisplay = libX11->XOpenDisplay(NULL);
72 }
73 #endif
74
75 static DisplayImplementation display(dpy, nativeDisplay);
76
77 return &display;
78 }
79
Display(EGLDisplay eglDisplay,void * nativeDisplay)80 Display::Display(EGLDisplay eglDisplay, void *nativeDisplay) : eglDisplay(eglDisplay), nativeDisplay(nativeDisplay)
81 {
82 mMinSwapInterval = 1;
83 mMaxSwapInterval = 1;
84 }
85
~Display()86 Display::~Display()
87 {
88 terminate();
89
90 #if defined(__linux__) && !defined(__ANDROID__)
91 if(nativeDisplay && libX11->XCloseDisplay)
92 {
93 libX11->XCloseDisplay((::Display*)nativeDisplay);
94 }
95 #endif
96 }
97
98 #if !defined(__i386__) && defined(_M_IX86)
99 #define __i386__ 1
100 #endif
101
102 #if !defined(__x86_64__) && (defined(_M_AMD64) || defined (_M_X64))
103 #define __x86_64__ 1
104 #endif
105
cpuid(int registers[4],int info)106 static void cpuid(int registers[4], int info)
107 {
108 #if defined(__i386__) || defined(__x86_64__)
109 #if defined(_WIN32)
110 __cpuid(registers, info);
111 #else
112 __asm volatile("cpuid": "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3]): "a" (info));
113 #endif
114 #else
115 registers[0] = 0;
116 registers[1] = 0;
117 registers[2] = 0;
118 registers[3] = 0;
119 #endif
120 }
121
detectSSE()122 static bool detectSSE()
123 {
124 int registers[4];
125 cpuid(registers, 1);
126 return (registers[3] & 0x02000000) != 0;
127 }
128
initialize()129 bool Display::initialize()
130 {
131 if(isInitialized())
132 {
133 return true;
134 }
135
136 #if defined(__i386__) || defined(__x86_64__)
137 if(!detectSSE())
138 {
139 return false;
140 }
141 #endif
142
143 mMinSwapInterval = 0;
144 mMaxSwapInterval = 4;
145
146 const int samples[] =
147 {
148 0,
149 2,
150 4
151 };
152
153 const sw::Format renderTargetFormats[] =
154 {
155 // sw::FORMAT_A1R5G5B5,
156 // sw::FORMAT_A2R10G10B10, // The color_ramp conformance test uses ReadPixels with UNSIGNED_BYTE causing it to think that rendering skipped a colour value.
157 sw::FORMAT_A8R8G8B8,
158 sw::FORMAT_A8B8G8R8,
159 sw::FORMAT_R5G6B5,
160 // sw::FORMAT_X1R5G5B5, // Has no compatible OpenGL ES renderbuffer format
161 sw::FORMAT_X8R8G8B8,
162 sw::FORMAT_X8B8G8R8
163 };
164
165 const sw::Format depthStencilFormats[] =
166 {
167 sw::FORMAT_NULL,
168 // sw::FORMAT_D16_LOCKABLE,
169 sw::FORMAT_D32,
170 // sw::FORMAT_D15S1,
171 sw::FORMAT_D24S8,
172 sw::FORMAT_D24X8,
173 // sw::FORMAT_D24X4S4,
174 sw::FORMAT_D16,
175 // sw::FORMAT_D32F_LOCKABLE,
176 // sw::FORMAT_D24FS8
177 };
178
179 sw::Format currentDisplayFormat = getDisplayFormat();
180 ConfigSet configSet;
181
182 for(unsigned int samplesIndex = 0; samplesIndex < sizeof(samples) / sizeof(int); samplesIndex++)
183 {
184 for(unsigned int formatIndex = 0; formatIndex < sizeof(renderTargetFormats) / sizeof(sw::Format); formatIndex++)
185 {
186 sw::Format renderTargetFormat = renderTargetFormats[formatIndex];
187
188 for(unsigned int depthStencilIndex = 0; depthStencilIndex < sizeof(depthStencilFormats) / sizeof(sw::Format); depthStencilIndex++)
189 {
190 sw::Format depthStencilFormat = depthStencilFormats[depthStencilIndex];
191
192 configSet.add(currentDisplayFormat, mMinSwapInterval, mMaxSwapInterval, renderTargetFormat, depthStencilFormat, samples[samplesIndex]);
193 }
194 }
195 }
196
197 // Give the sorted configs a unique ID and store them internally
198 EGLint index = 1;
199 for(ConfigSet::Iterator config = configSet.mSet.begin(); config != configSet.mSet.end(); config++)
200 {
201 Config configuration = *config;
202 configuration.mConfigID = index;
203 index++;
204
205 mConfigSet.mSet.insert(configuration);
206 }
207
208 if(!isInitialized())
209 {
210 terminate();
211
212 return false;
213 }
214
215 return true;
216 }
217
terminate()218 void Display::terminate()
219 {
220 while(!mSurfaceSet.empty())
221 {
222 destroySurface(*mSurfaceSet.begin());
223 }
224
225 while(!mContextSet.empty())
226 {
227 destroyContext(*mContextSet.begin());
228 }
229
230 while(!mSharedImageNameSpace.empty())
231 {
232 destroySharedImage(reinterpret_cast<EGLImageKHR>((intptr_t)mSharedImageNameSpace.firstName()));
233 }
234 }
235
getConfigs(EGLConfig * configs,const EGLint * attribList,EGLint configSize,EGLint * numConfig)236 bool Display::getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig)
237 {
238 return mConfigSet.getConfigs(configs, attribList, configSize, numConfig);
239 }
240
getConfigAttrib(EGLConfig config,EGLint attribute,EGLint * value)241 bool Display::getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value)
242 {
243 const egl::Config *configuration = mConfigSet.get(config);
244
245 switch(attribute)
246 {
247 case EGL_BUFFER_SIZE: *value = configuration->mBufferSize; break;
248 case EGL_ALPHA_SIZE: *value = configuration->mAlphaSize; break;
249 case EGL_BLUE_SIZE: *value = configuration->mBlueSize; break;
250 case EGL_GREEN_SIZE: *value = configuration->mGreenSize; break;
251 case EGL_RED_SIZE: *value = configuration->mRedSize; break;
252 case EGL_DEPTH_SIZE: *value = configuration->mDepthSize; break;
253 case EGL_STENCIL_SIZE: *value = configuration->mStencilSize; break;
254 case EGL_CONFIG_CAVEAT: *value = configuration->mConfigCaveat; break;
255 case EGL_CONFIG_ID: *value = configuration->mConfigID; break;
256 case EGL_LEVEL: *value = configuration->mLevel; break;
257 case EGL_NATIVE_RENDERABLE: *value = configuration->mNativeRenderable; break;
258 case EGL_NATIVE_VISUAL_ID: *value = configuration->mNativeVisualID; break;
259 case EGL_NATIVE_VISUAL_TYPE: *value = configuration->mNativeVisualType; break;
260 case EGL_SAMPLES: *value = configuration->mSamples; break;
261 case EGL_SAMPLE_BUFFERS: *value = configuration->mSampleBuffers; break;
262 case EGL_SURFACE_TYPE: *value = configuration->mSurfaceType; break;
263 case EGL_TRANSPARENT_TYPE: *value = configuration->mTransparentType; break;
264 case EGL_TRANSPARENT_BLUE_VALUE: *value = configuration->mTransparentBlueValue; break;
265 case EGL_TRANSPARENT_GREEN_VALUE: *value = configuration->mTransparentGreenValue; break;
266 case EGL_TRANSPARENT_RED_VALUE: *value = configuration->mTransparentRedValue; break;
267 case EGL_BIND_TO_TEXTURE_RGB: *value = configuration->mBindToTextureRGB; break;
268 case EGL_BIND_TO_TEXTURE_RGBA: *value = configuration->mBindToTextureRGBA; break;
269 case EGL_MIN_SWAP_INTERVAL: *value = configuration->mMinSwapInterval; break;
270 case EGL_MAX_SWAP_INTERVAL: *value = configuration->mMaxSwapInterval; break;
271 case EGL_LUMINANCE_SIZE: *value = configuration->mLuminanceSize; break;
272 case EGL_ALPHA_MASK_SIZE: *value = configuration->mAlphaMaskSize; break;
273 case EGL_COLOR_BUFFER_TYPE: *value = configuration->mColorBufferType; break;
274 case EGL_RENDERABLE_TYPE: *value = configuration->mRenderableType; break;
275 case EGL_MATCH_NATIVE_PIXMAP: *value = EGL_FALSE; UNIMPLEMENTED(); break;
276 case EGL_CONFORMANT: *value = configuration->mConformant; break;
277 case EGL_MAX_PBUFFER_WIDTH: *value = configuration->mMaxPBufferWidth; break;
278 case EGL_MAX_PBUFFER_HEIGHT: *value = configuration->mMaxPBufferHeight; break;
279 case EGL_MAX_PBUFFER_PIXELS: *value = configuration->mMaxPBufferPixels; break;
280 case EGL_RECORDABLE_ANDROID: *value = configuration->mRecordableAndroid; break;
281 case EGL_FRAMEBUFFER_TARGET_ANDROID: *value = configuration->mFramebufferTargetAndroid; break;
282 default:
283 return false;
284 }
285
286 return true;
287 }
288
createWindowSurface(EGLNativeWindowType window,EGLConfig config,const EGLint * attribList)289 EGLSurface Display::createWindowSurface(EGLNativeWindowType window, EGLConfig config, const EGLint *attribList)
290 {
291 const Config *configuration = mConfigSet.get(config);
292
293 if(attribList)
294 {
295 while(*attribList != EGL_NONE)
296 {
297 switch(attribList[0])
298 {
299 case EGL_RENDER_BUFFER:
300 switch(attribList[1])
301 {
302 case EGL_BACK_BUFFER:
303 break;
304 case EGL_SINGLE_BUFFER:
305 return error(EGL_BAD_MATCH, EGL_NO_SURFACE); // Rendering directly to front buffer not supported
306 default:
307 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
308 }
309 break;
310 case EGL_VG_COLORSPACE:
311 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
312 case EGL_VG_ALPHA_FORMAT:
313 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
314 default:
315 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
316 }
317
318 attribList += 2;
319 }
320 }
321
322 if(hasExistingWindowSurface(window))
323 {
324 return error(EGL_BAD_ALLOC, EGL_NO_SURFACE);
325 }
326
327 Surface *surface = new WindowSurface(this, configuration, window);
328
329 if(!surface->initialize())
330 {
331 surface->release();
332 return EGL_NO_SURFACE;
333 }
334
335 surface->addRef();
336 mSurfaceSet.insert(surface);
337
338 return success(surface);
339 }
340
createPBufferSurface(EGLConfig config,const EGLint * attribList)341 EGLSurface Display::createPBufferSurface(EGLConfig config, const EGLint *attribList)
342 {
343 EGLint width = 0, height = 0;
344 EGLenum textureFormat = EGL_NO_TEXTURE;
345 EGLenum textureTarget = EGL_NO_TEXTURE;
346 EGLBoolean largestPBuffer = EGL_FALSE;
347 const Config *configuration = mConfigSet.get(config);
348
349 if(attribList)
350 {
351 while(*attribList != EGL_NONE)
352 {
353 switch(attribList[0])
354 {
355 case EGL_WIDTH:
356 width = attribList[1];
357 break;
358 case EGL_HEIGHT:
359 height = attribList[1];
360 break;
361 case EGL_LARGEST_PBUFFER:
362 largestPBuffer = attribList[1];
363 break;
364 case EGL_TEXTURE_FORMAT:
365 switch(attribList[1])
366 {
367 case EGL_NO_TEXTURE:
368 case EGL_TEXTURE_RGB:
369 case EGL_TEXTURE_RGBA:
370 textureFormat = attribList[1];
371 break;
372 default:
373 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
374 }
375 break;
376 case EGL_TEXTURE_TARGET:
377 switch(attribList[1])
378 {
379 case EGL_NO_TEXTURE:
380 case EGL_TEXTURE_2D:
381 textureTarget = attribList[1];
382 break;
383 default:
384 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
385 }
386 break;
387 case EGL_MIPMAP_TEXTURE:
388 if(attribList[1] != EGL_FALSE)
389 {
390 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
391 }
392 break;
393 case EGL_VG_COLORSPACE:
394 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
395 case EGL_VG_ALPHA_FORMAT:
396 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
397 default:
398 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
399 }
400
401 attribList += 2;
402 }
403 }
404
405 if(width < 0 || height < 0)
406 {
407 return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
408 }
409
410 if(width == 0 || height == 0)
411 {
412 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
413 }
414
415 if((textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) ||
416 (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE))
417 {
418 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
419 }
420
421 if(!(configuration->mSurfaceType & EGL_PBUFFER_BIT))
422 {
423 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
424 }
425
426 if((textureFormat == EGL_TEXTURE_RGB && configuration->mBindToTextureRGB != EGL_TRUE) ||
427 (textureFormat == EGL_TEXTURE_RGBA && configuration->mBindToTextureRGBA != EGL_TRUE))
428 {
429 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
430 }
431
432 Surface *surface = new PBufferSurface(this, configuration, width, height, textureFormat, textureTarget, largestPBuffer);
433
434 if(!surface->initialize())
435 {
436 surface->release();
437 return EGL_NO_SURFACE;
438 }
439
440 surface->addRef();
441 mSurfaceSet.insert(surface);
442
443 return success(surface);
444 }
445
createContext(EGLConfig configHandle,const egl::Context * shareContext,EGLint clientVersion)446 EGLContext Display::createContext(EGLConfig configHandle, const egl::Context *shareContext, EGLint clientVersion)
447 {
448 const egl::Config *config = mConfigSet.get(configHandle);
449 egl::Context *context = nullptr;
450
451 if(clientVersion == 1 && config->mRenderableType & EGL_OPENGL_ES_BIT)
452 {
453 if(libGLES_CM)
454 {
455 context = libGLES_CM->es1CreateContext(this, shareContext, config);
456 }
457 }
458 else if((clientVersion == 2 && config->mRenderableType & EGL_OPENGL_ES2_BIT) ||
459 (clientVersion == 3 && config->mRenderableType & EGL_OPENGL_ES3_BIT))
460 {
461 if(libGLESv2)
462 {
463 context = libGLESv2->es2CreateContext(this, shareContext, clientVersion, config);
464 }
465 }
466 else
467 {
468 return error(EGL_BAD_CONFIG, EGL_NO_CONTEXT);
469 }
470
471 if(!context)
472 {
473 return error(EGL_BAD_ALLOC, EGL_NO_CONTEXT);
474 }
475
476 context->addRef();
477 mContextSet.insert(context);
478
479 return success(context);
480 }
481
createSync(Context * context)482 EGLSyncKHR Display::createSync(Context *context)
483 {
484 FenceSync *fenceSync = new egl::FenceSync(context);
485 LockGuard lock(mSyncSetMutex);
486 mSyncSet.insert(fenceSync);
487 return fenceSync;
488 }
489
destroySurface(egl::Surface * surface)490 void Display::destroySurface(egl::Surface *surface)
491 {
492 surface->release();
493 mSurfaceSet.erase(surface);
494
495 if(surface == getCurrentDrawSurface())
496 {
497 setCurrentDrawSurface(nullptr);
498 }
499
500 if(surface == getCurrentReadSurface())
501 {
502 setCurrentReadSurface(nullptr);
503 }
504 }
505
destroyContext(egl::Context * context)506 void Display::destroyContext(egl::Context *context)
507 {
508 context->release();
509 mContextSet.erase(context);
510
511 if(context == getCurrentContext())
512 {
513 setCurrentContext(nullptr);
514 setCurrentDrawSurface(nullptr);
515 setCurrentReadSurface(nullptr);
516 }
517 }
518
destroySync(FenceSync * sync)519 void Display::destroySync(FenceSync *sync)
520 {
521 {
522 LockGuard lock(mSyncSetMutex);
523 mSyncSet.erase(sync);
524 }
525 delete sync;
526 }
527
isInitialized() const528 bool Display::isInitialized() const
529 {
530 return mConfigSet.size() > 0;
531 }
532
isValidConfig(EGLConfig config)533 bool Display::isValidConfig(EGLConfig config)
534 {
535 return mConfigSet.get(config) != nullptr;
536 }
537
isValidContext(egl::Context * context)538 bool Display::isValidContext(egl::Context *context)
539 {
540 return mContextSet.find(context) != mContextSet.end();
541 }
542
isValidSurface(egl::Surface * surface)543 bool Display::isValidSurface(egl::Surface *surface)
544 {
545 return mSurfaceSet.find(surface) != mSurfaceSet.end();
546 }
547
isValidWindow(EGLNativeWindowType window)548 bool Display::isValidWindow(EGLNativeWindowType window)
549 {
550 #if defined(_WIN32)
551 return IsWindow(window) == TRUE;
552 #elif defined(__ANDROID__)
553 if(!window)
554 {
555 ALOGE("%s called with window==NULL %s:%d", __FUNCTION__, __FILE__, __LINE__);
556 return false;
557 }
558 if(static_cast<ANativeWindow*>(window)->common.magic != ANDROID_NATIVE_WINDOW_MAGIC)
559 {
560 ALOGE("%s called with window==%p bad magic %s:%d", __FUNCTION__, window, __FILE__, __LINE__);
561 return false;
562 }
563 return true;
564 #elif defined(__linux__)
565 if(nativeDisplay)
566 {
567 XWindowAttributes windowAttributes;
568 Status status = libX11->XGetWindowAttributes((::Display*)nativeDisplay, window, &windowAttributes);
569
570 return status == True;
571 }
572 return false;
573 #elif defined(__APPLE__)
574 return sw::OSX::IsValidWindow(window);
575 #else
576 #error "Display::isValidWindow unimplemented for this platform"
577 return false;
578 #endif
579 }
580
hasExistingWindowSurface(EGLNativeWindowType window)581 bool Display::hasExistingWindowSurface(EGLNativeWindowType window)
582 {
583 for(SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
584 {
585 if((*surface)->isWindowSurface())
586 {
587 if((*surface)->getWindowHandle() == window)
588 {
589 return true;
590 }
591 }
592 }
593
594 return false;
595 }
596
isValidSync(FenceSync * sync)597 bool Display::isValidSync(FenceSync *sync)
598 {
599 LockGuard lock(mSyncSetMutex);
600 return mSyncSet.find(sync) != mSyncSet.end();
601 }
602
getMinSwapInterval() const603 EGLint Display::getMinSwapInterval() const
604 {
605 return mMinSwapInterval;
606 }
607
getMaxSwapInterval() const608 EGLint Display::getMaxSwapInterval() const
609 {
610 return mMaxSwapInterval;
611 }
612
getEGLDisplay() const613 EGLDisplay Display::getEGLDisplay() const
614 {
615 return eglDisplay;
616 }
617
getNativeDisplay() const618 void *Display::getNativeDisplay() const
619 {
620 return nativeDisplay;
621 }
622
createSharedImage(Image * image)623 EGLImageKHR Display::createSharedImage(Image *image)
624 {
625 return reinterpret_cast<EGLImageKHR>((intptr_t)mSharedImageNameSpace.allocate(image));
626 }
627
destroySharedImage(EGLImageKHR image)628 bool Display::destroySharedImage(EGLImageKHR image)
629 {
630 GLuint name = (GLuint)reinterpret_cast<intptr_t>(image);
631 Image *eglImage = mSharedImageNameSpace.find(name);
632
633 if(!eglImage)
634 {
635 return false;
636 }
637
638 eglImage->destroyShared();
639 mSharedImageNameSpace.remove(name);
640
641 return true;
642 }
643
getSharedImage(EGLImageKHR image)644 Image *Display::getSharedImage(EGLImageKHR image)
645 {
646 GLuint name = (GLuint)reinterpret_cast<intptr_t>(image);
647 return mSharedImageNameSpace.find(name);
648 }
649
getDisplayFormat() const650 sw::Format Display::getDisplayFormat() const
651 {
652 #if defined(_WIN32)
653 HDC deviceContext = GetDC(0);
654 unsigned int bpp = ::GetDeviceCaps(deviceContext, BITSPIXEL);
655 ReleaseDC(0, deviceContext);
656
657 switch(bpp)
658 {
659 case 32: return sw::FORMAT_X8R8G8B8;
660 case 24: return sw::FORMAT_R8G8B8;
661 case 16: return sw::FORMAT_R5G6B5;
662 default: UNREACHABLE(bpp); // Unexpected display mode color depth
663 }
664 #elif defined(__ANDROID__)
665 static const char *const framebuffer[] =
666 {
667 "/dev/graphics/fb0",
668 "/dev/fb0",
669 0
670 };
671
672 for(int i = 0; framebuffer[i]; i++)
673 {
674 int fd = open(framebuffer[i], O_RDONLY, 0);
675
676 if(fd != -1)
677 {
678 struct fb_var_screeninfo info;
679 int io = ioctl(fd, FBIOGET_VSCREENINFO, &info);
680 close(fd);
681
682 if(io >= 0)
683 {
684 switch(info.bits_per_pixel)
685 {
686 case 16:
687 return sw::FORMAT_R5G6B5;
688 case 32:
689 if(info.red.length == 8 && info.red.offset == 16 &&
690 info.green.length == 8 && info.green.offset == 8 &&
691 info.blue.length == 8 && info.blue.offset == 0 &&
692 info.transp.length == 0)
693 {
694 return sw::FORMAT_X8R8G8B8;
695 }
696 if(info.red.length == 8 && info.red.offset == 0 &&
697 info.green.length == 8 && info.green.offset == 8 &&
698 info.blue.length == 8 && info.blue.offset == 16 &&
699 info.transp.length == 0)
700 {
701 return sw::FORMAT_X8B8G8R8;
702 }
703 if(info.red.length == 8 && info.red.offset == 16 &&
704 info.green.length == 8 && info.green.offset == 8 &&
705 info.blue.length == 8 && info.blue.offset == 0 &&
706 info.transp.length == 8 && info.transp.offset == 24)
707 {
708 return sw::FORMAT_A8R8G8B8;
709 }
710 if(info.red.length == 8 && info.red.offset == 0 &&
711 info.green.length == 8 && info.green.offset == 8 &&
712 info.blue.length == 8 && info.blue.offset == 16 &&
713 info.transp.length == 8 && info.transp.offset == 24)
714 {
715 return sw::FORMAT_A8B8G8R8;
716 }
717 else UNIMPLEMENTED();
718 default:
719 UNIMPLEMENTED();
720 }
721 }
722 }
723 }
724
725 // No framebuffer device found, or we're in user space
726 return sw::FORMAT_X8B8G8R8;
727 #elif defined(__linux__)
728 if(nativeDisplay)
729 {
730 Screen *screen = libX11->XDefaultScreenOfDisplay((::Display*)nativeDisplay);
731 unsigned int bpp = libX11->XPlanesOfScreen(screen);
732
733 switch(bpp)
734 {
735 case 32: return sw::FORMAT_X8R8G8B8;
736 case 24: return sw::FORMAT_R8G8B8;
737 case 16: return sw::FORMAT_R5G6B5;
738 default: UNREACHABLE(bpp); // Unexpected display mode color depth
739 }
740 }
741 else
742 {
743 return sw::FORMAT_X8R8G8B8;
744 }
745 #elif defined(__APPLE__)
746 return sw::FORMAT_A8B8G8R8;
747 #else
748 #error "Display::isValidWindow unimplemented for this platform"
749 #endif
750
751 return sw::FORMAT_X8R8G8B8;
752 }
753
754 }
755