void SWRenderDisplayWindowProvider::create(DisplayWindowSite *new_site, const DisplayWindowDescription &description)
{
	site = new_site;
	flip_timer_set = false;

	refresh_rate = description.get_refresh_rate();
	if (!refresh_rate)	// Default the refresh rate to 100 if not defined
		refresh_rate = 100;
	swap_interval = description.get_swap_interval();

#ifdef WIN32
	window.create(site, description);
#elif !defined(__APPLE__)
	::Display *disp = window.get_display();

	int bpp = 24;
	XVisualInfo visual_info;
	int screen =  DefaultScreen(disp); //RootWindow(disp,  0);

	if (XMatchVisualInfo(disp, screen, 24, TrueColor, &visual_info)) {bpp = 24;} 
	else if (XMatchVisualInfo(disp, screen, 16, TrueColor, &visual_info)) {bpp = 16;}
	else if (XMatchVisualInfo(disp, screen, 15, TrueColor, &visual_info)) {bpp = 15;}
	else if (XMatchVisualInfo(disp, screen, 32, TrueColor, &visual_info)) {bpp = 32;}
	else if (XMatchVisualInfo(disp, screen, 8, PseudoColor, &visual_info)) {bpp = 8;}
	else if (XMatchVisualInfo(disp, screen, 8, GrayScale, &visual_info)) {bpp = 8;}
	else if (XMatchVisualInfo(disp, screen, 8, StaticGray, &visual_info)) {bpp = 8;}
	else if (XMatchVisualInfo(disp, screen, 1, StaticGray, &visual_info)) {bpp = 1;}
	else { throw Exception("Cannot match visual info"); }

	window.create(&visual_info, site, description);
#endif
	gc = GraphicContext(new SWRenderGraphicContextProvider(this));
}
void D3DDisplayWindowProvider::create(DisplayWindowSite *new_site, const DisplayWindowDescription &description)
{
	site = new_site;

	if (device)
		D3DShareList::device_destroyed(device);
	info_queue.clear();
	debug.clear();
	back_buffer_rtv.clear();
	fake_front_buffer.clear();
	back_buffer.clear();
	swap_chain.clear();
	device_context.clear();
	device.clear();

	window.create(site, description);

	use_fake_front_buffer = description.is_update_supported();

	D3D_FEATURE_LEVEL request_levels[] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0 };
	DXGI_SWAP_CHAIN_DESC swap_chain_description;
	swap_chain_description.BufferCount = description.get_flipping_buffers();
	swap_chain_description.BufferDesc.Width = 0;
	swap_chain_description.BufferDesc.Height = 0;
	swap_chain_description.BufferDesc.RefreshRate.Numerator = 60;
	swap_chain_description.BufferDesc.RefreshRate.Denominator = 1;
	swap_chain_description.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
	swap_chain_description.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
	swap_chain_description.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
	swap_chain_description.SampleDesc.Count = 1;
	swap_chain_description.SampleDesc.Quality = 0;
	swap_chain_description.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
	swap_chain_description.OutputWindow = window.get_hwnd();
	swap_chain_description.Windowed = TRUE; // Seems the documentation wants us to call IDXGISwapChain::SetFullscreenState afterwards
	swap_chain_description.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
	swap_chain_description.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;

	bool debug_mode = false; // To do: fetch this from DisplayWindowDescription using same method as clanGL (or maybe promote debug flag to clanDisplay?)

	UINT device_flags = 0;
	if (debug_mode)
		device_flags |= D3D11_CREATE_DEVICE_DEBUG;

	MutexSection mutex_lock(&d3d11_mutex);
	if (d3d11_dll == 0)
	{
		d3d11_dll = LoadLibrary(L"d3d11.dll");
		if (d3d11_dll == 0)
			throw Exception("Unable to load d3d11.dll");

		try
		{
			d3d11_createdeviceandswapchain = reinterpret_cast<FuncD3D11CreateDeviceAndSwapChain>(GetProcAddress(d3d11_dll, "D3D11CreateDeviceAndSwapChain"));
			if (d3d11_createdeviceandswapchain == 0)
				throw Exception("D3D11CreateDeviceAndSwapChain function not found!");

		}
		catch (...)
		{
			CloseHandle(d3d11_dll);
			d3d11_dll = 0;
			d3d11_createdeviceandswapchain = 0;
			throw;
		}
	}
	HRESULT result = d3d11_createdeviceandswapchain(
		0,
		D3D_DRIVER_TYPE_HARDWARE,
		0,
		device_flags,
		request_levels, 3,
		D3D11_SDK_VERSION,
		&swap_chain_description,
		swap_chain.output_variable(),
		device.output_variable(),
		&feature_level,
		device_context.output_variable());
	D3DTarget::throw_if_failed("D3D11CreateDeviceAndSwapChain failed", result);

	if (debug_mode)
	{
		result = device->QueryInterface(__uuidof(ID3D11Debug), (void**)debug.output_variable());
		if (FAILED(result))
			debug.clear(); // No debug info available.  Should this throw an exception instead?
		result = device->QueryInterface(__uuidof(ID3D11InfoQueue), (void**)info_queue.output_variable());
		if (FAILED(result))
			info_queue.clear(); // No debug messages available.
	}

	// Disable mouse lag (no, 3 frames rendered ahead is NOT a good default Microsoft):
	ComPtr<IDXGIDevice1> dxgi_device;
	result = swap_chain->GetDevice(__uuidof(IDXGIDevice1), (void**)dxgi_device.output_variable());
	D3DTarget::throw_if_failed("Unable to retrieve IDXGIDevice1 from swap chain", result);
	dxgi_device->SetMaximumFrameLatency(1);

	create_swap_chain_buffers();

	gc = GraphicContext(new D3DGraphicContextProvider(this, description));

	if (description.is_fullscreen())
		swap_chain->SetFullscreenState(TRUE, 0);

	D3DGraphicContextProvider *d3d_gc = static_cast<D3DGraphicContextProvider*>(gc.get_provider());
	d3d_gc->standard_programs = StandardPrograms(gc);
}
	void OpenGLWindowProvider::create(DisplayWindowSite *new_site, const DisplayWindowDescription &desc)
	{
		window_handle = desc.get_handle();
		if (window_handle.window == nullptr)
			throw Exception("Window handle must exist in the display description");

		ANativeWindow *window = window_handle.window;

		const EGLint attribs[] = {
			EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
			EGL_BLUE_SIZE, 8,
			EGL_GREEN_SIZE, 8,
			EGL_RED_SIZE, 8,
			EGL_NONE
		};
		EGLint format;
		EGLint numConfigs;
		EGLConfig config;

		display = eglGetDisplay(EGL_DEFAULT_DISPLAY);

		eglInitialize(display, 0, 0);

		/* Here, the application chooses the configuration it desires. In this
		* sample, we have a very simplified selection process, where we pick
		* the first EGLConfig that matches our criteria */
		if (!eglChooseConfig(display, attribs, &config, 1, &numConfigs))
			throw Exception("eglChooseConfig failed");
		if (numConfigs < 1)
			throw Exception("Found configs failed");

		/* EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is
		* guaranteed to be accepted by ANativeWindow_setBuffersGeometry().
		* As soon as we picked a EGLConfig, we can safely reconfigure the
		* ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID. */
		eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);

		ANativeWindow_setBuffersGeometry(window, 0, 0, format);

		surface = eglCreateWindowSurface(display, config, window, NULL);
		if (surface == EGL_NO_SURFACE)
			throw Exception("eglCreateWindowSurface failed");

		context = eglCreateContext(display, config, NULL, NULL);
		if (context == EGL_NO_CONTEXT)
			throw Exception("eglCreateWindowSurface failed");

		if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)
		{
			throw Exception("Unable to eglMakeCurrent");
		}
		bool use_gl3;
		int desc_version_major = opengl_desc.get_version_major();
		int desc_version_minor = opengl_desc.get_version_minor();

		// Do not attempt GL3, if not requested that version
		if (desc_version_major < 3)
		{
			use_gl3 = false;
		}
		else if (!opengl_desc.get_allow_lower_versions())	// Else, if we do not allow lower versions, only attempt GL3
		{
			use_gl3 = true;
		}
		else
		{
			// Choose the target depending on the current opengl version
			int gl_version_major;
			int gl_version_minor;
			get_opengl_version(gl_version_major, gl_version_minor);
			if (gl_version_major < 3)
			{
				use_gl3 = false;
			}
			else
			{
				use_gl3 = true;
			}

		}

		if (use_gl3)
		{
			using_gl3 = true;
			gc = GraphicContext(new GL3GraphicContextProvider(this));
		}
		else
		{
			using_gl3 = false;
			gc = GraphicContext(new GL1GraphicContextProvider(this));
		}
		swap_interval = desc.get_swap_interval();
		if (swap_interval != -1)
			eglSwapInterval(display, swap_interval);

	}
	void OpenGLWindowProvider::create(DisplayWindowSite *new_site, const DisplayWindowDescription &desc)
	{
		site = new_site;
		fullscreen = desc.is_fullscreen();

		win32_window.create(site, desc);

		if (!opengl_context)
		{
			HWND handle = win32_window.get_hwnd();
			dwm_layered = false;

			if (desc.is_layered() && !DwmFunctions::is_composition_enabled())
			{
				create_shadow_window(handle);
			}
			else
			{
				if (desc.is_layered())
					dwm_layered = true;
			}

			desc.is_layered() ? double_buffered = false : double_buffered = true;	// Only can use Layered windows that are single buffered with OpenGL (via shadow window) ( PFD_DOUBLEBUFFER_DONTCARE set in OpenGLCreationHelper::set_multisampling_pixel_format)

			device_context = GetDC(handle);

			HGLRC share_context = get_share_context();

			OpenGLCreationHelper helper(handle, device_context);
			helper.set_multisampling_pixel_format(desc);

			int gl_major = opengl_desc.get_version_major();
			int gl_minor = opengl_desc.get_version_minor();
			if (opengl_desc.get_allow_lower_versions() == false)
			{
				opengl_context = helper.create_opengl3_context(share_context, gl_major, gl_minor, opengl_desc);
				if (!opengl_context)
					throw Exception(string_format("This application requires OpenGL %1.%2 or above. Try updating your drivers, or upgrade to a newer graphics card.", gl_major, gl_minor));
			}
			else
			{
				static const char opengl_version_list[] =
				{
					// Clanlib supported version pairs
					4, 5,
					4, 4,
					4, 3,
					4, 2,
					4, 1,
					4, 0,
					3, 3,
					3, 2,
					3, 1,
					3, 0,
					0, 0,	// End of list
				};

				const char *opengl_version_list_ptr = opengl_version_list;
				do
				{
					int major = *(opengl_version_list_ptr++);
					if (major == 0)
						break;

					int minor = *(opengl_version_list_ptr++);

					// Find the appropriate version in the list
					if (major > gl_major)
						continue;

					if (major == gl_major)
					{
						if (minor > gl_minor)
							continue;
					}

					opengl_context = helper.create_opengl3_context(share_context, major, minor, opengl_desc);
				} while (!opengl_context);

				if (!opengl_context)
					opengl_context = helper.create_opengl2_context(share_context);

				if (!opengl_context)
					throw Exception("This application requires OpenGL. Try updating your drivers, or upgrade to a newer graphics card.");

			}

			bool use_gl3;
			int desc_version_major = opengl_desc.get_version_major();
			int desc_version_minor = opengl_desc.get_version_minor();

			// Do not attempt GL3, if not requested that version
			if (desc_version_major < 3)
			{
				use_gl3 = false;
			}
			else if (!opengl_desc.get_allow_lower_versions())	// Else, if we do not allow lower versions, only attempt GL3
			{
				use_gl3 = true;
			}
			else
			{
				// Choose the target depending on the current opengl version
				int gl_version_major;
				int gl_version_minor;
				get_opengl_version(gl_version_major, gl_version_minor);
				if (gl_version_major < 3)
				{
					use_gl3 = false;
				}
				else
				{
					use_gl3 = true;
				}

			}

			if (use_gl3)
			{
				using_gl3 = true;
				gc = GraphicContext(new GL3GraphicContextProvider(this));
			}
			else
			{
				using_gl3 = false;
				gc = GraphicContext(new GL1GraphicContextProvider(this));
			}
		}

		wglSwapIntervalEXT = (ptr_wglSwapIntervalEXT)OpenGL::get_proc_address("wglSwapIntervalEXT");
		swap_interval = desc.get_swap_interval();
		if (wglSwapIntervalEXT && swap_interval != -1)
			wglSwapIntervalEXT(swap_interval);
	}