Ping - on this series.

-Brian

On 03/13/2015 01:22 PM, Brian Paul wrote:
_glapi_new_nop_table() creates a new dispatch table populated with
pointers to no-op functions.

_glapi_set_nop_handler() is used to register a callback function which
will be called from each of the no-op functions.

Now we always generate a separate no-op function for each GL entrypoint.
This allows us to do proper stack clean-up for Windows __stdcall and
lets us report the actual function name in error messages.  Before this
change, for non-Windows release builds we used a single no-op function
for all entrypoints.
---
  src/mapi/glapi/glapi.h     | 11 ++++++
  src/mapi/glapi/glapi_nop.c | 84 ++++++++++++++++++++++++++--------------------
  src/mapi/mapi_glapi.c      | 23 +++++++++++++
  src/mapi/table.c           | 23 ++++++++++---
  src/mapi/table.h           |  8 +++++
  5 files changed, 108 insertions(+), 41 deletions(-)

diff --git a/src/mapi/glapi/glapi.h b/src/mapi/glapi/glapi.h
index 8d991fb..673295b 100644
--- a/src/mapi/glapi/glapi.h
+++ b/src/mapi/glapi/glapi.h
@@ -80,6 +80,9 @@ extern "C" {
  #endif

  typedef void (*_glapi_proc)(void);
+
+typedef void (*_glapi_nop_handler_proc)(const char *name);
+
  struct _glapi_table;


@@ -159,6 +162,14 @@ _GLAPI_EXPORT struct _glapi_table *
  _glapi_create_table_from_handle(void *handle, const char *symbol_prefix);


+_GLAPI_EXPORT void
+_glapi_set_nop_handler(_glapi_nop_handler_proc func);
+
+/** Return pointer to new dispatch table filled with no-op functions */
+_GLAPI_EXPORT struct _glapi_table *
+_glapi_new_nop_table(unsigned num_entries);
+
+
  /** Deprecated function */
  _GLAPI_EXPORT unsigned long
  _glthread_GetID(void);
diff --git a/src/mapi/glapi/glapi_nop.c b/src/mapi/glapi/glapi_nop.c
index 628276e..0041ed5 100644
--- a/src/mapi/glapi/glapi_nop.c
+++ b/src/mapi/glapi/glapi_nop.c
@@ -30,14 +30,21 @@
   * This file defines a special dispatch table which is loaded with no-op
   * functions.
   *
- * When there's no current rendering context, calling a GL function like
- * glBegin() is a no-op.  Apps should never normally do this.  So as a
- * debugging aid, each of the no-op functions will emit a warning to
- * stderr if the MESA_DEBUG or LIBGL_DEBUG env var is set.
+ * Mesa can register a "no-op handler function" which will be called in
+ * the event that a no-op function is called.
+ *
+ * In the past, the dispatch table was loaded with pointers to a single
+ * no-op function.  But that broke on Windows because the GL entrypoints
+ * use __stdcall convention.  __stdcall means the callee cleans up the
+ * stack.  So one no-op function can't properly clean up the stack.  This
+ * would lead to crashes.
+ *
+ * Another benefit of unique no-op functions is we can accurately report
+ * the function's name in an error message.
   */


-
+#include <string.h>
  #include "glapi/glapi_priv.h"


@@ -51,25 +58,32 @@ _glapi_set_warning_func(_glapi_proc func)
  {
  }

-/*
- * When GLAPIENTRY is __stdcall (i.e. Windows), the stack is popped by the
- * callee making the number/type of arguments significant.
+
+/**
+ * We'll jump though this function pointer whenever a no-op function
+ * is called.
   */
-#if defined(_WIN32) || defined(DEBUG)
+static _glapi_nop_handler_proc nop_handler = NULL;
+
+
+/**
+ * Register the no-op handler call-back function.
+ */
+void
+_glapi_set_nop_handler(_glapi_nop_handler_proc func)
+{
+   nop_handler = func;
+}
+

  /**
   * Called by each of the no-op GL entrypoints.
   */
-static int
-Warn(const char *func)
+static void
+nop(const char *func)
  {
-#if defined(DEBUG)
-   if (getenv("MESA_DEBUG") || getenv("LIBGL_DEBUG")) {
-      fprintf(stderr, "GL User Error: gl%s called without a rendering 
context\n",
-              func);
-   }
-#endif
-   return 0;
+   if (nop_handler)
+      nop_handler(func);
  }


@@ -79,7 +93,8 @@ Warn(const char *func)
  static GLint
  NoOpUnused(void)
  {
-   return Warn(" function");
+   nop("unused GL entry point");
+   return 0;
  }

  /*
@@ -89,31 +104,28 @@ NoOpUnused(void)
  #define KEYWORD1_ALT static
  #define KEYWORD2 GLAPIENTRY
  #define NAME(func)  NoOp##func
-#define DISPATCH(func, args, msg)  Warn(#func);
-#define RETURN_DISPATCH(func, args, msg)  Warn(#func); return 0
+#define DISPATCH(func, args, msg)  nop(#func);
+#define RETURN_DISPATCH(func, args, msg)  nop(#func); return 0


  /*
   * Defines for the table of no-op entry points.
   */
  #define TABLE_ENTRY(name) (_glapi_proc) NoOp##name
+#define DISPATCH_TABLE_NAME __glapi_noop_table
+#define UNUSED_TABLE_NAME __unused_noop_functions
+
+#include "glapi/glapitemp.h"

-#else

-static int
-NoOpGeneric(void)
+/** Return pointer to new dispatch table filled with no-op functions */
+struct _glapi_table *
+_glapi_new_nop_table(unsigned num_entries)
  {
-   if (getenv("MESA_DEBUG") || getenv("LIBGL_DEBUG")) {
-      fprintf(stderr, "GL User Error: calling GL function without a rendering 
context\n");
+   struct _glapi_table *table = malloc(num_entries * sizeof(_glapi_proc));
+   if (table) {
+      memcpy(table, __glapi_noop_table,
+             num_entries * sizeof(_glapi_proc));
     }
-   return 0;
+   return table;
  }
-
-#define TABLE_ENTRY(name) (_glapi_proc) NoOpGeneric
-
-#endif
-
-#define DISPATCH_TABLE_NAME __glapi_noop_table
-#define UNUSED_TABLE_NAME __unused_noop_functions
-
-#include "glapi/glapitemp.h"
diff --git a/src/mapi/mapi_glapi.c b/src/mapi/mapi_glapi.c
index 127dfaf..70605f3 100644
--- a/src/mapi/mapi_glapi.c
+++ b/src/mapi/mapi_glapi.c
@@ -27,6 +27,7 @@
   */

  #include <string.h>
+#include <stdlib.h>
  #include "glapi/glapi.h"
  #include "u_current.h"
  #include "table.h" /* for MAPI_TABLE_NUM_SLOTS */
@@ -222,6 +223,28 @@ _glapi_get_proc_name(unsigned int offset)
     return stub ? stub_get_name(stub) : NULL;
  }

+/** Return pointer to new dispatch table filled with no-op functions */
+struct _glapi_table *
+_glapi_new_nop_table(unsigned num_entries)
+{
+   struct _glapi_table *table;
+
+   if (num_entries > MAPI_TABLE_NUM_SLOTS)
+      num_entries = MAPI_TABLE_NUM_SLOTS;
+
+   table = malloc(num_entries * sizeof(mapi_func));
+   if (table) {
+      memcpy(table, table_noop_array, num_entries * sizeof(mapi_func));
+   }
+   return table;
+}
+
+void
+_glapi_set_nop_handler(_glapi_nop_handler_proc func)
+{
+   table_set_noop_handler(func);
+}
+
  /**
   * This is a deprecated function which should not be used anymore.
   * It's only present to satisfy linking with older versions of libGL.
diff --git a/src/mapi/table.c b/src/mapi/table.c
index 0d28666..7487501 100644
--- a/src/mapi/table.c
+++ b/src/mapi/table.c
@@ -30,16 +30,29 @@

  #include "table.h"

+static nop_handler_proc nop_handler = NULL;
+
+void
+table_set_noop_handler(nop_handler_proc func)
+{
+   nop_handler = func;
+}
+
  static void
  noop_warn(const char *name)
  {
-   static int debug = -1;
+   if (nop_handler) {
+      nop_handler(name);
+   }
+   else {
+      static int debug = -1;

-   if (debug < 0)
-      debug = (getenv("MESA_DEBUG") || getenv("LIBGL_DEBUG"));
+      if (debug < 0)
+         debug = (getenv("MESA_DEBUG") || getenv("LIBGL_DEBUG"));

-   if (debug)
-      fprintf(stderr, "%s is no-op\n", name);
+      if (debug)
+         fprintf(stderr, "%s is no-op\n", name);
+   }
  }

  static int
diff --git a/src/mapi/table.h b/src/mapi/table.h
index e2d6ef0..a1af40c 100644
--- a/src/mapi/table.h
+++ b/src/mapi/table.h
@@ -41,6 +41,14 @@ struct mapi_table;

  extern const mapi_func table_noop_array[];

+
+typedef void (*nop_handler_proc)(const char *name);
+
+
+void
+table_set_noop_handler(nop_handler_proc func);
+
+
  /**
   * Get the no-op dispatch table.
   */


_______________________________________________
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/mesa-dev

Reply via email to