Implement EGL_KHR_get_all_proc_addresses.

This also improves GetProcAddress performance by using binary search
instead of linear search.

Fixes bug b/20110899

Change-Id: I6c58e17f0580904338e4d806e310cccbec398f28
Reviewed-on: https://swiftshader-review.googlesource.com/15748
Tested-by: Krzysztof Kosiński <krzysio@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/OpenGL/libEGL/libEGL.cpp b/src/OpenGL/libEGL/libEGL.cpp
index 21ef933..08861c2 100644
--- a/src/OpenGL/libEGL/libEGL.cpp
+++ b/src/OpenGL/libEGL/libEGL.cpp
@@ -29,6 +29,7 @@
 #include "Main/libX11.hpp"
 #endif
 
+#include <algorithm>
 #include <string.h>
 
 using namespace egl;
@@ -174,6 +175,7 @@
 	if(dpy == EGL_NO_DISPLAY && name == EGL_EXTENSIONS)
 	{
 		return success(
+			"EGL_KHR_client_get_all_proc_addresses "
 #if defined(__linux__) && !defined(__ANDROID__)
 			"EGL_KHR_platform_gbm "
 			"EGL_KHR_platform_x11 "
@@ -195,6 +197,7 @@
 		return success("OpenGL_ES");
 	case EGL_EXTENSIONS:
 		return success("EGL_KHR_create_context "
+		               "EGL_KHR_get_all_proc_addresses "
 		               "EGL_KHR_gl_texture_2D_image "
 		               "EGL_KHR_gl_texture_cubemap_image "
 		               "EGL_KHR_gl_renderbuffer_image "
@@ -1241,34 +1244,85 @@
 {
 	TRACE("(const char *procname = \"%s\")", procname);
 
-	struct Extension
+	struct Function
 	{
 		const char *name;
 		__eglMustCastToProperFunctionPointerType address;
 	};
 
-	static const Extension eglExtensions[] =
+	struct CompareFunctor
 	{
-		#define EXTENSION(name) {#name, (__eglMustCastToProperFunctionPointerType)name}
-
-		EXTENSION(eglCreateImageKHR),
-		EXTENSION(eglDestroyImageKHR),
-		EXTENSION(eglGetPlatformDisplayEXT),
-		EXTENSION(eglCreatePlatformWindowSurfaceEXT),
-		EXTENSION(eglCreatePlatformPixmapSurfaceEXT),
-		EXTENSION(eglCreateSyncKHR),
-		EXTENSION(eglDestroySyncKHR),
-		EXTENSION(eglClientWaitSyncKHR),
-		EXTENSION(eglGetSyncAttribKHR),
-
-		#undef EXTENSION
+		bool operator()(const Function &a, const Function &b) const
+		{
+			return strcmp(a.name, b.name) < 0;
+		}
 	};
 
-	for(unsigned int ext = 0; ext < sizeof(eglExtensions) / sizeof(Extension); ext++)
+	// This array must be kept sorted with respect to strcmp(), so that binary search works correctly.
+	// The Unix command "LC_COLLATE=C sort" will generate the correct order.
+	static const Function eglFunctions[] =
 	{
-		if(strcmp(procname, eglExtensions[ext].name) == 0)
+		#define FUNCTION(name) {#name, (__eglMustCastToProperFunctionPointerType)name}
+
+		FUNCTION(eglBindAPI),
+		FUNCTION(eglBindTexImage),
+		FUNCTION(eglChooseConfig),
+		FUNCTION(eglClientWaitSyncKHR),
+		FUNCTION(eglCopyBuffers),
+		FUNCTION(eglCreateContext),
+		FUNCTION(eglCreateImageKHR),
+		FUNCTION(eglCreatePbufferFromClientBuffer),
+		FUNCTION(eglCreatePbufferSurface),
+		FUNCTION(eglCreatePixmapSurface),
+		FUNCTION(eglCreatePlatformPixmapSurfaceEXT),
+		FUNCTION(eglCreatePlatformWindowSurfaceEXT),
+		FUNCTION(eglCreateSyncKHR),
+		FUNCTION(eglCreateWindowSurface),
+		FUNCTION(eglDestroyContext),
+		FUNCTION(eglDestroyImageKHR),
+		FUNCTION(eglDestroySurface),
+		FUNCTION(eglDestroySyncKHR),
+		FUNCTION(eglGetConfigAttrib),
+		FUNCTION(eglGetConfigs),
+		FUNCTION(eglGetCurrentContext),
+		FUNCTION(eglGetCurrentDisplay),
+		FUNCTION(eglGetCurrentSurface),
+		FUNCTION(eglGetDisplay),
+		FUNCTION(eglGetError),
+		FUNCTION(eglGetPlatformDisplayEXT),
+		FUNCTION(eglGetProcAddress),
+		FUNCTION(eglGetSyncAttribKHR),
+		FUNCTION(eglInitialize),
+		FUNCTION(eglMakeCurrent),
+		FUNCTION(eglQueryAPI),
+		FUNCTION(eglQueryContext),
+		FUNCTION(eglQueryString),
+		FUNCTION(eglQuerySurface),
+		FUNCTION(eglReleaseTexImage),
+		FUNCTION(eglReleaseThread),
+		FUNCTION(eglSurfaceAttrib),
+		FUNCTION(eglSwapBuffers),
+		FUNCTION(eglSwapInterval),
+		FUNCTION(eglTerminate),
+		FUNCTION(eglWaitClient),
+		FUNCTION(eglWaitGL),
+		FUNCTION(eglWaitNative),
+
+		#undef FUNCTION
+	};
+
+	static const size_t numFunctions = sizeof eglFunctions / sizeof(Function);
+	static const Function *const eglFunctionsEnd = eglFunctions + numFunctions;
+
+	Function needle;
+	needle.name = procname;
+
+	if(procname && strncmp("egl", procname, 3) == 0)
+	{
+		const Function *result = std::lower_bound(eglFunctions, eglFunctionsEnd, needle, CompareFunctor());
+		if (result != eglFunctionsEnd && strcmp(procname, result->name) == 0)
 		{
-			return success((__eglMustCastToProperFunctionPointerType)eglExtensions[ext].address);
+			return success((__eglMustCastToProperFunctionPointerType)result->address);
 		}
 	}