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