• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(USE_X11)
34 #include "Main/libX11.hpp"
35 #elif defined(__APPLE__)
36 #include "OSXUtils.hpp"
37 #include <CoreFoundation/CoreFoundation.h>
38 #include <IOSurface/IOSurface.h>
39 #endif
40 
41 #include <algorithm>
42 #include <vector>
43 #include <map>
44 
45 namespace egl
46 {
47 
48 class DisplayImplementation : public Display
49 {
50 public:
DisplayImplementation(EGLDisplay dpy,void * nativeDisplay)51 	DisplayImplementation(EGLDisplay dpy, void *nativeDisplay) : Display(dpy, nativeDisplay) {}
~DisplayImplementation()52 	~DisplayImplementation() override {}
53 
getSharedImage(EGLImageKHR name)54 	Image *getSharedImage(EGLImageKHR name) override
55 	{
56 		return Display::getSharedImage(name);
57 	}
58 };
59 
get(EGLDisplay dpy)60 Display *Display::get(EGLDisplay dpy)
61 {
62 	if(dpy != PRIMARY_DISPLAY && dpy != HEADLESS_DISPLAY)   // We only support the default display
63 	{
64 		return nullptr;
65 	}
66 
67 	static void *nativeDisplay = nullptr;
68 
69 	#if defined(USE_X11)
70 		// Even if the application provides a native display handle, we open (and close) our own connection
71 		if(!nativeDisplay && dpy != HEADLESS_DISPLAY && libX11 && libX11->XOpenDisplay)
72 		{
73 			nativeDisplay = libX11->XOpenDisplay(NULL);
74 		}
75 	#endif
76 
77 	static DisplayImplementation display(dpy, nativeDisplay);
78 
79 	return &display;
80 }
81 
Display(EGLDisplay eglDisplay,void * nativeDisplay)82 Display::Display(EGLDisplay eglDisplay, void *nativeDisplay) : eglDisplay(eglDisplay), nativeDisplay(nativeDisplay)
83 {
84 	mMinSwapInterval = 1;
85 	mMaxSwapInterval = 1;
86 }
87 
~Display()88 Display::~Display()
89 {
90 	terminate();
91 
92 	#if defined(USE_X11)
93 		if(nativeDisplay && libX11->XCloseDisplay)
94 		{
95 			libX11->XCloseDisplay((::Display*)nativeDisplay);
96 		}
97 	#endif
98 }
99 
100 #if !defined(__i386__) && defined(_M_IX86)
101 	#define __i386__ 1
102 #endif
103 
104 #if !defined(__x86_64__) && (defined(_M_AMD64) || defined (_M_X64))
105 	#define __x86_64__ 1
106 #endif
107 
108 #if defined(__i386__) || defined(__x86_64__)
cpuid(int registers[4],int info)109 static void cpuid(int registers[4], int info)
110 {
111 	#if defined(__i386__) || defined(__x86_64__)
112 		#if defined(_WIN32)
113 			__cpuid(registers, info);
114 		#else
115 			__asm volatile("cpuid": "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3]): "a" (info));
116 		#endif
117 	#else
118 		registers[0] = 0;
119 		registers[1] = 0;
120 		registers[2] = 0;
121 		registers[3] = 0;
122 	#endif
123 }
124 
detectSSE()125 static bool detectSSE()
126 {
127 	int registers[4];
128 	cpuid(registers, 1);
129 	return (registers[3] & 0x02000000) != 0;
130 }
131 #endif
132 
initialize()133 bool Display::initialize()
134 {
135 	if(isInitialized())
136 	{
137 		return true;
138 	}
139 
140 	#if defined(__i386__) || defined(__x86_64__)
141 		if(!detectSSE())
142 		{
143 			return false;
144 		}
145 	#endif
146 
147 	mMinSwapInterval = 0;
148 	mMaxSwapInterval = 4;
149 
150 	const int samples[] =
151 	{
152 		0,
153 		2,
154 		4
155 	};
156 
157 	const sw::Format renderTargetFormats[] =
158 	{
159 	//	sw::FORMAT_A1R5G5B5,
160 	//  sw::FORMAT_A2R10G10B10,   // The color_ramp conformance test uses ReadPixels with UNSIGNED_BYTE causing it to think that rendering skipped a colour value.
161 		sw::FORMAT_A8R8G8B8,
162 		sw::FORMAT_A8B8G8R8,
163 		sw::FORMAT_R5G6B5,
164 	//  sw::FORMAT_X1R5G5B5,      // Has no compatible OpenGL ES renderbuffer format
165 		sw::FORMAT_X8R8G8B8,
166 		sw::FORMAT_X8B8G8R8
167 	};
168 
169 	const sw::Format depthStencilFormats[] =
170 	{
171 		sw::FORMAT_NULL,
172 	//  sw::FORMAT_D16_LOCKABLE,
173 		sw::FORMAT_D32,
174 	//  sw::FORMAT_D15S1,
175 		sw::FORMAT_D24S8,
176 		sw::FORMAT_D24X8,
177 	//  sw::FORMAT_D24X4S4,
178 		sw::FORMAT_D16,
179 	//  sw::FORMAT_D32F_LOCKABLE,
180 	//  sw::FORMAT_D24FS8
181 	};
182 
183 	sw::Format currentDisplayFormat = getDisplayFormat();
184 	ConfigSet configSet;
185 
186 	for(unsigned int samplesIndex = 0; samplesIndex < sizeof(samples) / sizeof(int); samplesIndex++)
187 	{
188 		for(sw::Format renderTargetFormat : renderTargetFormats)
189 		{
190 			for(sw::Format depthStencilFormat : depthStencilFormats)
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 EGLAttrib * attribList)289 EGLSurface Display::createWindowSurface(EGLNativeWindowType window, EGLConfig config, const EGLAttrib *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,EGLClientBuffer clientBuffer)341 EGLSurface Display::createPBufferSurface(EGLConfig config, const EGLint *attribList, EGLClientBuffer clientBuffer)
342 {
343 	EGLint width = -1, height = -1, ioSurfacePlane = -1;
344 	EGLenum textureFormat = EGL_NO_TEXTURE;
345 	EGLenum textureTarget = EGL_NO_TEXTURE;
346 	EGLenum clientBufferFormat = EGL_NO_TEXTURE;
347 	EGLenum clientBufferType = EGL_NO_TEXTURE;
348 	EGLBoolean largestPBuffer = EGL_FALSE;
349 	const Config *configuration = mConfigSet.get(config);
350 
351 	if(attribList)
352 	{
353 		while(*attribList != EGL_NONE)
354 		{
355 			switch(attribList[0])
356 			{
357 			case EGL_WIDTH:
358 				width = attribList[1];
359 				break;
360 			case EGL_HEIGHT:
361 				height = attribList[1];
362 				break;
363 			case EGL_LARGEST_PBUFFER:
364 				largestPBuffer = attribList[1];
365 				break;
366 			case EGL_TEXTURE_FORMAT:
367 				switch(attribList[1])
368 				{
369 				case EGL_NO_TEXTURE:
370 				case EGL_TEXTURE_RGB:
371 				case EGL_TEXTURE_RGBA:
372 					textureFormat = attribList[1];
373 					break;
374 				default:
375 					return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
376 				}
377 				break;
378 			case EGL_TEXTURE_INTERNAL_FORMAT_ANGLE:
379 				switch(attribList[1])
380 				{
381 				case GL_RED:
382 				case GL_R16UI:
383 				case GL_RG:
384 				case GL_BGRA_EXT:
385 				case GL_RGBA:
386 					clientBufferFormat = attribList[1];
387 					break;
388 				default:
389 					return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
390 				}
391 				break;
392 			case EGL_TEXTURE_TYPE_ANGLE:
393 				switch(attribList[1])
394 				{
395 				case GL_UNSIGNED_BYTE:
396 				case GL_UNSIGNED_SHORT:
397 				case GL_HALF_FLOAT_OES:
398 				case GL_HALF_FLOAT:
399 					clientBufferType = attribList[1];
400 					break;
401 				default:
402 					return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
403 				}
404 				break;
405 			case EGL_IOSURFACE_PLANE_ANGLE:
406 				if(attribList[1] < 0)
407 				{
408 					return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
409 				}
410 				ioSurfacePlane = attribList[1];
411 				break;
412 			case EGL_TEXTURE_TARGET:
413 				switch(attribList[1])
414 				{
415 				case EGL_NO_TEXTURE:
416 				case EGL_TEXTURE_2D:
417 				case EGL_TEXTURE_RECTANGLE_ANGLE:
418 					textureTarget = attribList[1];
419 					break;
420 				default:
421 					return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
422 				}
423 				break;
424 			case EGL_MIPMAP_TEXTURE:
425 				if(attribList[1] != EGL_FALSE)
426 				{
427 					UNIMPLEMENTED();
428 					return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
429 				}
430 				break;
431 			case EGL_VG_COLORSPACE:
432 				return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
433 			case EGL_VG_ALPHA_FORMAT:
434 				return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
435 			default:
436 				return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
437 			}
438 
439 			attribList += 2;
440 		}
441 	}
442 
443 	if(width < 0 || height < 0)
444 	{
445 		return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
446 	}
447 
448 	if(width == 0 || height == 0)
449 	{
450 		return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
451 	}
452 
453 	if((textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) ||
454 	   (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE))
455 	{
456 		return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
457 	}
458 
459 	if(!(configuration->mSurfaceType & EGL_PBUFFER_BIT))
460 	{
461 		return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
462 	}
463 
464 	if(clientBuffer)
465 	{
466 		switch(clientBufferType)
467 		{
468 		case GL_UNSIGNED_BYTE:
469 			switch(clientBufferFormat)
470 			{
471 			case GL_RED:
472 			case GL_RG:
473 			case GL_BGRA_EXT:
474 				break;
475 			case GL_R16UI:
476 			case GL_RGBA:
477 				return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
478 			default:
479 				return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
480 			}
481 			break;
482 		case GL_UNSIGNED_SHORT:
483 			switch(clientBufferFormat)
484 			{
485 			case GL_R16UI:
486 				break;
487 			case GL_RED:
488 			case GL_RG:
489 			case GL_BGRA_EXT:
490 			case GL_RGBA:
491 				return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
492 			default:
493 				return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
494 			}
495 			break;
496 		case GL_HALF_FLOAT_OES:
497 		case GL_HALF_FLOAT:
498 			switch(clientBufferFormat)
499 			{
500 			case GL_RGBA:
501 				break;
502 			case GL_RED:
503 			case GL_R16UI:
504 			case GL_RG:
505 			case GL_BGRA_EXT:
506 				return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
507 			default:
508 				return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
509 			}
510 			break;
511 		default:
512 			return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
513 		}
514 
515 		if(ioSurfacePlane < 0)
516 		{
517 			return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
518 		}
519 
520 		if(textureFormat != EGL_TEXTURE_RGBA)
521 		{
522 			return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
523 		}
524 
525 		if(textureTarget != EGL_TEXTURE_RECTANGLE_ANGLE)
526 		{
527 			return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
528 		}
529 
530 #if defined(__APPLE__)
531 		IOSurfaceRef ioSurface = reinterpret_cast<IOSurfaceRef>(clientBuffer);
532 		size_t planeCount = IOSurfaceGetPlaneCount(ioSurface);
533 		if((static_cast<size_t>(width) > IOSurfaceGetWidthOfPlane(ioSurface, ioSurfacePlane)) ||
534 		   (static_cast<size_t>(height) > IOSurfaceGetHeightOfPlane(ioSurface, ioSurfacePlane)) ||
535 		   ((planeCount != 0) && static_cast<size_t>(ioSurfacePlane) >= planeCount))
536 		{
537 			return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
538 		}
539 #endif
540 	}
541 	else
542 	{
543 		if((textureFormat == EGL_TEXTURE_RGB && configuration->mBindToTextureRGB != EGL_TRUE) ||
544 		   ((textureFormat == EGL_TEXTURE_RGBA && configuration->mBindToTextureRGBA != EGL_TRUE)))
545 		{
546 			return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
547 		}
548 	}
549 
550 	Surface *surface = new PBufferSurface(this, configuration, width, height, textureFormat, textureTarget, clientBufferFormat, clientBufferType, largestPBuffer, clientBuffer, ioSurfacePlane);
551 
552 	if(!surface->initialize())
553 	{
554 		surface->release();
555 		return EGL_NO_SURFACE;
556 	}
557 
558 	surface->addRef();
559 	mSurfaceSet.insert(surface);
560 
561 	return success(surface);
562 }
563 
createContext(EGLConfig configHandle,const egl::Context * shareContext,EGLint clientVersion)564 EGLContext Display::createContext(EGLConfig configHandle, const egl::Context *shareContext, EGLint clientVersion)
565 {
566 	const egl::Config *config = mConfigSet.get(configHandle);
567 	egl::Context *context = nullptr;
568 
569 	if(clientVersion == 1 && config->mRenderableType & EGL_OPENGL_ES_BIT)
570 	{
571 		if(libGLES_CM)
572 		{
573 			context = libGLES_CM->es1CreateContext(this, shareContext, config);
574 		}
575 	}
576 	else if((clientVersion == 2 && config->mRenderableType & EGL_OPENGL_ES2_BIT) ||
577 	        (clientVersion == 3 && config->mRenderableType & EGL_OPENGL_ES3_BIT))
578 	{
579 		if(libGLESv2)
580 		{
581 			context = libGLESv2->es2CreateContext(this, shareContext, config);
582 		}
583 	}
584 	else
585 	{
586 		return error(EGL_BAD_CONFIG, EGL_NO_CONTEXT);
587 	}
588 
589 	if(!context)
590 	{
591 		return error(EGL_BAD_ALLOC, EGL_NO_CONTEXT);
592 	}
593 
594 	context->addRef();
595 	mContextSet.insert(context);
596 
597 	return success(context);
598 }
599 
createSync(Context * context)600 EGLSyncKHR Display::createSync(Context *context)
601 {
602 	FenceSync *fenceSync = new egl::FenceSync(context);
603 	LockGuard lock(mSyncSetMutex);
604 	mSyncSet.insert(fenceSync);
605 	return fenceSync;
606 }
607 
destroySurface(egl::Surface * surface)608 void Display::destroySurface(egl::Surface *surface)
609 {
610 	surface->release();
611 	mSurfaceSet.erase(surface);
612 
613 	if(surface == getCurrentDrawSurface())
614 	{
615 		setCurrentDrawSurface(nullptr);
616 	}
617 
618 	if(surface == getCurrentReadSurface())
619 	{
620 		setCurrentReadSurface(nullptr);
621 	}
622 }
623 
destroyContext(egl::Context * context)624 void Display::destroyContext(egl::Context *context)
625 {
626 	context->release();
627 	mContextSet.erase(context);
628 
629 	if(context == getCurrentContext())
630 	{
631 		setCurrentContext(nullptr);
632 		setCurrentDrawSurface(nullptr);
633 		setCurrentReadSurface(nullptr);
634 	}
635 }
636 
destroySync(FenceSync * sync)637 void Display::destroySync(FenceSync *sync)
638 {
639 	{
640 		LockGuard lock(mSyncSetMutex);
641 		mSyncSet.erase(sync);
642 	}
643 	delete sync;
644 }
645 
isInitialized() const646 bool Display::isInitialized() const
647 {
648 	return mConfigSet.size() > 0;
649 }
650 
isValidConfig(EGLConfig config)651 bool Display::isValidConfig(EGLConfig config)
652 {
653 	return mConfigSet.get(config) != nullptr;
654 }
655 
isValidContext(egl::Context * context)656 bool Display::isValidContext(egl::Context *context)
657 {
658 	return mContextSet.find(context) != mContextSet.end();
659 }
660 
isValidSurface(egl::Surface * surface)661 bool Display::isValidSurface(egl::Surface *surface)
662 {
663 	return mSurfaceSet.find(surface) != mSurfaceSet.end();
664 }
665 
isValidWindow(EGLNativeWindowType window)666 bool Display::isValidWindow(EGLNativeWindowType window)
667 {
668 	#if defined(_WIN32)
669 		return IsWindow(window) == TRUE;
670 	#elif defined(__ANDROID__)
671 		if(!window)
672 		{
673 			ERR("%s called with window==NULL %s:%d", __FUNCTION__, __FILE__, __LINE__);
674 			return false;
675 		}
676 		if(static_cast<ANativeWindow*>(window)->common.magic != ANDROID_NATIVE_WINDOW_MAGIC)
677 		{
678 			ERR("%s called with window==%p bad magic %s:%d", __FUNCTION__, window, __FILE__, __LINE__);
679 			return false;
680 		}
681 		return true;
682 	#elif defined(USE_X11)
683 		if(nativeDisplay)
684 		{
685 			XWindowAttributes windowAttributes;
686 			Status status = libX11->XGetWindowAttributes((::Display*)nativeDisplay, window, &windowAttributes);
687 
688 			return status != 0;
689 		}
690 		return false;
691 	#elif defined(__linux__)
692 		return false;  // Non X11 linux is headless only
693 	#elif defined(__APPLE__)
694 		return sw::OSX::IsValidWindow(window);
695 	#elif defined(__Fuchsia__)
696 		// TODO(crbug.com/800951): Integrate with Mozart.
697 		return true;
698 	#else
699 		#error "Display::isValidWindow unimplemented for this platform"
700 		return false;
701 	#endif
702 }
703 
hasExistingWindowSurface(EGLNativeWindowType window)704 bool Display::hasExistingWindowSurface(EGLNativeWindowType window)
705 {
706 	for(const auto &surface : mSurfaceSet)
707 	{
708 		if(surface->isWindowSurface())
709 		{
710 			if(surface->getWindowHandle() == window)
711 			{
712 				return true;
713 			}
714 		}
715 	}
716 
717 	return false;
718 }
719 
isValidSync(FenceSync * sync)720 bool Display::isValidSync(FenceSync *sync)
721 {
722 	LockGuard lock(mSyncSetMutex);
723 	return mSyncSet.find(sync) != mSyncSet.end();
724 }
725 
getMinSwapInterval() const726 EGLint Display::getMinSwapInterval() const
727 {
728 	return mMinSwapInterval;
729 }
730 
getMaxSwapInterval() const731 EGLint Display::getMaxSwapInterval() const
732 {
733 	return mMaxSwapInterval;
734 }
735 
getEGLDisplay() const736 EGLDisplay Display::getEGLDisplay() const
737 {
738 	return eglDisplay;
739 }
740 
getNativeDisplay() const741 void *Display::getNativeDisplay() const
742 {
743 	return nativeDisplay;
744 }
745 
createSharedImage(Image * image)746 EGLImageKHR Display::createSharedImage(Image *image)
747 {
748 	return reinterpret_cast<EGLImageKHR>((intptr_t)mSharedImageNameSpace.allocate(image));
749 }
750 
destroySharedImage(EGLImageKHR image)751 bool Display::destroySharedImage(EGLImageKHR image)
752 {
753 	GLuint name = (GLuint)reinterpret_cast<intptr_t>(image);
754 	Image *eglImage = mSharedImageNameSpace.find(name);
755 
756 	if(!eglImage)
757 	{
758 		return false;
759 	}
760 
761 	eglImage->destroyShared();
762 	mSharedImageNameSpace.remove(name);
763 
764 	return true;
765 }
766 
getSharedImage(EGLImageKHR image)767 Image *Display::getSharedImage(EGLImageKHR image)
768 {
769 	GLuint name = (GLuint)reinterpret_cast<intptr_t>(image);
770 	return mSharedImageNameSpace.find(name);
771 }
772 
getDisplayFormat() const773 sw::Format Display::getDisplayFormat() const
774 {
775 	#if defined(_WIN32)
776 		HDC deviceContext = GetDC(0);
777 		unsigned int bpp = ::GetDeviceCaps(deviceContext, BITSPIXEL);
778 		ReleaseDC(0, deviceContext);
779 
780 		switch(bpp)
781 		{
782 		case 32: return sw::FORMAT_X8R8G8B8;
783 		case 24: return sw::FORMAT_R8G8B8;
784 		case 16: return sw::FORMAT_R5G6B5;
785 		default: UNREACHABLE(bpp);   // Unexpected display mode color depth
786 		}
787 	#elif defined(__ANDROID__)
788 		static const char *const framebuffer[] =
789 		{
790 			"/dev/graphics/fb0",
791 			"/dev/fb0",
792 			0
793 		};
794 
795 		for(int i = 0; framebuffer[i]; i++)
796 		{
797 			int fd = open(framebuffer[i], O_RDONLY, 0);
798 
799 			if(fd != -1)
800 			{
801 				struct fb_var_screeninfo info;
802 				int io = ioctl(fd, FBIOGET_VSCREENINFO, &info);
803 				close(fd);
804 
805 				if(io >= 0)
806 				{
807 					switch(info.bits_per_pixel)
808 					{
809 					case 16:
810 						return sw::FORMAT_R5G6B5;
811 					case 32:
812 						if(info.red.length    == 8 && info.red.offset    == 16 &&
813 						   info.green.length  == 8 && info.green.offset  == 8  &&
814 						   info.blue.length   == 8 && info.blue.offset   == 0  &&
815 						   info.transp.length == 0)
816 						{
817 							return sw::FORMAT_X8R8G8B8;
818 						}
819 						if(info.red.length    == 8 && info.red.offset    == 0  &&
820 						   info.green.length  == 8 && info.green.offset  == 8  &&
821 						   info.blue.length   == 8 && info.blue.offset   == 16 &&
822 						   info.transp.length == 0)
823 						{
824 							return sw::FORMAT_X8B8G8R8;
825 						}
826 						if(info.red.length    == 8 && info.red.offset    == 16 &&
827 						   info.green.length  == 8 && info.green.offset  == 8  &&
828 						   info.blue.length   == 8 && info.blue.offset   == 0  &&
829 						   info.transp.length == 8 && info.transp.offset == 24)
830 						{
831 							return sw::FORMAT_A8R8G8B8;
832 						}
833 						if(info.red.length    == 8 && info.red.offset    == 0  &&
834 						   info.green.length  == 8 && info.green.offset  == 8  &&
835 						   info.blue.length   == 8 && info.blue.offset   == 16 &&
836 						   info.transp.length == 8 && info.transp.offset == 24)
837 						{
838 							return sw::FORMAT_A8B8G8R8;
839 						}
840 						else UNIMPLEMENTED();
841 					default:
842 						UNIMPLEMENTED();
843 					}
844 				}
845 			}
846 		}
847 
848 		// No framebuffer device found, or we're in user space
849 		return sw::FORMAT_X8B8G8R8;
850 	#elif defined(USE_X11)
851 		if(nativeDisplay)
852 		{
853 			Screen *screen = libX11->XDefaultScreenOfDisplay((::Display*)nativeDisplay);
854 			unsigned int bpp = libX11->XPlanesOfScreen(screen);
855 
856 			switch(bpp)
857 			{
858 			case 32: return sw::FORMAT_X8R8G8B8;
859 			case 24: return sw::FORMAT_R8G8B8;
860 			case 16: return sw::FORMAT_R5G6B5;
861 			default: UNREACHABLE(bpp);   // Unexpected display mode color depth
862 			}
863 		}
864 		else
865 		{
866 			return sw::FORMAT_X8R8G8B8;
867 		}
868 	#elif defined(__linux__)  // Non X11 linux is headless only
869 		return sw::FORMAT_A8B8G8R8;
870 	#elif defined(__APPLE__)
871 		return sw::FORMAT_A8B8G8R8;
872 	#elif defined(__Fuchsia__)
873 		return sw::FORMAT_A8B8G8R8;
874 	#else
875 		#error "Display::isValidWindow unimplemented for this platform"
876 	#endif
877 
878 	return sw::FORMAT_X8R8G8B8;
879 }
880 
881 }
882