glapi: Encapsulate nop table knowledge in new _mesa_new_nop_table function
[mesa.git] / src / mesa / main / context.c
index 8eb426d5904ea7ad5e9558b28bac4e48f8ba5190..e4faf3d462a618b868083e2159e02a5e26964ee9 100644 (file)
 #include "scissor.h"
 #include "shared.h"
 #include "shaderobj.h"
-#include "simple_list.h"
+#include "shaderimage.h"
+#include "util/simple_list.h"
 #include "state.h"
 #include "stencil.h"
 #include "texcompress_s3tc.h"
 #include "program/prog_print.h"
 #include "math/m_matrix.h"
 #include "main/dispatch.h" /* for _gloffset_COUNT */
+#include "uniforms.h"
+#include "macros.h"
 
 #ifdef USE_SPARC_ASM
 #include "sparc/sparc.h"
@@ -396,6 +399,8 @@ one_time_init( struct gl_context *ctx )
       assert( sizeof(GLint) == 4 );
       assert( sizeof(GLuint) == 4 );
 
+      _mesa_one_time_init_extension_overrides();
+
       _mesa_get_cpu_features();
 
       for (i = 0; i < 256; i++) {
@@ -443,7 +448,7 @@ _mesa_init_current(struct gl_context *ctx)
    GLuint i;
 
    /* Init all to (0,0,0,1) */
-   for (i = 0; i < Elements(ctx->Current.Attrib); i++) {
+   for (i = 0; i < ARRAY_SIZE(ctx->Current.Attrib); i++) {
       ASSIGN_4V( ctx->Current.Attrib[i], 0.0, 0.0, 0.0, 1.0 );
    }
 
@@ -462,7 +467,7 @@ _mesa_init_current(struct gl_context *ctx)
  * Important: drivers should override these with actual limits.
  */
 static void
-init_program_limits(struct gl_context *ctx, gl_shader_stage stage,
+init_program_limits(struct gl_constants *consts, gl_shader_stage stage,
                     struct gl_program_constants *prog)
 {
    prog->MaxInstructions = MAX_PROGRAM_INSTRUCTIONS;
@@ -544,7 +549,7 @@ init_program_limits(struct gl_context *ctx, gl_shader_stage stage,
 
    prog->MaxUniformBlocks = 12;
    prog->MaxCombinedUniformComponents = (prog->MaxUniformComponents +
-                                         ctx->Const.MaxUniformBlockSize / 4 *
+                                         consts->MaxUniformBlockSize / 4 *
                                          prog->MaxUniformBlocks);
 
    prog->MaxAtomicBuffers = 0;
@@ -557,160 +562,168 @@ init_program_limits(struct gl_context *ctx, gl_shader_stage stage,
  * Use defaults from config.h.  The device drivers will often override
  * some of these values (such as number of texture units).
  */
-static void 
-_mesa_init_constants(struct gl_context *ctx)
+void
+_mesa_init_constants(struct gl_constants *consts, gl_api api)
 {
    int i;
-   assert(ctx);
+   assert(consts);
 
    /* Constants, may be overriden (usually only reduced) by device drivers */
-   ctx->Const.MaxTextureMbytes = MAX_TEXTURE_MBYTES;
-   ctx->Const.MaxTextureLevels = MAX_TEXTURE_LEVELS;
-   ctx->Const.Max3DTextureLevels = MAX_3D_TEXTURE_LEVELS;
-   ctx->Const.MaxCubeTextureLevels = MAX_CUBE_TEXTURE_LEVELS;
-   ctx->Const.MaxTextureRectSize = MAX_TEXTURE_RECT_SIZE;
-   ctx->Const.MaxArrayTextureLayers = MAX_ARRAY_TEXTURE_LAYERS;
-   ctx->Const.MaxTextureCoordUnits = MAX_TEXTURE_COORD_UNITS;
-   ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS;
-   ctx->Const.MaxTextureUnits = MIN2(ctx->Const.MaxTextureCoordUnits,
-                                     ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxTextureImageUnits);
-   ctx->Const.MaxTextureMaxAnisotropy = MAX_TEXTURE_MAX_ANISOTROPY;
-   ctx->Const.MaxTextureLodBias = MAX_TEXTURE_LOD_BIAS;
-   ctx->Const.MaxTextureBufferSize = 65536;
-   ctx->Const.TextureBufferOffsetAlignment = 1;
-   ctx->Const.MaxArrayLockSize = MAX_ARRAY_LOCK_SIZE;
-   ctx->Const.SubPixelBits = SUB_PIXEL_BITS;
-   ctx->Const.MinPointSize = MIN_POINT_SIZE;
-   ctx->Const.MaxPointSize = MAX_POINT_SIZE;
-   ctx->Const.MinPointSizeAA = MIN_POINT_SIZE;
-   ctx->Const.MaxPointSizeAA = MAX_POINT_SIZE;
-   ctx->Const.PointSizeGranularity = (GLfloat) POINT_SIZE_GRANULARITY;
-   ctx->Const.MinLineWidth = MIN_LINE_WIDTH;
-   ctx->Const.MaxLineWidth = MAX_LINE_WIDTH;
-   ctx->Const.MinLineWidthAA = MIN_LINE_WIDTH;
-   ctx->Const.MaxLineWidthAA = MAX_LINE_WIDTH;
-   ctx->Const.LineWidthGranularity = (GLfloat) LINE_WIDTH_GRANULARITY;
-   ctx->Const.MaxClipPlanes = 6;
-   ctx->Const.MaxLights = MAX_LIGHTS;
-   ctx->Const.MaxShininess = 128.0;
-   ctx->Const.MaxSpotExponent = 128.0;
-   ctx->Const.MaxViewportWidth = MAX_VIEWPORT_WIDTH;
-   ctx->Const.MaxViewportHeight = MAX_VIEWPORT_HEIGHT;
-   ctx->Const.MinMapBufferAlignment = 64;
+   consts->MaxTextureMbytes = MAX_TEXTURE_MBYTES;
+   consts->MaxTextureLevels = MAX_TEXTURE_LEVELS;
+   consts->Max3DTextureLevels = MAX_3D_TEXTURE_LEVELS;
+   consts->MaxCubeTextureLevels = MAX_CUBE_TEXTURE_LEVELS;
+   consts->MaxTextureRectSize = MAX_TEXTURE_RECT_SIZE;
+   consts->MaxArrayTextureLayers = MAX_ARRAY_TEXTURE_LAYERS;
+   consts->MaxTextureCoordUnits = MAX_TEXTURE_COORD_UNITS;
+   consts->Program[MESA_SHADER_FRAGMENT].MaxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS;
+   consts->MaxTextureUnits = MIN2(consts->MaxTextureCoordUnits,
+                                     consts->Program[MESA_SHADER_FRAGMENT].MaxTextureImageUnits);
+   consts->MaxTextureMaxAnisotropy = MAX_TEXTURE_MAX_ANISOTROPY;
+   consts->MaxTextureLodBias = MAX_TEXTURE_LOD_BIAS;
+   consts->MaxTextureBufferSize = 65536;
+   consts->TextureBufferOffsetAlignment = 1;
+   consts->MaxArrayLockSize = MAX_ARRAY_LOCK_SIZE;
+   consts->SubPixelBits = SUB_PIXEL_BITS;
+   consts->MinPointSize = MIN_POINT_SIZE;
+   consts->MaxPointSize = MAX_POINT_SIZE;
+   consts->MinPointSizeAA = MIN_POINT_SIZE;
+   consts->MaxPointSizeAA = MAX_POINT_SIZE;
+   consts->PointSizeGranularity = (GLfloat) POINT_SIZE_GRANULARITY;
+   consts->MinLineWidth = MIN_LINE_WIDTH;
+   consts->MaxLineWidth = MAX_LINE_WIDTH;
+   consts->MinLineWidthAA = MIN_LINE_WIDTH;
+   consts->MaxLineWidthAA = MAX_LINE_WIDTH;
+   consts->LineWidthGranularity = (GLfloat) LINE_WIDTH_GRANULARITY;
+   consts->MaxClipPlanes = 6;
+   consts->MaxLights = MAX_LIGHTS;
+   consts->MaxShininess = 128.0;
+   consts->MaxSpotExponent = 128.0;
+   consts->MaxViewportWidth = MAX_VIEWPORT_WIDTH;
+   consts->MaxViewportHeight = MAX_VIEWPORT_HEIGHT;
+   consts->MinMapBufferAlignment = 64;
 
    /* Driver must override these values if ARB_viewport_array is supported. */
-   ctx->Const.MaxViewports = 1;
-   ctx->Const.ViewportSubpixelBits = 0;
-   ctx->Const.ViewportBounds.Min = 0;
-   ctx->Const.ViewportBounds.Max = 0;
+   consts->MaxViewports = 1;
+   consts->ViewportSubpixelBits = 0;
+   consts->ViewportBounds.Min = 0;
+   consts->ViewportBounds.Max = 0;
 
    /** GL_ARB_uniform_buffer_object */
-   ctx->Const.MaxCombinedUniformBlocks = 36;
-   ctx->Const.MaxUniformBufferBindings = 36;
-   ctx->Const.MaxUniformBlockSize = 16384;
-   ctx->Const.UniformBufferOffsetAlignment = 1;
+   consts->MaxCombinedUniformBlocks = 36;
+   consts->MaxUniformBufferBindings = 36;
+   consts->MaxUniformBlockSize = 16384;
+   consts->UniformBufferOffsetAlignment = 1;
+
+   /* GL_ARB_explicit_uniform_location, GL_MAX_UNIFORM_LOCATIONS */
+   consts->MaxUserAssignableUniformLocations =
+      4 * MESA_SHADER_STAGES * MAX_UNIFORMS;
 
    for (i = 0; i < MESA_SHADER_STAGES; i++)
-      init_program_limits(ctx, i, &ctx->Const.Program[i]);
+      init_program_limits(consts, i, &consts->Program[i]);
 
-   ctx->Const.MaxProgramMatrices = MAX_PROGRAM_MATRICES;
-   ctx->Const.MaxProgramMatrixStackDepth = MAX_PROGRAM_MATRIX_STACK_DEPTH;
+   consts->MaxProgramMatrices = MAX_PROGRAM_MATRICES;
+   consts->MaxProgramMatrixStackDepth = MAX_PROGRAM_MATRIX_STACK_DEPTH;
 
-   /* CheckArrayBounds is overriden by drivers/x11 for X server */
-   ctx->Const.CheckArrayBounds = GL_FALSE;
+   /* Assume that if GLSL 1.30+ (or GLSL ES 3.00+) is supported that
+    * gl_VertexID is implemented using a native hardware register with OpenGL
+    * semantics.
+    */
+   consts->VertexID_is_zero_based = false;
 
    /* GL_ARB_draw_buffers */
-   ctx->Const.MaxDrawBuffers = MAX_DRAW_BUFFERS;
+   consts->MaxDrawBuffers = MAX_DRAW_BUFFERS;
 
-   ctx->Const.MaxColorAttachments = MAX_COLOR_ATTACHMENTS;
-   ctx->Const.MaxRenderbufferSize = MAX_RENDERBUFFER_SIZE;
+   consts->MaxColorAttachments = MAX_COLOR_ATTACHMENTS;
+   consts->MaxRenderbufferSize = MAX_RENDERBUFFER_SIZE;
 
-   ctx->Const.Program[MESA_SHADER_VERTEX].MaxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS;
-   ctx->Const.MaxCombinedTextureImageUnits = MAX_COMBINED_TEXTURE_IMAGE_UNITS;
-   ctx->Const.MaxVarying = 16; /* old limit not to break tnl and swrast */
-   ctx->Const.Program[MESA_SHADER_GEOMETRY].MaxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS;
-   ctx->Const.MaxGeometryOutputVertices = MAX_GEOMETRY_OUTPUT_VERTICES;
-   ctx->Const.MaxGeometryTotalOutputComponents = MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS;
+   consts->Program[MESA_SHADER_VERTEX].MaxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS;
+   consts->MaxCombinedTextureImageUnits = MAX_COMBINED_TEXTURE_IMAGE_UNITS;
+   consts->MaxVarying = 16; /* old limit not to break tnl and swrast */
+   consts->Program[MESA_SHADER_GEOMETRY].MaxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS;
+   consts->MaxGeometryOutputVertices = MAX_GEOMETRY_OUTPUT_VERTICES;
+   consts->MaxGeometryTotalOutputComponents = MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS;
 
    /* Shading language version */
-   if (_mesa_is_desktop_gl(ctx)) {
-      ctx->Const.GLSLVersion = 120;
-      _mesa_override_glsl_version(ctx);
-   }
-   else if (ctx->API == API_OPENGLES2) {
-      ctx->Const.GLSLVersion = 100;
-   }
-   else if (ctx->API == API_OPENGLES) {
-      ctx->Const.GLSLVersion = 0; /* GLSL not supported */
-   }
+   consts->GLSLVersion = 120;
+   _mesa_override_glsl_version(consts);
+
+#ifdef DEBUG
+   consts->GenerateTemporaryNames = true;
+#else
+   consts->GenerateTemporaryNames = false;
+#endif
 
    /* GL_ARB_framebuffer_object */
-   ctx->Const.MaxSamples = 0;
+   consts->MaxSamples = 0;
 
-   /* GL_ARB_sync */
-   ctx->Const.MaxServerWaitTimeout = 0x1fff7fffffffULL;
+   /* GLSL default if NativeIntegers == FALSE */
+   consts->UniformBooleanTrue = FLOAT_AS_UNION(1.0f).u;
 
-   /* GL_ATI_envmap_bumpmap */
-   ctx->Const.SupportedBumpUnits = SUPPORTED_ATI_BUMP_UNITS;
+   /* GL_ARB_sync */
+   consts->MaxServerWaitTimeout = 0x1fff7fffffffULL;
 
    /* GL_EXT_provoking_vertex */
-   ctx->Const.QuadsFollowProvokingVertexConvention = GL_TRUE;
+   consts->QuadsFollowProvokingVertexConvention = GL_TRUE;
 
    /* GL_EXT_transform_feedback */
-   ctx->Const.MaxTransformFeedbackBuffers = MAX_FEEDBACK_BUFFERS;
-   ctx->Const.MaxTransformFeedbackSeparateComponents = 4 * MAX_FEEDBACK_ATTRIBS;
-   ctx->Const.MaxTransformFeedbackInterleavedComponents = 4 * MAX_FEEDBACK_ATTRIBS;
-   ctx->Const.MaxVertexStreams = 1;
+   consts->MaxTransformFeedbackBuffers = MAX_FEEDBACK_BUFFERS;
+   consts->MaxTransformFeedbackSeparateComponents = 4 * MAX_FEEDBACK_ATTRIBS;
+   consts->MaxTransformFeedbackInterleavedComponents = 4 * MAX_FEEDBACK_ATTRIBS;
+   consts->MaxVertexStreams = 1;
 
    /* GL 3.2  */
-   ctx->Const.ProfileMask = ctx->API == API_OPENGL_CORE
+   consts->ProfileMask = api == API_OPENGL_CORE
                           ? GL_CONTEXT_CORE_PROFILE_BIT
                           : GL_CONTEXT_COMPATIBILITY_PROFILE_BIT;
 
+   /* GL 4.4 */
+   consts->MaxVertexAttribStride = 2048;
+
    /** GL_EXT_gpu_shader4 */
-   ctx->Const.MinProgramTexelOffset = -8;
-   ctx->Const.MaxProgramTexelOffset = 7;
+   consts->MinProgramTexelOffset = -8;
+   consts->MaxProgramTexelOffset = 7;
 
    /* GL_ARB_texture_gather */
-   ctx->Const.MinProgramTextureGatherOffset = -8;
-   ctx->Const.MaxProgramTextureGatherOffset = 7;
+   consts->MinProgramTextureGatherOffset = -8;
+   consts->MaxProgramTextureGatherOffset = 7;
 
    /* GL_ARB_robustness */
-   ctx->Const.ResetStrategy = GL_NO_RESET_NOTIFICATION_ARB;
-
-   /* PrimitiveRestart */
-   ctx->Const.PrimitiveRestartInSoftware = GL_FALSE;
+   consts->ResetStrategy = GL_NO_RESET_NOTIFICATION_ARB;
 
    /* ES 3.0 or ARB_ES3_compatibility */
-   ctx->Const.MaxElementIndex = 0xffffffffu;
+   consts->MaxElementIndex = 0xffffffffu;
 
    /* GL_ARB_texture_multisample */
-   ctx->Const.MaxColorTextureSamples = 1;
-   ctx->Const.MaxDepthTextureSamples = 1;
-   ctx->Const.MaxIntegerSamples = 1;
+   consts->MaxColorTextureSamples = 1;
+   consts->MaxDepthTextureSamples = 1;
+   consts->MaxIntegerSamples = 1;
 
    /* GL_ARB_shader_atomic_counters */
-   ctx->Const.MaxAtomicBufferBindings = MAX_COMBINED_ATOMIC_BUFFERS;
-   ctx->Const.MaxAtomicBufferSize = MAX_ATOMIC_COUNTERS * ATOMIC_COUNTER_SIZE;
-   ctx->Const.MaxCombinedAtomicBuffers = MAX_COMBINED_ATOMIC_BUFFERS;
-   ctx->Const.MaxCombinedAtomicCounters = MAX_ATOMIC_COUNTERS;
+   consts->MaxAtomicBufferBindings = MAX_COMBINED_ATOMIC_BUFFERS;
+   consts->MaxAtomicBufferSize = MAX_ATOMIC_COUNTERS * ATOMIC_COUNTER_SIZE;
+   consts->MaxCombinedAtomicBuffers = MAX_COMBINED_ATOMIC_BUFFERS;
+   consts->MaxCombinedAtomicCounters = MAX_ATOMIC_COUNTERS;
 
    /* GL_ARB_vertex_attrib_binding */
-   ctx->Const.MaxVertexAttribRelativeOffset = 2047;
-   ctx->Const.MaxVertexAttribBindings = MAX_VERTEX_GENERIC_ATTRIBS;
+   consts->MaxVertexAttribRelativeOffset = 2047;
+   consts->MaxVertexAttribBindings = MAX_VERTEX_GENERIC_ATTRIBS;
 
    /* GL_ARB_compute_shader */
-   ctx->Const.MaxComputeWorkGroupCount[0] = 65535;
-   ctx->Const.MaxComputeWorkGroupCount[1] = 65535;
-   ctx->Const.MaxComputeWorkGroupCount[2] = 65535;
-   ctx->Const.MaxComputeWorkGroupSize[0] = 1024;
-   ctx->Const.MaxComputeWorkGroupSize[1] = 1024;
-   ctx->Const.MaxComputeWorkGroupSize[2] = 64;
-   ctx->Const.MaxComputeWorkGroupInvocations = 1024;
+   consts->MaxComputeWorkGroupCount[0] = 65535;
+   consts->MaxComputeWorkGroupCount[1] = 65535;
+   consts->MaxComputeWorkGroupCount[2] = 65535;
+   consts->MaxComputeWorkGroupSize[0] = 1024;
+   consts->MaxComputeWorkGroupSize[1] = 1024;
+   consts->MaxComputeWorkGroupSize[2] = 64;
+   consts->MaxComputeWorkGroupInvocations = 1024;
 
    /** GL_ARB_gpu_shader5 */
-   ctx->Const.MinFragmentInterpolationOffset = MIN_FRAGMENT_INTERPOLATION_OFFSET;
-   ctx->Const.MaxFragmentInterpolationOffset = MAX_FRAGMENT_INTERPOLATION_OFFSET;
+   consts->MinFragmentInterpolationOffset = MIN_FRAGMENT_INTERPOLATION_OFFSET;
+   consts->MaxFragmentInterpolationOffset = MAX_FRAGMENT_INTERPOLATION_OFFSET;
+
+   /** GL_KHR_context_flush_control */
+   consts->ContextReleaseBehavior = GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH;
 }
 
 
@@ -721,6 +734,8 @@ _mesa_init_constants(struct gl_context *ctx)
 static void
 check_context_limits(struct gl_context *ctx)
 {
+   (void) ctx;
+
    /* check that we don't exceed the size of various bitfields */
    assert(VARYING_SLOT_MAX <=
          (8 * sizeof(ctx->VertexProgram._Current->Base.OutputsWritten)));
@@ -787,10 +802,10 @@ init_attrib_groups(struct gl_context *ctx)
    assert(ctx);
 
    /* Constants */
-   _mesa_init_constants( ctx );
+   _mesa_init_constants(&ctx->Const, ctx->API);
 
    /* Extensions */
-   _mesa_init_extensions( ctx );
+   _mesa_init_extensions(&ctx->Extensions);
 
    /* Attribute Groups */
    _mesa_init_accum( ctx );
@@ -807,6 +822,7 @@ init_attrib_groups(struct gl_context *ctx)
    _mesa_init_feedback( ctx );
    _mesa_init_fog( ctx );
    _mesa_init_hint( ctx );
+   _mesa_init_image_units( ctx );
    _mesa_init_line( ctx );
    _mesa_init_lighting( ctx );
    _mesa_init_matrix( ctx );
@@ -867,13 +883,69 @@ update_default_objects(struct gl_context *ctx)
 }
 
 
+/* XXX this is temporary and should be removed at some point in the
+ * future when there's a reasonable expectation that the libGL library
+ * contains the _glapi_new_nop_table() and _glapi_set_nop_handler()
+ * functions which were added in Mesa 10.6.
+ */
+#if !defined(_WIN32)
+/* Avoid libGL / driver ABI break */
+#define USE_GLAPI_NOP_FEATURES 0
+#else
+#define USE_GLAPI_NOP_FEATURES 1
+#endif
+
+
+/**
+ * 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
+ */
+#if USE_GLAPI_NOP_FEATURES
+static void
+nop_handler(const char *name)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   if (ctx) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "%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
+}
+#endif
+
+
 /**
- * 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.
+ * Special no-op glFlush, see below.
  */
-int
-_mesa_generic_nop(void)
+#if defined(_WIN32)
+static void GLAPIENTRY
+nop_glFlush(void)
+{
+   /* don't record an error like we do in nop_handler() */
+}
+#endif
+
+
+#if !USE_GLAPI_NOP_FEATURES
+static int
+generic_nop(void)
 {
    GET_CURRENT_CONTEXT(ctx);
    _mesa_error(ctx, GL_INVALID_OPERATION,
@@ -881,30 +953,79 @@ _mesa_generic_nop(void)
                "(unsupported extension or deprecated function?)");
    return 0;
 }
+#endif
 
 
 /**
- * Allocate and initialize a new dispatch table.
+ * Create a new API dispatch table in which all entries point to the
+ * generic_nop() function.  This will not work on Windows because of
+ * the __stdcall convention which requires the callee to clean up the
+ * call stack.  That's impossible with one generic no-op function.
  */
 struct _glapi_table *
-_mesa_alloc_dispatch_table()
+_mesa_new_nop_table(unsigned numEntries)
 {
-   /* Find the larger of Mesa's dispatch table and libGL's dispatch table.
-    * In practice, this'll be the same for stand-alone Mesa.  But for DRI
-    * Mesa we do this to accomodate different versions of libGL and various
-    * DRI drivers.
-    */
-   GLint numEntries = MAX2(_glapi_get_dispatch_table_size(), _gloffset_COUNT);
    struct _glapi_table *table;
 
+#if !USE_GLAPI_NOP_FEATURES
    table = malloc(numEntries * sizeof(_glapi_proc));
    if (table) {
       _glapi_proc *entry = (_glapi_proc *) table;
-      GLint i;
+      unsigned i;
       for (i = 0; i < numEntries; i++) {
-         entry[i] = (_glapi_proc) _mesa_generic_nop;
+         entry[i] = (_glapi_proc) generic_nop;
       }
    }
+#else
+   table = _glapi_new_nop_table(numEntries);
+#endif
+   return table;
+}
+
+
+/**
+ * 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.
+ */
+static struct _glapi_table *
+alloc_dispatch_table(void)
+{
+   /* Find the larger of Mesa's dispatch table and libGL's dispatch table.
+    * In practice, this'll be the same for stand-alone Mesa.  But for DRI
+    * Mesa we do this to accommodate different versions of libGL and various
+    * DRI drivers.
+    */
+   int numEntries = MAX2(_glapi_get_dispatch_table_size(), _gloffset_COUNT);
+
+   struct _glapi_table *table = _mesa_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().
+       *
+       * The MS opengl32.dll library apparently calls glFlush from
+       * wglGetProcAddress().  If we're inside glBegin/End(), glFlush
+       * will dispatch to _mesa_generic_nop() and we'll generate a
+       * GL_INVALID_OPERATION error.
+       *
+       * The specific case which hits this is piglit's primitive-restart
+       * test which calls glPrimitiveRestartNV() inside glBegin/End.  The
+       * first time we call glPrimitiveRestartNV() Piglit's API dispatch
+       * code will try to resolve the function by calling wglGetProcAddress.
+       * This raises GL_INVALID_OPERATION and an assert(glGetError()==0)
+       * will fail causing the test to fail.  By suppressing the error, the
+       * assertion passes and the test continues.
+       */
+      SET_Flush(table, nop_glFlush);
+   }
+#endif
+
+#if USE_GLAPI_NOP_FEATURES
+   _glapi_set_nop_handler(nop_handler);
+#endif
+
    return table;
 }
 
@@ -940,7 +1061,7 @@ create_beginend_table(const struct gl_context *ctx)
 {
    struct _glapi_table *table;
 
-   table = _mesa_alloc_dispatch_table();
+   table = alloc_dispatch_table();
    if (!table)
       return NULL;
 
@@ -1079,17 +1200,17 @@ _mesa_initialize_context(struct gl_context *ctx,
       goto fail;
 
    /* setup the API dispatch tables with all nop functions */
-   ctx->OutsideBeginEnd = _mesa_alloc_dispatch_table();
+   ctx->OutsideBeginEnd = alloc_dispatch_table();
    if (!ctx->OutsideBeginEnd)
       goto fail;
    ctx->Exec = ctx->OutsideBeginEnd;
    ctx->CurrentDispatch = ctx->OutsideBeginEnd;
 
    ctx->FragmentProgram._MaintainTexEnvProgram
-      = (_mesa_getenv("MESA_TEX_PROG") != NULL);
+      = (getenv("MESA_TEX_PROG") != NULL);
 
    ctx->VertexProgram._MaintainTnlProgram
-      = (_mesa_getenv("MESA_TNL_PROG") != NULL);
+      = (getenv("MESA_TNL_PROG") != NULL);
    if (ctx->VertexProgram._MaintainTnlProgram) {
       /* this is required... */
       ctx->FragmentProgram._MaintainTexEnvProgram = GL_TRUE;
@@ -1106,7 +1227,7 @@ _mesa_initialize_context(struct gl_context *ctx,
    switch (ctx->API) {
    case API_OPENGL_COMPAT:
       ctx->BeginEnd = create_beginend_table(ctx);
-      ctx->Save = _mesa_alloc_dispatch_table();
+      ctx->Save = alloc_dispatch_table();
       if (!ctx->BeginEnd || !ctx->Save)
          goto fail;
 
@@ -1212,6 +1333,9 @@ _mesa_free_context_data( struct gl_context *ctx )
    _mesa_reference_vertprog(ctx, &ctx->VertexProgram._Current, NULL);
    _mesa_reference_vertprog(ctx, &ctx->VertexProgram._TnlProgram, NULL);
 
+   _mesa_reference_geomprog(ctx, &ctx->GeometryProgram.Current, NULL);
+   _mesa_reference_geomprog(ctx, &ctx->GeometryProgram._Current, NULL);
+
    _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, NULL);
    _mesa_reference_fragprog(ctx, &ctx->FragmentProgram._Current, NULL);
    _mesa_reference_fragprog(ctx, &ctx->FragmentProgram._TexEnvProgram, NULL);
@@ -1221,11 +1345,9 @@ _mesa_free_context_data( struct gl_context *ctx )
 
    _mesa_free_attrib_data(ctx);
    _mesa_free_buffer_objects(ctx);
-   _mesa_free_lighting_data( ctx );
    _mesa_free_eval_data( ctx );
    _mesa_free_texture_data( ctx );
    _mesa_free_matrix_data( ctx );
-   _mesa_free_viewport_data( ctx );
    _mesa_free_pipeline_data(ctx);
    _mesa_free_program_data(ctx);
    _mesa_free_shader_state(ctx);
@@ -1386,17 +1508,10 @@ _mesa_copy_context( const struct gl_context *src, struct gl_context *dst,
       dst->Transform = src->Transform;
    }
    if (mask & GL_VIEWPORT_BIT) {
-      /* Cannot use memcpy, because of pointers in GLmatrix _WindowMap */
       unsigned i;
       for (i = 0; i < src->Const.MaxViewports; i++) {
-         dst->ViewportArray[i].X = src->ViewportArray[i].X;
-         dst->ViewportArray[i].Y = src->ViewportArray[i].Y;
-         dst->ViewportArray[i].Width = src->ViewportArray[i].Width;
-         dst->ViewportArray[i].Height = src->ViewportArray[i].Height;
-         dst->ViewportArray[i].Near = src->ViewportArray[i].Near;
-         dst->ViewportArray[i].Far = src->ViewportArray[i].Far;
-         _math_matrix_copy(&dst->ViewportArray[i]._WindowMap,
-                           &src->ViewportArray[i]._WindowMap);
+         /* OK to memcpy */
+         dst->ViewportArray[i] = src->ViewportArray[i];
       }
    }
 
@@ -1489,7 +1604,10 @@ handle_first_current(struct gl_context *ctx)
    GLenum buffer;
    GLint bufferIndex;
 
-   assert(ctx->Version > 0);
+   if (ctx->Version == 0) {
+      /* probably in the process of tearing down the context */
+      return;
+   }
 
    ctx->Extensions.String = _mesa_make_extension_string(ctx);
 
@@ -1505,7 +1623,8 @@ handle_first_current(struct gl_context *ctx)
          else
             buffer = GL_FRONT;
 
-         _mesa_drawbuffers(ctx, 1, &buffer, NULL /* destMask */);
+         _mesa_drawbuffers(ctx, ctx->DrawBuffer, 1, &buffer,
+                           NULL /* destMask */);
       }
 
       if (ctx->ReadBuffer != _mesa_get_incomplete_framebuffer()) {
@@ -1518,7 +1637,7 @@ handle_first_current(struct gl_context *ctx)
             bufferIndex = BUFFER_FRONT_LEFT;
          }
 
-         _mesa_readbuffer(ctx, buffer, bufferIndex);
+         _mesa_readbuffer(ctx, ctx->ReadBuffer, buffer, bufferIndex);
       }
    }
 
@@ -1527,7 +1646,7 @@ handle_first_current(struct gl_context *ctx)
     * first time each context is made current we'll print some useful
     * information.
     */
-   if (_mesa_getenv("MESA_INFO")) {
+   if (getenv("MESA_INFO")) {
       _mesa_print_info(ctx);
    }
 }
@@ -1574,14 +1693,16 @@ _mesa_make_current( struct gl_context *newCtx,
    }
 
    if (curCtx && 
-      (curCtx->WinSysDrawBuffer || curCtx->WinSysReadBuffer) &&
+       (curCtx->WinSysDrawBuffer || curCtx->WinSysReadBuffer) &&
        /* make sure this context is valid for flushing */
-      curCtx != newCtx)
+       curCtx != newCtx &&
+       curCtx->Const.ContextReleaseBehavior ==
+       GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH)
       _mesa_flush(curCtx);
 
    /* We used to call _glapi_check_multithread() here.  Now do it in drivers */
    _glapi_set_context((void *) newCtx);
-   ASSERT(_mesa_get_current_context() == newCtx);
+   assert(_mesa_get_current_context() == newCtx);
 
    if (!newCtx) {
       _glapi_set_dispatch(NULL);  /* none current */
@@ -1590,8 +1711,8 @@ _mesa_make_current( struct gl_context *newCtx,
       _glapi_set_dispatch(newCtx->CurrentDispatch);
 
       if (drawBuffer && readBuffer) {
-         ASSERT(_mesa_is_winsys_fbo(drawBuffer));
-         ASSERT(_mesa_is_winsys_fbo(readBuffer));
+         assert(_mesa_is_winsys_fbo(drawBuffer));
+         assert(_mesa_is_winsys_fbo(readBuffer));
          _mesa_reference_framebuffer(&newCtx->WinSysDrawBuffer, drawBuffer);
          _mesa_reference_framebuffer(&newCtx->WinSysReadBuffer, readBuffer);
 
@@ -1848,49 +1969,69 @@ shader_linked_or_absent(struct gl_context *ctx,
 GLboolean
 _mesa_valid_to_render(struct gl_context *ctx, const char *where)
 {
-   bool from_glsl_shader[MESA_SHADER_COMPUTE] = { false };
    unsigned i;
 
    /* This depends on having up to date derived state (shaders) */
    if (ctx->NewState)
       _mesa_update_state(ctx);
 
-   for (i = 0; i < MESA_SHADER_COMPUTE; i++) {
-      if (!shader_linked_or_absent(ctx, ctx->_Shader->CurrentProgram[i],
-                                   &from_glsl_shader[i], where))
-         return GL_FALSE;
-   }
+   if (ctx->API == API_OPENGL_CORE || ctx->API == API_OPENGLES2) {
+      bool from_glsl_shader[MESA_SHADER_COMPUTE] = { false };
 
-   /* Any shader stages that are not supplied by the GLSL shader and have
-    * assembly shaders enabled must now be validated.
-    */
-   if (!from_glsl_shader[MESA_SHADER_VERTEX]
-       && ctx->VertexProgram.Enabled && !ctx->VertexProgram._Enabled) {
-      _mesa_error(ctx, GL_INVALID_OPERATION,
-                 "%s(vertex program not valid)", where);
-      return GL_FALSE;
-   }
+      for (i = 0; i < MESA_SHADER_COMPUTE; i++) {
+         if (!shader_linked_or_absent(ctx, ctx->_Shader->CurrentProgram[i],
+                                      &from_glsl_shader[i], where))
+            return GL_FALSE;
+      }
 
-   /* FINISHME: If GL_NV_geometry_program4 is ever supported, the current
-    * FINISHME: geometry program should validated here.
-    */
-   (void) from_glsl_shader[MESA_SHADER_GEOMETRY];
+      /* In OpenGL Core Profile and OpenGL ES 2.0 / 3.0, there are no assembly
+       * shaders.  Don't check state related to those.
+       */
+   } else {
+      bool has_vertex_shader = false;
+      bool has_fragment_shader = false;
+
+      /* In OpenGL Compatibility Profile, there is only vertex shader and
+       * fragment shader.  We take this path also for API_OPENGLES because
+       * optimizing that path would make the other (more common) paths
+       * slightly slower.
+       */
+      if (!shader_linked_or_absent(ctx,
+                                   ctx->_Shader->CurrentProgram[MESA_SHADER_VERTEX],
+                                   &has_vertex_shader, where))
+         return GL_FALSE;
 
-   if (!from_glsl_shader[MESA_SHADER_FRAGMENT]) {
-      if (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled) {
-        _mesa_error(ctx, GL_INVALID_OPERATION,
-                    "%s(fragment program not valid)", where);
-        return GL_FALSE;
-      }
+      if (!shader_linked_or_absent(ctx,
+                                   ctx->_Shader->CurrentProgram[MESA_SHADER_FRAGMENT],
+                                   &has_fragment_shader, where))
+         return GL_FALSE;
 
-      /* If drawing to integer-valued color buffers, there must be an
-       * active fragment shader (GL_EXT_texture_integer).
+      /* Any shader stages that are not supplied by the GLSL shader and have
+       * assembly shaders enabled must now be validated.
        */
-      if (ctx->DrawBuffer && ctx->DrawBuffer->_IntegerColor) {
+      if (!has_vertex_shader
+          && ctx->VertexProgram.Enabled && !ctx->VertexProgram._Enabled) {
          _mesa_error(ctx, GL_INVALID_OPERATION,
-                     "%s(integer format but no fragment shader)", where);
+                     "%s(vertex program not valid)", where);
          return GL_FALSE;
       }
+
+      if (!has_fragment_shader) {
+         if (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled) {
+            _mesa_error(ctx, GL_INVALID_OPERATION,
+                        "%s(fragment program not valid)", where);
+            return GL_FALSE;
+         }
+
+         /* If drawing to integer-valued color buffers, there must be an
+          * active fragment shader (GL_EXT_texture_integer).
+          */
+         if (ctx->DrawBuffer && ctx->DrawBuffer->_IntegerColor) {
+            _mesa_error(ctx, GL_INVALID_OPERATION,
+                        "%s(integer format but no fragment shader)", where);
+            return GL_FALSE;
+         }
+      }
    }
 
    /* A pipeline object is bound */
@@ -1902,6 +2043,17 @@ _mesa_valid_to_render(struct gl_context *ctx, const char *where)
       }
    }
 
+   /* If a program is active and SSO not in use, check if validation of
+    * samplers succeeded for the active program. */
+   if (ctx->_Shader->ActiveProgram && ctx->_Shader != ctx->Pipeline.Current) {
+      char errMsg[100];
+      if (!_mesa_sampler_uniforms_are_valid(ctx->_Shader->ActiveProgram,
+                                            errMsg, 100)) {
+         _mesa_error(ctx, GL_INVALID_OPERATION, "%s", errMsg);
+         return GL_FALSE;
+      }
+   }
+
    if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
       _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
                   "%s(incomplete framebuffer)", where);