From 201e36e77d6ca616f75f14d5f1c31f0062ae4366 Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Fri, 13 Mar 2015 10:20:29 -0600 Subject: [PATCH] mapi: add new _glapi_new_nop_table() and _glapi_set_nop_handler() _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. Reviewed-by: Jose Fonseca --- 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 8d991fb3b8a..673295bca46 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 628276e932b..0041ed5a876 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 #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 127dfafac30..70605f3dfa1 100644 --- a/src/mapi/mapi_glapi.c +++ b/src/mapi/mapi_glapi.c @@ -27,6 +27,7 @@ */ #include +#include #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 0d28666181b..748750197c6 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 e2d6ef03d76..a1af40c6fc1 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. */ -- 2.30.2