Add GetProcAddress to OpenGL control interface

R=jamesr@chromium.org
BUG=

Review URL: https://codereview.chromium.org/1354353002 .
diff --git a/mojo/BUILD.gn b/mojo/BUILD.gn
index f83617f..b016b74 100644
--- a/mojo/BUILD.gn
+++ b/mojo/BUILD.gn
@@ -58,6 +58,7 @@
     "//mojo/services/view_manager/public/cpp/tests:mojo_view_manager_lib_unittests",
     "//mojo/tests:mojo_task_tracker_perftests",
     "//mojo/tools:message_generator",
+    "//mojo/gles2:mgl_unittests",
     "//mojo/gpu:apptests",
     "//mojo/services/files/public/c:apptests",
   ]
diff --git a/mojo/gles2/BUILD.gn b/mojo/gles2/BUILD.gn
index ee32ab1..bb67923 100644
--- a/mojo/gles2/BUILD.gn
+++ b/mojo/gles2/BUILD.gn
@@ -2,6 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//testing/test.gni")
 import("//mojo/public/tools/bindings/mojom.gni")
 
 config("mojo_use_gles2") {
@@ -79,3 +80,22 @@
     "//mojo/public/cpp/system",
   ]
 }
+
+test("mgl_unittests") {
+  deps = [
+    ":mgl",
+    "//base",
+    "//base/test:test_support",
+    "//mojo/edk/system",
+    "//mojo/edk/test:run_all_unittests",
+    "//mojo/edk/test:test_support_impl",
+    "//mojo/public/c/gpu:MGL",
+    "//mojo/public/c/test_support:test_support",
+    "//mojo/public/cpp/environment:standalone",
+    "//testing/gtest:gtest",
+  ]
+
+  sources = [
+    "mgl_unittest.cc",
+  ]
+}
diff --git a/mojo/gles2/control_thunks_impl.cc b/mojo/gles2/control_thunks_impl.cc
index 81cad38..67e4bbb 100644
--- a/mojo/gles2/control_thunks_impl.cc
+++ b/mojo/gles2/control_thunks_impl.cc
@@ -7,6 +7,15 @@
 #include "mojo/gles2/gles2_context.h"
 #include "mojo/public/cpp/system/message_pipe.h"
 
+extern "C" {
+
+#define VISIT_GL_CALL(Function, ReturnType, PARAMETERS, ARGUMENTS) \
+  ReturnType MojoGLES2gl##Function PARAMETERS;
+#include "mojo/public/platform/native/gles2/call_visitor.h"
+#undef VISIT_GL_CALL
+
+}
+
 namespace gles2 {
 
 // static
@@ -52,6 +61,18 @@
   current_context_tls_.Get()->interface()->SwapBuffers();
 }
 
+
+MGLMustCastToProperFunctionPointerType ControlThunksImpl::GetProcAddress(
+    const char* name) {
+#define VISIT_GL_CALL(Function, ReturnType, PARAMETERS, ARGUMENTS) \
+  if (!strcmp(name, "gl"#Function)) \
+    return reinterpret_cast<MGLMustCastToProperFunctionPointerType>( \
+        MojoGLES2gl##Function);
+#include "mojo/public/platform/native/gles2/call_visitor.h"
+#undef VISIT_GL_CALL
+  return nullptr;
+}
+
 void* ControlThunksImpl::GetGLES2Interface(MGLContext context) {
   GLES2Context* client = reinterpret_cast<GLES2Context*>(context);
   DCHECK(client);
diff --git a/mojo/gles2/control_thunks_impl.h b/mojo/gles2/control_thunks_impl.h
index 95b9c08..c240939 100644
--- a/mojo/gles2/control_thunks_impl.h
+++ b/mojo/gles2/control_thunks_impl.h
@@ -45,6 +45,8 @@
 
   void SwapBuffers();
 
+  MGLMustCastToProperFunctionPointerType GetProcAddress(const char* procname);
+
   void* GetGLES2Interface(MGLContext context);
 
   void SignalSyncPoint(uint32_t sync_point,
diff --git a/mojo/gles2/mgl_impl.cc b/mojo/gles2/mgl_impl.cc
index 0423a69..7cad469 100644
--- a/mojo/gles2/mgl_impl.cc
+++ b/mojo/gles2/mgl_impl.cc
@@ -49,4 +49,8 @@
   return gles2::ControlThunksImpl::Get()->SwapBuffers();
 }
 
+MGLMustCastToProperFunctionPointerType MGLGetProcAddress(const char* procname) {
+  return gles2::ControlThunksImpl::Get()->GetProcAddress(procname);
+}
+
 }  // extern "C"
diff --git a/mojo/gles2/mgl_unittest.cc b/mojo/gles2/mgl_unittest.cc
new file mode 100644
index 0000000..244044e
--- /dev/null
+++ b/mojo/gles2/mgl_unittest.cc
@@ -0,0 +1,20 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "mojo/public/c/gpu/MGL/mgl.h"
+
+#include <string.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+namespace {
+
+TEST(MGLTest, GetProcAddress) {
+  EXPECT_EQ(nullptr, MGLGetProcAddress(""));
+  EXPECT_NE(nullptr, MGLGetProcAddress("glActiveTexture"));
+}
+
+}  // namespace
+}  // namespace mojo
diff --git a/mojo/public/c/gpu/MGL/mgl.h b/mojo/public/c/gpu/MGL/mgl.h
index 2633976..1b5a9a4 100644
--- a/mojo/public/c/gpu/MGL/mgl.h
+++ b/mojo/public/c/gpu/MGL/mgl.h
@@ -55,6 +55,13 @@
 // if there is none.
 MGLContext MGLGetCurrentContext(void);
 
+// Returns GL function usable in any context that advertise the corresponding
+// extension in their GL_EXTENSIONS string, or null for functions that the
+// implementation does not support. The implementation only advertises GL
+// functions.
+// |name| is the name of the GL function.
+MGLMustCastToProperFunctionPointerType MGLGetProcAddress(const char* name);
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif
diff --git a/mojo/public/c/gpu/MGL/mgl_types.h b/mojo/public/c/gpu/MGL/mgl_types.h
index 2253456..b28aee6 100644
--- a/mojo/public/c/gpu/MGL/mgl_types.h
+++ b/mojo/public/c/gpu/MGL/mgl_types.h
@@ -15,6 +15,10 @@
 typedef void (*MGLContextLostCallback)(void* closure);
 typedef void (*MGLSignalSyncPointCallback)(void* closure);
 
+// This is a generic function pointer type, which must be cast to the proper
+// type and calling convention before use.
+typedef void (*MGLMustCastToProperFunctionPointerType)(void);
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif
diff --git a/mojo/public/platform/native/gles2/call_visitor.h b/mojo/public/platform/native/gles2/call_visitor.h
new file mode 100644
index 0000000..76d8ed0
--- /dev/null
+++ b/mojo/public/platform/native/gles2/call_visitor.h
@@ -0,0 +1,20 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Note: This header intentionally does not have a header guard.
+
+#include "mojo/public/platform/native/gles2/call_visitor_autogen.h"
+#include "mojo/public/platform/native/gles2/call_visitor_chromium_bind_uniform_location_autogen.h"
+#include "mojo/public/platform/native/gles2/call_visitor_chromium_map_sub_autogen.h"
+#include "mojo/public/platform/native/gles2/call_visitor_chromium_miscellaneous_autogen.h"
+#include "mojo/public/platform/native/gles2/call_visitor_chromium_resize_autogen.h"
+#include "mojo/public/platform/native/gles2/call_visitor_chromium_sync_point_autogen.h"
+#include "mojo/public/platform/native/gles2/call_visitor_chromium_texture_mailbox_autogen.h"
+#include "mojo/public/platform/native/gles2/call_visitor_ext_debug_marker_autogen.h"
+#include "mojo/public/platform/native/gles2/call_visitor_ext_discard_framebuffer_autogen.h"
+#include "mojo/public/platform/native/gles2/call_visitor_ext_multisampled_render_to_texture_autogen.h"
+#include "mojo/public/platform/native/gles2/call_visitor_ext_occlusion_query_autogen.h"
+#include "mojo/public/platform/native/gles2/call_visitor_ext_texture_storage_autogen.h"
+#include "mojo/public/platform/native/gles2/call_visitor_khr_blend_equation_advanced_autogen.h"
+#include "mojo/public/platform/native/gles2/call_visitor_oes_vertex_array_object_autogen.h"
diff --git a/mojo/public/platform/native/mgl_thunks.c b/mojo/public/platform/native/mgl_thunks.c
index 2e8e9d8..9b74f0c 100644
--- a/mojo/public/platform/native/mgl_thunks.c
+++ b/mojo/public/platform/native/mgl_thunks.c
@@ -43,3 +43,8 @@
     g_thunks = *mgl_thunks;
   return sizeof(g_thunks);
 }
+
+MGLMustCastToProperFunctionPointerType MGLGetProcAddress(const char* name) {
+  assert(g_thunks.MGLGetProcAddress);
+  return g_thunks.MGLGetProcAddress(name);
+}
diff --git a/mojo/public/platform/native/mgl_thunks.h b/mojo/public/platform/native/mgl_thunks.h
index 8a56474..0c4e099 100644
--- a/mojo/public/platform/native/mgl_thunks.h
+++ b/mojo/public/platform/native/mgl_thunks.h
@@ -27,6 +27,7 @@
   void (*MGLDestroyContext)(MGLContext context);
   void (*MGLMakeCurrent)(MGLContext context);
   MGLContext (*MGLGetCurrentContext)(void);
+  MGLMustCastToProperFunctionPointerType (*MGLGetProcAddress)(const char* name);
 };
 #pragma pack(pop)
 
@@ -39,6 +40,7 @@
       MGLDestroyContext,
       MGLMakeCurrent,
       MGLGetCurrentContext,
+      MGLGetProcAddress,
   };
 
   return mgl_thunks;