Home | History | Annotate | Download | only in libEGL
      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 #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:
     51 	DisplayImplementation(EGLDisplay dpy, void *nativeDisplay) : Display(dpy, nativeDisplay) {}
     52 	~DisplayImplementation() override {}
     53 
     54 	Image *getSharedImage(EGLImageKHR name) override
     55 	{
     56 		return Display::getSharedImage(name);
     57 	}
     58 };
     59 
     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(__linux__) && !defined(__ANDROID__)
     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 
     82 Display::Display(EGLDisplay eglDisplay, void *nativeDisplay) : eglDisplay(eglDisplay), nativeDisplay(nativeDisplay)
     83 {
     84 	mMinSwapInterval = 1;
     85 	mMaxSwapInterval = 1;
     86 }
     87 
     88 Display::~Display()
     89 {
     90 	terminate();
     91 
     92 	#if defined(__linux__) && !defined(__ANDROID__)
     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 static void cpuid(int registers[4], int info)
    109 {
    110 	#if defined(__i386__) || defined(__x86_64__)
    111 		#if defined(_WIN32)
    112 			__cpuid(registers, info);
    113 		#else
    114 			__asm volatile("cpuid": "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3]): "a" (info));
    115 		#endif
    116 	#else
    117 		registers[0] = 0;
    118 		registers[1] = 0;
    119 		registers[2] = 0;
    120 		registers[3] = 0;
    121 	#endif
    122 }
    123 
    124 static bool detectSSE()
    125 {
    126 	int registers[4];
    127 	cpuid(registers, 1);
    128 	return (registers[3] & 0x02000000) != 0;
    129 }
    130 
    131 bool Display::initialize()
    132 {
    133 	if(isInitialized())
    134 	{
    135 		return true;
    136 	}
    137 
    138 	#if defined(__i386__) || defined(__x86_64__)
    139 		if(!detectSSE())
    140 		{
    141 			return false;
    142 		}
    143 	#endif
    144 
    145 	mMinSwapInterval = 0;
    146 	mMaxSwapInterval = 4;
    147 
    148 	const int samples[] =
    149 	{
    150 		0,
    151 		2,
    152 		4
    153 	};
    154 
    155 	const sw::Format renderTargetFormats[] =
    156 	{
    157 	//	sw::FORMAT_A1R5G5B5,
    158 	//  sw::FORMAT_A2R10G10B10,   // The color_ramp conformance test uses ReadPixels with UNSIGNED_BYTE causing it to think that rendering skipped a colour value.
    159 		sw::FORMAT_A8R8G8B8,
    160 		sw::FORMAT_A8B8G8R8,
    161 		sw::FORMAT_R5G6B5,
    162 	//  sw::FORMAT_X1R5G5B5,      // Has no compatible OpenGL ES renderbuffer format
    163 		sw::FORMAT_X8R8G8B8,
    164 		sw::FORMAT_X8B8G8R8
    165 	};
    166 
    167 	const sw::Format depthStencilFormats[] =
    168 	{
    169 		sw::FORMAT_NULL,
    170 	//  sw::FORMAT_D16_LOCKABLE,
    171 		sw::FORMAT_D32,
    172 	//  sw::FORMAT_D15S1,
    173 		sw::FORMAT_D24S8,
    174 		sw::FORMAT_D24X8,
    175 	//  sw::FORMAT_D24X4S4,
    176 		sw::FORMAT_D16,
    177 	//  sw::FORMAT_D32F_LOCKABLE,
    178 	//  sw::FORMAT_D24FS8
    179 	};
    180 
    181 	sw::Format currentDisplayFormat = getDisplayFormat();
    182 	ConfigSet configSet;
    183 
    184 	for(unsigned int samplesIndex = 0; samplesIndex < sizeof(samples) / sizeof(int); samplesIndex++)
    185 	{
    186 		for(unsigned int formatIndex = 0; formatIndex < sizeof(renderTargetFormats) / sizeof(sw::Format); formatIndex++)
    187 		{
    188 			sw::Format renderTargetFormat = renderTargetFormats[formatIndex];
    189 
    190 			for(unsigned int depthStencilIndex = 0; depthStencilIndex < sizeof(depthStencilFormats) / sizeof(sw::Format); depthStencilIndex++)
    191 			{
    192 				sw::Format depthStencilFormat = depthStencilFormats[depthStencilIndex];
    193 
    194 				configSet.add(currentDisplayFormat, mMinSwapInterval, mMaxSwapInterval, renderTargetFormat, depthStencilFormat, samples[samplesIndex]);
    195 			}
    196 		}
    197 	}
    198 
    199 	// Give the sorted configs a unique ID and store them internally
    200 	EGLint index = 1;
    201 	for(ConfigSet::Iterator config = configSet.mSet.begin(); config != configSet.mSet.end(); config++)
    202 	{
    203 		Config configuration = *config;
    204 		configuration.mConfigID = index;
    205 		index++;
    206 
    207 		mConfigSet.mSet.insert(configuration);
    208 	}
    209 
    210 	if(!isInitialized())
    211 	{
    212 		terminate();
    213 
    214 		return false;
    215 	}
    216 
    217 	return true;
    218 }
    219 
    220 void Display::terminate()
    221 {
    222 	while(!mSurfaceSet.empty())
    223 	{
    224 		destroySurface(*mSurfaceSet.begin());
    225 	}
    226 
    227 	while(!mContextSet.empty())
    228 	{
    229 		destroyContext(*mContextSet.begin());
    230 	}
    231 
    232 	while(!mSharedImageNameSpace.empty())
    233 	{
    234 		destroySharedImage(reinterpret_cast<EGLImageKHR>((intptr_t)mSharedImageNameSpace.firstName()));
    235 	}
    236 }
    237 
    238 bool Display::getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig)
    239 {
    240 	return mConfigSet.getConfigs(configs, attribList, configSize, numConfig);
    241 }
    242 
    243 bool Display::getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value)
    244 {
    245 	const egl::Config *configuration = mConfigSet.get(config);
    246 
    247 	switch(attribute)
    248 	{
    249 	case EGL_BUFFER_SIZE:                *value = configuration->mBufferSize;               break;
    250 	case EGL_ALPHA_SIZE:                 *value = configuration->mAlphaSize;                break;
    251 	case EGL_BLUE_SIZE:                  *value = configuration->mBlueSize;                 break;
    252 	case EGL_GREEN_SIZE:                 *value = configuration->mGreenSize;                break;
    253 	case EGL_RED_SIZE:                   *value = configuration->mRedSize;                  break;
    254 	case EGL_DEPTH_SIZE:                 *value = configuration->mDepthSize;                break;
    255 	case EGL_STENCIL_SIZE:               *value = configuration->mStencilSize;              break;
    256 	case EGL_CONFIG_CAVEAT:              *value = configuration->mConfigCaveat;             break;
    257 	case EGL_CONFIG_ID:                  *value = configuration->mConfigID;                 break;
    258 	case EGL_LEVEL:                      *value = configuration->mLevel;                    break;
    259 	case EGL_NATIVE_RENDERABLE:          *value = configuration->mNativeRenderable;         break;
    260 	case EGL_NATIVE_VISUAL_ID:           *value = configuration->mNativeVisualID;           break;
    261 	case EGL_NATIVE_VISUAL_TYPE:         *value = configuration->mNativeVisualType;         break;
    262 	case EGL_SAMPLES:                    *value = configuration->mSamples;                  break;
    263 	case EGL_SAMPLE_BUFFERS:             *value = configuration->mSampleBuffers;            break;
    264 	case EGL_SURFACE_TYPE:               *value = configuration->mSurfaceType;              break;
    265 	case EGL_TRANSPARENT_TYPE:           *value = configuration->mTransparentType;          break;
    266 	case EGL_TRANSPARENT_BLUE_VALUE:     *value = configuration->mTransparentBlueValue;     break;
    267 	case EGL_TRANSPARENT_GREEN_VALUE:    *value = configuration->mTransparentGreenValue;    break;
    268 	case EGL_TRANSPARENT_RED_VALUE:      *value = configuration->mTransparentRedValue;      break;
    269 	case EGL_BIND_TO_TEXTURE_RGB:        *value = configuration->mBindToTextureRGB;         break;
    270 	case EGL_BIND_TO_TEXTURE_RGBA:       *value = configuration->mBindToTextureRGBA;        break;
    271 	case EGL_MIN_SWAP_INTERVAL:          *value = configuration->mMinSwapInterval;          break;
    272 	case EGL_MAX_SWAP_INTERVAL:          *value = configuration->mMaxSwapInterval;          break;
    273 	case EGL_LUMINANCE_SIZE:             *value = configuration->mLuminanceSize;            break;
    274 	case EGL_ALPHA_MASK_SIZE:            *value = configuration->mAlphaMaskSize;            break;
    275 	case EGL_COLOR_BUFFER_TYPE:          *value = configuration->mColorBufferType;          break;
    276 	case EGL_RENDERABLE_TYPE:            *value = configuration->mRenderableType;           break;
    277 	case EGL_MATCH_NATIVE_PIXMAP:        *value = EGL_FALSE; UNIMPLEMENTED();               break;
    278 	case EGL_CONFORMANT:                 *value = configuration->mConformant;               break;
    279 	case EGL_MAX_PBUFFER_WIDTH:          *value = configuration->mMaxPBufferWidth;          break;
    280 	case EGL_MAX_PBUFFER_HEIGHT:         *value = configuration->mMaxPBufferHeight;         break;
    281 	case EGL_MAX_PBUFFER_PIXELS:         *value = configuration->mMaxPBufferPixels;         break;
    282 	case EGL_RECORDABLE_ANDROID:         *value = configuration->mRecordableAndroid;        break;
    283 	case EGL_FRAMEBUFFER_TARGET_ANDROID: *value = configuration->mFramebufferTargetAndroid; break;
    284 	default:
    285 		return false;
    286 	}
    287 
    288 	return true;
    289 }
    290 
    291 EGLSurface Display::createWindowSurface(EGLNativeWindowType window, EGLConfig config, const EGLint *attribList)
    292 {
    293 	const Config *configuration = mConfigSet.get(config);
    294 
    295 	if(attribList)
    296 	{
    297 		while(*attribList != EGL_NONE)
    298 		{
    299 			switch(attribList[0])
    300 			{
    301 			case EGL_RENDER_BUFFER:
    302 				switch(attribList[1])
    303 				{
    304 				case EGL_BACK_BUFFER:
    305 					break;
    306 				case EGL_SINGLE_BUFFER:
    307 					return error(EGL_BAD_MATCH, EGL_NO_SURFACE);   // Rendering directly to front buffer not supported
    308 				default:
    309 					return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
    310 				}
    311 				break;
    312 			case EGL_VG_COLORSPACE:
    313 				return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
    314 			case EGL_VG_ALPHA_FORMAT:
    315 				return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
    316 			default:
    317 				return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
    318 			}
    319 
    320 			attribList += 2;
    321 		}
    322 	}
    323 
    324 	if(hasExistingWindowSurface(window))
    325 	{
    326 		return error(EGL_BAD_ALLOC, EGL_NO_SURFACE);
    327 	}
    328 
    329 	Surface *surface = new WindowSurface(this, configuration, window);
    330 
    331 	if(!surface->initialize())
    332 	{
    333 		surface->release();
    334 		return EGL_NO_SURFACE;
    335 	}
    336 
    337 	surface->addRef();
    338 	mSurfaceSet.insert(surface);
    339 
    340 	return success(surface);
    341 }
    342 
    343 EGLSurface Display::createPBufferSurface(EGLConfig config, const EGLint *attribList, EGLClientBuffer clientBuffer)
    344 {
    345 	EGLint width = -1, height = -1, ioSurfacePlane = -1;
    346 	EGLenum textureFormat = EGL_NO_TEXTURE;
    347 	EGLenum textureTarget = EGL_NO_TEXTURE;
    348 	EGLenum clientBufferFormat = EGL_NO_TEXTURE;
    349 	EGLenum clientBufferType = EGL_NO_TEXTURE;
    350 	EGLBoolean largestPBuffer = EGL_FALSE;
    351 	const Config *configuration = mConfigSet.get(config);
    352 
    353 	if(attribList)
    354 	{
    355 		while(*attribList != EGL_NONE)
    356 		{
    357 			switch(attribList[0])
    358 			{
    359 			case EGL_WIDTH:
    360 				width = attribList[1];
    361 				break;
    362 			case EGL_HEIGHT:
    363 				height = attribList[1];
    364 				break;
    365 			case EGL_LARGEST_PBUFFER:
    366 				largestPBuffer = attribList[1];
    367 				break;
    368 			case EGL_TEXTURE_FORMAT:
    369 				switch(attribList[1])
    370 				{
    371 				case EGL_NO_TEXTURE:
    372 				case EGL_TEXTURE_RGB:
    373 				case EGL_TEXTURE_RGBA:
    374 					textureFormat = attribList[1];
    375 					break;
    376 				default:
    377 					return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
    378 				}
    379 				break;
    380 			case EGL_TEXTURE_INTERNAL_FORMAT_ANGLE:
    381 				switch(attribList[1])
    382 				{
    383 				case GL_RED:
    384 				case GL_R16UI:
    385 				case GL_RG:
    386 				case GL_BGRA_EXT:
    387 				case GL_RGBA:
    388 					clientBufferFormat = attribList[1];
    389 					break;
    390 				default:
    391 					return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
    392 				}
    393 				break;
    394 			case EGL_TEXTURE_TYPE_ANGLE:
    395 				switch(attribList[1])
    396 				{
    397 				case GL_UNSIGNED_BYTE:
    398 				case GL_UNSIGNED_SHORT:
    399 				case GL_HALF_FLOAT_OES:
    400 				case GL_HALF_FLOAT:
    401 					clientBufferType = attribList[1];
    402 					break;
    403 				default:
    404 					return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
    405 				}
    406 				break;
    407 			case EGL_IOSURFACE_PLANE_ANGLE:
    408 				if(attribList[1] < 0)
    409 				{
    410 					return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
    411 				}
    412 				ioSurfacePlane = attribList[1];
    413 				break;
    414 			case EGL_TEXTURE_TARGET:
    415 				switch(attribList[1])
    416 				{
    417 				case EGL_NO_TEXTURE:
    418 				case EGL_TEXTURE_2D:
    419 				case EGL_TEXTURE_RECTANGLE_ANGLE:
    420 					textureTarget = attribList[1];
    421 					break;
    422 				default:
    423 					return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
    424 				}
    425 				break;
    426 			case EGL_MIPMAP_TEXTURE:
    427 				if(attribList[1] != EGL_FALSE)
    428 				{
    429 					return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
    430 				}
    431 				break;
    432 			case EGL_VG_COLORSPACE:
    433 				return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
    434 			case EGL_VG_ALPHA_FORMAT:
    435 				return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
    436 			default:
    437 				return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
    438 			}
    439 
    440 			attribList += 2;
    441 		}
    442 	}
    443 
    444 	if(width < 0 || height < 0)
    445 	{
    446 		return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
    447 	}
    448 
    449 	if(width == 0 || height == 0)
    450 	{
    451 		return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
    452 	}
    453 
    454 	if((textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) ||
    455 	   (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE))
    456 	{
    457 		return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
    458 	}
    459 
    460 	if(!(configuration->mSurfaceType & EGL_PBUFFER_BIT))
    461 	{
    462 		return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
    463 	}
    464 
    465 	if(clientBuffer)
    466 	{
    467 		switch(clientBufferType)
    468 		{
    469 		case GL_UNSIGNED_BYTE:
    470 			switch(clientBufferFormat)
    471 			{
    472 			case GL_RED:
    473 			case GL_RG:
    474 			case GL_BGRA_EXT:
    475 				break;
    476 			case GL_R16UI:
    477 			case GL_RGBA:
    478 				return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
    479 			default:
    480 				return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
    481 			}
    482 			break;
    483 		case GL_UNSIGNED_SHORT:
    484 			switch(clientBufferFormat)
    485 			{
    486 			case GL_R16UI:
    487 				break;
    488 			case GL_RED:
    489 			case GL_RG:
    490 			case GL_BGRA_EXT:
    491 			case GL_RGBA:
    492 				return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
    493 			default:
    494 				return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
    495 			}
    496 			break;
    497 		case GL_HALF_FLOAT_OES:
    498 		case GL_HALF_FLOAT:
    499 			switch(clientBufferFormat)
    500 			{
    501 			case GL_RGBA:
    502 				break;
    503 			case GL_RED:
    504 			case GL_R16UI:
    505 			case GL_RG:
    506 			case GL_BGRA_EXT:
    507 				return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
    508 			default:
    509 				return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
    510 			}
    511 			break;
    512 		default:
    513 			return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
    514 		}
    515 
    516 		if(ioSurfacePlane < 0)
    517 		{
    518 			return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
    519 		}
    520 
    521 		if(textureFormat != EGL_TEXTURE_RGBA)
    522 		{
    523 			return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
    524 		}
    525 
    526 		if(textureTarget != EGL_TEXTURE_RECTANGLE_ANGLE)
    527 		{
    528 			return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
    529 		}
    530 
    531 #if defined(__APPLE__)
    532 		IOSurfaceRef ioSurface = reinterpret_cast<IOSurfaceRef>(clientBuffer);
    533 		size_t planeCount = IOSurfaceGetPlaneCount(ioSurface);
    534 		if((static_cast<size_t>(width) > IOSurfaceGetWidthOfPlane(ioSurface, ioSurfacePlane)) ||
    535 		   (static_cast<size_t>(height) > IOSurfaceGetHeightOfPlane(ioSurface, ioSurfacePlane)) ||
    536 		   ((planeCount != 0) && static_cast<size_t>(ioSurfacePlane) >= planeCount))
    537 		{
    538 			return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
    539 		}
    540 #endif
    541 	}
    542 	else
    543 	{
    544 		if((textureFormat == EGL_TEXTURE_RGB && configuration->mBindToTextureRGB != EGL_TRUE) ||
    545 		   ((textureFormat == EGL_TEXTURE_RGBA && configuration->mBindToTextureRGBA != EGL_TRUE)))
    546 		{
    547 			return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
    548 		}
    549 	}
    550 
    551 	Surface *surface = new PBufferSurface(this, configuration, width, height, textureFormat, textureTarget, clientBufferFormat, clientBufferType, largestPBuffer, clientBuffer, ioSurfacePlane);
    552 
    553 	if(!surface->initialize())
    554 	{
    555 		surface->release();
    556 		return EGL_NO_SURFACE;
    557 	}
    558 
    559 	surface->addRef();
    560 	mSurfaceSet.insert(surface);
    561 
    562 	return success(surface);
    563 }
    564 
    565 EGLContext Display::createContext(EGLConfig configHandle, const egl::Context *shareContext, EGLint clientVersion)
    566 {
    567 	const egl::Config *config = mConfigSet.get(configHandle);
    568 	egl::Context *context = nullptr;
    569 
    570 	if(clientVersion == 1 && config->mRenderableType & EGL_OPENGL_ES_BIT)
    571 	{
    572 		if(libGLES_CM)
    573 		{
    574 			context = libGLES_CM->es1CreateContext(this, shareContext, config);
    575 		}
    576 	}
    577 	else if((clientVersion == 2 && config->mRenderableType & EGL_OPENGL_ES2_BIT) ||
    578 	        (clientVersion == 3 && config->mRenderableType & EGL_OPENGL_ES3_BIT))
    579 	{
    580 		if(libGLESv2)
    581 		{
    582 			context = libGLESv2->es2CreateContext(this, shareContext, clientVersion, config);
    583 		}
    584 	}
    585 	else
    586 	{
    587 		return error(EGL_BAD_CONFIG, EGL_NO_CONTEXT);
    588 	}
    589 
    590 	if(!context)
    591 	{
    592 		return error(EGL_BAD_ALLOC, EGL_NO_CONTEXT);
    593 	}
    594 
    595 	context->addRef();
    596 	mContextSet.insert(context);
    597 
    598 	return success(context);
    599 }
    600 
    601 EGLSyncKHR Display::createSync(Context *context)
    602 {
    603 	FenceSync *fenceSync = new egl::FenceSync(context);
    604 	LockGuard lock(mSyncSetMutex);
    605 	mSyncSet.insert(fenceSync);
    606 	return fenceSync;
    607 }
    608 
    609 void Display::destroySurface(egl::Surface *surface)
    610 {
    611 	surface->release();
    612 	mSurfaceSet.erase(surface);
    613 
    614 	if(surface == getCurrentDrawSurface())
    615 	{
    616 		setCurrentDrawSurface(nullptr);
    617 	}
    618 
    619 	if(surface == getCurrentReadSurface())
    620 	{
    621 		setCurrentReadSurface(nullptr);
    622 	}
    623 }
    624 
    625 void Display::destroyContext(egl::Context *context)
    626 {
    627 	context->release();
    628 	mContextSet.erase(context);
    629 
    630 	if(context == getCurrentContext())
    631 	{
    632 		setCurrentContext(nullptr);
    633 		setCurrentDrawSurface(nullptr);
    634 		setCurrentReadSurface(nullptr);
    635 	}
    636 }
    637 
    638 void Display::destroySync(FenceSync *sync)
    639 {
    640 	{
    641 		LockGuard lock(mSyncSetMutex);
    642 		mSyncSet.erase(sync);
    643 	}
    644 	delete sync;
    645 }
    646 
    647 bool Display::isInitialized() const
    648 {
    649 	return mConfigSet.size() > 0;
    650 }
    651 
    652 bool Display::isValidConfig(EGLConfig config)
    653 {
    654 	return mConfigSet.get(config) != nullptr;
    655 }
    656 
    657 bool Display::isValidContext(egl::Context *context)
    658 {
    659 	return mContextSet.find(context) != mContextSet.end();
    660 }
    661 
    662 bool Display::isValidSurface(egl::Surface *surface)
    663 {
    664 	return mSurfaceSet.find(surface) != mSurfaceSet.end();
    665 }
    666 
    667 bool Display::isValidWindow(EGLNativeWindowType window)
    668 {
    669 	#if defined(_WIN32)
    670 		return IsWindow(window) == TRUE;
    671 	#elif defined(__ANDROID__)
    672 		if(!window)
    673 		{
    674 			ALOGE("%s called with window==NULL %s:%d", __FUNCTION__, __FILE__, __LINE__);
    675 			return false;
    676 		}
    677 		if(static_cast<ANativeWindow*>(window)->common.magic != ANDROID_NATIVE_WINDOW_MAGIC)
    678 		{
    679 			ALOGE("%s called with window==%p bad magic %s:%d", __FUNCTION__, window, __FILE__, __LINE__);
    680 			return false;
    681 		}
    682 		return true;
    683 	#elif defined(__linux__)
    684 		if(nativeDisplay)
    685 		{
    686 			XWindowAttributes windowAttributes;
    687 			Status status = libX11->XGetWindowAttributes((::Display*)nativeDisplay, window, &windowAttributes);
    688 
    689 			return status != 0;
    690 		}
    691 		return false;
    692 	#elif defined(__APPLE__)
    693 		return sw::OSX::IsValidWindow(window);
    694 	#elif defined(__Fuchsia__)
    695 		// TODO(crbug.com/800951): Integrate with Mozart.
    696 		return true;
    697 	#else
    698 		#error "Display::isValidWindow unimplemented for this platform"
    699 		return false;
    700 	#endif
    701 }
    702 
    703 bool Display::hasExistingWindowSurface(EGLNativeWindowType window)
    704 {
    705 	for(const auto &surface : mSurfaceSet)
    706 	{
    707 		if(surface->isWindowSurface())
    708 		{
    709 			if(surface->getWindowHandle() == window)
    710 			{
    711 				return true;
    712 			}
    713 		}
    714 	}
    715 
    716 	return false;
    717 }
    718 
    719 bool Display::isValidSync(FenceSync *sync)
    720 {
    721 	LockGuard lock(mSyncSetMutex);
    722 	return mSyncSet.find(sync) != mSyncSet.end();
    723 }
    724 
    725 EGLint Display::getMinSwapInterval() const
    726 {
    727 	return mMinSwapInterval;
    728 }
    729 
    730 EGLint Display::getMaxSwapInterval() const
    731 {
    732 	return mMaxSwapInterval;
    733 }
    734 
    735 EGLDisplay Display::getEGLDisplay() const
    736 {
    737 	return eglDisplay;
    738 }
    739 
    740 void *Display::getNativeDisplay() const
    741 {
    742 	return nativeDisplay;
    743 }
    744 
    745 EGLImageKHR Display::createSharedImage(Image *image)
    746 {
    747 	return reinterpret_cast<EGLImageKHR>((intptr_t)mSharedImageNameSpace.allocate(image));
    748 }
    749 
    750 bool Display::destroySharedImage(EGLImageKHR image)
    751 {
    752 	GLuint name = (GLuint)reinterpret_cast<intptr_t>(image);
    753 	Image *eglImage = mSharedImageNameSpace.find(name);
    754 
    755 	if(!eglImage)
    756 	{
    757 		return false;
    758 	}
    759 
    760 	eglImage->destroyShared();
    761 	mSharedImageNameSpace.remove(name);
    762 
    763 	return true;
    764 }
    765 
    766 Image *Display::getSharedImage(EGLImageKHR image)
    767 {
    768 	GLuint name = (GLuint)reinterpret_cast<intptr_t>(image);
    769 	return mSharedImageNameSpace.find(name);
    770 }
    771 
    772 sw::Format Display::getDisplayFormat() const
    773 {
    774 	#if defined(_WIN32)
    775 		HDC deviceContext = GetDC(0);
    776 		unsigned int bpp = ::GetDeviceCaps(deviceContext, BITSPIXEL);
    777 		ReleaseDC(0, deviceContext);
    778 
    779 		switch(bpp)
    780 		{
    781 		case 32: return sw::FORMAT_X8R8G8B8;
    782 		case 24: return sw::FORMAT_R8G8B8;
    783 		case 16: return sw::FORMAT_R5G6B5;
    784 		default: UNREACHABLE(bpp);   // Unexpected display mode color depth
    785 		}
    786 	#elif defined(__ANDROID__)
    787 		static const char *const framebuffer[] =
    788 		{
    789 			"/dev/graphics/fb0",
    790 			"/dev/fb0",
    791 			0
    792 		};
    793 
    794 		for(int i = 0; framebuffer[i]; i++)
    795 		{
    796 			int fd = open(framebuffer[i], O_RDONLY, 0);
    797 
    798 			if(fd != -1)
    799 			{
    800 				struct fb_var_screeninfo info;
    801 				int io = ioctl(fd, FBIOGET_VSCREENINFO, &info);
    802 				close(fd);
    803 
    804 				if(io >= 0)
    805 				{
    806 					switch(info.bits_per_pixel)
    807 					{
    808 					case 16:
    809 						return sw::FORMAT_R5G6B5;
    810 					case 32:
    811 						if(info.red.length    == 8 && info.red.offset    == 16 &&
    812 						   info.green.length  == 8 && info.green.offset  == 8  &&
    813 						   info.blue.length   == 8 && info.blue.offset   == 0  &&
    814 						   info.transp.length == 0)
    815 						{
    816 							return sw::FORMAT_X8R8G8B8;
    817 						}
    818 						if(info.red.length    == 8 && info.red.offset    == 0  &&
    819 						   info.green.length  == 8 && info.green.offset  == 8  &&
    820 						   info.blue.length   == 8 && info.blue.offset   == 16 &&
    821 						   info.transp.length == 0)
    822 						{
    823 							return sw::FORMAT_X8B8G8R8;
    824 						}
    825 						if(info.red.length    == 8 && info.red.offset    == 16 &&
    826 						   info.green.length  == 8 && info.green.offset  == 8  &&
    827 						   info.blue.length   == 8 && info.blue.offset   == 0  &&
    828 						   info.transp.length == 8 && info.transp.offset == 24)
    829 						{
    830 							return sw::FORMAT_A8R8G8B8;
    831 						}
    832 						if(info.red.length    == 8 && info.red.offset    == 0  &&
    833 						   info.green.length  == 8 && info.green.offset  == 8  &&
    834 						   info.blue.length   == 8 && info.blue.offset   == 16 &&
    835 						   info.transp.length == 8 && info.transp.offset == 24)
    836 						{
    837 							return sw::FORMAT_A8B8G8R8;
    838 						}
    839 						else UNIMPLEMENTED();
    840 					default:
    841 						UNIMPLEMENTED();
    842 					}
    843 				}
    844 			}
    845 		}
    846 
    847 		// No framebuffer device found, or we're in user space
    848 		return sw::FORMAT_X8B8G8R8;
    849 	#elif defined(__linux__)
    850 		if(nativeDisplay)
    851 		{
    852 			Screen *screen = libX11->XDefaultScreenOfDisplay((::Display*)nativeDisplay);
    853 			unsigned int bpp = libX11->XPlanesOfScreen(screen);
    854 
    855 			switch(bpp)
    856 			{
    857 			case 32: return sw::FORMAT_X8R8G8B8;
    858 			case 24: return sw::FORMAT_R8G8B8;
    859 			case 16: return sw::FORMAT_R5G6B5;
    860 			default: UNREACHABLE(bpp);   // Unexpected display mode color depth
    861 			}
    862 		}
    863 		else
    864 		{
    865 			return sw::FORMAT_X8R8G8B8;
    866 		}
    867 	#elif defined(__APPLE__)
    868 		return sw::FORMAT_A8B8G8R8;
    869 	#elif defined(__Fuchsia__)
    870 		return sw::FORMAT_A8B8G8R8;
    871 	#else
    872 		#error "Display::isValidWindow unimplemented for this platform"
    873 	#endif
    874 
    875 	return sw::FORMAT_X8R8G8B8;
    876 }
    877 
    878 }
    879