mesa: reimplement dispatch table no-op function handling
authorBrian Paul <brianp@vmware.com>
Fri, 13 Mar 2015 17:43:44 +0000 (11:43 -0600)
committerBrian Paul <brianp@vmware.com>
Wed, 18 Mar 2015 15:01:50 +0000 (09:01 -0600)
Use the new _glapi_new_nop_table() and _glapi_set_nop_handler() to
improve how we handle calling no-op GL functions.

If there's a current context for the calling thread, generate a
GL_INVALID_OPERATION error.  This will happen if the app calls an
unimplemented extension function or it calls an illegal function
between glBegin/glEnd.

If there's no current context, print an error to stdout if it's a debug
build.

The dispatch_sanity.cpp file has some previous checks removed since
the _mesa_generic_nop() function no longer exists.

This fixes the piglit gl-1.0-dlist-begin-end and gl-1.0-beginend-coverage
tests on Windows.

Reviewed-by: Jose Fonseca <jfonseca@vmware.com>
src/mesa/main/context.c
src/mesa/main/context.h
src/mesa/main/tests/dispatch_sanity.cpp

index 22c2341d64fbff0e3b636eb17901887491853eab..e7d1f4d352aa8203cafa7d4370047ed493135578 100644 (file)
@@ -882,18 +882,35 @@ update_default_objects(struct gl_context *ctx)
 
 
 /**
- * This is the default function we plug into all dispatch table slots
- * This helps prevents a segfault when someone calls a GL function without
- * first checking if the extension's supported.
+ * This function is called by the glapi no-op functions.  For each OpenGL
+ * function/entrypoint there's a simple no-op function.  These "no-op"
+ * functions call this function.
+ *
+ * If there's a current OpenGL context for the calling thread, we record a
+ * GL_INVALID_OPERATION error.  This can happen either because the app's
+ * calling an unsupported extension function, or calling an illegal function
+ * (such as glClear between glBegin/glEnd).
+ *
+ * If there's no current OpenGL context for the calling thread, we can
+ * print a message to stderr.
+ *
+ * \param name  the name of the OpenGL function, without the "gl" prefix
  */
-int
-_mesa_generic_nop(void)
+static void
+nop_handler(const char *name)
 {
    GET_CURRENT_CONTEXT(ctx);
-   _mesa_error(ctx, GL_INVALID_OPERATION,
-               "unsupported function called "
-               "(unsupported extension or deprecated function?)");
-   return 0;
+   if (ctx) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "gl%s(invalid call)", name);
+   }
+#if defined(DEBUG)
+   else if (getenv("MESA_DEBUG") || getenv("LIBGL_DEBUG")) {
+      fprintf(stderr,
+              "GL User Error: gl%s called without a rendering context\n",
+              name);
+      fflush(stderr);
+   }
+#endif
 }
 
 
@@ -909,13 +926,10 @@ nop_glFlush(void)
 #endif
 
 
-extern void (*__glapi_noop_table[])(void);
-
-
 /**
- * Allocate and initialize a new dispatch table.  All the dispatch
- * function pointers will point at the _mesa_generic_nop() function
- * which raises GL_INVALID_OPERATION.
+ * Allocate and initialize a new dispatch table.  The table will be
+ * populated with pointers to "no-op" functions.  In turn, the no-op
+ * functions will call nop_handler() above.
  */
 struct _glapi_table *
 _mesa_alloc_dispatch_table(void)
@@ -926,23 +940,10 @@ _mesa_alloc_dispatch_table(void)
     * DRI drivers.
     */
    GLint numEntries = MAX2(_glapi_get_dispatch_table_size(), _gloffset_COUNT);
-   struct _glapi_table *table;
-
-   table = malloc(numEntries * sizeof(_glapi_proc));
-   if (table) {
-      _glapi_proc *entry = (_glapi_proc *) table;
-      GLint i;
-      for (i = 0; i < numEntries; i++) {
-#if defined(_WIN32)
-         /* FIXME: This will not generate an error, but at least it won't
-          * corrupt the stack like _mesa_generic_nop does. */
-         entry[i] = __glapi_noop_table[i];
-#else
-         entry[i] = (_glapi_proc) _mesa_generic_nop;
-#endif
-      }
+   struct _glapi_table *table = _glapi_new_nop_table(numEntries);
 
 #if defined(_WIN32)
+   if (table) {
       /* This is a special case for Windows in the event that
        * wglGetProcAddress is called between glBegin/End().
        *
@@ -960,8 +961,11 @@ _mesa_alloc_dispatch_table(void)
        * assertion passes and the test continues.
        */
       SET_Flush(table, nop_glFlush);
-#endif
    }
+#endif
+
+   _glapi_set_nop_handler(nop_handler);
+
    return table;
 }
 
index d5650877ed048c37f5d9e6e51a593bda6b1c6acf..1cd89a84af66fabc89ac3b558bba6ea7faafc2b3 100644 (file)
@@ -175,9 +175,6 @@ _mesa_finish(struct gl_context *ctx);
 extern void
 _mesa_flush(struct gl_context *ctx);
 
-extern int
-_mesa_generic_nop(void);
-
 extern void GLAPIENTRY
 _mesa_Finish( void );
 
index 5d849d4ddb03f76819e7217d78935447db19416b..59ebb21443fe333aa1cbab7d28573e7fe6baa9c8 100644 (file)
@@ -119,20 +119,14 @@ offset_to_proc_name_safe(unsigned offset)
 }
 
 /* Scan through the dispatch table and check that all the functions in
- * _glapi_proc *table exist. When found, set their pointers in the table
- * to _mesa_generic_nop.  */
+ * _glapi_proc *table exist.
+ */
 static void
 validate_functions(struct gl_context *ctx, const struct function *function_table)
 {
    _glapi_proc *table = (_glapi_proc *) ctx->Exec;
 
    for (unsigned i = 0; function_table[i].name != NULL; i++) {
-      /* The context version is >= the GL version where the
-         function was introduced. Therefore, the function cannot
-         be set to the nop function.
-       */
-      bool cant_be_nop = ctx->Version >= function_table[i].Version;
-
       const int offset = (function_table[i].offset != -1)
          ? function_table[i].offset
          : _glapi_get_proc_offset(function_table[i].name);
@@ -142,27 +136,6 @@ validate_functions(struct gl_context *ctx, const struct function *function_table
       ASSERT_EQ(offset,
                 _glapi_get_proc_offset(function_table[i].name))
          << "Function: " << function_table[i].name;
-      if (cant_be_nop) {
-         EXPECT_NE((_glapi_proc) _mesa_generic_nop, table[offset])
-            << "Function: " << function_table[i].name
-            << " at offset " << offset;
-      }
-
-      table[offset] = (_glapi_proc) _mesa_generic_nop;
-   }
-}
-
-/* Scan through the table and ensure that there is nothing except
- * _mesa_generic_nop (as set by validate_functions().  */
-static void
-validate_nops(struct gl_context *ctx)
-{
-   _glapi_proc *table = (_glapi_proc *) ctx->Exec;
-
-   const unsigned size = _glapi_get_dispatch_table_size();
-   for (unsigned i = 0; i < size; i++) {
-      EXPECT_EQ((_glapi_proc) _mesa_generic_nop, table[i])
-         << "i = " << i << " (" << offset_to_proc_name_safe(i) << ")";
    }
 }
 
@@ -170,21 +143,18 @@ TEST_F(DispatchSanity_test, GL31_CORE)
 {
    SetUpCtx(API_OPENGL_CORE, 31);
    validate_functions(&ctx, gl_core_functions_possible);
-   validate_nops(&ctx);
 }
 
 TEST_F(DispatchSanity_test, GLES11)
 {
    SetUpCtx(API_OPENGLES, 11);
    validate_functions(&ctx, gles11_functions_possible);
-   validate_nops(&ctx);
 }
 
 TEST_F(DispatchSanity_test, GLES2)
 {
    SetUpCtx(API_OPENGLES2, 20);
    validate_functions(&ctx, gles2_functions_possible);
-   validate_nops(&ctx);
 }
 
 TEST_F(DispatchSanity_test, GLES3)
@@ -192,7 +162,6 @@ TEST_F(DispatchSanity_test, GLES3)
    SetUpCtx(API_OPENGLES2, 30);
    validate_functions(&ctx, gles2_functions_possible);
    validate_functions(&ctx, gles3_functions_possible);
-   validate_nops(&ctx);
 }
 
 const struct function gl_core_functions_possible[] = {